美文网首页
调试信息的格式对调试器的影响

调试信息的格式对调试器的影响

作者: 沙漠中的猴 | 来源:发表于2018-08-28 18:56 被阅读0次

    简介

    调试代码的时候离不开调试信息,代码有代码的规范,调试信息也同样有调试信息格式的规范。我们以elf64文件格式为例来讲解dwarf和stabs两种调试信息格式对gdb的影响。

    环境

    docker : Ubuntu 16.04镜像
    nasm : 2.13.02 // 一款编译器
    gdb:8.1.0 // 调试器

    源码

    global _start
    
    section .text
        _start:
            mov rax, 1
            mov rbx, 2
    
            cmp rax, rbx
            jne .exit
    
            inc rax
    
        .exit:
            mov rax, 60
            xor rdi, rdi
            syscall
    

    上面的代码的意思是:如果寄存器rax与rbx的值不相等,则退出。如果相等,则将rax的值自加。

    调试信息的格式

    我们可以输入一下命令来查看elf64格式文件支持什么调试信息格式

    root@000d3fada0b3:~/go/src/asm# nasm -f elf64 -y
    
    valid debug formats for 'elf64' output format are ('*' denotes default):
        dwarf     ELF64 (x86-64) dwarf debug format for Linux/Unix
        stabs     ELF64 (x86-64) stabs debug format for Linux/Unix
    

    我们可以看到,elf64 文件格式支持 dwarf 和 stabs 两种调试信息格式。

    我们分别生成两种调试信息的可执行文件来进行对比。

    dwarf格式

    编译文件

    root@000d3fada0b3:~/go/src/asm# nasm -f elf64 -F dwarf -o dwarf_jmp.o jmp.s       // 编译 -f 指定文件格式,-F 指定调试信息格式。-o 输出目标文件
    root@000d3fada0b3:~/go/src/asm# ld -o dwarf_jmp dwarf_jmp.o
    root@000d3fada0b3:~/go/src/asm# ls
    dwarf_jmp  dwarf_jmp.o  jmp.s
    

    可以看到,我们生成了dwarf_jmp可执行文件。并指定了该可执行文件的调试信息格式为 dwarf

    使用gdb调试

    1. 进入 gdb 调试命令行
    gdb dwarf_jmp
    
    1. 在 _start 标签处设置断点
    (gdb) b _start
    
    1. 执行
    (gdb) r
    
    1. 单步执行断点
    (gdb) n
    7           mov rbx, 2
    (gdb) n
    9           cmp rax, rbx
    (gdb)
    

    通过以上命令,我们可以看到,gdb可以单步进行调试。

    stabs格式

    编译文件

    root@000d3fada0b3:~/go/src/asm# nasm -f elf64 -F stabs -o stabs_jmp.o jmp.s
    root@000d3fada0b3:~/go/src/asm# ld -o stabs_jmp stabs_jmp.o
    root@000d3fada0b3:~/go/src/asm# ls
    dwarf_jmp  dwarf_jmp.o  jmp.s  stabs_jmp  stabs_jmp.o
    

    可以看到,我们生成了stabs_jmp可执行文件。并指定了该可执行文件的调试信息格式为 stabs

    使用gdb调试

    1. 进入 gdb 调试命令行
    gdb stabs_jmp
    
    1. 在 _start 标签处设置断点
    (gdb) b _start
    
    1. 执行
    (gdb) r
    
    1. 单步执行断点
    (gdb) n
    Single stepping until exit from function _start,
    which has no line number information.
    0x0000000000400092 in _start.exit ()
    

    通过以上步骤,我们发现,单步调试并没有生效。

    到底是什么原因导致了这种情况发生?

    对比段(Section)头 的信息

    dwarf 格式

    root@000d3fada0b3:~/go/src/asm# readelf -S dwarf_jmp
    There are 12 section headers, starting at offset 0x3b0:
    
    Section Headers:
      [Nr] Name              Type             Address           Offset
           Size              EntSize          Flags  Link  Info  Align
      [ 0]                   NULL             0000000000000000  00000000
           0000000000000000  0000000000000000           0     0     0
      [ 1] .text             PROGBITS         0000000000400080  00000080
           000000000000001c  0000000000000000  AX       0     0     16
      [ 2] .debug_aranges    PROGBITS         0000000000000000  0000009c
           0000000000000030  0000000000000000           0     0     1
      [ 3] .debug_pubnames   PROGBITS         0000000000000000  000000cc
           0000000000000012  0000000000000000           0     0     1
      [ 4] .debug_info       PROGBITS         0000000000000000  000000de
           0000000000000047  0000000000000000           0     0     1
      [ 5] .debug_abbrev     PROGBITS         0000000000000000  00000125
           000000000000001b  0000000000000000           0     0     1
      [ 6] .debug_line       PROGBITS         0000000000000000  00000140
           000000000000003e  0000000000000000           0     0     1
      [ 7] .debug_frame      PROGBITS         0000000000000000  00000180
           0000000000000004  0000000000000000           0     0     8
      [ 8] .debug_loc        PROGBITS         0000000000000000  00000184
           0000000000000010  0000000000000000           0     0     1
      [ 9] .symtab           SYMTAB           0000000000000000  00000198
           0000000000000168  0000000000000018          10    11     8
      [10] .strtab           STRTAB           0000000000000000  00000300
           000000000000002b  0000000000000000           0     0     1
      [11] .shstrtab         STRTAB           0000000000000000  0000032b
           000000000000007e  0000000000000000           0     0     1
    Key to Flags:
      W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
      L (link order), O (extra OS processing required), G (group), T (TLS),
      C (compressed), x (unknown), o (OS specific), E (exclude),
      l (large), p (processor specific)
    

    stabs 格式

    root@000d3fada0b3:~/go/src/asm# readelf -S stabs_jmp
    There are 7 section headers, starting at offset 0x278:
    
    Section Headers:
      [Nr] Name              Type             Address           Offset
           Size              EntSize          Flags  Link  Info  Align
      [ 0]                   NULL             0000000000000000  00000000
           0000000000000000  0000000000000000           0     0     0
      [ 1] .text             PROGBITS         0000000000400080  00000080
           000000000000001c  0000000000000000  AX       0     0     16
      [ 2] .stab             PROGBITS         0000000000000000  0000009c
           0000000000000084  0000000000000014           3     0     4
      [ 3] .stabstr          STRTAB           0000000000000000  00000120
           0000000000000007  0000000000000000           0     0     1
      [ 4] .symtab           SYMTAB           0000000000000000  00000128
           00000000000000f0  0000000000000018           5     6     8
      [ 5] .strtab           STRTAB           0000000000000000  00000218
           000000000000002b  0000000000000000           0     0     1
      [ 6] .shstrtab         STRTAB           0000000000000000  00000243
           0000000000000030  0000000000000000           0     0     1
    Key to Flags:
      W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
      L (link order), O (extra OS processing required), G (group), T (TLS),
      C (compressed), x (unknown), o (OS specific), E (exclude),
      l (large), p (processor specific)
    

    对比两种格式的段(Section)头的信息,我们可以发现 dwarf 调试信息格式的文件比 stabs 调试信息格式的文件多了以下debug相关的段(Section)内容:

    debug_info:  包含所有 DIE 的 DWARF 核心信息。包括函数 
    debug_abbrev:debug_info段(Section)中所用的缩写信息。
    debug_line:行号信息
    debug_aranges:内存地址与编译的映射信息。
    debug_pubnames:全局对象和函数的查找表
    debug_frame: 堆栈信息
    

    参考

    https://www.taodocs.com/p-14959260.html
    https://blog.csdn.net/js072110/article/details/44153303

    相关文章

      网友评论

          本文标题:调试信息的格式对调试器的影响

          本文链接:https://www.haomeiwen.com/subject/vdeqwftx.html