Exception Linux中的零除异常处理
我很想了解linux中的零除异常处理。当执行除零操作时,将生成陷阱,即Exception Linux中的零除异常处理,exception,linux-kernel,signals,Exception,Linux Kernel,Signals,我很想了解linux中的零除异常处理。当执行除零操作时,将生成陷阱,即INT0发送到处理器,并最终SIGFPE信号发送到执行该操作的进程 如我所见,被零除异常在trap\u init()函数中注册为 set_trap_gate(0, ÷_error); 我想详细地知道,在生成INT0和将SIGFPE发送到进程之前,发生了什么事情?陷阱处理程序从 set\u intr\u gate将处理程序函数的地址写入idt\u表 如何定义除法误差函数?作为一个 宏DO\u ERROR\u
INT0
发送到处理器,并最终SIGFPE
信号发送到执行该操作的进程
如我所见,被零除异常在trap\u init()
函数中注册为
set_trap_gate(0, ÷_error);
我想详细地知道,在生成
INT0
和将SIGFPE
发送到进程之前,发生了什么事情?陷阱处理程序从
set\u intr\u gate
将处理程序函数的地址写入idt\u表
如何定义除法误差函数?作为一个
宏DO\u ERROR\u INFO
定义如下:
(实际上,它定义了do_divide_error
函数,该函数由带有准备参数的小型asm编码存根“入口点”调用。宏在entry_32.S
as和entry_64.S
as:)中定义)
因此,当用户除以零时(此操作到达OoO中的失效缓冲区),硬件生成陷阱,将%eip设置为divide\u error
存根,它设置帧并调用C函数do\u divide\u error
。函数do\u divide\u error
将创建描述错误的siginfo\u t
struct(signo=SIGFPE
,addr=失败指令的地址等),然后它将尝试通知所有已注册的通知程序(实际上它是一个钩子,有时由;kprobe的-仅用于int3或gpf;uprobe的-再次仅用于int3,等等)
由于DIE_陷阱通常不会被通知程序阻止,因此将调用。它有一个短代码do\u trap
:
139 static void __kprobes
140 do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
141 long error_code, siginfo_t *info)
142 {
143 struct task_struct *tsk = current;
...
157 tsk->thread.error_code = error_code;
158 tsk->thread.trap_nr = trapnr;
170
171 if (info)
172 force_sig_info(signr, info, tsk);
...
175 }
do_trap
将向当前进程发送一个信号,该信号将“强制一个进程不能忽略的信号”。。如果进程有一个活动的调试器(我们当前的进程是由gdb或strace设置的ptrace
),那么send\u signal
将信号SIGFPE从do\u trap
转换为SIGTRAP到调试器。如果没有调试器-信号SIGFPE应该在保存核心文件时终止我们的进程,因为这是SIGFPE的默认操作(检查“标准信号”部分,在表中搜索SIGFPE)
进程不能将SIGFPE设置为忽略它(这里我不确定:),但它可以定义自己的信号处理程序来处理信号()。此处理程序可能只是从siginfo打印%eip,运行backtrace()
并死亡;或者它甚至可以尝试恢复情况并返回失败的指令。例如,在一些JIT中,如qemu
、java
或valgrind
,这可能很有用;或者在高级语言中,如java
或ghc
,这可以将SIGFPE转换为语言异常,并且这些语言中的程序可以处理异常(例如,来自的意大利面)
debian中有一个SIGFPE处理程序列表,可通过codesearch查找或查找此文件的可能副本。
DO_ERROR_INFO(X86_TRAP_DE, SIGFPE, "divide error", divide_error, FPE_INTDIV,
regs->ip)
193 #define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
194 dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \
195 { \
196 siginfo_t info; \
197 enum ctx_state prev_state; \
198 \
199 info.si_signo = signr; \
200 info.si_errno = 0; \
201 info.si_code = sicode; \
202 info.si_addr = (void __user *)siaddr; \
203 prev_state = exception_enter(); \
204 if (notify_die(DIE_TRAP, str, regs, error_code, \
205 trapnr, signr) == NOTIFY_STOP) { \
206 exception_exit(prev_state); \
207 return; \
208 } \
209 conditional_sti(regs); \
210 do_trap(trapnr, signr, str, regs, error_code, &info); \
211 exception_exit(prev_state); \
212 }
139 static void __kprobes
140 do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
141 long error_code, siginfo_t *info)
142 {
143 struct task_struct *tsk = current;
...
157 tsk->thread.error_code = error_code;
158 tsk->thread.trap_nr = trapnr;
170
171 if (info)
172 force_sig_info(signr, info, tsk);
...
175 }