diff options
Diffstat (limited to 'rts/StgCRun.c')
-rw-r--r-- | rts/StgCRun.c | 175 |
1 files changed, 10 insertions, 165 deletions
diff --git a/rts/StgCRun.c b/rts/StgCRun.c index 82d4a4c372..ab66c649fc 100644 --- a/rts/StgCRun.c +++ b/rts/StgCRun.c @@ -59,8 +59,8 @@ #include "StgRun.h" #include "Capability.h" -#include "RtsUtils.h" #if defined(DEBUG) +#include "RtsUtils.h" #include "Printer.h" #endif @@ -90,6 +90,14 @@ StgFunPtr StgReturn(void) #else /* !USE_MINIINTERPRETER */ +#if defined(LEADING_UNDERSCORE) +#define STG_RUN "_StgRun" +#define STG_RETURN "_StgReturn" +#else +#define STG_RUN "StgRun" +#define STG_RETURN "StgReturn" +#endif + #if defined(mingw32_HOST_OS) /* * Note [Windows Stack allocations] @@ -249,122 +257,6 @@ StgRunIsImplementedInAssembler(void) #define STG_HIDDEN ".hidden " #endif -/* -Note [Unwinding foreign exports on x86-64] -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -For foreign exports, that is Haskell functions exported as C functions when -we unwind we have to unwind from Haskell code into C code. The current story -is as follows: - - * The Haskell stack always has stg_stop_thread_info frame at the bottom - * We annotate stg_stop_thread_info to unwind the instruction pointer to a - label inside StgRun called StgRunJmp. It's the last instruction before the - code jumps into Haskell. - * StgRun - which is implemented in assembler is annotated with some manual - unwinding information. It unwinds all the registers that it has saved - on the stack. This is important as rsp and rbp are often required for - getting to the next frame and the rest of the saved registers are useful - when inspecting locals in gdb. - - - Example x86-64 stack for an FFI call - from C into a Haskell function: - - - HASKELL HEAP - "ADDRESS SPACE" - - +--------------------+ <------ rbp - | | - | | - | | - | | - | Haskell | - | evaluation stack | - | | - | | - |--------------------| - |stg_catch_frame_info| - |--------------------| - | stg_forceIO_info | - |--------------------| - |stg_stop_thread_info| ------- - +--------------------+ | - ... | - (other heap objects) | - ... | - | - | - | - C STACK "ADDRESS SPACE" | - v - +-----------------------------+ <------ rsp - | | - | RESERVED_C_STACK_BYTES ~16k | - | | - |-----------------------------| - | rbx || - |-----------------------------| \ - | rbp | | - |-----------------------------| \ - | r12 | | - |-----------------------------| \ - | r13 | | STG_RUN_STACK_FRAME_SIZE - |-----------------------------| / - | r14 | | - |-----------------------------| / - | r15 | | - |-----------------------------|/ - | rip saved by call StgRun | - | in schedule() | - +-----------------------------+ - ... - schedule() stack frame - - - Lower addresses on the top - -One little snag in this approach is that the annotations accepted by the -assembler are surprisingly unexpressive. I had to resort to a .cfi_escape -and hand-assemble a DWARF expression. What made it worse was that big numbers -are LEB128 encoded, which makes them variable byte length, with length depending -on the magnitude. I took a shortcut and assumed the magnitude of the relevant -constant. I think it changes very rarely, so it shouldn't be a big burden. - -Here's an example stack generated this way: - - Thread 1 "m" hit Breakpoint 1, Fib_zdfstableZZC0ZZCmainZZCFibZZCfib1_info () at Fib.hs:9 - 9 fib a = return (a + 1) - #0 Fib_zdfstableZZC0ZZCmainZZCFibZZCfib1_info () at Fib.hs:9 - #1 stg_catch_frame_info () at rts/Exception.cmm:372 - #2 stg_forceIO_info () at rts/StgStartup.cmm:178 - #3 stg_stop_thread_info () at rts/StgStartup.cmm:42 - #4 0x00000000007048ab in StgRunIsImplementedInAssembler () at rts/StgCRun.c:255 - #5 0x00000000006fcf42 in schedule (initialCapability=initialCapability@entry=0x8adac0 <MainCapability>, task=task@entry=0x8cf2a0) at rts/Schedule.c:451 - #6 0x00000000006fe18e in scheduleWaitThread (tso=0x4200006388, ret=<optimized out>, pcap=0x7fffffffdac0) at rts/Schedule.c:2533 - #7 0x000000000040a21e in hs_fib () - #8 0x000000000040a083 in main (argc=1, argv=0x7fffffffdc48) at m.cpp:15 - -(This is from patched gdb. See Note [Info Offset].) - -The previous approach was to encode the unwinding information for select -registers in stg_stop_thread_info with Cmm annotations. The unfortunate thing -about that approach was that it required introduction of an artificial MachSp -register that wasn't meaningful outside unwinding. I discovered that to get -stack unwinding working under -threaded runtime I also needed to unwind rbp -which would require adding MachRbp. If we wanted to see saved locals in gdb, -we'd have to add more. The core of the problem is that Cmm is architecture -independent, while unwinding isn't. - -Note [Unwinding foreign imports] -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -For unwinding foreign imports, that is C functions exposed as Haskell functions -no special handling is required. The C function unwinds according to the rip -saved on the stack by the call instruction. Then we perform regular Haskell -stack unwinding. -*/ - - static void GNUC3_ATTRIBUTE(used) StgRunIsImplementedInAssembler(void) { @@ -405,28 +297,6 @@ StgRunIsImplementedInAssembler(void) "movq %%xmm14,128(%%rax)\n\t" "movq %%xmm15,136(%%rax)\n\t" #endif - - /* - * Let the unwinder know where we saved the registers - * See Note [Unwinding foreign exports on x86-64]. - */ - ".cfi_def_cfa rsp, 0\n\t" - ".cfi_offset rbx, %c2\n\t" - ".cfi_offset rbp, %c3\n\t" - ".cfi_offset r12, %c4\n\t" - ".cfi_offset r13, %c5\n\t" - ".cfi_offset r14, %c6\n\t" - ".cfi_offset r15, %c7\n\t" - ".cfi_offset rip, %c8\n\t" - ".cfi_escape " // DW_CFA_val_expression is not expressible otherwise - "0x16, " // DW_CFA_val_expression - "0x07, " // register num 7 - rsp - "0x04, " // block length - "0x77, " // DW_OP_breg7 - signed LEB128 offset from rsp - "%c9, " // signed LEB128 encoded delta - byte 1 - "%c10, " // signed LEB128 encoded delta - byte 2 - "%c11\n\t" // signed LEB128 encoded delta - byte 2 - /* * Set BaseReg */ @@ -443,12 +313,6 @@ StgRunIsImplementedInAssembler(void) #else "movq %%rdi,%%rax\n\t" #endif - - STG_GLOBAL xstr(STG_RUN_JMP) "\n" -#if !defined(mingw32_HOST_OS) - STG_HIDDEN xstr(STG_RUN_JMP) "\n" -#endif - xstr(STG_RUN_JMP) ":\n\t" "jmp *%%rax\n\t" ".globl " STG_RETURN "\n" @@ -485,26 +349,7 @@ StgRunIsImplementedInAssembler(void) : : "i"(RESERVED_C_STACK_BYTES), - "i"(STG_RUN_STACK_FRAME_SIZE /* stack frame size */), - "i"(RESERVED_C_STACK_BYTES /* rbx relative to cfa (rsp) */), - "i"(RESERVED_C_STACK_BYTES + 8 /* rbp relative to cfa (rsp) */), - "i"(RESERVED_C_STACK_BYTES + 16 /* r12 relative to cfa (rsp) */), - "i"(RESERVED_C_STACK_BYTES + 24 /* r13 relative to cfa (rsp) */), - "i"(RESERVED_C_STACK_BYTES + 32 /* r14 relative to cfa (rsp) */), - "i"(RESERVED_C_STACK_BYTES + 40 /* r15 relative to cfa (rsp) */), - "i"(RESERVED_C_STACK_BYTES + STG_RUN_STACK_FRAME_SIZE - /* rip relative to cfa */), -#define RSP_DELTA (RESERVED_C_STACK_BYTES + STG_RUN_STACK_FRAME_SIZE + 8) -#if (RSP_DELTA < (1<<14)) || (RSP_DELTA >= (1<<21)) -#error "RSP_DELTA signed LEB128 encoding isn't 3 bytes" -#endif - "i"((RSP_DELTA & 127) | 128 - /* signed LEB128-encoded delta from rsp - byte 1 */), - "i"(((RSP_DELTA >> 7) & 127) | 128 - /* signed LEB128-encoded delta from rsp - byte 2 */), - "i"((RSP_DELTA >> 14) & 127 - /* signed LEB128-encoded delta from rsp - byte 3 */) -#undef RSP_DELTA + "i"(STG_RUN_STACK_FRAME_SIZE /* stack frame size */) ); /* * See Note [Stack Alignment on X86] |