Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def predict(self):
prophecy.going = jump_reg_table.get(line.mnemonic)(self.ql.arch.regs.ecx)

if prophecy.going:
takeaway_list = ["ptr", "dword", "[", "]"]
takeaway_list = ["ptr", "dword", "qword", "[", "]"]

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


prophecy.where = check_and_eval(new_line)

elif line.op_str in self.ql.arch.regs.register_mapping:
Expand Down
101 changes: 100 additions & 1 deletion qiling/debugger/qdb/qdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
import cmd

from typing import Optional, Tuple, Union
from contextlib import contextmanager

from qiling import Qiling
from qiling.const import QL_OS, QL_ARCH
from qiling.const import QL_OS, QL_ARCH, QL_ENDIAN
from qiling.debugger import QlDebugger

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

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):
"""
helper function for fetching specific context by emulating instructions
"""
saved_states = self.ql.save(reg=reg, mem=mem)
yield self
self.ql.restore(saved_states)

def save_reg_dump(func) -> None:
"""
decorator function for saving register dump
Expand Down Expand Up @@ -417,6 +427,94 @@ def do_mark(self, args=""):

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

@parse_int
def do_show_args(self, argc: int = -1):
"""
show arguments of a function call
default argc is 2 since we don't know the function definition
"""

if argc is None:
argc = -1

elif argc > 16:
qdb_print(QDB_MSG.ERROR, 'Maximum argc is 16.')
return

prophecy = self.predictor.predict()
if not prophecy.going:
qdb_print(QDB_MSG.ERROR, 'Not on a braching instruction currently.')
return

if argc == -1:
reg_n, stk_n = 2, 0
else:
if argc > 4:
stk_n = argc - 4
elif argc <= 4:
reg_n, stk_n = argc, 0

ptr_size = self.ql.arch.pointersize

reg_args = []
arch_type = self.ql.arch.type
if arch_type in (QL_ARCH.MIPS, QL_ARCH.ARM, QL_ARCH.CORTEX_M, QL_ARCH.X8664):

reg_idx = None
if arch_type == QL_ARCH.MIPS:
slot_addr = self.cur_addr + ptr_size

op_str = self.predictor.disasm(slot_addr).op_str
# register may be changed due to dealy slot
if '$a' in op_str.split(',')[0]:
dst_reg = op_str.split(',')[0].strip('$')
reg_idx = int(dst_reg.strip('a'))

# fetch real value by emulating instruction in delay slot
with self._save() as qdb:
qdb._run(slot_addr, 0, count=1)
real_val = self.ql.arch.regs.read(dst_reg)

reg_names = [f'a{d}'for d in range(reg_n)]
if reg_idx != None:
reg_names.pop(reg_idx)

elif arch_type in (QL_ARCH.ARM, QL_ARCH.CORTEX_M):
reg_names = [f'r{d}'for d in range(reg_n)]

elif arch_type == QL_ARCH.X8664:
reg_names = ('rdi', 'rsi', 'rdx', 'rcx', 'r8', 'r9')[:reg_n]

reg_args = [self.ql.arch.regs.read(reg_name) for reg_name in reg_names]
if reg_idx != None:
reg_args.insert(reg_idx, real_val)

reg_args = list(map(hex, reg_args))

elif arch_type == QL_ARCH.X86:
stk_n = 2 if argc == -1 else argc

# read arguments on stack
if stk_n >= 0:
shadow_n = 0
base_offset = self.ql.arch.regs.arch_sp

if arch_type in (QL_ARCH.X86, QL_ARCH.X8664):
# shadow 1 pointer size for return address
shadow_n = 1

elif arch_type == QL_ARCH.MIPS:
# shadow 4 pointer size for mips
shadow_n = 4

base_offset = self.ql.arch.regs.arch_sp + shadow_n * ptr_size
stk_args = [self.ql.mem.read(base_offset+offset*ptr_size, ptr_size) for offset in range(stk_n)]
endian = 'little' if self.ql.arch.endian == QL_ENDIAN.EL else 'big'
stk_args = list(map(hex, map(lambda x: int.from_bytes(x, endian), stk_args)))

args = reg_args + stk_args
qdb_print(QDB_MSG.INFO, f'args: {args}')

def do_show(self, *args) -> None:
"""
show some runtime information
Expand Down Expand Up @@ -473,6 +571,7 @@ def do_EOF(self, *args) -> None:
do_r = do_run
do_s = do_step_in
do_n = do_step_over
do_a = do_show_args
do_j = do_jump
do_m = do_mark
do_q = do_quit
Expand Down