Skip to content

Commit 49b9f3f

Browse files
committed
qdb: partial mcu supported
1 parent 1f5e113 commit 49b9f3f

File tree

3 files changed

+80
-49
lines changed

3 files changed

+80
-49
lines changed

qiling/debugger/qdb/frontend.py

Lines changed: 42 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -164,67 +164,78 @@ def context_reg(ql: Qiling, saved_states: Optional[Mapping[str, int]] = None, /,
164164

165165
print(lines.format(*_cur_regs.values()))
166166

167-
elif ql.archtype in (QL_ARCH.ARM, QL_ARCH.ARM_THUMB):
167+
elif ql.archtype in (QL_ARCH.ARM, QL_ARCH.ARM_THUMB, QL_ARCH.CORTEX_M):
168+
169+
regs_in_row = 4
170+
if ql.archtype == QL_ARCH.CORTEX_M:
171+
regs_in_row = 3
168172

169173
_cur_regs.update({"sl": _cur_regs.pop("r10")})
170-
_cur_regs.update({"fp": _cur_regs.pop("r11")})
171174
_cur_regs.update({"ip": _cur_regs.pop("r12")})
175+
_cur_regs.update({"fp": _cur_regs.pop("r11")})
176+
177+
# for re-order
178+
_cur_regs.update({"xpsr": _cur_regs.pop("xpsr")})
179+
_cur_regs.update({"control": _cur_regs.pop("control")})
180+
_cur_regs.update({"primask": _cur_regs.pop("primask")})
181+
_cur_regs.update({"faultmask": _cur_regs.pop("faultmask")})
182+
_cur_regs.update({"basepri": _cur_regs.pop("basepri")})
172183

184+
_diff = None
173185
if saved_states is not None:
174186
_saved_states = copy.deepcopy(saved_states)
175187
_saved_states.update({"sl": _saved_states.pop("r10")})
176-
_saved_states.update({"fp": _saved_states.pop("r11")})
177188
_saved_states.update({"ip": _saved_states.pop("r12")})
189+
_saved_states.update({"fp": _saved_states.pop("r11")})
178190
_diff = [k for k in _cur_regs if _cur_regs[k] != _saved_states[k]]
179191

180-
else:
181-
_diff = None
182-
183192
lines = ""
184193
for idx, r in enumerate(_cur_regs, 1):
185-
line = "{}{:}: 0x{{:08x}} {}\t".format(_colors[(idx-1) // 4], r, color.END)
194+
195+
line = "{}{:}: 0x{{:08x}} {} ".format(_colors[(idx-1) // regs_in_row], r, color.END)
186196

187197
if _diff and r in _diff:
188198
line = "{}{}".format(color.UNDERLINE, color.BOLD) + line
189199

190-
if idx % 4 == 0:
200+
if idx % regs_in_row == 0:
191201
line += "\n"
192202

193203
lines += line
194204

195205
print(lines.format(*_cur_regs.values()))
196206
print(color.GREEN, "[{cpsr[mode]} mode], Thumb: {cpsr[thumb]}, FIQ: {cpsr[fiq]}, IRQ: {cpsr[irq]}, NEG: {cpsr[neg]}, ZERO: {cpsr[zero]}, Carry: {cpsr[carry]}, Overflow: {cpsr[overflow]}".format(cpsr=get_arm_flags(ql.reg.cpsr)), color.END, sep="")
197207

198-
# context render for Stack
199-
with context_printer(ql, "[ STACK ]", ruler="─"):
200-
201-
for idx in range(10):
202-
addr = ql.reg.arch_sp + idx * ql.pointersize
203-
val = ql.mem.read(addr, ql.pointersize)
204-
print(f"$sp+0x{idx*ql.pointersize:02x}│ [0x{addr:08x}] —▸ 0x{ql.unpack(val):08x}", end="")
208+
if ql.archtype != QL_ARCH.CORTEX_M:
209+
# context render for Stack, skip this for CORTEX_M
210+
with context_printer(ql, "[ STACK ]", ruler="─"):
205211

206-
try: # try to deference wether its a pointer
207-
buf = ql.mem.read(addr, ql.pointersize)
208-
except:
209-
buf = None
212+
for idx in range(10):
213+
addr = ql.reg.arch_sp + idx * ql.pointersize
214+
val = ql.mem.read(addr, ql.pointersize)
215+
print(f"$sp+0x{idx*ql.pointersize:02x}│ [0x{addr:08x}] —▸ 0x{ql.unpack(val):08x}", end="")
210216

211-
if (addr := ql.unpack(buf)):
212-
try: # try to deference again
217+
try: # try to deference wether its a pointer
213218
buf = ql.mem.read(addr, ql.pointersize)
214219
except:
215220
buf = None
216221

217-
if buf:
218-
try:
219-
s = ql.mem.string(addr)
222+
if (addr := ql.unpack(buf)):
223+
try: # try to deference again
224+
buf = ql.mem.read(addr, ql.pointersize)
220225
except:
221-
s = None
226+
buf = None
222227

223-
if s and s.isprintable():
224-
print(f" ◂— {ql.mem.string(addr)}", end="")
225-
else:
226-
print(f" ◂— 0x{ql.unpack(buf):08x}", end="")
227-
print()
228+
if buf:
229+
try:
230+
s = ql.mem.string(addr)
231+
except:
232+
s = None
233+
234+
if s and s.isprintable():
235+
print(f" ◂— {ql.mem.string(addr)}", end="")
236+
else:
237+
print(f" ◂— 0x{ql.unpack(buf):08x}", end="")
238+
print()
228239

229240

230241
def print_asm(ql: Qiling, insn: CsInsn, to_jump: Optional[bool] = None, address: int = None) -> None:
@@ -251,9 +262,7 @@ def context_asm(ql: Qiling, address: int) -> None:
251262

252263
past_list = []
253264

254-
if ql.archtype in (QL_ARCH.MIPS, QL_ARCH.ARM, QL_ARCH.ARM_THUMB):
255-
256-
line = disasm(ql, address-0x10)
265+
line = disasm(ql, address-0x10)
257266

258267
while line:
259268
if line.address == address:

qiling/debugger/qdb/qdb.py

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,15 @@ def dbg_hook(self: QlQdb, init_hook: str):
3939

4040
# self.ql.loader.entry_point # ld.so
4141
# self.ql.loader.elf_entry # .text of binary
42+
if not self.ql.baremetal:
4243

43-
if init_hook:
44-
init_hook = parse_int(init_hook)
44+
if init_hook:
45+
init_hook = parse_int(init_hook)
4546

46-
self.set_breakpoint(init_hook, is_temp=True)
47+
self.set_breakpoint(init_hook, is_temp=True)
4748

48-
self.cur_addr = self.ql.loader.entry_point
49-
self._init_state = self.ql.save()
49+
self.cur_addr = self.ql.loader.entry_point
50+
self._init_state = self.ql.save()
5051

5152
self.do_context()
5253
self.interactive()
@@ -102,18 +103,18 @@ def _restore(self: QlQdb, *args) -> None:
102103

103104
self.ql.restore(self._states_list.pop())
104105

105-
def _run(self: Qldbg, address: int = 0, count: int = 0) -> None:
106+
def _run(self: Qldbg, address: int = 0, end: int = 0, count: int = 0) -> None:
106107
"""
107108
internal function for emulating instruction
108109
"""
109110

110111
if not address:
111112
address = self.cur_addr
112113

113-
if self.ql.archtype in (QL_ARCH.ARM, QL_ARCH.ARM_THUMB) and is_thumb(self.ql.reg.cpsr):
114+
if self.ql.archtype in (QL_ARCH.ARM, QL_ARCH.ARM_THUMB, QL_ARCH.CORTEX_M) and is_thumb(self.ql.reg.cpsr):
114115
address |= 1
115116

116-
self.ql.emu_start(address, 0, count=count)
117+
self.ql.emu_start(begin=address, end=end, count=count)
117118

118119
def parseline(self: QlQdb, line: str) -> Tuple[Optional[str], Optional[str], str]:
119120
"""
@@ -196,6 +197,7 @@ def do_step(self: QlQdb, *args) -> Optional[bool]:
196197
print(f"{color.RED}[!] The program is not being run.{color.END}")
197198

198199
else:
200+
# save reg dump for data chaged highliting
199201
self._saved_reg_dump = dict(filter(lambda d: isinstance(d[0], str), self.ql.reg.save().items()))
200202

201203
_, next_stop = handle_bnj(self.ql, self.cur_addr)
@@ -206,13 +208,21 @@ def do_step(self: QlQdb, *args) -> Optional[bool]:
206208
if self.rr:
207209
self._save()
208210

209-
count = 1
210-
if self.ql.archtype == QL_ARCH.MIPS and next_stop != self.cur_addr + 4:
211-
# make sure delay slot executed
212-
count = 2
211+
if self.ql.baremetal:
212+
self.ql.arch.step()
213+
# self.ql.arch.run(count=1, end=self.ql.exit_point)
214+
# self._run(count=1)
215+
self.do_context()
213216

214-
self._run(count=count)
215-
self.do_context()
217+
else:
218+
219+
count = 1
220+
if self.ql.archtype == QL_ARCH.MIPS and next_stop != self.cur_addr + 4:
221+
# make sure delay slot executed
222+
count = 2
223+
224+
self._run(count=count)
225+
self.do_context()
216226

217227
def set_breakpoint(self: QlQdb, address: int, is_temp: bool = False) -> None:
218228
"""
@@ -262,6 +272,7 @@ def do_continue(self: QlQdb, address: str = "") -> None:
262272
address = parse_int(address)
263273

264274
print(f"{color.CYAN}continued from 0x{self.cur_addr:08x}{color.END}")
275+
265276
self._run(address)
266277

267278
def do_examine(self: QlQdb, line: str) -> None:

qiling/debugger/qdb/utils.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,16 @@ def dump_regs(ql: Qiling) -> Mapping[str, int]:
3636
"r12", "sp", "lr", "pc",
3737
)
3838

39+
elif ql.archtype == QL_ARCH.CORTEX_M:
40+
41+
_reg_order = (
42+
"r0", "r1", "r2", "r3",
43+
"r4", "r5", "r6", "r7",
44+
"r8", "r9", "r10", "r11",
45+
"r12", "sp", "lr", "pc",
46+
"xpsr", "control", "primask", "basepri", "faultmask"
47+
)
48+
3949
return {reg_name: getattr(ql.reg, reg_name) for reg_name in _reg_order}
4050

4151

@@ -87,6 +97,7 @@ def handle_bnj(ql: Qiling, cur_addr: str) -> Callable[[Qiling, str], int]:
8797
QL_ARCH.MIPS : handle_bnj_mips,
8898
QL_ARCH.ARM : handle_bnj_arm,
8999
QL_ARCH.ARM_THUMB: handle_bnj_arm,
100+
QL_ARCH.CORTEX_M : handle_bnj_arm,
90101
}.get(ql.archtype)(ql, cur_addr)
91102

92103

@@ -116,11 +127,11 @@ def disasm(ql: Qiling, address: int, detail: bool = False) -> Optional[int]:
116127
return ret
117128

118129

119-
def _read_inst(ql: Qiling, addr: str) -> int:
130+
def _read_inst(ql: Qiling, addr: int) -> int:
120131

121132
result = ql.mem.read(addr, 4)
122133

123-
if ql.archtype in (QL_ARCH.ARM, QL_ARCH.ARM_THUMB):
134+
if ql.archtype in (QL_ARCH.ARM, QL_ARCH.ARM_THUMB, QL_ARCH.CORTEX_M):
124135
if is_thumb(ql.reg.cpsr):
125136

126137
first_two = ql.unpack16(ql.mem.read(addr, 2))

0 commit comments

Comments
 (0)