diff options
Diffstat (limited to 'erts/emulator/hipe/hipe_risc_stack.c')
-rw-r--r-- | erts/emulator/hipe/hipe_risc_stack.c | 312 |
1 files changed, 312 insertions, 0 deletions
diff --git a/erts/emulator/hipe/hipe_risc_stack.c b/erts/emulator/hipe/hipe_risc_stack.c new file mode 100644 index 0000000000..976ca0b85d --- /dev/null +++ b/erts/emulator/hipe/hipe_risc_stack.c @@ -0,0 +1,312 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2008-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* $Id$ + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "global.h" +#include "bif.h" +#include "hipe_stack.h" + +/* get NR_ARG_REGS from the arch */ +#if defined(__arm__) +#include "hipe_arm_asm.h" +#elif defined(__powerpc__) || defined(__ppc__) || defined(__powerpc64__) +#include "hipe_ppc_asm.h" +#elif defined(__sparc__) +#include "hipe_sparc_asm.h" +#endif + +AEXTERN(void,nbif_fail,(void)); +AEXTERN(void,nbif_stack_trap_ra,(void)); + +/* + * hipe_print_nstack() is called from hipe_bifs:show_nstack/1. + */ +static void print_slot(Eterm *sp, unsigned int live) +{ + Eterm val = *sp; + printf(" | 0x%0*lx | 0x%0*lx | ", + 2*(int)sizeof(long), (unsigned long)sp, + 2*(int)sizeof(long), val); + if (live) + erts_printf("%.30T", val); + printf("\r\n"); +} + +void hipe_print_nstack(Process *p) +{ + Eterm *nsp; + Eterm *nsp_end; + const struct sdesc *sdesc1; + const struct sdesc *sdesc; + unsigned long ra; + unsigned long exnra; + unsigned int mask; + unsigned int sdesc_size; + unsigned int i; + unsigned int nstkarity; + static const char dashes[2*sizeof(long)+5] = { + [0 ... 2*sizeof(long)+3] = '-' + }; + + printf(" | NATIVE STACK |\r\n"); + printf(" |%s|%s|\r\n", dashes, dashes); + printf(" | %*s | 0x%0*lx |\r\n", + 2+2*(int)sizeof(long), "heap", + 2*(int)sizeof(long), (unsigned long)p->heap); + printf(" | %*s | 0x%0*lx |\r\n", + 2+2*(int)sizeof(long), "high_water", + 2*(int)sizeof(long), (unsigned long)p->high_water); + printf(" | %*s | 0x%0*lx |\r\n", + 2+2*(int)sizeof(long), "hend", + 2*(int)sizeof(long), (unsigned long)p->htop); + printf(" | %*s | 0x%0*lx |\r\n", + 2+2*(int)sizeof(long), "old_heap", + 2*(int)sizeof(long), (unsigned long)p->old_heap); + printf(" | %*s | 0x%0*lx |\r\n", + 2+2*(int)sizeof(long), "old_hend", + 2*(int)sizeof(long), (unsigned long)p->old_hend); + printf(" | %*s | 0x%0*lx |\r\n", + 2+2*(int)sizeof(long), "nsp", + 2*(int)sizeof(long), (unsigned long)p->hipe.nsp); + printf(" | %*s | 0x%0*lx |\r\n", + 2+2*(int)sizeof(long), "nstend", + 2*(int)sizeof(long), (unsigned long)p->hipe.nstend); + printf(" | %*s| 0x%0*lx |\r\n", + 2+2*(int)sizeof(long)+1, "nstblacklim", + 2*(int)sizeof(long), (unsigned long)p->hipe.nstblacklim); + printf(" | %*s | 0x%0*lx |\r\n", + 2+2*(int)sizeof(long), "nstgraylim", + 2*(int)sizeof(long), (unsigned long)p->hipe.nstgraylim); + printf(" | %*s | 0x%0*lx |\r\n", + 2+2*(int)sizeof(long), "nra", + 2*(int)sizeof(long), (unsigned long)p->hipe.nra); + printf(" | %*s | 0x%0*x |\r\n", + 2+2*(int)sizeof(long), "narity", + 2*(int)sizeof(long), p->hipe.narity); + printf(" |%s|%s|\r\n", dashes, dashes); + printf(" | %*s | %*s |\r\n", + 2+2*(int)sizeof(long), "Address", + 2+2*(int)sizeof(long), "Contents"); + + ra = (unsigned long)p->hipe.nra; + if (!ra) + return; + nsp = p->hipe.nsp; + nsp_end = p->hipe.nstend - 1; + + nstkarity = p->hipe.narity - NR_ARG_REGS; + if ((int)nstkarity < 0) + nstkarity = 0; + + /* First RA not on stack. Dump current args first. */ + printf(" |%s|%s|\r\n", dashes, dashes); + for (i = 0; i < nstkarity; ++i) + print_slot(&nsp[i], 1); + nsp += nstkarity; + + if (ra == (unsigned long)&nbif_stack_trap_ra) + ra = (unsigned long)p->hipe.ngra; + sdesc = hipe_find_sdesc(ra); + + for (;;) { /* INV: nsp at bottom of frame described by sdesc */ + printf(" |%s|%s|\r\n", dashes, dashes); + if (nsp >= nsp_end) { + if (nsp == nsp_end) + return; + fprintf(stderr, "%s: passed end of stack\r\n", __FUNCTION__); + break; + } + ra = nsp[sdesc_fsize(sdesc)]; + if (ra == (unsigned long)&nbif_stack_trap_ra) + sdesc1 = hipe_find_sdesc((unsigned long)p->hipe.ngra); + else + sdesc1 = hipe_find_sdesc(ra); + sdesc_size = sdesc_fsize(sdesc) + 1 + sdesc_arity(sdesc); + i = 0; + mask = sdesc->livebits[0]; + for (;;) { + if (i == sdesc_fsize(sdesc)) { + printf(" | 0x%0*lx | 0x%0*lx | ", + 2*(int)sizeof(long), (unsigned long)&nsp[i], + 2*(int)sizeof(long), ra); + if (ra == (unsigned long)&nbif_stack_trap_ra) + printf("STACK TRAP, ORIG RA 0x%lx", (unsigned long)p->hipe.ngra); + else + printf("NATIVE RA"); + if ((exnra = sdesc_exnra(sdesc1)) != 0) + printf(", EXNRA 0x%lx", exnra); + printf("\r\n"); + } else + print_slot(&nsp[i], (mask & 1)); + if (++i >= sdesc_size) + break; + if (i & 31) + mask >>= 1; + else + mask = sdesc->livebits[i >> 5]; + } + nsp += sdesc_size; + sdesc = sdesc1; + } + abort(); +} + +/* XXX: x86's values, not yet tuned for anyone else */ +#define MINSTACK 128 +#define NSKIPFRAMES 4 + +void hipe_update_stack_trap(Process *p, const struct sdesc *sdesc) +{ + Eterm *nsp; + Eterm *nsp_end; + unsigned long ra; + int n; + + nsp = p->hipe.nsp; + nsp_end = p->hipe.nstend - 1; + if ((unsigned long)((char*)nsp_end - (char*)nsp) < MINSTACK*sizeof(Eterm*)) { + p->hipe.nstgraylim = NULL; + return; + } + n = NSKIPFRAMES; + for (;;) { + nsp += sdesc_fsize(sdesc); + if (nsp >= nsp_end) { + p->hipe.nstgraylim = NULL; + return; + } + ra = nsp[0]; + if (--n <= 0) + break; + nsp += 1 + sdesc_arity(sdesc); + sdesc = hipe_find_sdesc(ra); + } + p->hipe.nstgraylim = nsp + 1 + sdesc_arity(sdesc); + p->hipe.ngra = (void(*)(void))ra; + nsp[0] = (unsigned long)&nbif_stack_trap_ra; +} + +/* + * hipe_handle_stack_trap() is called when the mutator returns to + * nbif_stack_trap_ra, which marks the gray/white stack boundary frame. + * The gray/white boundary is moved back one or more frames. + * + * The function head below is "interesting". + */ +void (*hipe_handle_stack_trap(Process *p))(void) +{ + void (*ngra)(void) = p->hipe.ngra; + const struct sdesc *sdesc = hipe_find_sdesc((unsigned long)ngra); + hipe_update_stack_trap(p, sdesc); + return ngra; +} + +/* + * hipe_find_handler() is called from hipe_handle_exception() to locate + * the current exception handler's PC and SP. + * The native stack MUST contain a stack frame as it appears on + * entry to a function (actuals, caller's frame, caller's return address). + * p->hipe.narity MUST contain the arity (number of actuals). + * On exit, p->hipe.ncallee is set to the handler's PC and p->hipe.nsp + * is set to its SP (low address of its stack frame). + */ +void hipe_find_handler(Process *p) +{ + Eterm *nsp; + Eterm *nsp_end; + unsigned long ra; + unsigned long exnra; + unsigned int arity; + const struct sdesc *sdesc; + + nsp = p->hipe.nsp; + nsp_end = p->hipe.nstend; + arity = p->hipe.narity - NR_ARG_REGS; + if ((int)arity < 0) + arity = 0; + + ra = (unsigned long)p->hipe.nra; + + while (nsp < nsp_end) { + nsp += arity; /* skip actuals */ + if (ra == (unsigned long)&nbif_stack_trap_ra) + ra = (unsigned long)p->hipe.ngra; + sdesc = hipe_find_sdesc(ra); + if ((exnra = sdesc_exnra(sdesc)) != 0 && + (p->catches >= 0 || + exnra == (unsigned long)&nbif_fail)) { + p->hipe.ncallee = (void(*)(void)) exnra; + p->hipe.nsp = nsp; + p->hipe.narity = 0; + /* update the gray/white boundary if we threw past it */ + if (p->hipe.nstgraylim && nsp >= p->hipe.nstgraylim) + hipe_update_stack_trap(p, sdesc); + return; + } + nsp += sdesc_fsize(sdesc); /* skip locals */ + arity = sdesc_arity(sdesc); + ra = *nsp++; /* fetch & skip saved ra */ + } + fprintf(stderr, "%s: no native CATCH found!\r\n", __FUNCTION__); + abort(); +} + +int hipe_fill_stacktrace(Process *p, int depth, Eterm **trace) +{ + Eterm *nsp; + Eterm *nsp_end; + unsigned long ra, prev_ra; + unsigned int arity; + const struct sdesc *sdesc; + int i; + + if (depth < 1) + return 0; + + nsp = p->hipe.nsp; + nsp_end = p->hipe.nstend; + arity = p->hipe.narity - NR_ARG_REGS; + if ((int)arity < 0) + arity = 0; + + ra = (unsigned long)p->hipe.nra; + prev_ra = 0; + i = 0; + for (;;) { + if (ra == (unsigned long)nbif_stack_trap_ra) + ra = (unsigned long)p->hipe.ngra; + if (ra != prev_ra) { + trace[i] = (Eterm*)ra; + ++i; + if (i == depth) + break; + prev_ra = ra; + } + if (nsp >= nsp_end) + break; + sdesc = hipe_find_sdesc(ra); + nsp += arity + sdesc_fsize(sdesc); + arity = sdesc_arity(sdesc); + ra = *nsp++; + } + return i; +} |