[原创文章] 作者:[email protected] 欢迎转载,转载请指明出处: http://blog.csdn.net/whqwhqwhq/article/details/6853084
GCC的-pg 会为每个function call 插入一个_mcount的routine 功能,这个_mcount的原型为
void _mcount(void);
在linux调试时常不知道driver死在了哪个function中, 如果写自己的 _mcount 并且在其中打印出caller那不就解决了!
需要解决的两个问题是
1. 写自己的 void _mcount(void), 并且注意此function 编译时不能加 -pg属性,否则就会自己无限调用自己,直到stack溢出死机!
2. 在_count 中查找caller的地址。这是个小难点。
经测试是可行的。我在mips平台上做的实验,以下内容的mips32平台相关。
mips利用ra寄存器保存caller的返回地址,并且保存在sp中。相当反汇编代码为
00400840 <_mcount>:
400840: 27bdffe0 addiu sp,sp,-32
400844: afbf001c sw ra,28(sp)
400848: afbe0018 sw s8,24(sp)
40084c: 03a0f021 move s8,sp
即ra会保存在sp+28处,发现sp+28处即为ra地址!只要将sp+28值取出即可,这地址为function执行完后下一次指令。
这里取了个巧!因为sp是动态的,在实际代码编译出来之前,你不知道_mcount会用多少sp。先随便写一个值,如下
void _mcount(void)
{
int addr_calling;
asm(
"lw %0,12($30)\n"
"addi %0,%0,-8\n"
"nop\n"
:"=r"(addr_calling));
printf("Calling function address: 0x%p\n", addr_calling);
}
然后利用objdump查此处代码:
00400840 <_mcount>:
400840: 27bdffe0 addiu sp,sp,-32
400844: afbf001c sw ra,28(sp)
400848: afbe0018 sw s8,24(sp)
40084c: 03a0f021 move s8,sp
400850: 23c2000c lw v0,12(s8)
400854: 2042fffc addi v0,v0,-8
400858: 00000000 nop
发现sp利用了32个字节!将c code更改一下,为
void _mcount(void)
{
int addr_calling;
asm(
"lw %0,28($30)\n"
"addi %0,%0,-8\n"
"nop\n"
:"=r"(addr_calling));
printf("Calling function address: 0x%p\n", addr_calling);
}
在application 中证明是可行的,在调试驱动程序时也应该是可行的,毕竟这是gcc 的特性。
贴整个source code:
file: mcount.c
#include
void _mcount(void)
{
int addr_calling;
asm(
"lw %0,28($30)\n"
"addi %0,%0,-8\n"
"nop\n"
:"=r"(addr_calling));
printf("Calling function address: 0x%p\n", addr_calling);
}
file: main.c
#include "stdio.h"
extern void _mcount(void);
void call_sub1(int );
int main()
{
int a=10;
printf("in main function.\n");
call_sub1(a);
return 0;
}
void call_sub1(int a)
{
printf("in call_sub1, a is %d \n", a);
}
file: Makefile
CC = /opt/timesys/dbau1300/toolchain/bin/mipsisa32el-timesys-linux-gnu-gcc
OBJDUMP = /opt/timesys/dbau1300/toolchain/bin/mipsisa32el-timesys-linux-gnu-objdump
all:
$(CC) -c main.c -pg
$(CC) -c mcount.c
$(CC) main.o mcount.o -o test1 -pg
$(OBJDUMP) -D test1 >dis-pg.S
~
~