forked from cseagle/blc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
globalcontext.hh
325 lines (293 loc) · 17.8 KB
/
globalcontext.hh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __GLOBALCONTEXT__
#define __GLOBALCONTEXT__
/// \file globalcontext.hh
/// \brief Utilities for getting address-based context to the disassembler and decompiler
#include "pcoderaw.hh"
#include "partmap.hh"
/// \brief Description of a context variable within the disassembly context \e blob
///
/// Disassembly context is stored as individual (integer) values packed into a sequence of words. This class
/// represents the info for encoding or decoding a single value within this sequence. A value is
/// a contiguous range of bits within one context word. Size can range from 1 bit up to the size of a word.
class ContextBitRange {
int4 word; ///< Index of word containing this context value
int4 startbit; ///< Starting bit of the value within its word (0=most significant bit 1=least significant)
int4 endbit; ///< Ending bit of the value within its word
int4 shift; ///< Right-shift amount to apply when unpacking this value from its word
uintm mask; ///< Mask to apply (after shifting) when unpacking this value from its word
public:
ContextBitRange(void) { } ///< Constructor for use with restoreXml()
ContextBitRange(int4 sbit,int4 ebit); ///< Construct a context value given an absolute bit range
int4 getShift(void) const { return shift; } ///< Return the shift-amount for \b this value
uintm getMask(void) const { return mask; } ///< Return the mask for \b this value
int4 getWord(void) const { return word; } ///< Return the word index for \b this value
/// \brief Set \b this value within a given context blob
///
/// \param vec is the given context blob to alter (as an array of uintm words)
/// \param val is the integer value to set
void setValue(uintm *vec,uintm val) const {
uintm newval = vec[word];
newval &= ~(mask<<shift);
newval |= ((val & mask)<<shift);
vec[word] = newval;
}
/// \brief Retrieve \b this value from a given context blob
///
/// \param vec is the given context blob (as an array of uintm words)
/// \return the recovered integer value
uintm getValue(const uintm *vec) const {
return ((vec[word]>>shift)&mask);
}
};
/// \brief A tracked register (Varnode) and the value it contains
///
/// This is the object returned when querying for tracked registers,
/// via ContextDatabase::getTrackedSet(). It holds the storage details of the register and
/// the actual value it holds at the point of the query.
struct TrackedContext {
VarnodeData loc; ///< Storage details of the register being tracked
uintb val; ///< The value of the register
void restoreXml(const Element *el,const AddrSpaceManager *manage); ///< Restore \b this from an XML stream
void saveXml(ostream &s) const; ///< Save \b this to an XML stream
};
typedef vector<TrackedContext> TrackedSet; ///< A set of tracked registers and their values (at one code point)
/// \brief An interface to a database of disassembly/decompiler \b context information
///
/// \b Context \b information is a set of named variables that hold concrete values at specific
/// addresses in the target executable being analyzed. A variable can hold different values at
/// different addresses, but a specific value at a specific address never changes. Analysis recovers
/// these values over time, populating this database, and querying this database lets analysis
/// provides concrete values for memory locations in context.
///
/// Context variables come in two flavors:
/// - \b Low-level \b context \b variables:
/// These can affect instruction decoding. These can be as small as a single bit and need to
/// be defined in the Sleigh specification (so that Sleigh knows how they effect disassembly).
/// These variables are not mapped to normal memory locations with an address space and offset
/// (although they often have a corresponding embedding into a normal memory location).
/// The model to keep in mind is a control register with specialized bit-fields within it.
/// - \b High-level \b tracked \b variables:
/// These are normal memory locations that are to be treated as constants across some range of
/// code. These are normally registers that are being tracked by the compiler outside the
/// domain of normal local and global variables. They have a specific value established by
/// the compiler coming into a function but are not supposed to be interpreted as a high-level
/// variable. Typical examples are the direction flag (for \e string instructions) and segment
/// registers. All tracked variables are interpreted as a constant value at the start of a
/// function, although the memory location can be recycled for other calculations later in the
/// function.
///
/// Low-level context variables can be queried and set by name -- getVariable(), setVariable(),
/// setVariableRegion() -- but the disassembler accesses all the variables at an address as a group
/// via getContext(), setContextChangePoint(), setContextRegion(). In this setting, all the values
/// are packed together in an array of words, a context \e blob (See ContextBitRange).
///
/// Tracked variables are also queried as a group via getTrackedSet() and createSet(). These return
/// a list of TrackedContext objects.
class ContextDatabase {
protected:
static void saveTracked(ostream &s,const Address &addr,const TrackedSet &vec);
static void restoreTracked(const Element *el,const AddrSpaceManager *manage,TrackedSet &vec);
/// \brief Retrieve the context variable description object by name
///
/// If the variable doesn't exist an exception is thrown.
/// \param nm is the name of the context value
/// \return the ContextBitRange object matching the name
virtual ContextBitRange &getVariable(const string &nm)=0;
/// \brief Retrieve the context variable description object by name
///
/// If the variable doesn't exist an exception is thrown.
/// \param nm is the name of the context value
/// \return the ContextBitRange object matching the name
virtual const ContextBitRange &getVariable(const string &nm) const=0;
/// \brief Grab the context blob(s) for the given address range, marking bits that will be set
///
/// This is an internal routine for obtaining the actual memory regions holding context values
/// for the address range. This also informs the system which bits are getting set. A split is forced
/// at the first address, and at least one memory region is passed back. The second address can be
/// invalid in which case the memory region passed back is valid from the first address to whatever
/// the next split point is.
/// \param res will hold pointers to memory regions for the given range
/// \param addr1 is the starting address of the range
/// \param addr2 is (1 past) the last address of the range or is invalid
/// \param num is the word index for the context value that will be set
/// \param mask is a mask of the value being set (within its word)
virtual void getRegionForSet(vector<uintm *> &res,const Address &addr1,
const Address &addr2,int4 num,uintm mask)=0;
/// \brief Grab the context blob(s) starting at the given address up to the first point of change
///
/// This is an internal routine for obtaining the actual memory regions holding context values
/// starting at the given address. A specific context value is specified, and all memory regions
/// are returned up to the first address where that particular context value changes.
/// \param res will hold pointers to memory regions being passed back
/// \param addr is the starting address of the regions to fetch
/// \param num is the word index for the specific context value being set
/// \param mask is a mask of the context value being set (within its word)
virtual void getRegionToChangePoint(vector<uintm *> &res,const Address &addr,int4 num,uintm mask)=0;
/// \brief Retrieve the memory region holding all default context values
///
/// This fetches the active memory holding the default context values on top of which all other context
/// values are overlaid.
/// \return the memory region holding all the default context values
virtual uintm *getDefaultValue(void)=0;
/// \brief Retrieve the memory region holding all default context values
///
/// This fetches the active memory holding the default context values on top of which all other context
/// values are overlaid.
/// \return the memory region holding all the default context values
virtual const uintm *getDefaultValue(void) const=0;
public:
virtual ~ContextDatabase() {} ///< Destructor
/// \brief Retrieve the number of words (uintm) in a context \e blob
///
/// \return the number of words
virtual int4 getContextSize(void) const=0;
/// \brief Register a new named context variable (as a bit range) with the database
///
/// A new variable is registered by providing a name and the range of bits the value will occupy
/// within the context blob. The full blob size is automatically increased if necessary. The variable
/// must be contained within a single word, and all variables must be registered before any values can
/// be set.
/// \param nm is the name of the new variable
/// \param sbit is the position of the variable's most significant bit within the blob
/// \param ebit is the position of the variable's least significant bit within the blob
virtual void registerVariable(const string &nm,int4 sbit,int4 ebit)=0;
/// \brief Get the context blob of values associated with a given address
///
/// \param addr is the given address
/// \return the memory region holding the context values for the address
virtual const uintm *getContext(const Address &addr) const=0;
/// \brief Get the context blob of values associated with a given address and its bounding offsets
///
/// In addition to the memory region, the range of addresses for which the region is valid
/// is passed back as offsets into the address space.
/// \param addr is the given address
/// \param first will hold the starting offset of the valid range
/// \param last will hold the ending offset of the valid range
/// \return the memory region holding the context values for the address
virtual const uintm *getContext(const Address &addr,uintb &first,uintb &last) const=0;
/// \brief Get the set of default values for all tracked registers
///
/// \return the list of TrackedContext objects
virtual TrackedSet &getTrackedDefault(void)=0;
/// \brief Get the set of tracked register values associated with the given address
///
/// \param addr is the given address
/// \return the list of TrackedContext objects
virtual const TrackedSet &getTrackedSet(const Address &addr) const=0;
/// \brief Create a tracked register set that is valid over the given range
///
/// This really should be an internal routine. The created set is empty, old values are blown
/// away. If old/default values are to be preserved, they must be copied back in.
/// \param addr1 is the starting address of the given range
/// \param addr2 is (1 past) the ending address of the given range
/// \return the empty set of tracked register values
virtual TrackedSet &createSet(const Address &addr1,const Address &addr2)=0;
/// \brief Serialize the entire database to an XML stream
///
/// \param s is the output stream
virtual void saveXml(ostream &s) const=0;
/// \brief Restore the state of \b this database object from a serialized XML stream
///
/// \param el is the root element of the XML describing the database state
/// \param manage is used to resolve address space references
virtual void restoreXml(const Element *el,const AddrSpaceManager *manage)=0;
/// \brief Add initial context state from XML tags in compiler/processor specifications
///
/// The database can be configured with a consistent initial state by providing
/// \<context_data> tags in either the compiler or processor specification file for the architecture
/// \param el is a \<context_data> tag
/// \param manage is used to resolve address space references
virtual void restoreFromSpec(const Element *el,const AddrSpaceManager *manage)=0;
void setVariableDefault(const string &nm,uintm val); ///< Provide a default value for a context variable
uintm getDefaultValue(const string &nm) const; ///< Retrieve the default value for a context variable
void setVariable(const string &nm,const Address &addr,uintm value); ///< Set a context value at the given address
uintm getVariable(const string &nm,const Address &addr) const; ///< Retrieve a context value at the given address
void setContextChangePoint(const Address &addr,int4 num,uintm mask,uintm value);
void setContextRegion(const Address &addr1,const Address &addr2,int4 num,uintm mask,uintm value);
void setVariableRegion(const string &nm,const Address &begad,
const Address &endad,uintm value);
uintb getTrackedValue(const VarnodeData &mem,const Address &point) const;
};
/// \brief An in-memory implementation of the ContextDatabase interface
///
/// Context blobs are held in a partition map on addresses. Any address within the map
/// indicates a \e split point, where the value of a context variable was explicitly changed.
/// Sets of tracked registers are held in a separate partition map.
class ContextInternal : public ContextDatabase {
/// \brief A context blob, holding context values across some range of code addresses
///
/// This is an internal object that allocates the actual "array of words" for a context blob.
/// An associated mask array holds 1-bits for context variables that were explicitly set for the
/// specific split point.
struct FreeArray {
uintm *array; ///< The "array of words" holding context variable values
uintm *mask; ///< The mask array indicating which variables are explicitly set
int4 size; ///< The number of words in the array
FreeArray(void) { size=0; array = (uintm *)0; mask = (uintm *)0; } ///< Construct an empty context blob
~FreeArray(void) { if (size!=0) { delete [] array; delete [] mask; } } ///< Destructor
void reset(int4 sz); ///< Resize the context blob, preserving old values
FreeArray &operator=(const FreeArray &op2); ///< Assignment operator
};
int4 size; ///< Number of words in a context blob (for this architecture)
map<string,ContextBitRange> variables; ///< Map from context variable name to description object
partmap<Address,FreeArray> database; ///< Partition map of context blobs (FreeArray)
partmap<Address,TrackedSet> trackbase; ///< Partition map of tracked register sets
void saveContext(ostream &s,const Address &addr,const uintm *vec) const;
void restoreContext(const Element *el,const Address &addr1,const Address &addr2);
virtual ContextBitRange &getVariable(const string &nm);
virtual const ContextBitRange &getVariable(const string &nm) const;
virtual void getRegionForSet(vector<uintm *> &res,const Address &addr1,
const Address &addr2,int4 num,uintm mask);
virtual void getRegionToChangePoint(vector<uintm *> &res,const Address &addr,int4 num,uintm mask);
virtual uintm *getDefaultValue(void) { return database.defaultValue().array; }
virtual const uintm *getDefaultValue(void) const { return database.defaultValue().array; }
public:
ContextInternal(void) { size = 0; }
virtual ~ContextInternal(void) {}
virtual int4 getContextSize(void) const { return size; }
virtual void registerVariable(const string &nm,int4 sbit,int4 ebit);
virtual const uintm *getContext(const Address &addr) const { return database.getValue(addr).array; }
virtual const uintm *getContext(const Address &addr,uintb &first,uintb &last) const;
virtual TrackedSet &getTrackedDefault(void) { return trackbase.defaultValue(); }
virtual const TrackedSet &getTrackedSet(const Address &addr) const { return trackbase.getValue(addr); }
virtual TrackedSet &createSet(const Address &addr1,const Address &addr2);
virtual void saveXml(ostream &s) const;
virtual void restoreXml(const Element *el,const AddrSpaceManager *manage);
virtual void restoreFromSpec(const Element *el,const AddrSpaceManager *manage);
};
/// \brief A helper class for caching the active context blob to minimize database lookups
///
/// This merely caches the last retrieved context blob ("array of words") and the range of
/// addresses over which the blob is valid. It encapsulates the ContextDatabase itself and
/// exposes a minimal interface (getContext() and setContext()).
class ContextCache {
ContextDatabase *database; ///< The encapsulated context database
bool allowset; ///< If set to \b false, and setContext() call is dropped
mutable AddrSpace *curspace; ///< Address space of the current valid range
mutable uintb first; ///< Starting offset of the current valid range
mutable uintb last; ///< Ending offset of the current valid range
mutable const uintm *context; ///< The current cached context blob
public:
ContextCache(ContextDatabase *db); ///< Construct given a context database
ContextDatabase *getDatabase(void) const { return database; } ///< Retrieve the encapsulated database object
void allowSet(bool val) { allowset = val; } ///< Toggle whether setContext() calls are ignored
void getContext(const Address &addr,uintm *buf) const; ///< Retrieve the context blob for the given address
void setContext(const Address &addr,int4 num,uintm mask,uintm value);
void setContext(const Address &addr1,const Address &addr2,int4 num,uintm mask,uintm value);
};
#endif