-
Notifications
You must be signed in to change notification settings - Fork 50
/
context.hh
204 lines (190 loc) · 9.4 KB
/
context.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
/* ###
* 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 __CONTEXT_HH__
#define __CONTEXT_HH__
#include "globalcontext.hh"
#include "opcodes.hh"
namespace ghidra {
class Token { // A multiple-byte sized chunk of pattern in a bitstream
string name;
int4 size; // Number of bytes in token;
int4 index; // Index of this token, for resolving offsets
bool bigendian;
public:
Token(const string &nm,int4 sz,bool be,int4 ind) : name(nm) { size = sz; bigendian=be; index = ind; }
int4 getSize(void) const { return size; }
bool isBigEndian(void) const { return bigendian; }
int4 getIndex(void) const { return index; }
const string &getName(void) const { return name; }
};
struct FixedHandle { // A handle that is fully resolved
AddrSpace *space;
uint4 size;
AddrSpace *offset_space; // Either null or where dynamic offset is stored
uintb offset_offset; // Either static offset or ptr offset
uint4 offset_size; // Size of pointer
AddrSpace *temp_space; // Consistent temporary location for value
uintb temp_offset;
};
class Constructor;
struct ConstructState {
Constructor *ct;
FixedHandle hand;
vector<ConstructState *> resolve;
ConstructState *parent;
int4 length; // Length of this instantiation of the constructor
uint4 offset; // Absolute offset (from start of instruction)
};
class TripleSymbol;
struct ContextSet { // Instructions for setting a global context value
TripleSymbol *sym; // Resolves to address where setting takes effect
ConstructState *point; // Point at which context set was made
int4 num; // Number of context word affected
uintm mask; // Bits within word affected
uintm value; // New setting for bits
bool flow; // Does the new context flow from its set point
};
class ParserWalker; // Forward declaration
class ParserWalkerChange;
class Translate;
class ParserContext {
friend class ParserWalker;
friend class ParserWalkerChange;
public:
enum { // Possible states of the ParserContext
uninitialized = 0, // Instruction has not been parsed at all
disassembly = 1, // Instruction is parsed in preparation for disassembly
pcode = 2 // Instruction is parsed in preparation for generating p-code
};
private:
Translate *translate; // Instruction parser
int4 parsestate;
AddrSpace *const_space;
uint1 buf[16]; // Buffer of bytes in the instruction stream
uintm *context; // Pointer to local context
int4 contextsize; // Number of entries in context array
ContextCache *contcache; // Interface for getting/setting context
vector<ContextSet> contextcommit;
Address addr; // Address of start of instruction
Address naddr; // Address of next instruction
mutable Address n2addr; // Address of instruction after the next
Address calladdr; // For injections, this is the address of the call being overridden
vector<ConstructState> state; // Current resolved instruction
ConstructState *base_state;
int4 alloc; // Number of ConstructState's allocated
int4 delayslot; // delayslot depth
public:
ParserContext(ContextCache *ccache,Translate *trans);
~ParserContext(void) { if (context != (uintm *)0) delete [] context; }
uint1 *getBuffer(void) { return buf; }
void initialize(int4 maxstate,int4 maxparam,AddrSpace *spc);
int4 getParserState(void) const { return parsestate; }
void setParserState(int4 st) { parsestate = st; }
void deallocateState(ParserWalkerChange &walker);
void allocateOperand(int4 i,ParserWalkerChange &walker);
void setAddr(const Address &ad) { addr = ad; n2addr = Address(); }
void setNaddr(const Address &ad) { naddr = ad; }
void setCalladdr(const Address &ad) { calladdr = ad; }
void addCommit(TripleSymbol *sym,int4 num,uintm mask,bool flow,ConstructState *point);
void clearCommits(void) { contextcommit.clear(); }
void applyCommits(void);
const Address &getAddr(void) const { return addr; }
const Address &getNaddr(void) const { return naddr; }
const Address &getN2addr(void) const;
const Address &getDestAddr(void) const { return calladdr; }
const Address &getRefAddr(void) const { return calladdr; }
AddrSpace *getCurSpace(void) const { return addr.getSpace(); }
AddrSpace *getConstSpace(void) const { return const_space; }
uintm getInstructionBytes(int4 byteoff,int4 numbytes,uint4 off) const;
uintm getContextBytes(int4 byteoff,int4 numbytes) const;
uintm getInstructionBits(int4 startbit,int4 size,uint4 off) const;
uintm getContextBits(int4 startbit,int4 size) const;
void setContextWord(int4 i,uintm val,uintm mask) { context[i] = (context[i]&(~mask))|(mask&val); }
void loadContext(void) { contcache->getContext(addr,context); }
int4 getLength(void) const { return base_state->length; }
void setDelaySlot(int4 val) { delayslot = val; }
int4 getDelaySlot(void) const { return delayslot; }
};
class ParserWalker { // A class for walking the ParserContext
const ParserContext *const_context;
const ParserContext *cross_context;
protected:
ConstructState *point; // The current node being visited
int4 depth; // Depth of the current node
int4 breadcrumb[32]; // Path of operands from root
public:
ParserWalker(const ParserContext *c) { const_context = c; cross_context = (const ParserContext *)0; }
ParserWalker(const ParserContext *c,const ParserContext *cross) { const_context = c; cross_context = cross; }
const ParserContext *getParserContext(void) const { return const_context; }
void baseState(void) { point = const_context->base_state; depth=0; breadcrumb[0] = 0; }
void setOutOfBandState(Constructor *ct,int4 index,ConstructState *tempstate,const ParserWalker &otherwalker);
bool isState(void) const { return (point != (ConstructState *)0); }
void pushOperand(int4 i) { breadcrumb[depth++] = i+1; point = point->resolve[i]; breadcrumb[depth] = 0; }
void popOperand(void) { point = point->parent; depth-= 1; }
uint4 getOffset(int4 i) const { if (i<0) return point->offset;
ConstructState *op=point->resolve[i]; return op->offset + op->length; }
Constructor *getConstructor(void) const { return point->ct; }
int4 getOperand(void) const { return breadcrumb[depth]; }
FixedHandle &getParentHandle(void) { return point->hand; }
const FixedHandle &getFixedHandle(int4 i) const { return point->resolve[i]->hand; }
AddrSpace *getCurSpace(void) const { return const_context->getCurSpace(); }
AddrSpace *getConstSpace(void) const { return const_context->getConstSpace(); }
const Address &getAddr(void) const { if (cross_context != (const ParserContext *)0) { return cross_context->getAddr(); } return const_context->getAddr(); }
const Address &getNaddr(void) const { if (cross_context != (const ParserContext *)0) { return cross_context->getNaddr();} return const_context->getNaddr(); }
const Address &getN2addr(void) const { if (cross_context != (const ParserContext *)0) { return cross_context->getN2addr();} return const_context->getN2addr(); }
const Address &getRefAddr(void) const { if (cross_context != (const ParserContext *)0) { return cross_context->getRefAddr();} return const_context->getRefAddr(); }
const Address &getDestAddr(void) const { if (cross_context != (const ParserContext *)0) { return cross_context->getDestAddr();} return const_context->getDestAddr(); }
int4 getLength(void) const { return const_context->getLength(); }
uintm getInstructionBytes(int4 byteoff,int4 numbytes) const {
return const_context->getInstructionBytes(byteoff,numbytes,point->offset); }
uintm getContextBytes(int4 byteoff,int4 numbytes) const {
return const_context->getContextBytes(byteoff,numbytes); }
uintm getInstructionBits(int4 startbit,int4 size) const {
return const_context->getInstructionBits(startbit,size,point->offset); }
uintm getContextBits(int4 startbit,int4 size) const {
return const_context->getContextBits(startbit,size); }
};
class ParserWalkerChange : public ParserWalker { // Extension to walker that allows for on the fly modifications to tree
friend class ParserContext;
ParserContext *context;
public:
ParserWalkerChange(ParserContext *c) : ParserWalker(c) { context = c; }
ParserContext *getParserContext(void) { return context; }
ConstructState *getPoint(void) { return point; }
void setOffset(uint4 off) { point->offset = off; }
void setConstructor(Constructor *c) { point->ct = c; }
void setCurrentLength(int4 len) { point->length = len; }
void calcCurrentLength(int4 length,int4 numopers);
};
struct SleighError : public LowlevelError {
SleighError(const string &s) : LowlevelError(s) {}
};
inline void ParserContext::deallocateState(ParserWalkerChange &walker) {
alloc = 1;
walker.context=this;
walker.baseState();
}
inline void ParserContext::allocateOperand(int4 i,ParserWalkerChange &walker) {
ConstructState *opstate = &state[alloc++];
opstate->parent = walker.point;
opstate->ct = (Constructor *)0;
walker.point->resolve[i] = opstate;
walker.breadcrumb[walker.depth++] += 1;
walker.point = opstate;
walker.breadcrumb[walker.depth] = 0;
}
} // End namespace ghidra
#endif