@@ -60,6 +60,7 @@ def get_pypcode_context(
60
60
61
61
Arguments:
62
62
arch: Quokka program architecture
63
+ endian: Architecture endianness
63
64
64
65
Raises:
65
66
PypcodeError: if the conversion for arch is not found
@@ -74,7 +75,7 @@ def get_pypcode_context(
74
75
quokka .analysis .ArchARM64 : "AARCH64:LE:64:v8A" ,
75
76
quokka .analysis .ArchARMThumb : "ARM:LE:32:v8T" ,
76
77
quokka .analysis .ArchMIPS : "MIPS:LE:32:default" ,
77
- quokka .analysis .ArchMIPS : "MIPS:LE:64:default" ,
78
+ quokka .analysis .ArchMIPS64 : "MIPS:LE:64:default" ,
78
79
quokka .analysis .ArchPPC : "PowerPC:LE:32:default" ,
79
80
quokka .analysis .ArchPPC64 : "PowerPC:LE:64:default" ,
80
81
}
@@ -93,105 +94,6 @@ def get_pypcode_context(
93
94
return pypcode .Context (pcode_arch )
94
95
95
96
96
- def equality (self : pypcode .ContextObj , other : Any ) -> bool :
97
- """Check if two pypcode objets are the same
98
-
99
- We use monkey patching to attach the equality method to other classes and rely on
100
- __slots__ to check which fields to check.
101
-
102
- Arguments:
103
- self: First object
104
- other: Other variable
105
-
106
- Returns:
107
- Boolean for equality
108
- """
109
- return isinstance (other , self .__class__ ) and all (
110
- getattr (other , attr ) == getattr (self , attr )
111
- for attr in self .__slots__
112
- if attr != "cobj"
113
- )
114
-
115
-
116
- def object_hash (obj : pypcode .ContextObj ) -> int :
117
- """Create a hash value for a pypcode object
118
-
119
- This allows to create set of values.
120
-
121
- Arguments:
122
- obj: Object to hash
123
-
124
- Returns:
125
- An integer for the hash
126
- """
127
-
128
- assert isinstance (obj , pypcode .ContextObj )
129
- return sum (hash (getattr (obj , attr )) for attr in obj .__slots__ if attr != "cobj" )
130
-
131
-
132
- pypcode .Varnode .__eq__ = equality
133
- pypcode .Varnode .__hash__ = object_hash
134
-
135
- pypcode .AddrSpace .__eq__ = equality
136
- pypcode .AddrSpace .__hash__ = object_hash
137
-
138
- pypcode .PcodeOp .__eq__ = equality
139
- pypcode .PcodeOp .__hash__ = object_hash
140
-
141
-
142
- def combine_instructions (
143
- block : quokka .Block , translated_instructions : Sequence [pypcode .Translation ]
144
- ) -> List [pypcode .PcodeOp ]:
145
- """Combine instructions between the Quokka and PyPcode
146
-
147
- Some instruction are split between IDA and Ghidra, so we have to account for it.
148
- A problem for example is the support of prefixes (such LOCK) which are decoded as 2
149
- instructions by Ghidra (wrong) but only 1 by IDA (correct).
150
-
151
- Arguments:
152
- block: Quokka block
153
- translated_instructions: Translated instructions by Pypcode
154
-
155
- Raises
156
- PypcodeError: if the combination doesn't work
157
-
158
- Returns:
159
- A list of Pypcode statements
160
- """
161
- pcode_instructions : List [pypcode .PcodeOp ] = []
162
- translated_instructions = iter (translated_instructions )
163
-
164
- instruction : quokka .Instruction
165
- for instruction in block .instructions :
166
- instruction ._pcode_insts = []
167
- remaining_size : int = instruction .size
168
- while remaining_size > 0 :
169
- try :
170
- pcode_inst : pypcode .Translation = next (translated_instructions )
171
- except StopIteration as exc :
172
- logger .error (
173
- "Disassembly discrepancy between Pypcode / IDA: missing inst"
174
- )
175
- raise quokka .PypcodeError (
176
- f"Decoding error for block at 0x{ block .start :x} "
177
- ) from exc
178
-
179
- remaining_size -= pcode_inst .length
180
- instruction ._pcode_insts .extend (pcode_inst .ops )
181
-
182
- if remaining_size < 0 :
183
- logger .error (
184
- "Disassembly discrepancy between Pypcode / IDA: sizes mismatch"
185
- )
186
- raise quokka .PypcodeError (
187
- f"Decoding error for block at 0x{ block .start :x} "
188
- )
189
-
190
- pcode_instructions .extend (list (pcode_inst .ops ))
191
-
192
- return pcode_instructions
193
-
194
-
195
97
def update_pypcode_context (program : quokka .Program , is_thumb : bool ) -> pypcode .Context :
196
98
"""Return an appropriate pypcode context for the decoding
197
99
@@ -246,19 +148,22 @@ def pypcode_decode_block(block: quokka.Block) -> List[pypcode.PcodeOp]:
246
148
block .program , first_instruction .thumb
247
149
)
248
150
249
- # Translate
250
- translation = context .translate (
251
- code = block .bytes ,
252
- base = block .start ,
253
- max_inst = 0 ,
254
- )
255
-
256
- if translation .error :
257
- logger .error (translation .error .explain )
258
- raise quokka .PypcodeError (f"Decoding error for block at 0x{ block .start :x} " )
151
+ try :
152
+ # Translate
153
+ translation = context .translate (
154
+ block .bytes , # buf
155
+ block .start , # base_address
156
+ 0 , # max_bytes
157
+ 0 , # max_instructions
158
+ )
159
+ return translation .ops
259
160
260
- pcode_instructions = combine_instructions (block , translation .instructions )
261
- return pcode_instructions
161
+ except pypcode .BadDataError as e :
162
+ logger .error (e )
163
+ raise quokka .PypcodeError (f"Decoding error for block at 0x{ block .start :x} (BadDataError)" )
164
+ except pypcode .UnimplError as e :
165
+ logger .error (e )
166
+ raise quokka .PypcodeError (f"Decoding error for block at 0x{ block .start :x} (UnimplError)" )
262
167
263
168
264
169
def pypcode_decode_instruction (
@@ -268,7 +173,7 @@ def pypcode_decode_instruction(
268
173
269
174
This will return the list of Pcode operations done for the instruction.
270
175
Note that a (binary) instruction is expected to have several pcode instructions
271
- associated.
176
+ associated. When decoding a single instruction IMARK instructions are excluded!
272
177
273
178
Arguments:
274
179
inst: Instruction to translate
@@ -281,22 +186,19 @@ def pypcode_decode_instruction(
281
186
"""
282
187
283
188
context : pypcode .Context = update_pypcode_context (inst .program , inst .thumb )
284
- translation = context .translate (
285
- code = inst .bytes ,
286
- base = inst .address ,
287
- max_inst = 1 ,
288
- )
289
-
290
- if not translation .error :
291
-
292
- instructions = translation .instructions
293
- if len (instructions ) > 1 :
294
- logger .warning ("Mismatch of instruction size IDA/Pypcode" )
295
-
296
- instructions = list (
297
- itertools .chain .from_iterable (inst .ops for inst in instructions )
189
+ try :
190
+ translation = context .translate (
191
+ inst .bytes , # buf
192
+ inst .address , # base_address
193
+ 0 , # max_bytes
194
+ 1 , # max_instructions
298
195
)
299
- return instructions
300
196
301
- logger .error (translation .error .explain )
302
- raise quokka .PypcodeError ("Unable to decode instruction" )
197
+ return [x for x in translation .ops if x .opcode != pypcode .OpCode .IMARK ]
198
+
199
+ except pypcode .BadDataError as e :
200
+ logger .error (e )
201
+ raise quokka .PypcodeError (f"Unable to decode instruction (BadDataError)" )
202
+ except pypcode .UnimplError as e :
203
+ logger .error (e )
204
+ raise quokka .PypcodeError (f"Unable to decode instruction (UnimplError)" )
0 commit comments