broadcom6838开发环境实现函数栈追踪
在嵌入式设备开发中。内核为内核模块的函数栈追踪已经提供了非常好的支持,但用户层的函数栈追踪确没有非常好的提供支持。
在网上收集学习函数栈跟踪大部分都是描写叙述INTER体系架构支持栈帧的实现机制。或者直接给出glibc的现成库函数。
但假设开发环境是broadcom相关方案,通常使用的是MIPS32的体系架构,而且C库使用的是更小的uclibc。尽管MIPS32体系架构中也定义了栈帧寄存器s8(类似于Inter体系架构中常见的ebp寄存器),但经过GCC编译器的优化选项控制后,通常在O1以上的优化就已经去除了s8栈帧的使用,所以给函数栈追踪的实现就带来了一点点小麻烦。
通常情况下。函数的返回值还是使用压栈实现,所以仅仅要知道了函数每次调用时,返回值(ra寄存器)与当前栈顶(sp寄存器)的偏移量,就能够实现函数栈追踪,对函数反汇编能够了解到这个偏移量通过sw ra, xxxx(sp)能够得到,还有一个难题是怎么得到函数每次调用时的当前栈顶(sp寄存器),通过函数反汇编能够了解到addiu sp, sp, xxxx指令就是每次给函数分配当前栈帧大小的,所以仅仅要得到这个栈帧大小然后用sp进行差值计算就能够往回推出上一个sp的值了。还剩下最后一个问题,一步步获取上一个函数的栈顶,什么时候结束?答案就是仅仅要栈顶sp的寄存器为0就追踪到头了。通过这些分析我们能够了解到当前实现机制根本没用到程序的栈段内容。对,全然从程序指令段做为线索,获取程序执行时指令一步步找出函数栈的调用。看起来非常酷。但现实也比較残酷,比方我们上面分析说要得到栈顶sp的寄存器为0表示追踪到头,我当前调试环境在__start(能够參考一些链接载入的相关技术资料了解,其他main并非c的起始函数。__start才是c语言的起始函数)函数中使得sp为0的汇编指令为addu
ra, zero, zero,我还不清楚其他编译器是否会使用其他指令方法进行设置。所以我们当前实现的这个函数栈追跟踪功能的实现代码并非非常标准的。假设读者有幸參考该代码,请一定要在理解上面描写叙述的原理基础上。另外须要在您自己的编译开发环境进行调试,确保这个追踪功能代码自己不会引发Crash再使用,否则那玩笑就开的大了。
剩下就不多说了。直接付上我当前的开发环境及实现源代码,以及终于在broadcom6838板上执行的測试程序的效果图。
开发环境:
实现源代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <ucontext.h> #define abs(s) ((s) < 0 ? -(s) : (s)) #define CALL_TRACE_MAX_SIZE (10) #define MIPS_ADDIU_SP_SP_XXXX (0x27bd0000) /* instruction code for addiu sp, sp, xxxx */
#define MIPS_SW_RA_XXXX_SP (0xafbf0000) /* instruction code for sw ra, xxxx(sp) */
#define MIPS_ADDU_RA_ZERO_ZERO (0x0000f821) /* instruction code for addu ra, zero, zero */ void getCodeIn(unsigned long codeAddr, char *pCodeIn, int iCodeInSize, unsigned long *pOffset)
{
FILE *pFile = NULL;
char szLine[1000] = {0}; pFile = fopen("/proc/self/maps", "r");
if ( pFile != NULL )
{
while (fgets(szLine, sizeof(szLine), pFile))
{
char *pTmp = NULL;
char szAddr[500] = {0};
char szCodeIn[500] = {0};
unsigned long begin = 0;
unsigned long end = 0; sscanf(szLine, "%s %*s %*s %*s %*s %s", szAddr, szCodeIn); pTmp = strchr(szAddr, '-');
if ( pTmp != NULL )
{
*pTmp++ = '\0';
begin = strtoul(szAddr, NULL, 16);
end = strtoul(pTmp, NULL, 16);
} if ( codeAddr >= begin && codeAddr <= end )
{
strncpy(pCodeIn, szCodeIn, iCodeInSize);
*pOffset = codeAddr - begin;
return;
}
} fclose(pFile);
} strncpy(pCodeIn, "unknown", iCodeInSize);
*pOffset = 0;
} int backtrace_mips32(void **buffer, int size, ucontext_t *uc)
{
unsigned long *tmpl = NULL;
unsigned long *addr = NULL;
unsigned long *ra = NULL;
unsigned long *sp = NULL;
unsigned long *pc = NULL;
size_t ra_offset = 0;
size_t stack_size = 0;
int depth = 0; if (size == 0)
{
return 0;
} if (buffer == NULL || size < 0 || uc == NULL)
{
return -1;
} pc = (unsigned long *)(unsigned long)uc->uc_mcontext.pc;
ra = (unsigned long *)(unsigned long)uc->uc_mcontext.gregs[31];
sp = (unsigned long *)(unsigned long)uc->uc_mcontext.gregs[29]; buffer[0] = pc; if ( size == 1 )
{
return 1;
} for ( addr = pc; !ra_offset || !stack_size; --addr )
{
if ( ((*addr) & 0xffff0000) == MIPS_SW_RA_XXXX_SP)
{
ra_offset = (short)((*addr) & 0xffff);
}
else if ( ((*addr) & 0xffff0000) == MIPS_ADDIU_SP_SP_XXXX)
{
stack_size = abs((short)((*addr) & 0xffff));
}
else if ( (*addr) == MIPS_ADDU_RA_ZERO_ZERO )
{
return 1;
}
} if ( ra_offset > 0 )
{
tmpl = (unsigned long *)((char *)sp + ra_offset);
ra = (unsigned long *)(*tmpl);
} if ( stack_size > 0 )
{
sp = (unsigned long *)((unsigned long)sp + stack_size);
} for (depth = 1; depth < size && ra; ++depth)
{
buffer[depth] = ra; ra_offset = 0;
stack_size = 0; for (addr = ra; !ra_offset || !stack_size; --addr)
{
if ( ((*addr) & 0xffff0000) == MIPS_SW_RA_XXXX_SP)
{
ra_offset = (short)((*addr) & 0xffff);
}
else if ( ((*addr) & 0xffff0000) == MIPS_ADDIU_SP_SP_XXXX)
{
stack_size = abs((short)((*addr) & 0xffff));
}
else if ( (*addr) == MIPS_ADDU_RA_ZERO_ZERO )
{
return depth + 1;
}
} tmpl = (unsigned long *)((char *)sp + ra_offset);
ra = (unsigned long *)(*tmpl);
sp = (unsigned long *)((unsigned long)sp + stack_size);
} return depth;
} void signal_process(int sig_no, siginfo_t *sig_info, void *ucontext)
{
int i = 0;
unsigned long *callStack[CALL_TRACE_MAX_SIZE] = {0}; printf("\r\n*******************************************\r\n"); printf("recv signo %d\r\n", sig_no); backtrace_mips32((void **)callStack, CALL_TRACE_MAX_SIZE, (ucontext_t *)ucontext); printf("\r\ncall tracing:\r\n");
for ( i = 0; i < CALL_TRACE_MAX_SIZE; i++ )
{
char szCodeIn[100] = {0};
unsigned long addrOffset = 0; if ( callStack[i] == 0 )
{
break;
} getCodeIn((unsigned long)callStack[i], szCodeIn, sizeof(szCodeIn), &addrOffset); printf("\t[%02d] addr 0x%08x(offset 0x%08x), in %s\r\n", i, callStack[i], addrOffset, szCodeIn);
} printf("*******************************************\r\n"); if (sig_no == SIGSEGV)
{
signal(sig_no, SIG_DFL);
} sleep(3);
} void c(void)
{
int *p = 0;
printf("I am function [c]\r\n");
*p = 888;
} void b(void)
{
printf("I am function [b]\r\n");
c();
} void a(void)
{
printf("I am function [a]\r\n");
b();
} int main(int argc, char *argv[])
{
struct sigaction act = {0}; act.sa_sigaction = signal_process;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_SIGINFO; sigaction(SIGSEGV, &act, NULL); printf("I am function [main]\r\n"); a(); return 0;
}
执行效果图:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGl1amlhbmZlbmcxOTg0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
broadcom6838开发环境实现函数栈追踪的更多相关文章
- 转-subl配置全栈开发环境
为 Sublime Text 3 设置 Python 的全栈开发环境 Sublime Text 3 (ST3) 是一个轻量级的跨平台文字编辑器,尤以其轻快的速度,易用性和强大的社区支持而著称.它一经面 ...
- Win10构建Python全栈开发环境With WSL
目录 Win10构建Python全栈开发环境With WSL 启动WSL 总结 对<Dev on Windows with WSL>的补充 Win10构建Python全栈开发环境With ...
- Vue+koa2开发一款全栈小程序(5.服务端环境搭建和项目初始化)
1.微信公众平台小程序关联腾讯云 腾讯云的开发环境是给免费的一个后台,但是只能够用于开发,如果用于生产是需要花钱的,我们先用开发环境吧 1.用小程序开发邮箱账号登录微信公众平台 2.[设置]→[开发者 ...
- python全栈开发 生成器 :生成器函数,推导式及生成器表达式
python 全栈开发 1.生成器函数 2.推导式 3.生成器表达式 一.生成器函数 1.生成器: 生成器的本质就是迭代器 (1)生成器的特点和迭代器一样.取值方式和迭代器一样(__next__(), ...
- python全栈开发之匿名函数和递归函数
python 匿名函数和递归函数 python全栈开发,匿名函数,递归函数 匿名函数 lambda函数也叫匿名函数,即函数没有具体的名称.是为了解决一些功能很简单需求而设计的一句话函数.如下: #这段 ...
- 痞子衡嵌入式:在IAR开发环境下将关键函数重定向到RAM中执行的三种方法
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是在IAR开发环境下将关键函数重定向到RAM中执行的三种方法. 嵌入式项目里应用程序代码正常是放在 Flash 中执行的,但有时候也需要将 ...
- 痞子衡嵌入式:在MDK开发环境下将关键函数重定向到RAM中执行的几种方法
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是在MDK开发环境下将关键函数重定向到RAM中执行的几种方法. 这个关键函数重定向到 RAM 中执行系列文章,痞子衡已经写过 <IA ...
- 痞子衡嵌入式:在IAR开发环境下RT-Thread工程函数重定向失效分析
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是在IAR开发环境下RT-Thread工程函数重定向失效分析. 痞子衡旧文 <在IAR下将关键函数重定向到RAM中执行的方法> ...
- Python 全栈开发 -- 开发环境篇
开发环境是一个文本编辑器和 Python 解释器的组合.文本编辑器用来写代码,解释器提供了一种方法来运行编写的代码.一个文本编辑器可以像 Windows 上的 Notepad 一样简单,或是一个复杂的 ...
随机推荐
- C#的静态构造函数
“静态构造函数”典型应用于第一次使用类时的初始化工作,注意“第一次”,意思是它只执行一次. 有同学说了,类的初始化不是有构造函数嘛?我们回答:构造函数是每个实例被声明时都会执行的,它属于每一个实例,而 ...
- 关于android多点触控
最近项目需要一个多点触控缩放的功能.然后上网查了下资料 总结一下: 首先android sdk版本很重要,比如你在AndroidManifest.xml中指定android:minSdkVersion ...
- ASM丢失disk header导致ORA-15032、ORA-15040、ORA-15042 Diskgroup无法mount
SQL> select * from v$version; BANNER --------------------------– Oracle Database 11g Enterprise E ...
- 创建webservice 用service.xml配置(复杂点的方法)
用Axis2实现Web Service,虽然可以将POJO类放在axis2/WEB-INF/pojo目录中直接发布成Web Service,这样做不需要进行任何配置,但这些POJO类不能在任何包中.这 ...
- hdu1087Super Jumping! Jumping! Jumping!(最大递增序列和)
题意:棋牌游戏如今,一种被称为“超级跳!跳!跳!“HDU是非常流行的.也许你是个好孩子,这个游戏知之甚少,所以我介绍给你吧. 可以玩游戏由两个或两个以上的球员 .它由一个棋盘(棋盘)和一些棋子(棋子) ...
- JavaScript编程:使用DOM操作样式表
6.使用DOM操作样式表: 操纵元素的Style样式属性: background-color:style.backgroundColor color:style.col ...
- 已成功与服务器建立连接,但是在登录过程中发生错误。 (provider: SSL Provider, error: 0 - 接收到的消息异常,或格式不正确。)
之前做好的asp.net部署后,发现 访问数据库时: 异常:已捕获: "已成功与服务器建立连接,但是在登录过程中发生错误. (provider: SSL Provider, error: 0 ...
- 深度RAMOS,把操作系统全部安装在内存上
你看下深度RAMOS就知道了 RAMOS+音速启动+绿色软件+云端 很爽 http://www.shenduwin7.com/jiaocheng/52.html
- [Android学习笔记]try-catch
private boolean test() { boolean result = true; String str = null; try { Log.d("test",&quo ...
- STM8S 串口应用 UART2 STM8S105
//少说话.多做事,下面是我验证过没有问题的串口发送接受数据 //使用MCU stm8s105c6 UART2 //初始化时调用: GPIO_DeInit(GPIOD); /* Configure P ...