首页 > *nix技术, 跟踪调试 > gdb调试内联函数与宏

gdb调试内联函数与宏

2012年8月27日 发表评论 阅读评论 13,728 次浏览

在用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://www.lenky.info/archives/2012/08/1910http://lenky.info/?p=1910


备注:如无特殊说明,文章内容均出自Lenky个人的真实理解而并非存心妄自揣测来故意愚人耳目。由于个人水平有限,虽力求内容正确无误,但仍然难免出错,请勿见怪,如果可以则请留言告之,并欢迎来讨论。另外值得说明的是,Lenky的部分文章以及部分内容参考借鉴了网络上各位网友的热心分享,特别是一些带有完全参考的文章,其后附带的链接内容也许更直接、更丰富,而我只是做了一下归纳&转述,在此也一并表示感谢。关于本站的所有技术文章,欢迎转载,但请遵从CC创作共享协议,而一些私人性质较强的心情随笔,建议不要转载。

法律:根据最新颁布的《信息网络传播权保护条例》,如果您认为本文章的任何内容侵犯了您的权利,请以Email或书面等方式告知,本站将及时删除相关内容或链接。

  1. 本文目前尚无任何评论.
  1. 本文目前尚无任何 trackbacks 和 pingbacks.