一、堆、栈
在分析段错误之前,先了解一下什么是堆?什么是栈?
堆:一般由开发者分配释放,如果没有释放,程序结束时,在有的OS中可能会被自动释放,分配方式类似于链表。堆的操作方式为,队列优先,先进先出的原则。
栈:由操作系统自动分配,存放函数的参数值,局部变量。栈的操作方式为,先进后出的原则。
堆栈中定义了一些操作。 两个最重要的是PUSH和POP。
PUSH:操作在堆栈的顶部加入一个元素。
POP:操作相反,在堆栈顶部移去一个元素,并将堆栈的大小减一
二、分析应用程序段错误
1、修改内核,让内核有打印应用程序段错误的能力。
在内核arch/arm/目录下检索,grep -nr "Unable to handle kernel"。在mm/fault.c中找到相应的处理函数。
static void
__do_user_fault(struct task_struct *tsk, unsigned long addr,
unsigned int fsr, unsigned int sig, int code,
struct pt_regs *regs)
{
struct siginfo si;
if (addr > TASK_SIZE)
harden_branch_predictor();
clear_siginfo(&si);
#ifdef CONFIG_DEBUG_USER
if (((user_debug & UDBG_SEGV) && (sig == SIGSEGV)) ||
((user_debug & UDBG_BUS) && (sig == SIGBUS))) {
printk(KERN_DEBUG "%s: unhandled page fault (%d) at 0x%08lx, code 0x%03x\n",
tsk->comm, sig, addr, fsr);
show_pte(tsk->mm, addr);
show_regs(regs);
}
#endif
tsk->thread.address = addr;
tsk->thread.error_code = fsr;
tsk->thread.trap_no = 14;
si.si_signo = sig;
si.si_errno = 0;
si.si_code = code;
si.si_addr = (void __user *)addr;
force_sig_info(sig, &si, tsk);
}
在.config文件中检查是否打开了这个宏CONFIG_DEBUG_USER。没有打开,就make menuconfig配置。内核一般默认是打开的。其次就是user_debug,这个变量在u-boot中指定,之前测试的u-boot一直没有打开。重启开发板,设置user_debug = 0xff,暴力一点吧。
set bootargs noinitrd root=/dev/mtdblock4 rw init=/linuxrc rootfstype=yaffs2 console=ttySAC0,115200 user_debug=0xff
这里简单写了一个段错误的测试代码:测试一下。
#include <stdio.h>
void C(int *p){
*p =