assembly 显示gdb中执行的每个汇编指令

42fyovps  于 2022-11-24  发布在  其他
关注(0)|答案(3)|浏览(198)

我目前有一个棘手的bug,它发生在我无法访问源代码或符号的地方,也就是说,我可以看到发生崩溃的指令及其地址,但仅此而已。我想做的是让gdb在不需要交互的情况下运行,并在运行时显示每条指令,但我还没有找到这样做的方法。
我希望实现的是这样的目标:

(gdb) /* some command */
0x2818a7c0: push   %ebp
0x2818a7c1: mov    %esp,%ebp
0x2818a7c3: push   %ebx
0x2818a7c4: sub    $0x4,%esp
...
0x28563622: mov    %esi,0x0(%eax)
Program received signal SIGSEGV, Segmentation fault.

我所做的是设置程序计数器的显示,如下所示:

(gdb) display/i $pc

然后使用stepi运行代码:

(gdb) stepi
1: x/i $pc  0x2818a7c0: push   %ebp

然而,崩溃是数百或数千条指令之遥,我希望有一种方法可以看到每一条指令(如果更喜欢的话,可以一起看到),而不必多次点击“enter”。此外,如果我手动操作,我会在每条指令之间看到一个(gdb)提示符,这是不太理想的。
我曾经简单地研究过scripting,但我唯一的想法是在main()上设置,让它显示并另一次中断(用于下一条指令),然后继续,但这样我就不能在commands块中使用commands,所以它不会像我想象的那样工作。
如果有必要的话,我正在开发FreeBSD。

k4ymrczo

k4ymrczo1#

以下内容应满足您的要求:

# not strictly required, but you'll likely want the log anyway
(gdb) set logging on

# ask gdb to not stop every screen-full
(gdb) set height 0

(gdb) while 1
 > x/i $pc
 > stepi
 > end

但是,这种调试方法很可能是徒劳的:即使在最琐碎的程序中也有太多的指令被执行。
一个更好的方法可能是运行程序直到崩溃,尝试了解当前函数正在做什么以及谁调用了它,并适当地设置断点。
在x86上,即使在完全剥离的可执行文件中,您也经常可以推导出函数边界。
另一件需要查看的事情是strace/truss输出,这样就可以看到崩溃点之前的系统调用。

iovurdzv

iovurdzv2#

Python脚本编写

这将给予比GDB脚本更大的灵活性来实现你疯狂的想法。
这里的主要问题,就像GDB脚本一样,对于大多数没有目标硬件支持的应用程序来说,这可能太慢了,例如:一个C hello世界只需要1分钟就可以处理18 k条指令。
gdb.py

class TraceAsm(gdb.Command):
    def __init__(self):
        super().__init__(
            'trace-asm',
            gdb.COMMAND_BREAKPOINTS,
            gdb.COMPLETE_NONE,
            False
        )
    def invoke(self, argument, from_tty):
        argv = gdb.string_to_argv(argument)
        if argv:
            gdb.write('Does not take any arguments.\n')
        else:
            done = False
            thread = gdb.inferiors()[0].threads()[0]
            last_path = None
            last_line = None
            with open('trace.tmp', 'w') as f:
                while thread.is_valid():
                    frame = gdb.selected_frame()
                    sal = frame.find_sal()
                    symtab = sal.symtab
                    if symtab:
                        path = symtab.fullname()
                        line = sal.line
                    else:
                        path = None
                        line = None
                    if path != last_path:
                        f.write("path {}{}".format(path, os.linesep))
                        last_path = path
                    if line != last_line:
                        f.write("line {}{}".format(line, os.linesep))
                        last_line = line
                    pc = frame.pc()
                    f.write("{} {} {}".format(hex(pc), frame.architecture().disassemble(pc)[0]['asm'], os.linesep))
                    gdb.execute('si', to_string=True)
TraceAsm()

GitHub上游。
主.S

global _start
_start:
    ; Write.
    mov rax, 1
    mov rdi, 1
    mov rsi, hello_world
    mov rdx, hello_world_len
    syscall

    ; Exit.
    mov rax, 60
    mov rdi, 0
    syscall

hello_world db "hello world", 10
hello_world_len equ $ - hello_world

GitHub upstream
组装和运行:

as -o main.o main.S
ld -o main.out main.o
gdb -nh -batch -ex 'source ~/test/gdb.py' -ex 'starti' -ex 'trace-asm' ./main.out
cat trace.tmp

输出量:

0x401000 mov    $0x1,%rax 
0x401007 mov    $0x1,%rdi 
0x40100e mov    $0x402000,%rsi 
0x401015 mov    $0xc,%rdx 
0x40101c syscall  
0x40101e mov    $0x3c,%rax 
0x401025 mov    $0x0,%rdi 
0x40102c syscall

QEMU仿真

编辑:-d in_asm只显示翻译块,所以如果一个块被执行多次,它不会显示多次。有一些额外的标志使它更准确,请参见:qemu跟踪哪些指令?QEMU的exec_tb跟踪后端可能会跟踪这些指令:如何使用QEMU的简单跟踪后端?
这比GDB python解决方案的执行速度要快得多,C hello works可以即时运行!但是,日志只有10 k条指令长,而不是同一个可执行文件上的18 k条指令长,所以它必须跳过一些通常会运行的内容。
例如,在用户模式模拟中:

qemu-x86_64 -d in_asm ./main.out

输出量:

warning: TCG doesn't support requested feature: CPUID.01H:ECX.vmx [bit 5]
----------------
IN: 
0x0000000000401000:  mov    $0x1,%rax
0x0000000000401007:  mov    $0x1,%rdi
0x000000000040100e:  mov    $0x402000,%rsi
0x0000000000401015:  mov    $0xc,%rdx
0x000000000040101c:  syscall 

hello world
----------------
IN: 
0x000000000040101e:  mov    $0x3c,%rax
0x0000000000401025:  mov    $0x0,%rdi
0x000000000040102c:  syscall

另请参阅。
在Ubuntu 18.10、GDB 8.2和QEMU 2.12.0中进行了测试。

ux6nzvsh

ux6nzvsh3#

1.分别反汇编二进制文件(例如,使用objdump),并在调试时查阅清单
1.使用IDA和它的调试器。更好地体验IMO。
(免责声明:我为Hex-Ray工作)

相关问题