Emit tracing info for each and every instruction that is about to be executed. Args: ql: the qiling instance address: the address of the instruction that is about to be executed size: size of the instruction (in bytes) md: initialized disassembler object
(ql: Qiling, address: int, size: int, md: Cs)
| 30 | CS_UC_REGS = __map_regs() |
| 31 | |
| 32 | def trace(ql: Qiling, address: int, size: int, md: Cs): |
| 33 | """Emit tracing info for each and every instruction that is about to be executed. |
| 34 | |
| 35 | Args: |
| 36 | ql: the qiling instance |
| 37 | address: the address of the instruction that is about to be executed |
| 38 | size: size of the instruction (in bytes) |
| 39 | md: initialized disassembler object |
| 40 | """ |
| 41 | |
| 42 | # read current instruction bytes and disassemble it |
| 43 | buf = ql.mem.read(address, size) |
| 44 | insn = next(md.disasm(buf, address)) |
| 45 | |
| 46 | nibbles = ql.arch.bits // 4 |
| 47 | color_faded = '\033[2m' |
| 48 | color_reset = '\033[0m' |
| 49 | |
| 50 | # get values of the registers referenced by this instruction. |
| 51 | # |
| 52 | # note: since this method is called before the instruction has been emulated, the 'rip' |
| 53 | # register still points to the current instruction, while the instruction considers it |
| 54 | # as if it was pointing to the next one. that will cause 'rip' to show an incorrect value |
| 55 | reads = (f'{md.reg_name(reg)} = {ql.arch.regs.read(CS_UC_REGS[reg]):#x}' for reg in insn.regs_access()[0]) |
| 56 | |
| 57 | # construct a human-readable trace line |
| 58 | trace_line = f'{insn.address:0{nibbles}x} | {insn.bytes.hex():24s} {insn.mnemonic:12} {insn.op_str:35s} | {", ".join(reads)}' |
| 59 | |
| 60 | # emit the trace line in a faded color, so it would be easier to tell trace info from other log entries |
| 61 | ql.log.info(f'{color_faded}{trace_line}{color_reset}') |
| 62 | |
| 63 | if __name__ == "__main__": |
| 64 | ql = Qiling([r"rootfs/x8664_linux/bin/x8664_hello"], r"rootfs/x8664_linux") |