下面是各命令的详细使用方法: addr2line
addr2line是用来将程序地址转换成其所对应的程序源文件及所对应的代码行,当然,也可以得到所对应的函数。为了说明addr2line是如何使用的,我们需要有一个练习用的程序。先采用编辑工具编辑一个test.c源文件,其内容如图所示。
运行如下的命令将test.c编译成可执行文件,
注意:必须加 -g 这个选项 并运行之。在运行test程序后,我们可以在其终端上看到它打印出的fun()函数的地址 —— 0x80483e4。
现在,我们可以用这一地址来看一看addr2line是如何使用的。在终端中运行如下的命令,从命令的运行结果来看,addr2line工具正确的指出了地址0x80483e4 所对于应的程序的具体位置是在哪以及所对应的函数名是什么。
可能有人会问了:这个0x80483e4地址是我们打印出来,即然有打印,我们一般情况下也会打印出其具体的函数位置,而不是只打印地址,我为何要这么绕一下通过addr2line去找到地址所对应的函数呢?其实,这里打印出地址只是为了得到一个地址以便用于练习。在现实中,地址往往是在调试过程中或是当程序崩溃时通过某种方式获得的。此外,采用nm工具(后面会讲到)可以得到如下的函数地址信息。
farsight@ubuntu:~/kernel$ nm -n test
w _Jv_RegisterClasses
w __gmon_start__
U __libc_start_main@@GLIBC_2.0
U printf@@GLIBC_2.0
080482b4 T _init
08048330 T _start
08048360 t __do_global_dtors_aux
080483c0 t frame_dummy
080483e4 T fun
08048401 T main
08048420 T __libc_csu_init
08048490 T __libc_csu_fini
08048492 T __i686.get_pc_thunk.bx
080484a0 t __do_global_ctors_aux
080484cc T _fini
080484e8 R _fp_hw
080484ec R _IO_stdin_used
0804862c r __FRAME_END__
08049f14 d __CTOR_LIST__
08049f14 d __init_array_end
08049f14 d __init_array_start
08049f18 d __CTOR_END__
08049f1c d __DTOR_LIST__
08049f20 D __DTOR_END__
08049f24 d __JCR_END__
08049f24 d __JCR_LIST__
08049f28 d _DYNAMIC
08049ff4 d _GLOBAL_OFFSET_TABLE_
0804a00c D __data_start
0804a00c W data_start
0804a010 D __dso_handle
0804a014 A __bss_start
0804a014 A _edata
0804a014 b completed.6159
0804a018 b dtor_idx.6161
0804a01c A _end
as
as汇编器,将汇编代码汇编成目标文件
** size **
size工具,就是列程序文件中各段的大小。在后面的章节中,我们会使用objdump查看段信息,除了这三个段还有.rdata和.idata两个段,其中.rdata段被归类到.text段中,而.idata段被归类到.data段中。下面是采用size工具所显示出的test中的段大小信息。
nm
nm用于列出程序文件中的符号,符号是指函数或是变量名什么的。
farsight@ubuntu:~/kernel$ nm -n test
w _Jv_RegisterClasses
w __gmon_start__
U __libc_start_main@@GLIBC_2.0
U printf@@GLIBC_2.0
080482b4 T _init
08048330 T _start
08048360 t __do_global_dtors_aux
080483c0 t frame_dummy
080483e4 T fun
08048401 T main
08048420 T __libc_csu_init
08048490 T __libc_csu_fini
08048492 T __i686.get_pc_thunk.bx
080484a0 t __do_global_ctors_aux
080484cc T _fini
080484e8 R _fp_hw
080484ec R _IO_stdin_used
0804862c r __FRAME_END__
08049f14 d __CTOR_LIST__
08049f14 d __init_array_end
08049f14 d __init_array_start
08049f18 d __CTOR_END__
08049f1c d __DTOR_LIST__
08049f20 D __DTOR_END__
08049f24 d __JCR_END__
08049f24 d __JCR_LIST__
08049f28 d _DYNAMIC
08049ff4 d _GLOBAL_OFFSET_TABLE_
0804a00c D __data_start
0804a00c W data_start
0804a010 D __dso_handle
0804a014 A __bss_start
0804a014 A _edata
0804a014 b completed.6159
0804a018 b dtor_idx.6161
0804a01c A _end
nm所列出的每一行有三部分组成:
第一列是指程序运行时的符号所对应的地址,对于函数则地址表示的是函数的开始地址,对于变量则表示的是变量的存储地址;
第二列是指相应符号是放在哪一个段的;
第三列则是指符号的名称。
在前面我们讲解addr2line时,我们提到addr2line是将程序地址转换成这一地址所对应的具体函数是什么,而nm则是全面的列出这些信息。但是,nm不具备列出符号所在的源文件及其行号这一功能,因此,我们说每一个工具有其特定的功能,在嵌入式系统的开发过程中我们需要灵活的运用它们。
对于nm列出的第二列信息,非常的有用,其意义在于可以了解我们在程序中所定义的一个符号(比如变量等等)是被放在程序的哪一个段的,下表列出了第二列将会出现的部分字母的含义,要参看所有字母的意思,请在你的开发环境中运行“man nm”。