我很好奇在linux中理解除以零異常處理。當執行除零操作時,產生陷阱,即,將INT0
發送到處理器,並最終將信號發送到執行該操作的過程。在Linux中除以零異常處理
依我之見,零異常的鴻溝是註冊於trap_init()
功能
set_trap_gate(0, ÷_error);
我想詳細的瞭解,什麼都INT0
之間發生在產生和SIGFPE
之前被送到處理?
我很好奇在linux中理解除以零異常處理。當執行除零操作時,產生陷阱,即,將INT0
發送到處理器,並最終將信號發送到執行該操作的過程。在Linux中除以零異常處理
依我之見,零異常的鴻溝是註冊於trap_init()
功能
set_trap_gate(0, ÷_error);
我想詳細的瞭解,什麼都INT0
之間發生在產生和SIGFPE
之前被送到處理?
陷阱處理程序在trap_init
函數註冊從arch/x86/kernel/traps.c
void __init trap_init(void)
..
set_intr_gate(X86_TRAP_DE, ÷_error);
set_intr_gate
寫處理函數的地址複製到idt_table
x86/include/asm/desc.h。
如何定義divide_error函數?作爲macro in traps.c
DO_ERROR_INFO(X86_TRAP_DE, SIGFPE, "divide error", divide_error, FPE_INTDIV,
regs->ip)
而且宏DO_ERROR_INFO
定義a bit above in the same traps.c:
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 }
(實際上它定義了do_divide_error
功能這是由小ASM編碼存根「入口點」與準備參數調用。該宏被定義爲entry_32.S
爲ENTRY(divide_error)
和entry_64.S
爲macro zeroentry
:1303 zeroentry divide_error do_divide_error
)
因此,當用戶除以零(並且此操作到達OoO中的退休緩衝區)時,硬件生成陷阱,將%eip設置爲divide_error
存根,它設置該框架並調用C函數do_divide_error
。函數do_divide_error
將創建描述錯誤的siginfo_t
結構(signo = SIGFPE
,addr =失敗指令的地址等),然後它會嘗試通知所有通知程序,並註冊爲register_die_notifier
(實際上它是一個掛鉤,有時由the in-kernel debugger "kgdb"使用; kprobe的kprobe_exceptions_notify - 僅適用於int3或gpf; uprobe的arch_uprobe_exception_notify
- 也只適用於int3等)。
由於DIE_TRAP通常不會被通知程序阻止,因此將調用do_trap
function。它有do_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
會發出一個信號發送到current
過程與force_sig_info
,這將「力的信號,這一進程不能忽視」。如果有一個積極的調試器(我們當前的進程是由gdb或strace執行的ptrace
),那麼send_signal
會將信號SIGFPE轉換爲當前進程從do_trap
到SIGTRAP到調試器。如果沒有調試器 - 信號SIGFPE應該在保存核心文件時終止我們的進程,因爲這是SIGFPE的默認操作(在「標準信號」部分查詢man 7 signal,在表格中搜索SIGFPE)。
該進程無法設置SIGFPE忽略它(我不確定這裏:1),但它可以定義自己的信號處理程序來處理信號(example of handing SIGFPEanother)。這個處理程序可能只是打印siginfo的%eip,運行backtrace()
並死亡;或者甚至可能試圖恢復情況並返回失敗的指令。例如,在某些JIT中可能會有用,如qemu
,java
或valgrind
;或者使用高級語言如java
或ghc
,這可能會將SIGFPE轉換爲語言異常,並且這些語言的程序可以處理該異常(例如,來自openjdk is in hotspot/src/os/linux/vm/os_linux.cpp
的意大利麪條)。
沒有爲siagaction SIGFPE或在通過於codesearch Debian的SIGFPE處理程序的列表signal SIGFPE
的
可能重複[爲什麼Linux內核使用陷阱門來處理鴻溝\ _error例外?](http://stackoverflow.com/問題/ 8530794/why-linux-kernel-use-trap-gate-to-handle-divide-error-exception)檢查出這個** [answer](http://stackoverflow.com/a/15501983/319204)* *。 – TheCodeArtist