forked from cseagle/blc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
context.cc
223 lines (197 loc) · 7.09 KB
/
context.cc
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
/* ###
* 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.
*/
#include "context.hh"
#include "slghsymbol.hh"
#include "translate.hh"
ParserContext::ParserContext(ContextCache *ccache)
{
parsestate = 0;
contcache = ccache;
if (ccache != (ContextCache *)0) {
contextsize = ccache->getDatabase()->getContextSize();
context = new uintm[ contextsize ];
}
else {
contextsize = 0;
context = (uintm *)0;
}
}
void ParserContext::initialize(int4 maxstate,int4 maxparam,AddrSpace *spc)
{
const_space = spc;
state.resize(maxstate);
state[0].parent = (ConstructState *)0;
for(int4 i=0;i<maxstate;++i)
state[i].resolve.resize(maxparam);
base_state = &state[0];
}
uintm ParserContext::getInstructionBytes(int4 bytestart,int4 size,uint4 off) const
{ // Get bytes from the instruction stream into a intm
// (assuming big endian format)
off += bytestart;
if (off >=16)
throw BadDataError("Instruction is using more than 16 bytes");
const uint1 *ptr = buf + off;
uintm res = 0;
for(int4 i=0;i<size;++i) {
res <<= 8;
res |= ptr[i];
}
return res;
}
uintm ParserContext::getInstructionBits(int4 startbit,int4 size,uint4 off) const
{
off += (startbit/8);
if (off >= 16)
throw BadDataError("Instruction is using more than 16 bytes");
const uint1 *ptr = buf + off;
startbit = startbit % 8;
int4 bytesize = (startbit+size-1)/8 + 1;
uintm res = 0;
for(int4 i=0;i<bytesize;++i) {
res <<= 8;
res |= ptr[i];
}
res <<= 8*(sizeof(uintm)-bytesize)+startbit; // Move starting bit to highest position
res >>= 8*sizeof(uintm)-size; // Shift to bottom of intm
return res;
}
uintm ParserContext::getContextBytes(int4 bytestart,int4 size) const
{ // Get bytes from context into a uintm
int4 intstart = bytestart / sizeof(uintm);
uintm res = context[ intstart ];
int4 byteOffset = bytestart % sizeof(uintm);
int4 unusedBytes = sizeof(uintm) - size;
res <<= byteOffset*8;
res >>= unusedBytes*8;
int4 remaining = size - sizeof(uintm) + byteOffset;
if ((remaining > 0)&&(++intstart < contextsize)) { // If we extend beyond boundary of a single uintm
uintm res2 = context[ intstart ];
unusedBytes = sizeof(uintm) - remaining;
res2 >>= unusedBytes * 8;
res |= res2;
}
return res;
}
uintm ParserContext::getContextBits(int4 startbit,int4 size) const
{
int4 intstart = startbit / (8*sizeof(uintm));
uintm res = context[ intstart ]; // Get intm containing highest bit
int4 bitOffset = startbit % (8*sizeof(uintm));
int4 unusedBits = 8*sizeof(uintm) - size;
res <<= bitOffset; // Shift startbit to highest position
res >>= unusedBits;
int4 remaining = size - 8*sizeof(uintm) + bitOffset;
if ((remaining > 0) && (++intstart < contextsize)) {
uintm res2 = context[ intstart ];
unusedBits = 8*sizeof(uintm) - remaining;
res2 >>= unusedBits;
res |= res2;
}
return res;
}
void ParserContext::addCommit(TripleSymbol *sym,int4 num,uintm mask,bool flow,ConstructState *point)
{
contextcommit.emplace_back();
ContextSet &set(contextcommit.back());
set.sym = sym;
set.point = point; // This is the current state
set.num = num;
set.mask = mask;
set.value = context[num] & mask;
set.flow = flow;
}
void ParserContext::applyCommits(void)
{
if (contextcommit.empty()) return;
ParserWalker walker(this);
walker.baseState();
vector<ContextSet>::iterator iter;
for(iter=contextcommit.begin();iter!=contextcommit.end();++iter) {
TripleSymbol *sym = (*iter).sym;
Address commitaddr;
if (sym->getType() == SleighSymbol::operand_symbol) {
// The value for an OperandSymbol is probabably already
// calculated, we just need to find the right
// tree node of the state
int4 i = ((OperandSymbol *)sym)->getIndex();
FixedHandle &h((*iter).point->resolve[i]->hand);
commitaddr = Address(h.space,h.offset_offset);
}
else {
FixedHandle hand;
sym->getFixedHandle(hand,walker);
commitaddr = Address(hand.space,hand.offset_offset);
}
if (commitaddr.isConstant()) {
// If the symbol handed to globalset was a computed value, the getFixedHandle calculation
// will return a value in the constant space. If this is a case, we explicitly convert the
// offset into the current address space
uintb newoff = AddrSpace::addressToByte(commitaddr.getOffset(),addr.getSpace()->getWordSize());
commitaddr = Address(addr.getSpace(),newoff);
}
// Commit context change
if ((*iter).flow) // The context flows
contcache->setContext(commitaddr,(*iter).num,(*iter).mask,(*iter).value);
else { // Set the context so that is doesn't flow
Address nextaddr = commitaddr + 1;
if (nextaddr.getOffset() < commitaddr.getOffset())
contcache->setContext(commitaddr,(*iter).num,(*iter).mask,(*iter).value);
else
contcache->setContext(commitaddr,nextaddr,(*iter).num,(*iter).mask,(*iter).value);
}
}
}
void ParserWalker::setOutOfBandState(Constructor *ct,int4 index,ConstructState *tempstate,const ParserWalker &otherwalker)
{ // Initialize walker for future calls into getInstructionBytes assuming -ct- is the current position in the walk
const ConstructState *pt = otherwalker.point;
int4 curdepth = otherwalker.depth;
while(pt->ct != ct) {
if (curdepth <= 0) return;
curdepth -= 1;
pt = pt->parent;
}
OperandSymbol *sym = ct->getOperand(index);
int4 i = sym->getOffsetBase();
// if i<0, i.e. the offset of the operand is constructor relative
// its possible that the branch corresponding to the operand
// has not been constructed yet. Context expressions are
// evaluated BEFORE the constructors branches are created.
// So we have to construct the offset explicitly.
if (i<0)
tempstate->offset = pt->offset + sym->getRelativeOffset();
else
tempstate->offset = pt->resolve[index]->offset;
tempstate->ct = ct;
tempstate->length = pt->length;
point = tempstate;
depth = 0;
breadcrumb[0] = 0;
}
void ParserWalkerChange::calcCurrentLength(int4 length,int4 numopers)
{ // Calculate the length of the current constructor
// state assuming all its operands are constructed
length += point->offset; // Convert relative length to absolute length
for(int4 i=0;i<numopers;++i) {
ConstructState *subpoint = point->resolve[i];
int4 sublength = subpoint->length + subpoint->offset;
// Since subpoint->offset is an absolute offset
// (relative to beginning of instruction) sublength
if (sublength > length) // is absolute and must be compared to absolute length
length = sublength;
}
point->length = length - point->offset; // Convert back to relative length
}