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

调试信息的格式对调试器的影响_第1张图片

简介

调试代码的时候离不开调试信息,代码有代码的规范,调试信息也同样有调试信息格式的规范。我们以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

你可能感兴趣的:(调试信息的格式对调试器的影响)