4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
6
6
* You may obtain a copy of the License at
7
- *
7
+ *
8
8
* http://www.apache.org/licenses/LICENSE-2.0
9
- *
9
+ *
10
10
* Unless required by applicable law or agreed to in writing, software
11
11
* distributed under the License is distributed on an "AS IS" BASIS,
12
12
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -114,34 +114,8 @@ private void processBranchIND(Function f, HighFunction hfunction, TaskMonitor mo
114
114
continue ; // skip switch owned by a different defined function
115
115
}
116
116
117
- AddressSetView containingBody =
118
- containingFunction != null ? containingFunction .getBody () : null ;
119
-
120
- Reference [] referencesFrom = instr .getReferencesFrom ();
121
- Address [] tableDest = table .getCases ();
122
-
123
- boolean foundNotThere = false ;
124
- int tableIndx ;
125
- for (tableIndx = 0 ; tableIndx < tableDest .length ; tableIndx ++) {
126
- monitor .checkCancelled ();
127
- boolean foundit = false ;
128
- if (containingBody != null && !containingBody .contains (tableDest [tableIndx ])) {
129
- // switch case missing from owner function's body
130
- foundNotThere = true ;
131
- break ;
132
- }
133
- for (Reference element : referencesFrom ) {
134
- if (element .getToAddress ().equals (tableDest [tableIndx ])) {
135
- foundit = true ;
136
- break ;
137
- }
138
- }
139
- if (!foundit ) {
140
- foundNotThere = true ;
141
- }
142
- }
143
117
// references already there, ignore this table
144
- if (! foundNotThere ) {
118
+ if (hasAllReferences ( monitor , table , instr , containingFunction ) ) {
145
119
continue ;
146
120
}
147
121
@@ -158,64 +132,156 @@ private void processBranchIND(Function f, HighFunction hfunction, TaskMonitor mo
158
132
labelSwitch (table , monitor );
159
133
160
134
// disassemble the table
161
- // pull out the current context so we can flow anything that needs to flow
162
- ProgramContext programContext = program .getProgramContext ();
163
- Register baseContextRegister = programContext .getBaseContextRegister ();
164
- RegisterValue switchContext = null ;
165
- if (baseContextRegister != null ) {
166
- // Use disassembler context based upon context register value at switch address (i.e., computed jump)
167
- // Only use flowing context bits
168
- switchContext = programContext .getRegisterValue (baseContextRegister , switchAddr );
169
- switchContext = programContext .getFlowValue (switchContext );
135
+ disassembleTable (monitor , table , instr , flowType );
136
+
137
+ // fixup the function body
138
+ fixupFunction (f , monitor , instr );
139
+ }
140
+ }
141
+
142
+ /*
143
+ * Fix the functions body with any newly reached code from the switch recovery
144
+ */
145
+ private void fixupFunction (Function f , TaskMonitor monitor , Instruction instr )
146
+ throws CancelledException {
147
+ Function fixupFunc = f ;
148
+
149
+ // Make sure this case isn't the result of an undefined function,
150
+ // that somehow one of the cases found a real function.
151
+ if (fixupFunc instanceof UndefinedFunction ) {
152
+ Function realFunc =
153
+ program .getFunctionManager ().getFunctionContaining (instr .getMinAddress ());
154
+ if (realFunc != null ) {
155
+ fixupFunc = realFunc ;
170
156
}
157
+ }
158
+ Instruction funcStartInstr =
159
+ program .getListing ().getInstructionAt (fixupFunc .getEntryPoint ());
160
+ CreateFunctionCmd .fixupFunctionBody (program , funcStartInstr , monitor );
161
+ }
171
162
172
- Listing listing = program .getListing ();
173
- Address [] cases = table .getCases ();
174
- AddressSet disSetList = new AddressSet ();
175
- for (Address caseStart : cases ) {
176
- monitor .checkCancelled ();
177
- instr .addMnemonicReference (caseStart , flowType , SourceType .ANALYSIS );
163
+ /*
164
+ * Disassemble all code reached from the table.
165
+ * Also adds the case flow references to the switching instruction.
166
+ */
167
+ private void disassembleTable (TaskMonitor monitor , JumpTable table ,
168
+ Instruction instr , FlowType flowType ) throws CancelledException {
169
+
170
+ Address switchAddr = table .getSwitchAddress ();
171
+
172
+ // pull out the current context so we can flow anything that needs to flow
173
+ ProgramContext programContext = program .getProgramContext ();
174
+ Register baseContextRegister = programContext .getBaseContextRegister ();
175
+ RegisterValue switchContext = null ;
176
+ if (baseContextRegister != null ) {
177
+ // Use disassembler context based upon context register value at switch address (i.e., computed jump)
178
+ // Only use flowing context bits
179
+ switchContext = programContext .getRegisterValue (baseContextRegister , switchAddr );
180
+ switchContext = programContext .getFlowValue (switchContext );
181
+ }
178
182
179
- // if conflict skip case
180
- if (listing .getUndefinedDataAt (caseStart ) == null ) {
181
- continue ;
182
- }
183
- // already done
184
- if (disSetList .contains (caseStart )) {
185
- continue ;
186
- }
187
- try {
188
- setSwitchTargetContext (programContext , caseStart , switchContext );
189
- }
190
- catch (ContextChangeException e ) {
191
- // This can occur when two or more threads are working on the same function
192
- continue ;
193
- }
194
- disSetList .add (caseStart );
183
+ Listing listing = program .getListing ();
184
+ Address [] cases = table .getCases ();
185
+ Integer [] caseValues = table .getLabelValues ();
186
+ AddressSet disSetList = new AddressSet ();
187
+
188
+ for (int caseIndex = 0 ; caseIndex < cases .length ; caseIndex ++) {
189
+ Address caseStart = cases [caseIndex ];
190
+ monitor .checkCancelled ();
191
+
192
+ if (!isDefaultCase (caseValues , caseIndex )) {
193
+ // only non-default cases should be added to the switching instruction
194
+ instr .addMnemonicReference (caseStart , flowType , SourceType .ANALYSIS );
195
195
}
196
196
197
- // do all cases at one time
198
- if (!disSetList .isEmpty ()) {
199
- DisassembleCommand cmd = new DisassembleCommand (disSetList , null , true );
200
- cmd .applyTo (program );
197
+ // if conflict skip case
198
+ if (listing .getUndefinedDataAt (caseStart ) == null ) {
199
+ continue ;
200
+ }
201
+ // already done
202
+ if (disSetList .contains (caseStart )) {
203
+ continue ;
204
+ }
205
+ try {
206
+ setSwitchTargetContext (programContext , caseStart , switchContext );
207
+ }
208
+ catch (ContextChangeException e ) {
209
+ // This can occur when two or more threads are working on the same function
210
+ continue ;
201
211
}
212
+ disSetList .add (caseStart );
213
+ }
202
214
203
- // fixup the function body
204
- // make sure this case isn't the result of an undefined function, that somehow one of the cases found a real function.
205
- Function fixupFunc = f ;
206
- if (fixupFunc instanceof UndefinedFunction ) {
207
- Function realFunc =
208
- program .getFunctionManager ().getFunctionContaining (instr .getMinAddress ());
209
- if (realFunc != null ) {
210
- fixupFunc = realFunc ;
215
+ // do all cases at one time
216
+ if (!disSetList .isEmpty ()) {
217
+ DisassembleCommand cmd = new DisassembleCommand (disSetList , null , true );
218
+ cmd .applyTo (program );
219
+ }
220
+ }
221
+
222
+ /*
223
+ * Check if this case index is a default case.
224
+ *
225
+ * In general, each case target address should have an associated caseValue.
226
+ * A case is default if it is first case to not have a case value, or has a magic case value.
227
+ * It is possible that there could be more than one case without a value. The code shouldn't
228
+ * blow up if this is the case.
229
+ *
230
+ * TODO: Should this check if the default case already has a reference to it
231
+ * from a conditional jump?
232
+ */
233
+ private boolean isDefaultCase (Integer [] caseValues , int caseIndex ) {
234
+ return (caseIndex == caseValues .length ) ||
235
+ (caseIndex < caseValues .length && caseValues [caseIndex ] == DEFAULT_CASE_VALUE );
236
+ }
237
+
238
+ /*
239
+ * Check if the switching instruction has all switch references already.
240
+ * Extra check for default case target as part of the table, when it shouldn't be.
241
+ */
242
+ public boolean hasAllReferences (TaskMonitor monitor , JumpTable table , Instruction instr ,
243
+ Function containingFunction ) throws CancelledException {
244
+ AddressSetView containingBody =
245
+ containingFunction != null ? containingFunction .getBody () : null ;
246
+
247
+ Reference [] referencesFrom = instr .getReferencesFrom ();
248
+ Address [] tableDest = table .getCases ();
249
+ Integer [] caseValues = table .getLabelValues ();
250
+
251
+ boolean allRefsFound = true ;
252
+ int caseIndex ;
253
+ for (caseIndex = 0 ; caseIndex < tableDest .length ; caseIndex ++) {
254
+ monitor .checkCancelled ();
255
+
256
+ // a case is default if it is first case to not have a value, or has a magic case value
257
+ boolean isDefaultCase = isDefaultCase (caseValues , caseIndex );
258
+
259
+ boolean foundit = false ;
260
+ if (containingBody != null && !containingBody .contains (tableDest [caseIndex ])) {
261
+ // switch case missing from owner function's body
262
+ allRefsFound = false ;
263
+ break ;
264
+ }
265
+ for (Reference element : referencesFrom ) {
266
+ if (element .getToAddress ().equals (tableDest [caseIndex ])) {
267
+ // good only if this isn't default case
268
+ // default case should not be on switching instruction
269
+ foundit = !isDefaultCase ;
270
+ break ;
271
+ } else if (isDefaultCase ) {
272
+ foundit = true ; // not finding default case is good
211
273
}
212
274
}
213
- Instruction funcStartInstr =
214
- program . getListing (). getInstructionAt ( fixupFunc . getEntryPoint ()) ;
215
- CreateFunctionCmd . fixupFunctionBody ( program , funcStartInstr , monitor );
275
+ if (! foundit ) {
276
+ allRefsFound = false ;
277
+ }
216
278
}
279
+ return allRefsFound ;
217
280
}
218
281
282
+ /*
283
+ * Set the context that should flow to the target so that target instruction will disassemble correctly
284
+ */
219
285
private void setSwitchTargetContext (ProgramContext programContext , Address targetStart , RegisterValue switchContext ) throws ContextChangeException {
220
286
if (switchContext == null ) {
221
287
return ;
@@ -236,6 +302,9 @@ private void setSwitchTargetContext(ProgramContext programContext, Address targe
236
302
program .getProgramContext ().setRegisterValue (targetStart , targetStart , switchContext );
237
303
}
238
304
305
+ /*
306
+ * Label switch table, cases, default with labels in namespace of the switch
307
+ */
239
308
private void labelSwitch (JumpTable table , TaskMonitor monitor ) throws CancelledException {
240
309
AddLabelCmd tableNameLabel =
241
310
new AddLabelCmd (table .getSwitchAddress (), "switchD" , SourceType .ANALYSIS );
@@ -266,27 +335,33 @@ private void labelSwitch(JumpTable table, TaskMonitor monitor) throws CancelledE
266
335
tableNameLabel .applyTo (program );
267
336
268
337
Address [] switchCases = table .getCases ();
269
- Integer [] caseLabels = table .getLabelValues ();
270
- Symbol [] caseSymbols = new Symbol [caseLabels .length ];
338
+ Integer [] caseValues = table .getLabelValues ();
339
+ Symbol [] caseSymbols = new Symbol [caseValues .length ];
271
340
SymbolTable symTable = program .getSymbolTable ();
272
- for (int i = 0 ; i < switchCases .length ; i ++) {
341
+
342
+ for (int caseIndex = 0 ; caseIndex < switchCases .length ; caseIndex ++) {
273
343
monitor .checkCancelled ();
274
- int offset = (i >= caseLabels .length ? i : caseLabels [i ]);
275
- String caseName = "caseD_" + Integer .toHexString (offset );
276
- if (offset == DEFAULT_CASE_VALUE ) { // magic constant to indicate default case
344
+
345
+ // if there are more switchCases than switch values, just use the caseIndex
346
+ int caseValue = (caseIndex < caseValues .length ) ? caseValues [caseIndex ] : caseIndex ;
347
+
348
+ boolean isDefaultCase = isDefaultCase (caseValues , caseIndex );
349
+
350
+ String caseName = "caseD_" + Integer .toHexString (caseValue );
351
+ if (isDefaultCase ) {
277
352
caseName = "default" ;
278
353
}
279
354
AddLabelCmd lcmd =
280
- new AddLabelCmd (switchCases [i ], caseName , space , SourceType .ANALYSIS );
355
+ new AddLabelCmd (switchCases [caseIndex ], caseName , space , SourceType .ANALYSIS );
281
356
282
357
Symbol oldSym = symTable .getPrimarySymbol (lcmd .getLabelAddr ());
283
358
if (oldSym != null && oldSym .getSource () == SourceType .ANALYSIS &&
284
359
oldSym .getName ().startsWith ("Addr" )) {
285
360
// cleanup AddressTableAnalyzer label
286
361
oldSym .delete ();
287
362
}
288
- if (lcmd .applyTo (program ) && i < caseSymbols .length ) {
289
- caseSymbols [i ] = symTable .getSymbol (caseName , switchCases [i ], space );
363
+ if (lcmd .applyTo (program ) && caseIndex < caseSymbols .length ) {
364
+ caseSymbols [caseIndex ] = symTable .getSymbol (caseName , switchCases [caseIndex ], space );
290
365
}
291
366
}
292
367
@@ -338,6 +413,9 @@ private Address[] getPointerTable(JumpTable.LoadTable loadtable, Address[] switc
338
413
return addresses ;
339
414
}
340
415
416
+ /*
417
+ * put labels on the switch table used to compute the target addresses of the switch.
418
+ */
341
419
private void labelLoadTable (JumpTable .LoadTable loadtable , Address [] switchCases ,
342
420
Symbol [] caseSymbols , Namespace space , TaskMonitor monitor ) throws CancelledException {
343
421
0 commit comments