Skip to content

Commit abc3bf2

Browse files
authored
Merge pull request #1289 from ucgJhe/qdb
2 parents 6e9d4be + 7fc02da commit abc3bf2

File tree

2 files changed

+101
-3
lines changed

2 files changed

+101
-3
lines changed

qiling/debugger/qdb/branch_predictor/branch_predictor_x8664.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ def predict(self):
9898
prophecy.going = jump_reg_table.get(line.mnemonic)(self.ql.arch.regs.ecx)
9999

100100
if prophecy.going:
101-
takeaway_list = ["ptr", "dword", "[", "]"]
101+
takeaway_list = ["ptr", "dword", "qword", "[", "]"]
102102

103103
if len(line.op_str.split()) > 1:
104104
new_line = line.op_str.replace(":", "+")
@@ -114,7 +114,6 @@ def predict(self):
114114
if each_reg in new_line:
115115
new_line = re.sub(each_reg, hex(self.read_reg(each_reg)), new_line)
116116

117-
118117
prophecy.where = check_and_eval(new_line)
119118

120119
elif line.op_str in self.ql.arch.regs.register_mapping:

qiling/debugger/qdb/qdb.py

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66
import cmd
77

88
from typing import Optional, Tuple, Union
9+
from contextlib import contextmanager
910

1011
from qiling import Qiling
11-
from qiling.const import QL_OS, QL_ARCH
12+
from qiling.const import QL_OS, QL_ARCH, QL_ENDIAN
1213
from qiling.debugger import QlDebugger
1314

1415
from .utils import setup_context_render, setup_branch_predictor, setup_address_marker, SnapshotManager, run_qdb_script
@@ -119,6 +120,15 @@ def _run(self, address: int = 0, end: int = 0, count: int = 0) -> None:
119120

120121
self.ql.emu_start(begin=address, end=end, count=count)
121122

123+
@contextmanager
124+
def _save(self, reg=True, mem=True, hw=False, fd=False, cpu_context=False, os=False, loader=False):
125+
"""
126+
helper function for fetching specific context by emulating instructions
127+
"""
128+
saved_states = self.ql.save(reg=reg, mem=mem)
129+
yield self
130+
self.ql.restore(saved_states)
131+
122132
def save_reg_dump(func) -> None:
123133
"""
124134
decorator function for saving register dump
@@ -417,6 +427,94 @@ def do_mark(self, args=""):
417427

418428
qdb_print(QDB_MSG.INFO, f"mark symbol '{sym_name}' at address: 0x{loc:08x} ...")
419429

430+
@parse_int
431+
def do_show_args(self, argc: int = -1):
432+
"""
433+
show arguments of a function call
434+
default argc is 2 since we don't know the function definition
435+
"""
436+
437+
if argc is None:
438+
argc = -1
439+
440+
elif argc > 16:
441+
qdb_print(QDB_MSG.ERROR, 'Maximum argc is 16.')
442+
return
443+
444+
prophecy = self.predictor.predict()
445+
if not prophecy.going:
446+
qdb_print(QDB_MSG.ERROR, 'Not on a braching instruction currently.')
447+
return
448+
449+
if argc == -1:
450+
reg_n, stk_n = 2, 0
451+
else:
452+
if argc > 4:
453+
stk_n = argc - 4
454+
elif argc <= 4:
455+
reg_n, stk_n = argc, 0
456+
457+
ptr_size = self.ql.arch.pointersize
458+
459+
reg_args = []
460+
arch_type = self.ql.arch.type
461+
if arch_type in (QL_ARCH.MIPS, QL_ARCH.ARM, QL_ARCH.CORTEX_M, QL_ARCH.X8664):
462+
463+
reg_idx = None
464+
if arch_type == QL_ARCH.MIPS:
465+
slot_addr = self.cur_addr + ptr_size
466+
467+
op_str = self.predictor.disasm(slot_addr).op_str
468+
# register may be changed due to dealy slot
469+
if '$a' in op_str.split(',')[0]:
470+
dst_reg = op_str.split(',')[0].strip('$')
471+
reg_idx = int(dst_reg.strip('a'))
472+
473+
# fetch real value by emulating instruction in delay slot
474+
with self._save() as qdb:
475+
qdb._run(slot_addr, 0, count=1)
476+
real_val = self.ql.arch.regs.read(dst_reg)
477+
478+
reg_names = [f'a{d}'for d in range(reg_n)]
479+
if reg_idx != None:
480+
reg_names.pop(reg_idx)
481+
482+
elif arch_type in (QL_ARCH.ARM, QL_ARCH.CORTEX_M):
483+
reg_names = [f'r{d}'for d in range(reg_n)]
484+
485+
elif arch_type == QL_ARCH.X8664:
486+
reg_names = ('rdi', 'rsi', 'rdx', 'rcx', 'r8', 'r9')[:reg_n]
487+
488+
reg_args = [self.ql.arch.regs.read(reg_name) for reg_name in reg_names]
489+
if reg_idx != None:
490+
reg_args.insert(reg_idx, real_val)
491+
492+
reg_args = list(map(hex, reg_args))
493+
494+
elif arch_type == QL_ARCH.X86:
495+
stk_n = 2 if argc == -1 else argc
496+
497+
# read arguments on stack
498+
if stk_n >= 0:
499+
shadow_n = 0
500+
base_offset = self.ql.arch.regs.arch_sp
501+
502+
if arch_type in (QL_ARCH.X86, QL_ARCH.X8664):
503+
# shadow 1 pointer size for return address
504+
shadow_n = 1
505+
506+
elif arch_type == QL_ARCH.MIPS:
507+
# shadow 4 pointer size for mips
508+
shadow_n = 4
509+
510+
base_offset = self.ql.arch.regs.arch_sp + shadow_n * ptr_size
511+
stk_args = [self.ql.mem.read(base_offset+offset*ptr_size, ptr_size) for offset in range(stk_n)]
512+
endian = 'little' if self.ql.arch.endian == QL_ENDIAN.EL else 'big'
513+
stk_args = list(map(hex, map(lambda x: int.from_bytes(x, endian), stk_args)))
514+
515+
args = reg_args + stk_args
516+
qdb_print(QDB_MSG.INFO, f'args: {args}')
517+
420518
def do_show(self, *args) -> None:
421519
"""
422520
show some runtime information
@@ -473,6 +571,7 @@ def do_EOF(self, *args) -> None:
473571
do_r = do_run
474572
do_s = do_step_in
475573
do_n = do_step_over
574+
do_a = do_show_args
476575
do_j = do_jump
477576
do_m = do_mark
478577
do_q = do_quit

0 commit comments

Comments
 (0)