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
|
import struct
from capstone import *
from capstone.ppc import *
from ..disassemble import *
from ..data.function import *
from ..context import Context
from ..builder import AsyncBuilder
class CPPDisassembler(Disassembler):
def __init__(self, builder: AsyncBuilder, function: Function, block_map, symbol_table, relocations, context: Context):
super().__init__([])
self.builder = builder
self.function = function
self.block_map = block_map
self.symbol_table = symbol_table
self.last_address = 0
self.relocations = relocations
self.unregister_references = set()
self.context = context
def get_symbol(self, addr):
if addr == self.function.addr:
return self.function
if addr in self.block_map:
return self.block_map[addr]
return self.symbol_table.always_get(addr)
def addr_to_label(self, addr) -> str:
symbol = self.get_symbol(addr)
if not symbol:
return None
return symbol.asm_reference(addr)
async def callback(self, address, insn, bytes):
if address in self.block_map:
block = self.block_map[address]
await self.builder.write("%s:" % block.identifier.label)
self.last_address = address
asm = None
raw = struct.unpack(">I", bytes)[0]
if insn != None:
asm = self.insn_to_text(address, insn, raw)
else:
# Capstone couldn't disassemble it
idx = (raw & 0xfc000000) >> 26
idx2 = (raw & 0x000007fe) >> 1
if idx == 31 and idx2 == 467: # mtspr
asm = disasm_mspr(raw, 1)
elif idx == 31 and idx2 == 339: # mfspr
asm = disasm_mspr(raw, 0)
elif idx == 31 and idx2 == 512: # mcrxr
asm = disasm_mcrxr(raw)
elif idx == 63 and idx2 == 32: # fcmpo
asm = disasm_fcmp(raw)
elif idx == 4:
asm = disasm_ps(raw) # Paired singles
elif idx in {56, 57, 60, 61}:
asm = disasm_ps_mem(raw, idx)
elif idx == 58:
asm = disasm_ld(raw) # ld
if asm == None:
asm = f".4byte 0x{raw:08X} /* unknown instruction */"
prefixComment = '/* %08X %02X %02X %02X %02X */' % (
address, bytes[0], bytes[1], bytes[2], bytes[3])
await self.builder.write(f"{prefixComment}\t{asm}")
def insn_to_text(self, addr, insn, raw) -> str:
id = insn.id
split_load = addr in self.splitDataLoads
offset_load = is_load_store_reg_offset(insn, None)
r2_addr = self.r2AddrInsns[addr]
r13_addr = self.r13AddrInsns[addr]
# Branch instruction replace immediate value with label
if id in {PPC_INS_B, PPC_INS_BL, PPC_INS_BDZ, PPC_INS_BDNZ}:
label = self.addr_to_label(insn.operands[0].imm)
if not label:
k = " ".join([f"{x:02X}" for x in insn.bytes])
self.context.warning(
f"{k}| '{label}' {addr:08X} to {insn.operands[0].imm:08X}, branch to unknown addr: {insn}")
sys.exit(1)
assert label
return f"{insn.mnemonic} {label}"
elif id == PPC_INS_BC:
branchPred = '+' if (insn.bytes[1] & 0x20) else ''
if insn.operands[0].type == PPC_OP_IMM:
label = self.addr_to_label(insn.operands[0].imm)
return f"{insn.mnemonic}{branchPred} {label}"
elif insn.operands[1].type == PPC_OP_IMM:
label = self.addr_to_label(insn.operands[1].imm)
reg = insn.reg_name(insn.operands[0].value.reg)
return f"{insn.mnemonic}{branchPred} {reg}, {label}"
# Handle split loads (high part)
elif id == PPC_INS_LIS and split_load:
loLoadInsn = self.linkedInsns[addr]
value = self.splitDataLoads[addr]
suffix = 'h' if loLoadInsn.id == PPC_INS_ORI else 'ha'
reg = insn.reg_name(insn.operands[0].reg)
name = self.addr_to_label(value)
if name:
return f"{insn.mnemonic} {reg}, {name}@{suffix} /* 0x{value:08X}@{suffix} */"
else:
if suffix == 'h':
fixed_value = value >> 16
fixed_value &= 0xFFFF
else:
fixed_value = value >> 16
fixed_value += (1 if (value & 0x8000) else 0)
fixed_value &= 0xFFFF
return f"{insn.mnemonic} {reg}, 0x{fixed_value:04X} /* 0x{value:08X}@{suffix} */"
# Handle split loads (low part)
elif id in {PPC_INS_ADDI, PPC_INS_ADDIC, PPC_INS_ORI} and split_load:
# NOTE: PPC_INS_ADDIC only works with a patched compiler
value = self.splitDataLoads[addr]
rA = insn.reg_name(insn.operands[0].reg)
rB = insn.reg_name(insn.operands[1].reg)
name = self.addr_to_label(value)
if name:
return f"{insn.mnemonic} {rA}, {rB}, {name}@l /* 0x{value:08X}@l */"
else:
fixed_value = value & 0xFFFF
return f"{insn.mnemonic} {rA}, {rB}, 0x{fixed_value:04X} /* 0x{value:08X}@l */"
elif offset_load and split_load:
value = self.splitDataLoads[addr]
rA = insn.reg_name(insn.operands[0].reg)
rB = insn.reg_name(insn.operands[1].mem.base)
name = self.addr_to_label(value)
if name:
return f"{insn.mnemonic} {rA}, {name}@l({rB}) /* 0x{value:08X}@l */"
else:
fixed_value = value & 0xFFFF
return f"{insn.mnemonic} {rA}, 0x{fixed_value:04X}({rB}) /* 0x{value:08X}@l */"
if r13_addr == self.common_r13_addr:
if id == PPC_INS_ADDI and insn.operands[1].reg == PPC_REG_R13:
imm = insn.operands[2].imm
value = r13_addr + sign_extend_16(imm)
rA = insn.reg_name(insn.operands[0].reg)
rB = insn.reg_name(insn.operands[1].reg)
name = self.addr_to_label(value)
if name:
# simplified mnemonic for: la rD,d(rA) equivalent to addi rD,rA,d
# https://www.nxp.com/docs/en/application-note/AN2491.pdf
return f"la {rA}, {name}({rB}) /* {value:08X}-_SDA_BASE_ */"
if is_load_store_reg_offset(insn, PPC_REG_R13):
value = r13_addr + \
sign_extend_16(insn.operands[1].mem.disp)
rA = insn.reg_name(insn.operands[0].reg)
rB = insn.reg_name(insn.operands[1].mem.base)
name = self.addr_to_label(value)
if name:
return f"{insn.mnemonic} {rA}, {name}({rB})"
if r2_addr == self.common_r2_addr:
if id == PPC_INS_ADDI and insn.operands[1].reg == PPC_REG_R2:
value = r2_addr + sign_extend_16(insn.operands[2].imm)
rA = insn.reg_name(insn.operands[0].reg)
rB = insn.reg_name(insn.operands[1].reg)
name = self.addr_to_label(value)
if name:
# simplified mnemonic for: la rD,d(rA) equivalent to addi rD,rA,d
# https://www.nxp.com/docs/en/application-note/AN2491.pdf
return f"la {rA}, {name}({rB}) /* {value:08X}-_SDA2_BASE_ */"
if is_load_store_reg_offset(insn, PPC_REG_R2):
value = r2_addr + \
sign_extend_16(insn.operands[1].mem.disp)
rA = insn.reg_name(insn.operands[0].reg)
rB = insn.reg_name(insn.operands[1].mem.base)
name = self.addr_to_label(value)
if name:
return f"{insn.mnemonic} {rA}, {name}({rB})"
# Sign-extend immediate values because Capstone is an idiot and doesn't do that automatically
if id in {PPC_INS_ADDI, PPC_INS_ADDIC, PPC_INS_SUBFIC, PPC_INS_MULLI} and (insn.operands[2].imm & 0x8000):
return "%s %s, %s, %i" % (insn.mnemonic, insn.reg_name(insn.operands[0].reg), insn.reg_name(insn.operands[1].value.reg), insn.operands[2].imm - 0x10000)
elif id in {PPC_INS_LI, PPC_INS_CMPWI} and (insn.operands[1].imm & 0x8000):
return "%s %s, %i" % (insn.mnemonic, insn.reg_name(insn.operands[0].reg), insn.operands[1].imm - 0x10000)
elif id == PPC_INS_CNTLZW:
return f"cntlzw {insn.op_str}"
elif id == PPC_INS_MTICCR:
A = 0x3fb
rB = insn.reg_name(insn.operands[0].reg)
return f"mtspr 0x{A:X}, {rB}"
elif id == PPC_INS_SYNC:
assert insn.operands[0].value.imm == 0
return 'sync'
elif id == PPC_INS_LWZ and insn.operands[0].type == PPC_OP_REG and insn.operands[0].reg == PPC_REG_R4 and insn.operands[1].type == PPC_OP_MEM and insn.operands[1].value.mem.base == PPC_REG_R0:
value = insn.operands[1].value.mem.disp
insn_str = 'lwz %s, %s0x%x(r0)' % (insn.reg_name(insn.operands[0].reg), '-' if (
value < 0) else '', ((-value) & 0xFFFF) if value < 0 else (value & 0xFFFF))
return insn_str
# "twui X" is shorthand for "twi 31, X"
elif id == PPC_INS_TWUI:
assert insn.operands[0].type == PPC_OP_REG
assert insn.operands[1].type == PPC_OP_IMM
rA = insn.reg_name(insn.operands[0].reg)
S = insn.operands[1].value.imm
insn_str = 'twi %i, %s, 0x%x' % (31, rA, S)
return insn_str
else:
if addr in self.registerLoads:
return f"{insn.mnemonic} {insn.op_str}\t/* effective address: {self.registerLoads[addr]:08X} */"
return f"{insn.mnemonic} {insn.op_str}"
|