昆山网站建设是什么,网页制作基础教程教学设计,网站设计原型图,网站开发语言总结有哪些〇、前言
事实上#xff0c;一个成熟的 debugger 是不会利用 break 0xADDR 类似的命令来打断点的#xff0c;这个需要改进#xff0c;使得它可以直接利用函数名、行数等来打断点。这就需要生成编译信息#xff0c;只需要在编译的时候#xff0c;在目标文件中加以下参数一个成熟的 debugger 是不会利用 break 0xADDR 类似的命令来打断点的这个需要改进使得它可以直接利用函数名、行数等来打断点。这就需要生成编译信息只需要在编译的时候在目标文件中加以下参数
# 添加编译器标志
set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -g -O0 -gdwarf-2)这样目标文件就携带了 dwarf 格式的 debug info我们还禁止了优化这有利于调试。
一、ELF DWARF
DWARF 和 ELF 的关系与区别
DWARF
DWARF 是一种关于调试信息的标准格式用于在编译时生成的调试信息中描述程序的各种数据结构。这包括但不限于变量的名称、类型、存储位置函数的名称、参数列表和源代码中的行号。DWARF 是与平台无关的这意味着它可以用在各种不同的操作系统和硬件上。
ELF (Executable and Linkable Format)
ELF 是一种常用的文件格式用于定义在类 Unix 系统如 Linux上运行的可执行文件、可重定位的代码和共享库。ELF 文件包含程序的代码和数据并定义了一个文件结构这个结构描述了如何在运行时将程序加载到内存中。
关系与区别
DWARF 信息通常被嵌入到 ELF 文件中在 .debug 节作为程序的一部分。这意味着 ELF 文件作为容器包含了执行程序所需的机器代码和如果编译时指定调试信息。在调试过程中调试器利用 ELF 文件中的 DWARF 信息来提供程序执行的详细视图比如变量值、程序执行的当前行等。虽然 DWARF 和 ELF 通常一起使用但它们是独立的标准DWARF 关注于描述调试数据ELF 关注于程序的布局和执行。
二、DWARF line table DWARF debug info
在讨论 DWARF 格式的调试信息时编译单元Compilation Unit, CU和行表Line Table是两个核心概念。这些信息极大地促进了源码级调试使调试器能够有效地将执行的机器代码映射回源代码。下面详细介绍这两个概念
编译单元Compilation Unit, CU
编译单元通常指的是单个源文件及其相关包含的文件通过预处理器展开在编译过程中形成的单元。在 DWARF 调试信息中每个编译单元生成一组特定的调试信息记录这些记录描述了该源文件中定义的数据结构、函数、变量、类型等。
编译单元的主要内容包括
全局变量和类型定义全局作用域中定义的变量和类型。局部变量和类型定义函数内部定义的变量和类型。子程序信息包括函数和方法的定义如函数名、返回类型、参数信息以及函数内的代码结构。源文件和目录信息描述编译单元对应的源文件和其在文件系统中的位置。
编译单元的信息对于调试器来说至关重要因为它们提供了代码结构的详细视图使得调试器可以准确地知道在任何时刻程序正在执行的代码部分。
行表Line Table
行表是 DWARF 调试信息中的一部分它为编译单元中的每一行源代码提供一个或多个对应的机器指令的映射。这允许调试器将正在执行的机器指令精确地对应到源代码中的具体行。
行表的关键作用
源代码到机器代码的映射行表记录了源代码行与生成的机器代码之间的对应关系。这包括代码地址的起始点和源代码行号。断点设置当在源代码中设置断点时调试器使用行表来确定应该在哪个具体的机器指令地址上设置断点。步进和步过操作在单步执行步进和执行至下一行步过时调试器利用行表来确定执行流程应该停留或跳过的代码段。
行表通常包含以下信息
地址对应机器代码的开始地址。行号源代码中的行号。文件名源代码的文件名尤其是在项目中包含多个文件时。其他标志如是否是语句的开始、是否是基本块的开始等。
而 CU 就是 debug info 的基本组成每一个 CU事实上就是一个源代码文件组成 debug info段的一部分。编译单元是调试信息的构建块每个编译单元封装了一个源文件的所有相关调试信息。这种组织方式不仅有助于维护信息的结构性和可查询性也使得调试过程更为高效和直观。
假设一个可执行程序包含了 DWARF 格式的调试信息包含了很多的源代码文件它的 debug_info 可能如下
objdump --dwarfinfo hello
hello: file format elf64-x86-64Contents of the .debug_info section:Compilation Unit offset 0x0:Length: 0x2612 (32-bit)Version: 2Abbrev Offset: 0x0Pointer Size: 80b: Abbrev Number: 1 (DW_TAG_compile_unit)c DW_AT_producer : (indirect string, offset: 0x109b): GNU C17 11.4.0 -mtunegeneric -marchx86-64 -g -gdwarf-2 -O0 -fasynchronous-unwind-tables -fstack-protector-strong -fstack-clash-protection -fcf-protection10 DW_AT_language : 4 (C)11 DW_AT_name : (indirect string, offset: 0x4ba): /home/luyoung/mydebugger/examples/hello.cpp15 DW_AT_comp_dir : (indirect string, offset: 0x154): /home/luyoung/mydebugger/build/examples19 DW_AT_low_pc : 0x118921 DW_AT_high_pc : 0x122029 DW_AT_stmt_list : 0x012d: Abbrev Number: 2 (DW_TAG_namespace)2e DW_AT_name : std32 DW_AT_decl_file : 633 DW_AT_decl_line : 27835 DW_AT_decl_column : 1136 DW_AT_sibling : 0xbab23a: Abbrev Number: 3 (DW_TAG_namespace)3b DW_AT_name : (indirect string, offset: 0x859): __cxx113f DW_AT_decl_file : 640 DW_AT_decl_line : 30242 DW_AT_decl_column : 6543 DW_AT_export_symbols: 1244: Abbrev Number: 4 (DW_TAG_imported_module)...225f2: Abbrev Number: 0125f3: Abbrev Number: 88 (DW_TAG_subprogram)25f4 DW_AT_external : 125f5 DW_AT_name : (indirect string, offset: 0x6b3): main25f9 DW_AT_decl_file : 125fa DW_AT_decl_line : 225fb DW_AT_decl_column : 525fc DW_AT_type : 0xd3d2600 DW_AT_low_pc : 0x11892608 DW_AT_high_pc : 0x11b12610 DW_AT_frame_base : 0xc0 (location list)2614 DW_AT_GNU_all_tail_call_sites: 112615: Abbrev Number: 0这些信息很难看非常不利于人类阅读因此我们可以利用更好的工具来理解这些信息这些工具对这些信息进行了组织比如 dwarfdump .debug_infoCOMPILE_UNITheader overall offset 0x00000000:00x0000000b DW_TAG_compile_unitDW_AT_producer GNU C17 11.4.0 -mtunegeneric -marchx86-64 -g -gdwarf-2 -O0 -fasynchronous-unwind-tables -fstack-protector-strong -fstack-clash-protection -fcf-protectionDW_AT_language DW_LANG_C_plus_plusDW_AT_name /home/luyoung/mydebugger/examples/hello.cppDW_AT_comp_dir /home/luyoung/mydebugger/build/examplesDW_AT_low_pc 0x00001189DW_AT_high_pc 0x00001220DW_AT_stmt_list 0x00000000LOCAL_SYMBOLS:10x0000002d DW_TAG_namespaceDW_AT_name stdDW_AT_decl_file 0x00000006 /usr/include/x86_64-linux-gnu/c/11/bits/cconfig.hDW_AT_decl_line 0x00000116DW_AT_decl_column 0x0000000bDW_AT_sibling 0x00000bab20x0000003a DW_TAG_namespace
.
.
.
.debug_line: line number info for a single cu
Source lines (from CU-DIE at .debug_info offset 0x0000000b):NS new statement, BB new basic block, ET end of text sequencePE prologue end, EB epilogue beginISval ISA number, DIval discriminator value
pc [lno,col] NS BB ET PE EB IS DI uri: filepath
0x00001189 [ 2,12] NS uri: /home/luyoung/mydebugger/examples/hello.cpp
0x00001191 [ 3,16] NS
0x000011aa [ 4,10] NS
0x000011af [ 5, 1] NS
0x000011b1 [ 5, 1] NS
0x000011c3 [ 5, 1] NS
0x000011c9 [ 5, 1] DI0x1
0x000011d2 [ 74,25] NS uri: /usr/include/c/11/iostream
0x00001204 [ 5, 1] NS uri: /home/luyoung/mydebugger/examples/hello.cpp
0x00001207 [ 5, 1] NS
0x0000120f [ 5, 1] NS
0x00001220 [ 5, 1] NS ET
.
.
.
.debug_str
name at offset 0x00000000, length 6 is getenv
name at offset 0x00000007, length 16 is __isoc99_vwscanf
name at offset 0x00000018, length 13 is uint_fast16_t
name at offset 0x00000026, length 7 is __debug
name at offset 0x0000002e, length 17 is int_p_cs_precedes
name at offset 0x00000040, length 42 is _ZNSt15__exception_ptr13exception_ptrC4EPv
name at offset 0x0000006b, length 8 is strtoull
name at offset 0x00000074, length 16 is __uint_least64_t
name at offset 0x00000085, length 7 is wcsxfrm
name at offset 0x0000008d, length 51 is _ZNSt15__exception_ptr13exception_ptr10_M_releaseEv
name at offset 0x000000c1, length 14 is ~exception_ptr
name at offset 0x000000d0, length 4 is atol
name at offset 0x000000d5, length 9 is _shortbuf
name at offset 0x000000df, length 10 is _IO_lock_t
name at offset 0x000000ea, length 7 is setvbuf
name at offset 0x000000f2, length 9 is gp_offset
.
.
.
.debug_arangesCOMPILE_UNITheader overall offset 0x00000000:00x0000000b DW_TAG_compile_unitDW_AT_producer GNU C17 11.4.0 -mtunegeneric -marchx86-64 -g -gdwarf-2 -O0 -fasynchronous-unwind-tables -fstack-protector-strong -fstack-clash-protection -fcf-protectionDW_AT_language DW_LANG_C_plus_plusDW_AT_name /home/luyoung/mydebugger/examples/hello.cppDW_AT_comp_dir /home/luyoung/mydebugger/build/examplesDW_AT_low_pc 0x00001189DW_AT_high_pc 0x00001220DW_AT_stmt_list 0x00000000arange starts at 0x00001189, length of 0x00000097, cu_die_offset 0x0000000b
arange end.debug_frame is not present可以看到dwarfdump 输出的信息更好理解它对信息进行了分类整理。还必须要理解的是这里的 pc 地址都是 offset在使用的时候需要加上 load_addr另外
pc [lno,col] NS BB ET PE EB IS DI uri: filepath
0x00001189 [ 2,12] NS uri: /home/luyoung/mydebugger/examples/hello.cpp
0x00001191 [ 3,16] NS
0x000011aa [ 4,10] NS
0x000011af [ 5, 1] NS
0x000011b1 [ 5, 1] NS
0x000011c3 [ 5, 1] NS
0x000011c9 [ 5, 1] DI0x1
0x000011d2 [ 74,25] NS uri: /usr/include/c/11/iostream
0x00001204 [ 5, 1] NS uri: /home/luyoung/mydebugger/examples/hello.cpp
0x00001207 [ 5, 1] NS
0x0000120f [ 5, 1] NS
0x00001220 [ 5, 1] NS ET和源代码相对应这为源代码 level 调试提供了基础
#1 #include iostream
#2 int main() {
#3 std::cerr hello,world0.\n;
#4 return 0;
#5}如果我们想在源代码第三行处打断点就应该把地址定在 0x00001191这也可以在 elf 中找到依据
0000000000001189 main:1189: f3 0f 1e fa endbr64 118d: 55 push %rbp118e: 48 89 e5 mov %rsp,%rbp1191: 48 8d 05 6c 0e 00 00 lea 0xe6c(%rip),%rax # 2004 _IO_stdin_used0x41198: 48 89 c6 mov %rax,%rsi119b: 48 8d 05 7e 2e 00 00 lea 0x2e7e(%rip),%rax # 4020 _ZSt4cerrGLIBCXX_3.411a2: 48 89 c7 mov %rax,%rdi11a5: e8 d6 fe ff ff call 1080 _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKcplt11aa: b8 00 00 00 00 mov $0x0,%eax11af: 5d pop %rbp11b0: c3 另外还可以看到编译单元中的
COMPILE_UNITheader overall offset 0x00000000:00x0000000b DW_TAG_compile_unit
...DW_AT_low_pc 0x00001189DW_AT_high_pc 0x00001220DW_AT_stmt_list 0x00000000...它们的 DW_AT_low_pc和 DW_AT_high_pc 和 line table 中的范围一致因此这也是重要的信息。