Skip to content

Commit 54158fe

Browse files
authored
Merge pull request #22134 from JuliaLang/yyc/signals/ill
Show failing instruction on SIGILL
2 parents 0931156 + e5983d7 commit 54158fe

File tree

4 files changed

+156
-8
lines changed

4 files changed

+156
-8
lines changed

src/signal-handling.c

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,13 @@
33
#include <stdlib.h>
44
#include <stddef.h>
55
#include <stdio.h>
6+
#include <inttypes.h>
67
#include "julia.h"
78
#include "julia_internal.h"
9+
#ifndef _OS_WINDOWS_
10+
#include <unistd.h>
11+
#include <sys/mman.h>
12+
#endif
813

914
#ifdef __cplusplus
1015
extern "C" {
@@ -88,12 +93,133 @@ JL_DLLEXPORT void jl_exit_on_sigint(int on)
8893
exit_on_sigint = on;
8994
}
9095

96+
static uintptr_t jl_get_pc_from_ctx(const void *_ctx);
97+
void jl_show_sigill(void *_ctx);
98+
static size_t jl_safe_read_mem(const volatile char *ptr, char *out, size_t len)
99+
{
100+
jl_ptls_t ptls = jl_get_ptls_states();
101+
jl_jmp_buf *old_buf = ptls->safe_restore;
102+
jl_jmp_buf buf;
103+
ptls->safe_restore = &buf;
104+
volatile size_t i = 0;
105+
if (!jl_setjmp(buf, 0)) {
106+
for (;i < len;i++) {
107+
out[i] = ptr[i];
108+
}
109+
}
110+
ptls->safe_restore = old_buf;
111+
return i;
112+
}
113+
91114
#if defined(_WIN32)
92115
#include "signals-win.c"
93116
#else
94117
#include "signals-unix.c"
95118
#endif
96119

120+
static uintptr_t jl_get_pc_from_ctx(const void *_ctx)
121+
{
122+
#if defined(_OS_LINUX_) && defined(_CPU_X86_64_)
123+
return ((ucontext_t*)_ctx)->uc_mcontext.gregs[REG_RIP];
124+
#elif defined(_OS_FREEBSD_) && defined(_CPU_X86_64_)
125+
return ((ucontext_t*)_ctx)->uc_mcontext.mc_rip;
126+
#elif defined(_OS_LINUX_) && defined(_CPU_X86_)
127+
return ((ucontext_t*)_ctx)->uc_mcontext.gregs[REG_EIP];
128+
#elif defined(_OS_FREEBSD_) && defined(_CPU_X86_)
129+
return ((ucontext_t*)_ctx)->uc_mcontext.mc_eip;
130+
#elif defined(_OS_DARWIN_)
131+
return ((ucontext64_t*)_ctx)->uc_mcontext64->__ss.__rip;
132+
#elif defined(_OS_WINDOWS_) && defined(_CPU_X86_)
133+
return ((CONTEXT*)_ctx)->Eip;
134+
#elif defined(_OS_WINDOWS_) && defined(_CPU_X86_64_)
135+
return ((CONTEXT*)_ctx)->Rip;
136+
#elif defined(_OS_LINUX_) && defined(_CPU_AARCH64_)
137+
return ((ucontext_t*)_ctx)->uc_mcontext.pc;
138+
#elif defined(_OS_LINUX_) && defined(_CPU_ARM_)
139+
return ((ucontext_t*)_ctx)->uc_mcontext.arm_pc;
140+
#else
141+
// TODO for PPC
142+
return 0;
143+
#endif
144+
}
145+
146+
void jl_show_sigill(void *_ctx)
147+
{
148+
char *pc = (char*)jl_get_pc_from_ctx(_ctx);
149+
// unsupported platform
150+
if (!pc)
151+
return;
152+
#if defined(_CPU_X86_64_) || defined(_CPU_X86_)
153+
uint8_t inst[15]; // max length of x86 instruction
154+
size_t len = jl_safe_read_mem(pc, (char*)inst, sizeof(inst));
155+
// ud2
156+
if (len >= 2 && inst[0] == 0x0f && inst[1] == 0x0b) {
157+
jl_safe_printf("Unreachable reached at %p\n", (void*)pc);
158+
}
159+
else {
160+
jl_safe_printf("Invalid instruction at %p: ", (void*)pc);
161+
for (int i = 0;i < len;i++) {
162+
if (i == 0) {
163+
jl_safe_printf("0x%02" PRIx8, inst[i]);
164+
}
165+
else {
166+
jl_safe_printf(", 0x%02" PRIx8, inst[i]);
167+
}
168+
}
169+
jl_safe_printf("\n");
170+
}
171+
#elif defined(_OS_LINUX_) && defined(_CPU_AARCH64_)
172+
uint32_t inst = 0;
173+
size_t len = jl_safe_read_mem(pc, (char*)&inst, 4);
174+
if (len < 4)
175+
jl_safe_printf("Fault when reading instruction: %d bytes read\n", (int)len);
176+
if (inst == 0xd4200020) { // brk #0x1
177+
// The signal might actually be SIGTRAP instead, doesn't hurt to handle it here though.
178+
jl_safe_printf("Unreachable reached at %p\n", pc);
179+
}
180+
else {
181+
jl_safe_printf("Invalid instruction at %p: 0x%08" PRIx32 "\n", pc, inst);
182+
}
183+
#elif defined(_OS_LINUX_) && defined(_CPU_ARM_)
184+
ucontext_t *ctx = (ucontext_t*)_ctx;
185+
if (ctx->uc_mcontext.arm_cpsr & (1 << 5)) {
186+
// Thumb
187+
uint16_t inst[2] = {0, 0};
188+
size_t len = jl_safe_read_mem(pc, (char*)&inst, 4);
189+
if (len < 2)
190+
jl_safe_printf("Fault when reading Thumb instruction: %d bytes read\n", (int)len);
191+
// LLVM and GCC uses different code for the trap...
192+
if (inst[0] == 0xdefe || inst[0] == 0xdeff) {
193+
// The signal might actually be SIGTRAP instead, doesn't hurt to handle it here though.
194+
jl_safe_printf("Unreachable reached in Thumb mode at %p: 0x%04" PRIx16 "\n",
195+
(void*)pc, inst[0]);
196+
}
197+
else {
198+
jl_safe_printf("Invalid Thumb instruction at %p: 0x%04" PRIx16 ", 0x%04" PRIx16 "\n",
199+
(void*)pc, inst[0], inst[1]);
200+
}
201+
}
202+
else {
203+
uint32_t inst = 0;
204+
size_t len = jl_safe_read_mem(pc, (char*)&inst, 4);
205+
if (len < 4)
206+
jl_safe_printf("Fault when reading instruction: %d bytes read\n", (int)len);
207+
// LLVM and GCC uses different code for the trap...
208+
if (inst == 0xe7ffdefe || inst == 0xe7f000f0) {
209+
// The signal might actually be SIGTRAP instead, doesn't hurt to handle it here though.
210+
jl_safe_printf("Unreachable reached in ARM mode at %p: 0x%08" PRIx32 "\n",
211+
(void*)pc, inst);
212+
}
213+
else {
214+
jl_safe_printf("Invalid ARM instruction at %p: 0x%08" PRIx32 "\n", (void*)pc, inst);
215+
}
216+
}
217+
#else
218+
// TODO for PPC
219+
(void)_ctx;
220+
#endif
221+
}
222+
97223
// what to do on a critical error
98224
void jl_critical_error(int sig, bt_context_t *context, uintptr_t *bt_data, size_t *bt_size)
99225
{

src/signals-mach.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,12 @@ static void jl_throw_in_thread(int tid, mach_port_t thread, jl_value_t *exceptio
141141
kern_return_t ret = thread_get_state(thread, x86_THREAD_STATE64, (thread_state_t)&state, &count);
142142
HANDLE_MACH_ERROR("thread_get_state", ret);
143143
jl_ptls_t ptls2 = jl_all_tls_states[tid];
144-
145-
ptls2->bt_size = rec_backtrace_ctx(ptls2->bt_data, JL_MAX_BT_SIZE,
146-
(bt_context_t*)&state);
147-
ptls2->exception_in_transit = exception;
144+
if (!ptls2->safe_restore) {
145+
assert(exception);
146+
ptls2->bt_size = rec_backtrace_ctx(ptls2->bt_data, JL_MAX_BT_SIZE,
147+
(bt_context_t*)&state);
148+
ptls2->exception_in_transit = exception;
149+
}
148150
jl_call_in_state(ptls2, &state, &jl_rethrow);
149151
ret = thread_set_state(thread, x86_THREAD_STATE64,
150152
(thread_state_t)&state, count);
@@ -214,6 +216,10 @@ kern_return_t catch_exception_raise(mach_port_t exception_port,
214216
}
215217
return KERN_SUCCESS;
216218
}
219+
if (ptls2->safe_restore) {
220+
jl_throw_in_thread(tid, thread, jl_stackovf_exception);
221+
return KERN_SUCCESS;
222+
}
217223
#ifdef SEGV_EXCEPTION
218224
if (1) {
219225
#else

src/signals-unix.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,8 @@ void sigdie_handler(int sig, siginfo_t *info, void *context)
177177
jl_ptls_t ptls = jl_get_ptls_states();
178178
sigset_t sset;
179179
uv_tty_reset_mode();
180+
if (sig == SIGILL)
181+
jl_show_sigill(context);
180182
jl_critical_error(sig, jl_to_bt_context(context),
181183
ptls->bt_data, &ptls->bt_size);
182184
sigfillset(&sset);

src/signals-win.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,12 @@ void __cdecl crt_sig_handler(int sig, int num)
8686
}
8787
break;
8888
default: // SIGSEGV, (SSIGTERM, IGILL)
89+
if (ptls->safe_restore)
90+
jl_rethrow();
8991
memset(&Context, 0, sizeof(Context));
9092
RtlCaptureContext(&Context);
93+
if (sig == SIGILL)
94+
jl_show_sigill(&Context);
9195
jl_critical_error(sig, &Context, ptls->bt_data, &ptls->bt_size);
9296
raise(sig);
9397
}
@@ -105,17 +109,19 @@ void restore_signals(void)
105109
void jl_throw_in_ctx(jl_value_t *excpt, CONTEXT *ctxThread, int bt)
106110
{
107111
jl_ptls_t ptls = jl_get_ptls_states();
108-
assert(excpt != NULL);
109112
#if defined(_CPU_X86_64_)
110113
DWORD64 Rsp = (ctxThread->Rsp&(DWORD64)-16) - 8;
111114
#elif defined(_CPU_X86_)
112115
DWORD32 Esp = (ctxThread->Esp&(DWORD32)-16) - 4;
113116
#else
114117
#error WIN16 not supported :P
115118
#endif
116-
ptls->bt_size = bt ? rec_backtrace_ctx(ptls->bt_data, JL_MAX_BT_SIZE,
117-
ctxThread) : 0;
118-
ptls->exception_in_transit = excpt;
119+
if (!ptls->safe_restore) {
120+
assert(excpt != NULL);
121+
ptls->bt_size = bt ? rec_backtrace_ctx(ptls->bt_data, JL_MAX_BT_SIZE,
122+
ctxThread) : 0;
123+
ptls->exception_in_transit = excpt;
124+
}
119125
#if defined(_CPU_X86_64_)
120126
*(DWORD64*)Rsp = 0;
121127
ctxThread->Rsp = Rsp;
@@ -220,12 +226,20 @@ static LONG WINAPI _exception_handler(struct _EXCEPTION_POINTERS *ExceptionInfo,
220226
}
221227
return EXCEPTION_CONTINUE_EXECUTION;
222228
}
229+
if (ptls->safe_restore) {
230+
jl_throw_in_ctx(NULL, ExceptionInfo->ContextRecord, in_ctx);
231+
return EXCEPTION_CONTINUE_EXECUTION;
232+
}
223233
if (ExceptionInfo->ExceptionRecord->ExceptionInformation[0] == 1) { // writing to read-only memory (e.g. mmap)
224234
jl_throw_in_ctx(jl_readonlymemory_exception,
225235
ExceptionInfo->ContextRecord,in_ctx);
226236
return EXCEPTION_CONTINUE_EXECUTION;
227237
}
228238
}
239+
if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION) {
240+
jl_safe_printf("\n");
241+
jl_show_sigill(ExceptionInfo->ContextRecord);
242+
}
229243
jl_safe_printf("\nPlease submit a bug report with steps to reproduce this fault, and any error messages that follow (in their entirety). Thanks.\nException: ");
230244
switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
231245
case EXCEPTION_ACCESS_VIOLATION:

0 commit comments

Comments
 (0)