Merge pull request #1407 from ucgJhe/qdb

Qdb improvements
This commit is contained in:
xwings
2023-11-12 19:30:29 +08:00
committed by GitHub
2 changed files with 68 additions and 29 deletions
+60 -24
View File
@@ -5,11 +5,11 @@
import cmd
from typing import Optional, Tuple, Union
from typing import Optional, Tuple, Union, List
from contextlib import contextmanager
from qiling import Qiling
from qiling.const import QL_OS, QL_ARCH, QL_ENDIAN
from qiling.const import QL_OS, QL_ARCH, QL_ENDIAN, QL_STATE, QL_VERBOSE
from qiling.debugger import QlDebugger
from .utils import setup_context_render, setup_branch_predictor, setup_address_marker, SnapshotManager, run_qdb_script
@@ -25,7 +25,7 @@ class QlQdb(cmd.Cmd, QlDebugger):
The built-in debugger of Qiling Framework
"""
def __init__(self, ql: Qiling, init_hook: str = "", rr: bool = False, script: str = "") -> None:
def __init__(self, ql: Qiling, init_hook: List[str] = [], rr: bool = False, script: str = "") -> None:
"""
@init_hook: the entry to be paused at
@rr: record/replay debugging
@@ -45,9 +45,10 @@ class QlQdb(cmd.Cmd, QlDebugger):
super().__init__()
self.dbg_hook(init_hook)
# filter out entry_point of loader if presented
self.dbg_hook(list(filter(lambda d: int(d, 0) != self.ql.loader.entry_point, init_hook)))
def dbg_hook(self, init_hook: str):
def dbg_hook(self, init_hook: List[str]):
"""
initial hook to prepare everything we need
"""
@@ -67,7 +68,7 @@ class QlQdb(cmd.Cmd, QlDebugger):
if bp.hitted:
return
qdb_print(QDB_MSG.INFO, f"hit breakpoint at 0x{self.cur_addr:08x}")
qdb_print(QDB_MSG.INFO, f"hit breakpoint at {self.cur_addr:#x}")
bp.hitted = True
ql.stop()
@@ -75,12 +76,6 @@ class QlQdb(cmd.Cmd, QlDebugger):
self.ql.hook_code(bp_handler, self.bp_list)
if self.ql.os.type == QL_OS.BLOB:
self.ql.loader.entry_point = self.ql.loader.load_address
elif init_hook and self.ql.loader.entry_point != int(init_hook, 0):
self.do_breakpoint(init_hook)
if self.ql.entry_point:
self.cur_addr = self.ql.entry_point
else:
@@ -88,6 +83,39 @@ class QlQdb(cmd.Cmd, QlDebugger):
self.init_state = self.ql.save()
# stop emulator once interp. have been done emulating
if addr_elf_entry := getattr(self.ql.loader, 'elf_entry'):
handler = self.ql.hook_address(lambda ql: ql.stop(), addr_elf_entry)
else:
handler = self.ql.hook_address(lambda ql: ql.stop(), self.ql.loader.entry_point)
# suppress logging temporary
_verbose = self.ql.verbose
self.ql.verbose = QL_VERBOSE.DISABLED
# init os for integrity of hooks and patches,
self.ql.os.run()
handler.remove()
# ignore the memory unmap error for now, due to the MIPS memory layout issue
try:
self.ql.mem.unmap_all()
except:
pass
self.ql.restore(self.init_state)
# resotre logging verbose
self.ql.verbose = _verbose
if self.ql.os.type is QL_OS.BLOB:
self.ql.loader.entry_point = self.ql.loader.load_address
elif init_hook:
for each_hook in init_hook:
self.do_breakpoint(each_hook)
if self._script:
run_qdb_script(self, self._script)
else:
@@ -121,14 +149,7 @@ class QlQdb(cmd.Cmd, QlDebugger):
if getattr(self.ql.arch, 'is_thumb', False):
address |= 0b1
# assume we're running PE if on Windows
if self.ql.os.type == QL_OS.WINDOWS:
self.ql.count = count
self.ql.entry_point = address
self.ql.os.run()
else:
self.ql.emu_start(begin=address, end=end, count=count)
self.ql.emu_start(begin=address, end=end, count=count)
@contextmanager
def _save(self, reg=True, mem=True, hw=False, fd=False, cpu_context=False, os=False, loader=False):
@@ -372,7 +393,6 @@ class QlQdb(cmd.Cmd, QlDebugger):
"""
if self.ql.arch != QL_ARCH.CORTEX_M:
self.ql.restore(self.init_state)
self.do_context()
@@ -528,13 +548,29 @@ class QlQdb(cmd.Cmd, QlDebugger):
args = reg_args + stk_args
qdb_print(QDB_MSG.INFO, f'args: {args}')
def do_show(self, *args) -> None:
def do_show(self, keyword: Optional[str] = None, *args) -> None:
"""
show some runtime information
"""
for info_line in self.ql.mem.get_formatted_mapinfo():
qdb_print(QDB_MSG.INFO, info_line)
qdb_print(QDB_MSG.INFO, f"Entry point: {self.ql.loader.entry_point:#x}")
if addr_elf_entry := getattr(self.ql.loader, 'elf_entry'):
qdb_print(QDB_MSG.INFO, f"ELF entry: {addr_elf_entry:#x}")
info_lines = iter(self.ql.mem.get_formatted_mapinfo())
# print filed name first
qdb_print(QDB_MSG.INFO, next(info_lines))
# keyword filtering
if keyword:
lines = filter(lambda line: keyword in line, info_lines)
else:
lines = info_lines
for line in lines:
qdb_print(QDB_MSG.INFO, line)
qdb_print(QDB_MSG.INFO, f"Breakpoints: {[hex(addr) for addr in self.bp_list.keys()]}")
qdb_print(QDB_MSG.INFO, f"Marked symbol: {[{key:hex(val)} for key,val in self.marker.mark_list]}")
+8 -5
View File
@@ -350,15 +350,18 @@ def select_debugger(options: Union[str, bool]) -> Optional[QlClassInit['QlDebugg
return None
# qdb init args are independent and may include any combination of: rr enable, init hook and script
for a in args:
if a == 'rr':
arg_init_hook = []
for arg in args:
if arg == 'rr':
kwargs['rr'] = True
elif __int_nothrow(a) is not None:
kwargs['init_hook'] = a
elif __int_nothrow(arg) is not None:
arg_init_hook.append(arg)
else:
kwargs['script'] = a
kwargs['script'] = arg
else:
kwargs['init_hook'] = arg_init_hook
else:
raise QlErrorOutput('Debugger not supported')