DWARF数据结构
调试信息条目
DWARF使用调试信息条目DIE(Debugging Information Entry)来表示每一个变量、数据类型、函数、编译单元等等。
- 每个DIE都包含一个tag(如DW_TAG_variable表示变量,DW_TAG_pointer_type表示指针类型,DW_TAG_subprogram表示一个函数等)以及一系列的attributes;
- 每个DIE还可以包含child DIEs,这些DIEs构成的树结构共同描述一个变量、数据类型、函数、编译单元等不同的程序构造;
- DIE中的每个attribute可以引用另一个DIE,例如一个描述变量的DIE,它会包含一个属性DW_AT_type来指向一个描述变量数据类型的DIE。
重要的表结构
符号级调试器需要两张非常大的表,一个是行号表(Line Number Table),一个是调用栈信息表(Call Frame Information)。
- 行号表(Line Number Table), 它将程序代码段的指令地址映射为源文件中的地址,如“源文件名:行号”。当然如果指定了源文件中的位置,也可以将其映射为程序代码段中的指令地址。这个表还有其他更细的用途,比如指出哪些指令是函数序言(prologues)或函数结尾(epilogues)部分的指令。
- 调用栈信息表(Call Frame Information), 它允许调试器根据指令地址来定位其在调用栈上的栈帧。
这两张表会占用非常大的存储空间,为了节省存储空间,DWARF专门设计了状态机和字节码指令,将上述两张表的冗余数据进行适当剔除后,将剩下的数据进一步通过字节码指令进行编码,这样两张表的空间占用就显著减小了。
当调试器加载了上述表数据后,希望构建出这两张表,该如何操作呢?前面提过了这里的数据都是字节码指令,只要交给对应的状态机执行,状态机执行字节码指令即可完成表的构建。
关于这两张表的更多内容,后续会进一步描述。