linux异常处理

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

linux下糟糕的异常处理方式

linux下发生异常,芯片会自动产生一个异常中断。在这异常中断处理程序中会判断异常来自用户程序或者内核,如果是发生在用户程序,那么会产生一个异常信号,再根据异常信号的回调函数通知用户程序发生异常。如果发生在内核里面,那么就会搜索内核模块的异常结构表,找到相应的处理调用地址,修改异常中断的返回地址为异常处理的地址,中断返回的时候程序就跳到异常处理程序处理执行了。但具体这两种处理方法都很糟糕,下面简要分析一下。

linux系统把所有进程数据结构都放于内核,这就增加了一些不必要的切换时间。linux 可以通过系统调用,安装信号的回调函数,这回调函数指针存放在内核的进程数据结构里面。这点windows处理得比较好,windows把进程数据结构分成了两部分,一部分敏感数据放于内核的进程数据结构里面,加以保护,另一部分不敏感数据就放于用户空间,这样当访问那些不加保护的数据时,就不用切换到内核,节约了时间。像windows下异常处理,也是一种回调函数,但因为结构放于用户空间,安装的时候就很方便,也节约切换时间。

上面那一点只是效率问题,但linux内核的异常处理那才是糟糕。先介绍一下linux内核的异常处理结构吧,看明白了你自然就知道糟糕到什么程度了。要了解这,显然应该是先从异常中断入手。下面主要是x86芯片的一些处理,但别的芯片下的也应该差不多。

文件:entry.S:

ENTRY(general_protection)

pushl $ SYMBOL_NAME(do_general_protection)

jmp error_code

这是异常中断入口,显然会执行do_general_protection。

文件traps.c:

asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)

{

if (regs->eflags & VM_MASK)

goto gp_in_vm86;

/*

虚拟8086下发生的异常否

*/

if (!(regs->xcs & 3))

goto gp_in_kernel;

/*

内核发生的异常否

*/

current->tss.error_code = error_code;

current->tss.trap_no = 13;

force_sig(SIGSEGV, current);

/*

用户程序发生的异常,产生异常信号,

根据异常信号的句柄回调处理函数

*/

return;

gp_in_vm86:

lock_kernel();

handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code);

/*

虚拟8086的处理

*/

unlock_kernel();

return;

gp_in_kernel:

{

unsigned long fixup;

fixup = search_exception_table(regs->eip);

/*

根据异常时的eip搜索异常结构链

找到处理程序地址

*/

if (fixup) {

regs->eip = fixup;

/*

找到异常处理地址,修改中断返回地址,中断返回时跳到异常处理程序处*/

return;

}

die("general protection fault", regs, error_code);

/*

没找到异常处理程序地址,显示内核异常信息后死机

*/

}

}

搜索异常处理程序代码文件extable.c:

extern const struct exception_table_entry __start___ex_table[];

extern const struct exception_table_entry __stop___ex_table[];

unsigned long search_exception_table(unsigned long addr)

{

unsigned long ret;

#ifndef CONFIG_MODULES

/* There is only the kernel to search.*/

ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr); if (ret) return ret;

#else

/* The kernel is the last "module" -- no need to treat it special.*/ struct module *mp;

for (mp = module_list; mp != NULL; mp = mp->next) {

if (mp->ex_table_start == NULL)

continue;

ret = search_one_table(mp->ex_table_start,

mp->ex_table_end - 1, addr);

if (ret) return ret;

}

#endif

return 0;

}

static inline unsigned long

search_one_table(const struct exception_table_entry *first,

const struct exception_table_entry *last,

unsigned long value)

{

while (first <= last) {

const struct exception_table_entry *mid;

long diff;

mid = (last - first) / 2 + first;

diff = mid->insn - value;

if (diff == 0)

return mid->fixup;

else if (diff < 0)

first = mid+1;

else

last = mid-1;

}

return 0;

}

相关文档
最新文档