fault.ha (3609B)
1 // SPDX-License-Identifier: MPL-2.0 2 // (c) Hare authors <https://harelang.org> 3 4 use debug::image; 5 use rt; 6 use unix::signal; 7 use unix::signal::{sig}; 8 use fmt; 9 10 // altstack.s 11 let altstack: [ALTSTACK_SIZE]uintptr; 12 13 // 16 KiB, sync with altstack.s 14 def ALTSTACK_SIZE: size = 16384; 15 16 @init fn init_overflow() void = { 17 rt::sigaltstack(&rt::stack_t { 18 ss_sp = rt::malloc(ALTSTACK_SIZE): *opaque, 19 ss_flags = 0, 20 ss_size = ALTSTACK_SIZE, 21 }, null)!; 22 signal::handle(sig::SEGV, &signal_handler, signal::flag::ONSTACK); 23 signal::handle(sig::FPE, &signal_handler, signal::flag::ONSTACK); 24 signal::handle(sig::BUS, &signal_handler, signal::flag::ONSTACK); 25 signal::handle(sig::ILL, &signal_handler, signal::flag::ONSTACK); 26 }; 27 28 fn signal_handler(sig: sig, info: *signal::siginfo, uctx: *opaque) void = { 29 signal::resetall(); 30 31 const ip = uctx_ip(uctx); 32 const sp = uctx_sp(uctx); 33 const addr = info.addr: uintptr; 34 let frame = uctx_frame(uctx); 35 36 switch (sig) { 37 case sig::SEGV => 38 const is_overflow = addr & ~0xFFFF == sp & ~0xFFFF; 39 fmt::errorfln("{} ({}) at address 0x{:x}", 40 if (is_overflow) "Stack overflow" 41 else "Illegal pointer access", 42 errcode_str(sig, info.code), addr): void; 43 case sig::BUS => 44 fmt::errorfln("Bus error ({}) at address 0x{:x}", 45 errcode_str(sig, info.code), addr): void; 46 case sig::FPE => 47 // addr is the location of the faulting instruction, construct 48 // an additional synethetic stack frame 49 let copy = frame; frame = mkframe(©, addr); 50 fmt::errorfln("Arithmetic exception ({})", 51 errcode_str(sig, info.code)): void; 52 case => void; 53 }; 54 55 const self = match (image::self()) { 56 case let img: image::image => 57 yield img; 58 case => halt(); 59 }; 60 defer image::close(&self); 61 62 fmt::errorln("Backtrace:")!; 63 backtrace(&self, frame); 64 65 halt(); 66 }; 67 68 fn errcode_str(sig: sig, code: signal::code) const str = { 69 // Note: this only handles a few cases by design 70 // It also is limited only to error codes defined by POSIX 71 switch (sig) { 72 case sig::ILL => 73 switch (code) { 74 case signal::code::ILLOPC => return "illegal opcode"; 75 case signal::code::ILLOPN => return "illegal operand"; 76 case signal::code::ILLADR => return "illegal addressing mode"; 77 case signal::code::ILLTRP => return "illegal trap"; 78 case signal::code::PRVOPC => return "privileged opcode"; 79 case signal::code::PRVREG => return "privileged register"; 80 case signal::code::COPROC => return "coprocessor error"; 81 case signal::code::BADSTK => return "internal stack error"; 82 case => void; 83 }; 84 case sig::FPE => 85 switch (code) { 86 case signal::code::INTDIV => return "integer divide by zero"; 87 case signal::code::INTOVF => return "integer overflow"; 88 case signal::code::FLTDIV => return "floating-point divide by zero"; 89 case signal::code::FLTOVF => return "floating-point overflow"; 90 case signal::code::FLTUND => return "floating-point underflow"; 91 case signal::code::FLTRES => return "floating-point inexact result"; 92 case signal::code::FLTINV => return "invalid floating-point operation"; 93 case signal::code::FLTSUB => return "subscript out of range"; 94 case => void; 95 }; 96 case sig::SEGV => 97 switch (code) { 98 case signal::code::MAPERR => return "address not mapped to object"; 99 case signal::code::ACCERR => return "invalid permissions for mapped object"; 100 case => void; 101 }; 102 case sig::BUS => 103 switch (code) { 104 case signal::code::ADRALN => return "invalid address alignment"; 105 case signal::code::ADRERR => return "nonexistent physical address"; 106 case signal::code::OBJERR => return "object-specific hardware error"; 107 case => void; 108 }; 109 case => void; 110 }; 111 112 return "unknown reason"; 113 };