GNU binutils工具提供了一系列二进制工具,用于日常开发过程中对程序调试和维护,经常会用到的工具如下:
下文会简单描述上述部分工具的基本用法,更为详细的使用方法建议查看对应工具的man和info信息。
addr2line可根据程序指令地址查找到所对应的函数名、以及函数所在的源文件名和行号。当含有调试信息的执行程序出现crash时,可使用addr2line快速定位出错代码的位置。其基本使用格式如下:
addr2line <程序运行地址> -e <可执行文件路径>
nm工具用于列出程序文件中的符号信息。以一个简单的hello world程序为例:
shell # nm helloworld
0000000100002008 d __dyld_private
0000000100000000 T __mh_execute_header
0000000100000f60 T _main
U _printf
U dyld_stub_binder
nm所列出的每一行信息由三部分组成:
对于第二列中的字符含义如下表所示:
字符 | 含义 |
---|---|
A | 表示符号所对应的值是绝对的,并且在后续的链接过程中也不会改变 |
B或b | 表示符号位于未初始化的数据段(.bss段)中,该段用于包含初始化为0或未初始化的数据 |
C | 表示未被初始化的公共符号 |
D或d | 表示符号位于初始化的数据段(.data段)中 |
N | 表示符号是调试用的 |
R或r | 表示符号位于只读数据段(.rdata)中 |
T或t | 表示符号位于代码段(.text段)中 |
U | 表示符号未被定义 |
通常程序中包含的符号种类比脚繁杂,可以定制选项显示需要查看的符号信息,一些常用的选项如下:
objcopy可以实现拷贝目标文件中特定的段,并且支持格式转化。objcopy支持的选项很多,比较常见的用法是创建二进制bin文件活着剥离目标文件中的调试信息。
在嵌入式开发中,经常需要向开发板rom中烧录引导程序,此时就可以使用objcopy从编译好的目标文件中将二进制执行代码拷贝出来。
objcopy -O binary boot.elf boot.bin
一般在程序发布时,是不会携带调试信息的,但是可以将调试信息提取出来作为文件,在程序调试时,可以将调试文件单独进行加载,比如gdb已经支持这个功能。
objcopy --only-keep-debug a.out a.out.dbg
objdump工具可用于查看目标文件或者可执行文件的段、节等构成信息,也可以用来对目标文件进行反汇编。objdump的常用选项如下:
使用objdump对程序文件进行反汇编,是日常调测用的较多的一个功能:
objdump -d -S a.out > a.out.S
strings用于查看程序文件中的可显示字符,功能相对简单。在此查看一个最简单的helloworld程序中包含的字符串:
shell # strings helloworld
/lib64/ld-linux-x86-64.so.2
libc.so.6
printf
__cxa_finalize
__libc_start_main
__stack_chk_fail
GLIBC_2.2.5
GLIBC_2.4
_ITM_deregisterTMCloneTable
__gmon_start__
_ITM_registerTMCloneTable
u/UH
[]A\A]A^A_
hello world!
;*3$"
对于strings工具来说,更为常见的用法时为了查询系统中运行模块的版本信息,相对于查看模块运行日志,strings提供了一个更快捷的手段,当然这需要开发过程中在程序中增加特定版本信息的字符串。