type
status
date
slug
summary
tags
category
icon
password
1 Introduction
- Understanding the overall process by which most major systems and infrastructure software is built and executed today
- how symbols in high-level languages are resolved to addresses and constants in machine code
- the coordination of linker and loader, particularly in systems exploiting virtual address spaces
- how linkers allocate space for variables and functions, including the role of symbol tables
- Become proficient as a software engineer at the intermediate level in the C language when separate compilation is used for medium and large programs
- separate compilation and the role of header files in creating modular code
- common mistakes
- best practices when declaring and defining functions and variables
- the role and purpose of static libraries
- the role and purpose of dynamic libraries
- the purpose of whole program link-time optimization
- the implications of virtual address space layout for debugging program faults
- how to use common tools such as
nm,objdump, etc
2 Compiler and Assembler
- Preprocessor performs textual insertion of include files
- Compiler resolves the following symbolic names:
- Local automatic variables, function parameters
- Field names in structures
- Assembler resolves certain labels for relative branches
- The resulting relocatable .o file still retains symbolic names for all functions and variables that are global in extent
2.1 Relocatable Object Files — Text Section
- Contain multiple sections
- Each section is laid out starting as if starting at 0
- Contains relocation records: placeholders and meta information about how to patch them up once actual addresses are known
2.2 Executable and Linkable Format(ELF)
- ELF is a standard format for relocatable object files, executables, and shared objects(dynamic libraries) used in System V and derived systems, include Linux
- Other formats include Mach-O(OSX), PE(Windows), a.out
- Provides the link between compiler → Linker → loader
- Carries all information needed by the next tool; also debugging and exception handling information
- Extensive tool support
- Details in
/usr/include/elf.h
readelf -a main.oreadelf -a main2.2.1 ELF Header
ELF文件中的ELF Header是文件的开始部分,它包含了关于二进制文件的全局信息,例如文件类型、架构、入口点等。让我们一起看一下它的字段及其含义:
字段 | 说明 |
e_ident | This is a array, Details will show below |
e_type | 0(No file type)
1(Relocatable file)
2(Executable file)
3(Shared object file)
4(Core file)
5(Number of defined types)
0xfe00(OS-specific range start)
0xfeff(OS-specific range end)
0xff00(Processor-specific range start)
0xffff(Processor-specific range end) |
e_machine | See /usr/include/elf.h for details |
e_version | 0(Invalid ELF version)
1(Current version) |
e_entry | Entry point virtual address |
e_phoff | Program header table file offset |
e_shoff | Section header table file offset |
e_flags | 这个字段包含了一些处理器特定的标志。对于一些特定类型的处理器,这些标志可能会影响或者改变代码的执行 |
e_ehsize | 这个字段表示ELF头部(ELF Header)的大小 |
e_phentsize | 这个字段表示程序头表中的一个条目的大小 |
e_phnum | 这个字段表示程序头表中的条目数量 |
e_shentsize | 这个字段表示节头表中的一个条目的大小 |
e_shnum | 这个字段表示节头表中的条目数量 |
e_shstrndx | 这个字段包含了节头字符串表(Section Header String Table)的节头表索引。这些字段组合在一起描述了ELF文件的结构和定位文件中的关键设计元素 |
e_identstruct member | index | meaning |
EI_MAG0 | 0-3 | File identification —— 7f 45 4c 46 mean “ELF” |
EI_CLASS | 4 | File class
1(32-bit objects)
2(64-bit objects) |
EI_DATA | 5 | Data encoding
0(Invalid data encoding)
1(2's complement, little endian)
2(2's complement, big endian) |
EI_VERSION | 6 | File version —— Value must be EV_CURRENT |
EI_OSABI | 7 | OS ABI
0(UNIX System V ABI)
1(HP-UX)
2(NetBSD)
3(Object uses GNU/LINUX ELF extensions)
6(Sun Solaris)
7(IBM AIX)
8(SGI Irix)
9(FreeBSD)
10(Compaq TRU64 UNIX)
11(Novell Modesto)
12(OpenBSD)
64(ARM EABI)
97(ARM)
255(Standalone (embedded) application) |
EI_ABIVERSION | 8 | ABI Version |
EI_PAD | 9-15 | Padding bytes |
Field | Meaning |
e_ident | Magic,Class, Data, Version,OS/ABI, ABI Version |
e_type | Type |
e_machine | Machine |
e_version | Version |
e_entry | Entry point address |
e_phoff | Start of program headers |
e_shoff | Start of section headers |
e_flags | Flags |
e_ehsize | Size of this header |
e_phentsize | Size of program headers |
e_phnum | Number of program headers |
e_shentsize | Size of section headers |
e_shnum | Number of section headers |
e_shstrndx | Section header string table index |
2.2.2 Program Header Table
紧随 ELF Header 之后的是 Program Header Table,包含了多个 Program Header,每个 Program Header 描述了一个段的信息,这些段用于进程映射。
2.2.3 Sections
在 ELF 文件中,Sections 是实际的数据或代码块。典型的 Sections 包括
.text(代码段)、.data(数据段)、.bss(未初始化数据段)、.rodata(只读数据段)、.symtab(符号表)、.strtab(字符串表)等。2.2.4 Section Header Table
Section Header Table 位于 ELF 文件的末尾或其他位置,它描述了各个 Section 的具体信息,例如大小、位置、类型等。
2.2.5 完整的 ELF 文件结构
下面是将所有部分结合在一起的完整示意图:
以上通过文字描述和分阶段的Mermaid示意图展示了ELF文件的结构,每个部分的具体作用和位置都清晰展示出来。
ELF header |
Program header table(required for EXE) |
.text section |
.data section |
.bss section |
.symtab |
.rel.text |
.rel.data |
.debug |
Section header table(required for relocatables) |
ELF文件中的
.symtab部分是符号表,它存储着程序中定义或引用的符号的信息,每一个符号都对应着符号表中的一个条目。每个条目都包含以下字段:字段 | 说明 |
st_name | 这是符号名的索引,指向字符串表(`.strtab` 部分)中的一个位置,那个位置保存了此符号的名称 |
st_value | 这个字段的意义视符号的类型和关联性而定。对于函数符号,它是函数的入口地址。对于全局变量或静态变量,它是变量的地址 |
st_size | 这个字段指示符号的大小。对于函数符号,它是函数代码的大小。对于变量符号,它是变量的大小 |
st_info | 这个字段包含符号的类型和绑定(关联性)信息。例如,符号可以是一个函数、一个对象(如全局变量)等。符号的绑定可以是局部的(不可以被其他对象文件访问),全局的(可以被其他对象文件访问),或者是弱的(如果其他对象文件定义了同名的全局符号,那么这个弱符号就不起作用) |
st_other | 这个字段在标准ELF文件中未定义,通常不使用 |
st_shndx | 这个字段包含了一个节头表索引,指出符号定义在哪个段或节。例如,函数符号通常在 .text段内,全局变量和静态变量通常在.data或.bss段内 |
以上就是
.symtab符号表中每一项的各个字段的含义。在一些处理或者解析ELF文件的工具中,你可以直接看到这些字段的值,从而得知程序中函数或变量的相关信息。GDB
Start
Command | Meaning |
gdb object | Normal start, load executable file |
gdb object core | Debug for executable + core file |
gdb object pid | Debug for running process |
gdb | Normal start, need manual loading file |
gdb -tui | Start gdb text ui (exchange CLI/TUI by ctrl-x ctrl-a) |
Help
Command | Meaning |
help | List command categories |
help running | View help information for a category |
help run | View run help |
help info | List the commands related to viewing the running status of the program |
help info line | List help for a specific running status command |
help show | List GDB status related commands |
help show commands | List help for show command |
Breakpoints
Command | Meaning |
break main | 对函数 main 设置一个断点,可简写为 b main |
break 101 | 对源代码的行号设置断点,可简写为 b 101 |
break basic.c:101 | 对源代码和行号设置断点 |
break basic.c:foo | 对源代码和函数名设置断点 |
break *0x00400448 | 对内存地址 0x00400448 设置断点 |
info breakpoints | 列出当前的所有断点信息,可简写为 info break |
delete 1 | 按编号删除一个断点 |
delete | 删除所有断点 |
clear | 删除在当前行的断点 |
clear function | 删除函数断点 |
clear line | 删除行号断点 |
clear basic.c:101 | 删除文件名和行号的断点 |
clear basic.c:main | 删除文件名和函数名的断点 |
clear *0x00400448 | 删除内存地址的断点 |
disable 2 | 禁用某断点,但是部删除 |
enable 2 | 允许某个之前被禁用的断点,让它生效 |
rbreak {regexpr} | 匹配正则的函数前断点,如 ex_* 将断点 ex_ 开头的函数 |
tbreak function/line | 临时断点 |
hbreak function/line | 硬件断点 |
ignore {id} {count} | 忽略某断点 N-1 次 |
condition {id} {expr} | 条件断点,只有在条件生效时才发生 |
condition 2 i == 20 | 2号断点只有在 i == 20 条件为真时才生效 |
watch {expr} | 对变量设置监视点 |
info watchpoints | 显示所有观察点 |
catch exec | 断点在exec事件,即子进程的入口地址 |
Run program
Command | Meaning |
run | 运行程序 |
run {args} | 以某参数运行程序 |
run < file | 以某文件为标准输入运行程序 |
run < <(cmd) | 以某命令的输出作为标准输入运行程序 |
run <<< $(cmd) | 以某命令的输出作为标准输入运行程序 |
set args {args} ... | 设置运行的参数 |
show args | 显示当前的运行参数 |
cont | 继续运行,可简写为 c |
step | 单步进入,碰到函数会进去 |
step {count} | 单步多少次 |
next | 单步跳过,碰到函数不会进入 |
next {count} | 单步多少次 |
CTRL+C | 发送 SIGINT 信号,中止当前运行的程序 |
attach {process-id} | 链接上当前正在运行的进程,开始调试 |
detach | 断开进程链接 |
finish | 结束当前函数的运行 |
until | 持续执行直到代码行号大于当前行号(跳出循环) |
until {line} | 持续执行直到执行到某行 |
kill | 杀死当前运行的函数 |
Stack frame
Command | Meaning |
bt | print backtrace |
frame | print current running stack frame |
up | 向上移动栈帧(向着 main 函数) |
down | 向下移动栈帧(远离 main 函数) |
info locals | 打印帧内的相关变量 |
info args | 打印函数的参数 |
Code viewing
Command | Meaning |
list 101 | 显示第 101 行周围 10行代码 |
list 1,10 | 显示 1 到 10 行代码 |
list main | 显示函数周围代码 |
list basic.c:main | 显示另外一个源代码文件的函数周围代码 |
list - | 重复之前 10 行代码 |
list *0x22e4 | 显示特定地址的代码 |
cd dir | 切换当前目录 |
pwd | 显示当前目录 |
search {regexpr} | 向前进行正则搜索 |
reverse-search {regexp} | 向后进行正则搜索 |
dir {dirname} | 增加源代码搜索路径 |
dir | 复位源代码搜索路径(清空) |
show directories | 显示源代码路径 |
Data viewing
Command | Meaning |
print {expression} | 打印表达式,并且增加到打印历史 |
print /x {expression} | 十六进制输出,print 可以简写为 p |
print array[i]@count | 打印数组范围 |
print $ | 打印之前的变量 |
print *$->next | 打印 list |
print $1 | 输出打印历史里第一条 |
print ::gx | 将变量可视范围(scope)设置为全局 |
print 'basic.c'::gx | 打印某源代码里的全局变量,(gdb 4.6) |
print /x &main | 打印函数地址 |
x *0x11223344 | 显示给定地址的内存数据 |
x /nfu {address} | 打印内存数据,n是多少个,f是格式,u是单位大小 |
x /10xb *0x11223344 | 按十六进制打印内存地址 0x11223344 处的十个字节 |
x/x &gx | 按十六进制打印变量 gx,x和斜杆后参数可以连写 |
x/4wx &main | 按十六进制打印位于 main 函数开头的四个 long |
x/gf &gd1 | 打印 double 类型 |
help x | 查看关于 x 命令的帮助 |
info locals | 打印本地局部变量 |
info functions {regexp} | 打印函数名称 |
info variables {regexp} | 打印全局变量名称 |
ptype name | 查看类型定义,比如 ptype FILE,查看 FILE 结构体定义 |
whatis {expression} | 查看表达式的类型 |
set var = {expression} | 变量赋值 |
display {expression} | 在单步指令后查看某表达式的值 |
undisplay | 删除单步后对某些值的监控 |
info display | 显示监视的表达式 |
show values | 查看记录到打印历史中的变量的值 (gdb 4.0) |
info history | 查看打印历史的帮助 (gdb 3.5) |
File operations
Command | Meaning |
file {object} | 加载新的可执行文件供调试 |
file | 放弃可执行和符号表信息 |
symbol-file {object} | 仅加载符号表 |
exec-file {object} | 指定用于调试的可执行文件(非符号表) |
core-file {core} | 加载 core 用于分析 |
Signal control
Command | Meaning |
info signals | 打印信号设置 |
handle {signo} {actions} | 设置信号的调试行为 |
handle INT print | 信号发生时打印信息 |
handle INT noprint | 信号发生时不打印信息 |
handle INT stop | 信号发生时中止被调试程序 |
handle INT nostop | 信号发生时不中止被调试程序 |
handle INT pass | 调试器接获信号,不让程序知道 |
handle INT nopass | 调试起不接获信号 |
signal signo | 继续并将信号转移给程序 |
signal 0 | 继续但不把信号给程序 |
Thread debug
Command | Meaning |
info threads | 查看当前线程和 id |
thread {id} | 切换当前调试线程为指定 id 的线程 |
break {line} thread all | 所有线程在指定行号处设置断点 |
thread apply {id..} cmd | 指定多个线程共同执行 gdb 命令 |
thread apply all cmd | 所有线程共同执行 gdb 命令 |
set schedule-locking ? | 调试一个线程时,其他线程是否执行 |
set non-stop on/off | 调试一个线程时,其他线程是否运行 |
set pagination on/off | 调试一个线程时,分页是否停止 |
set target-async on/off | 同步或者异步调试,是否等待线程中止的信息 |
Process debug
Command | Meaning |
info inferiors | 查看当前进程和 id |
inferior {id} | 切换某个进程 |
kill inferior {id...} | 杀死某个进程 |
set detach-on-fork on/off | 设置当进程调用fork时gdb是否同时调试父子进程 |
set follow-fork-mode parent/child | 设置当进程调用fork时是否进入子进程 |
Assembly debug
Command | Meaning |
info registers | 打印普通寄存器 |
info all-registers | 打印所有寄存器 |
print/x $pc | 打印单个寄存器 |
stepi | 指令级别单步进入 |
nexti | 指令级别单步跳过 |
display/i $pc | 监控寄存器(每条单步完以后会自动打印值) |
x/x &gx | 十六进制打印变量 |
info line 22 | 打印行号为 22 的内存地址信息 |
info line *0x2c4e | 打印给定内存地址对应的源代码和行号信息 |
disassemble {addr} | 对地址进行反汇编,比如 disassemble 0x2c4e |
Others
Command | Meaning |
show commands | 显示历史命令 (gdb 4.0) |
info editing | 显示历史命令 (gdb 3.5) |
ESC-CTRL-J | 切换到 Vi 命令行编辑模式 |
set history expansion on | 允许类 c-shell 的历史 |
break class::member | 在类成员处设置断点 |
list class:member | 显示类成员代码 |
ptype class | 查看类包含的成员 |
print *this | 查看 this 指针 |
define command ... end | 定义用户命令 |
<return> | 直接按回车执行上一条指令 |
shell {command} [args] | 执行 shell 命令 |
source {file} | 从文件加载 gdb 命令 |
quit | 退出 gdb |
- 作者:KaiGuo
- 链接:https://blog.kaiguov5.com/article/a554b339-67b5-4ba3-a7f0-d0714935ab3e
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。