Skip to content

Commit

Permalink
Automatically compute stack layout for backtrace
Browse files Browse the repository at this point in the history
Makes changing the interpreter state struct less error prone
  • Loading branch information
Keno authored and JeffBezanson committed Nov 7, 2017
1 parent 4e7ba61 commit 4288b0e
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 30 deletions.
73 changes: 43 additions & 30 deletions src/interpreter-stacktrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,20 +62,30 @@ uintptr_t __stop_jl_interpreter_frame = (uintptr_t)&__stop_jl_interpreter_frame_
#define STR(x) #x
#define XSTR(x) STR(x)

// Instructions: Make sure that MAX_INTERP_STATE_SIZE is a multiple of
// alignof(struct interpreter_state) and larger than
// sizeof(struct interpreter_state). Additionally, make sure that
// MAX_INTERP_STATE_SIZE+STACK_PADDING+8 is a multiple of 16 to
// ensure the proper stack alignment.
#define MAX_INTERP_STATE_SIZE 56
#define STACK_PADDING 0

static_assert(sizeof(interpreter_state) <= MAX_INTERP_STATE_SIZE, "Stack layout invariants violated.");
static_assert(MAX_INTERP_STATE_SIZE % alignof(interpreter_state) == 0, "Stack layout invariants violated");
static_assert(((MAX_INTERP_STATE_SIZE + STACK_PADDING + 8) % 16) == 0, "Stack layout invariants violated");

#ifdef _OS_WINDOWS_
#define STACK_PADDING 32
size_t TOTAL_STACK_PADDING = STACK_PADDING + 32;
#else
#define STACK_PADDING 0
size_t TOTAL_STACK_PADDING = STACK_PADDING;
#endif

asm(
ASM_ENTRY
MANGLE("enter_interpreter_frame") ":\n"
".cfi_startproc\n"
// Note: make sure stack is 8-byte aligned here even though
// sizeof(struct interpreter_state) might not be.
"\tsubq $56, %rsp\n"
".cfi_def_cfa_offset 64\n"
"\tsubq $" XSTR(MAX_INTERP_STATE_SIZE) " + " XSTR(STACK_PADDING)", %rsp\n"
".cfi_def_cfa_offset " XSTR(MAX_INTERP_STATE_SIZE) " + " XSTR(STACK_PADDING)" + 8\n"
#ifdef _OS_WINDOWS_
"\tmovq %rcx, %rax\n"
"\tleaq " XSTR(STACK_PADDING) "(%rsp), %rcx\n"
Expand All @@ -96,7 +106,7 @@ asm(
#ifdef _OS_WINDOWS_
"\taddq $32, %rsp\n"
#endif
"\taddq $56, %rsp\n"
"\taddq $" XSTR(MAX_INTERP_STATE_SIZE) " + " XSTR(STACK_PADDING)", %rsp\n"
#ifndef _OS_DARWIN_
// Somehow this throws off compact unwind info on OS X
".cfi_def_cfa_offset 8\n"
Expand All @@ -107,11 +117,22 @@ asm(
);

#define CALLBACK_ABI
static_assert(sizeof(interpreter_state) <= 56, "Update assembly code above");

#elif defined(_CPU_X86_)

#define STACK_PADDING 12
#define MAX_INTERP_STATE_SIZE 36
#ifndef _OS_WINDOWS_
#define STACK_PADDING 8
#else
#define STACK_PADDING 4
#endif

static_assert(sizeof(interpreter_state) <= MAX_INTERP_STATE_SIZE, "Update assembly code above");
static_assert(MAX_INTERP_STATE_SIZE % alignof(interpreter_state) == 0, "Update assembly code above");
#ifndef _OS_WINDOWS_
static_assert(MAX_INTERP_STATE_SIZE + STACK_PADDING % 16 == 0, "Update assembly code above");
#endif

asm(
ASM_ENTRY
MANGLE("enter_interpreter_frame") ":\n"
Expand Down Expand Up @@ -144,40 +165,32 @@ asm(
* incorrect stack address for the previous frame. To work around all of this,
* use ebp based addressing on win32
*/
#define FP_CAPTURE_OFFSET 32
#define FP_CAPTURE_OFFSET MAX_INTERP_STATE_SIZE
#define ENTRY_OFFSET 8
"\tpushl %ebp\n"
".cfi_def_cfa_offset 8\n"
".cfi_def_cfa_offset " XSTR(ENTRY_OFFSET)"\n"
"\tmovl %esp, %ebp\n"
#endif
// sizeof(struct interpreter_state) is 32
"\tsubl $36, %esp\n"
#ifdef _OS_WINDOWS_
".cfi_def_cfa_offset 44\n"
#else
".cfi_def_cfa_offset 40\n"
#define ENTRY_OFFSET 4
#endif
"\tsubl $" XSTR(MAX_INTERP_STATE_SIZE) ", %esp\n"
".cfi_def_cfa_offset " XSTR(MAX_INTERP_STATE_SIZE) " + " XSTR(ENTRY_OFFSET) "\n"
"\tmovl %ecx, %eax\n"
"\tmovl %esp, %ecx\n"
// Zero out the src field
"\tmovl $0, (%esp)\n"
// Restore 16 byte stack alignment
#ifdef _OS_WINDOWS_
// Technically not necessary, because we don't assume this alignment, but
// let's be nice if we ever start doing that.
"\tsubl $8, %esp\n"
#else
"\tsubl $12, %esp\n"
#endif
".cfi_def_cfa_offset 52\n"
// Technically not necessary on windows, because we don't assume this
// alignment, but let's be nice if we ever start doing that.
"\tsubl $" STACK_PADDING ", %esp\n"
".cfi_def_cfa_offset " XSTR(MAX_INTERP_STATE_SIZE) " + " XSTR(ENTRY_OFFSET) "\n"
"Lenter_interpreter_frame_start_val:\n"
"\tcalll *%eax\n"
"Lenter_interpreter_frame_end_val:\n"
"\taddl $" XSTR(MAX_INTERP_STATE_SIZE) " + " XSTR(STACK_PADDING) ", %esp\n"
#ifdef _OS_WINDOWS_
"\taddl $44, %esp\n"
".cfi_def_cfa_offset 8\n"
"\tpopl %ebp\n"
#else
"\taddl $48, %esp\n"
#endif
".cfi_def_cfa_offset 4\n"
"\tret\n"
Expand All @@ -186,7 +199,7 @@ asm(
);

#define CALLBACK_ABI __attribute__((fastcall))
static_assert(sizeof(interpreter_state) <= 32, "Update assembly code above");
static_assert(sizeof(interpreter_state) <= MAX_INTERP_STATE_SIZE, "Update assembly code above");

#else
#warning "Interpreter backtraces not implemented for this platform"
Expand Down Expand Up @@ -214,7 +227,7 @@ JL_DLLEXPORT size_t jl_capture_interp_frame(uintptr_t *data, uintptr_t sp, uintp
#ifdef FP_CAPTURE_OFFSET
interpreter_state *s = (interpreter_state *)(fp-FP_CAPTURE_OFFSET);
#else
interpreter_state *s = (interpreter_state *)(sp+STACK_PADDING);
interpreter_state *s = (interpreter_state *)(sp+TOTAL_STACK_PADDING);
#endif
if (space_remaining <= 1)
return 0;
Expand Down
10 changes: 10 additions & 0 deletions src/julia_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,16 @@
// For C++, C++11 or MSVC is required. Both provide `static_assert`.
#endif

#ifndef alignof
# ifndef __cplusplus
# ifdef __GNUC__
# define alignof _Alignof
# else
# define alignof(...) 1
# endif
# endif
#endif

#if jl_has_builtin(__builtin_assume)
#define jl_assume(cond) (__extension__ ({ \
__typeof__(cond) cond_ = (cond); \
Expand Down

0 comments on commit 4288b0e

Please sign in to comment.