gdb调试内联函数与宏
在用gdb调试程序的时候,会遇到内联函数与宏的问题,下面来看看。
[root@www 1]# cat t.h #ifndef _T_H #define _T_H #include <stdio.h> static inline long utilfunc(long a, long b, long c) { long xx = a + 2; long yy = b + 3; long zz = c + 4; long sum = xx + yy + zz; return xx * yy * zz + sum; } #endif [root@www 1]# cat t.c /** * gcc -Wall -g -o t t.c */ #include "t.h" #define A 1 #define B (2+A) long myfunc(long a, long b, long c, long d, long e, long f, long g, long h) { long xx = a * b * c * d * e * f * g * h; long yy = a + b + c + d + e + f + g + h; long zz = utilfunc(xx, yy, xx % yy); return zz + 20; } int main(int argc, char *argv[]) { myfunc(11, 22, 33, 44, 55, 66, 77, 88); printf("%d\n", B); return 0; }
上面是测试源代码,无需多说,下面是几个编译实例:
[root@www 1]# gcc -Wall -O2 -o t.O2 t.c #普通优化编译 [root@www 1]# gcc -Wall -O2 -g -o t.O2.g t.c #普通优化并-g编译 [root@www 1]# gcc -Wall -O2 -pg -o t.O2.pg t.c #支持profiling编译 [root@www 1]# ls t.c t.h t.O2 t.O2.g t.O2.pg [root@www 1]# gcc -time -o t.tmp t.c #查看编译时间 # cc1 0.02 0.02 # as 0.00 0.01 # collect2 0.03 0.02 [root@www 1]# gcc -Q -o t.tmp t.c #查看编译详情 utilfunc myfunc main Analyzing compilation unit Performing interprocedural optimizations <visibility> <early_local_cleanups> <summary generate> <inline>Assembling functions: utilfunc myfunc main Execution times (seconds) preprocessing : 0.00 ( 0%) usr 0.00 ( 0%) sys 0.01 (17%) wall 149 kB ( 7%) ggc lexical analysis : 0.00 ( 0%) usr 0.01 (33%) sys 0.01 (17%) wall 0 kB ( 0%) ggc integrated RA : 0.01 (100%) usr 0.00 ( 0%) sys 0.01 (17%) wall 6 kB ( 0%) ggc TOTAL : 0.01 0.03 0.06 2101 kB [root@www 1]# ls t.c t.h t.O2 t.O2.g t.O2.pg t.tmp [root@www 1]#
第一个问题,内联函数无法下断点:
[root@www 1]# gdb t.O2.g -q Reading symbols from /home/work/1/t.O2.g...done. (gdb) b utilfunc Function "utilfunc" not defined. Make breakpoint pending on future shared library load? (y or [n]) n (gdb) q
怎么解决,带上fno-inline选项:
[root@www 1]# gcc -Wall -O2 -fno-inline -g -o t.O2.noinline.g t.c [root@www 1]# gdb t.O2.noinline.g -q Reading symbols from /home/work/1/t.O2.noinline.g...done. (gdb) b utilfunc Breakpoint 1 at 0x4004d0: file t.h, line 7. (gdb) q [root@www 1]#
关于内联函数,如果不加优化选项(比如-O2),那么gcc在编译过程中是不会做内联处理的,即便函数前面有inline关键字。如果要既做优化,又要不打开内联处理,那么该选项就帮上忙了。
第二个问题,无法查看宏定义:
[root@www 1]# gdb t.O2.noinline.g -q Reading symbols from /home/work/1/t.O2.noinline.g...done. (gdb) b main Breakpoint 1 at 0x400550: file t.c, line 19. (gdb) r Starting program: /home/work/1/t.O2.noinline.g Breakpoint 1, main (argc=1, argv=0x7fffffffe578) at t.c:19 19 { Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.7.el6.x86_64 (gdb) info macro A The symbol `A' has no definition as a C/C++ preprocessor macro at <user-defined>:-1 (gdb) q A debugging session is active. Inferior 1 [process 14582] will be killed. Quit anyway? (y or n) y
这可以通过-ggdb3来明确指定:
[root@www 1]# gcc -Wall -O2 -ggdb3 -fno-inline -g -o t.O2.gdb3.noinline.g t.c [root@www 1]# gdb t.O2.gdb3.noinline.g -q Reading symbols from /home/work/1/t.O2.gdb3.noinline.g...done. (gdb) b main Breakpoint 1 at 0x400550: file t.c, line 19. (gdb) r Starting program: /home/work/1/t.O2.gdb3.noinline.g Breakpoint 1, main (argc=1, argv=0x7fffffffe568) at t.c:19 19 { Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.7.el6.x86_64 (gdb) info macro A Defined at /home/work/1/t.c:6 #define A 1 (gdb) info macro B Defined at /home/work/1/t.c:7 #define B (2+A) (gdb) macro A Undefined macro command: "A". Try "help macro". (gdb) macro expand A expands to: 1 (gdb) macro expand B expands to: (2+1) (gdb)
值得注意的是,macro宏是有“作用域”的,也就是说同一个宏名在不同的代码处可能有不同的展开,所以gdb是利用当前代码行作为选择“作用域”的参考点,这样说可能不容易懂,直接看实例:
[root@www 1]# cat m.c /** * gcc -Wall -g -o t m.c */ #include "t.h" #define A 1 #define B (2*A) long myfunc(long a, long b, long c, long d, long e, long f, long g, long h) { #undef B long xx = a * b * c * d * e * f * g * h; long yy = a + b + c + d + e + f + g + h; #define B (2+A) long zz = utilfunc(xx, yy, xx % yy); return zz + 20; #undef B } int main(int argc, char *argv[]) { #define B (2-A) myfunc(11, 22, 33, 44, 55, 66, 77, 88); printf("%d\n", B); return 0; } [root@www 1]# gdb -q m Reading symbols from /home/work/1/m...done. (gdb) b main Breakpoint 1 at 0x4005d2: file m.c, line 24. (gdb) r Starting program: /home/work/1/m Breakpoint 1, main (argc=1, argv=0x7fffffffe588) at m.c:24 24 myfunc(11, 22, 33, 44, 55, 66, 77, 88); Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.7.el6.x86_64 (gdb) macro expand B expands to: (2-1) (gdb) s myfunc (a=11, b=22, c=33, d=44, e=55, f=66, g=77, h=88) at m.c:13 13 long xx = a * b * c * d * e * f * g * h; (gdb) macro expand B expands to: B (gdb) n 14 long yy = a + b + c + d + e + f + g + h; (gdb) macro expand B expands to: B (gdb) n 16 long zz = utilfunc(xx, yy, xx % yy); (gdb) 17 return zz + 20; (gdb) macro expand B expands to: (2+1) (gdb) n 19 } (gdb) main (argc=1, argv=0x7fffffffe588) at m.c:25 25 printf("%d\n", B); (gdb) macro expand B expands to: (2-1) (gdb)
如果当前应用程序在执行当中,比如在main()函数处下断点,然后执行r命令后被断了下来,那么当前代码列表就是main函数里的第一行作为参考点,后续就以当前执行行作为参考点。
[root@www 1]# cat m.c /** * gcc -Wall -g -o t m.c */ #include "t.h" #define A 1 long myfunc(long a, long b, long c, long d, long e, long f, long g, long h) { #define B (2+A) long xx = a * b * c * d * e * f * g * h; long yy = a + b + c + d + e + f + g + h; long zz = utilfunc(xx, yy, xx % yy); return zz + 20; #undef B } int main(int argc, char *argv[]) { #define B (2-A) myfunc(11, 22, 33, 44, 55, 66, 77, 88); printf("%d\n", B); return 0; } [root@www 1]# gcc -ggdb3 -o m m.c [root@www 1]# gdb m -q Reading symbols from /home/work/1/m...done. (gdb) info macro A The symbol `A' has no definition as a C/C++ preprocessor macro at <user-defined>:-1 (gdb) list main 15 return zz + 20; 16 #undef B 17 } 18 19 int main(int argc, char *argv[]) 20 { 21 #define B (2-A) 22 myfunc(11, 22, 33, 44, 55, 66, 77, 88); 23 printf("%d\n", B); 24 return 0; (gdb) info macro A Defined at /home/work/1/m.c:6 #define A 1 (gdb) macro expand A expands to: 1 (gdb) macro expand B expands to: (2-1) (gdb) list myfunc 5 6 #define A 1 7 8 long myfunc(long a, long b, long c, long d, 9 long e, long f, long g, long h) 10 { 11 #define B (2+A) 12 long xx = a * b * c * d * e * f * g * h; 13 long yy = a + b + c + d + e + f + g + h; 14 long zz = utilfunc(xx, yy, xx % yy); (gdb) macro expand A expands to: 1 (gdb) macro expand B expands to: (2+1) (gdb) q [root@www 1]# gdb m -q Reading symbols from /home/work/1/m...done. (gdb) b main Breakpoint 1 at 0x4005d2: file m.c, line 22. (gdb) r Starting program: /home/work/1/m Breakpoint 1, main (argc=1, argv=0x7fffffffe588) at m.c:22 22 myfunc(11, 22, 33, 44, 55, 66, 77, 88); Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.7.el6.x86_64 (gdb) macro expand A expands to: 1 (gdb) macro expand B expands to: (2-1) (gdb) q A debugging session is active. Inferior 1 [process 22745] will be killed. Quit anyway? (y or n) y [root@www 1]#
如果如果应用程序当前未处于执行状态,并且也没有使用list命令指定当前当前代码行,那么宏可能无法显示,上面最开始的“The symbol `A’ has no definition as a C/C++ preprocessor macro”提示表明了这种情况。上面实例里另外两处不同的list命令(list还可直接指定到行,那么此时宏展开就以该行作为参考点),对应的宏B展开也各不相同。
关于gcc的更多选项,可以查看man手册。
另外,今天在用kgdb调试的时候,遇到一个实际问题,下断点提示不成功:
(gdb) b get_page_from_freelist Breakpoint 1 at 0xffffffff810dd020: file mm/page_alloc.c, line 1646 (gdb) c Continuing. Warning: Cannot insert breakpoint 1. Error accessing memory address 0xffffffff810dd020: Unknown error 18446744073709551615.
根据链接:http://kernel.org/pub/linux/kernel/people/jwessel/kdb/CompilingAKernel.html#CompileKGDB找到了解决方案:
If the architecture that you are using supports the kernel option CONFIG_DEBUG_RODATA, you should consider turning it off. This option will prevent the use of software breakpoints because it marks certain regions of the kernel’s memory space as read-only. If kgdb supports it for the architecture you are using, you can use hardware breakpoints if you desire to run with the CONFIG_DEBUG_RODATA option turned on, else you need to turn off this option.
修改.config文件后重编译内核后,OK。
转载请保留地址:http://lenky.info/archives/2012/08/27/1910 或 http://lenky.info/?p=1910
备注:如无特殊说明,文章内容均出自Lenky个人的真实理解而并非存心妄自揣测来故意愚人耳目。由于个人水平有限,虽力求内容正确无误,但仍然难免出错,请勿见怪,如果可以则请留言告之,并欢迎来讨论。另外值得说明的是,Lenky的部分文章以及部分内容参考借鉴了网络上各位网友的热心分享,特别是一些带有完全参考的文章,其后附带的链接内容也许更直接、更丰富,而我只是做了一下归纳&转述,在此也一并表示感谢。关于本站的所有技术文章,欢迎转载,但请遵从CC创作共享协议,而一些私人性质较强的心情随笔,建议不要转载。
法律:根据最新颁布的《信息网络传播权保护条例》,如果您认为本文章的任何内容侵犯了您的权利,请以或书面等方式告知,本站将及时删除相关内容或链接。