Skip to content

Commit 30612cd

Browse files
committed
Qdb: add command show_args
1 parent bf39f1b commit 30612cd

File tree

2 files changed

+103
-3
lines changed

2 files changed

+103
-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: 102 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,96 @@ 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+
reg_n, stk_n = 4, 0
453+
if argc > 4:
454+
stk_n = argc - 4
455+
456+
ptr_size = self.ql.arch.pointersize
457+
458+
reg_args = []
459+
arch_type = self.ql.arch.type
460+
if arch_type in (QL_ARCH.MIPS, QL_ARCH.ARM, QL_ARCH.CORTEX_M, QL_ARCH.X8664):
461+
462+
reg_idx = None
463+
if arch_type == QL_ARCH.MIPS:
464+
slot_addr = self.cur_addr + ptr_size
465+
466+
op_str = self.predictor.disasm(slot_addr).op_str
467+
# register may be changed due to dealy slot
468+
if '$a' in op_str.split(',')[0]:
469+
dst_reg = op_str.split(',')[0].strip('$')
470+
reg_idx = int(dst_reg.strip('a'))
471+
472+
# fetch real value by emulating instruction in delay slot
473+
with self._save() as qdb:
474+
qdb._run(slot_addr, 0, count=1)
475+
real_val = self.ql.arch.regs.read(dst_reg)
476+
477+
reg_names = [f'a{d}'for d in range(reg_n)]
478+
479+
elif arch_type in (QL_ARCH.ARM, QL_ARCH.CORTEX_M):
480+
reg_names = [f'r{d}'for d in range(reg_n)]
481+
482+
elif arch_type == QL_ARCH.X8664:
483+
if argc == -1:
484+
reg_n = 2
485+
else:
486+
reg_n = argc
487+
488+
reg_names = ('rdi', 'rsi', 'rdx', 'rcx', 'r8', 'r9')[:reg_n]
489+
490+
reg_args = [self.ql.arch.regs.read(reg_name) for reg_name in reg_names]
491+
if reg_idx:
492+
regs_args.insert(reg_idx, real_val)
493+
494+
reg_args = list(map(hex, reg_args))
495+
496+
elif arch_type == QL_ARCH.X86:
497+
stk_n = 2 if argc == -1 else argc
498+
499+
# read arguments on stack
500+
if stk_n >= 0:
501+
shadow_n = 0
502+
base_offset = self.ql.arch.regs.arch_sp
503+
504+
if arch_type in (QL_ARCH.X86, QL_ARCH.X8664):
505+
# shadow 1 pointer size for return address
506+
shadow_n = 1
507+
508+
elif arch_type == QL_ARCH.MIPS:
509+
# shadow 4 pointer size for mips
510+
shadow_n = 4
511+
512+
base_offset = self.ql.arch.regs.arch_sp + shadow_n * ptr_size
513+
stk_args = [self.ql.mem.read(base_offset+offset*ptr_size, ptr_size) for offset in range(stk_n)]
514+
endian = 'little' if self.ql.arch.endian == QL_ENDIAN.EL else 'big'
515+
stk_args = list(map(hex, map(lambda x: int.from_bytes(x, endian), stk_args)))
516+
517+
args = reg_args + stk_args
518+
qdb_print(QDB_MSG.INFO, f'args: {args}')
519+
420520
def do_show(self, *args) -> None:
421521
"""
422522
show some runtime information
@@ -473,6 +573,7 @@ def do_EOF(self, *args) -> None:
473573
do_r = do_run
474574
do_s = do_step_in
475575
do_n = do_step_over
576+
do_a = do_show_args
476577
do_j = do_jump
477578
do_m = do_mark
478579
do_q = do_quit

0 commit comments

Comments
 (0)