利用GCC 的-pg 属性调试linux app/driver

[原创文章] 作者:[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
~
~

你可能感兴趣的:(linux)