def enable_full_trace(ql: Qiling): """Enable instruction-level tracing. Trace line will be emitted for each instruction before it gets executed. The info includes static data along with the relevant registers state and symbols resolving. Args: ql: qiling instance """ # enable detailed disassembly info md = ql.create_disassembler() md.detail = True # if available, use symbols map to resolve memory accesses symsmap = getattr(ql.loader, 'symsmap', {}) # show trace lines in a darker color so they would be easily distinguished from # ordinary log records DarkGray = "\x1b[90m" Default = "\x1b[39m" def __trace_hook(ql: Qiling, address: int, size: int): """[internal] Trace hook callback. """ for record in __get_trace_records(ql, address, size, md): line = __to_trace_line(record, symsmap) ql.log.debug(f'{DarkGray}{line}{Default}') ql.hook_code(__trace_hook)
def enable_full_trace(ql: Qiling): """Enable instruction-level tracing. Trace line will be emitted for each instruction before it gets executed. The info includes static data along with the relevant registers state and symbols resolving. Args: ql: qiling instance """ # enable detailed disassembly info md = ql.create_disassembler() md.detail = True assert md.arch == CS_ARCH_X86, 'currently available only for intel architecture' # if available, use symbols map to resolve memory accesses symsmap = getattr(ql.loader, 'symsmap', {}) # show trace lines in a darker color so they would be easily distinguished from # ordinary log records faded_color = "\033[2m" reset_color = "\033[0m" def __trace_hook(ql: Qiling, address: int, size: int): """[internal] Trace hook callback. """ for record in __get_trace_records(ql, address, size, md): line = __to_trace_line(record, symsmap) ql.log.debug(f'{faded_color}{line}{reset_color}') ql.hook_code(__trace_hook)
def enable_history_trace(ql: Qiling, nrecords: int): """Enable instruction-level tracing in history mode. To allow faster execution, the trace info collected throughout program execution is not emitted and undergo as minimal post-processing as possible. When program crahses, the last `nrecords` trace lines are shown. Args: ql: qiling instance nrecords: number of last records to show """ # enable detailed disassembly info md = ql.create_disassembler() md.detail = True # if available, use symbols map to resolve memory accesses symsmap = getattr(ql.loader, 'symsmap', {}) # wrap the trace records list to allow it to be passed and modified by-ref history: UserList[TraceRecord] = UserList() def __trace_hook(ql: Qiling, address: int, size: int): """[internal] Trace hook callback. """ recent = list(__get_trace_records(ql, address, size, md)) history.data = (history + recent)[-nrecords:] ql.hook_code(__trace_hook) # replace the emulation error handler with our own so we can emit the trace # records when program crashes. before we do that, we save the original one # so we can call it. orig_emu_error = ql.os.emu_error def __emu_error(*args): # first run the original emulation error handler orig_emu_error(*args) # then parse and emit the trace info we collected ql.log.error(f'History:') for record in history: line = __to_trace_line(record, symsmap) ql.log.error(line) ql.log.error(f'') ql.os.emu_error = __emu_error
def enable_history_trace(ql: Qiling, nrecords: int): """Enable instruction-level tracing in history mode. To allow faster execution, the trace info collected throughout program execution is not emitted and undergo as minimal post-processing as possible. When program crahses, the last `nrecords` trace lines are shown. Args: ql: qiling instance nrecords: number of last records to show """ # enable detailed disassembly info md = ql.create_disassembler() md.detail = True assert md.arch == CS_ARCH_X86, 'currently available only for intel architecture' # if available, use symbols map to resolve memory accesses symsmap = getattr(ql.loader, 'symsmap', {}) history: Deque[TraceRecord] = deque(maxlen=nrecords) def __trace_hook(ql: Qiling, address: int, size: int): """[internal] Trace hook callback. """ history.extend(__get_trace_records(ql, address, size, md)) ql.hook_code(__trace_hook) # replace the emulation error handler with our own so we can emit the trace # records when program crashes. before we do that, we save the original one # so we can call it. orig_emu_error = ql.os.emu_error def __emu_error(*args): # first run the original emulation error handler orig_emu_error(*args) # then parse and emit the trace info we collected ql.log.error(f'History:') for record in history: line = __to_trace_line(record, symsmap) ql.log.error(line) ql.log.error(f'') ql.os.emu_error = __emu_error