diff --git a/src/ia64/rbs-ia64.c b/src/ia64/rbs-ia64.c index e69de29b..b92c71ee 100644 --- a/src/ia64/rbs-ia64.c +++ b/src/ia64/rbs-ia64.c @@ -0,0 +1,135 @@ +/* libunwind - a platform-independent unwind library + Copyright (C) 2003 Hewlett-Packard Co + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/* Logically, we like to think of the stack as a contiguous region of +memory. Unfortunately, this logical view doesn't work for the +register backing store, because the RSE is an asynchronous engine and +because UNIX/Linux allow for stack-switching via sigaltstack(2). +Specifically, this means that any given stacked register may or may +not be backed up by memory in the current stack. If not, then the +backing memory may be found in any of the "more inner" (younger) +stacks. The routines in this file help manage the discontiguous +nature of the register backing store. The routines are completely +independent of UNIX/Linux, but each stack frame that switches the +backing store is expected to reserve 4 words for use by libunwind. For +example, in the Linux sigcontext, sc_fr[0] and sc_fr[1] serve this +purpose. */ + +#include "unwind_i.h" + +HIDDEN int +rbs_record_switch (struct cursor *c, + unw_word_t saved_bsp, unw_word_t saved_bspstore, + unw_word_t saved_rnat_loc) +{ + unw_word_t ndirty, prev, last = c->rbs_wridx; + + debug (10, "%s: ", __FUNCTION__); + + ndirty = ia64_rse_num_regs (saved_bspstore, saved_bsp); + + if (ndirty == 0) + /* The last-recorded rbs-area is empty. No point in tracking it... */ + prev = last; + else + { + c->rbs_area[last].size = (c->rbs_area[last].end + - ia64_rse_skip_regs (c->bsp, -ndirty)); + debug (10, "\n\tinner=[0x%lx-0x%lx),\n\t", + (long) (c->rbs_area[last].end - c->rbs_area[last].size), + (long) c->rbs_area[last].end); + + last = ((last + NELEMS (c->rbs_area) - 1) % NELEMS (c->rbs_area)); + + ++c->rbs_nvalid; + if (c->rbs_nvalid > NELEMS (c->rbs_area)) + c->rbs_nvalid = NELEMS (c->rbs_area); + + assert (last != c->rbs_curr); + } + c->rbs_area[last].end = saved_bspstore; + c->rbs_area[last].size = ~(unw_word_t) 0; /* initial guess... */ + c->rbs_area[last].rnat_loc = saved_rnat_loc; + + debug (10, "outer=[??????????????????-0x%lx), rnat @ 0x%lx\n", + (long) c->rbs_area[last].end, (long) c->rbs_area[last].rnat_loc); + return 0; +} + +HIDDEN void +rbs_underflow (struct cursor *c) +{ + size_t num_regs; + + while (c->rbs_area[c->rbs_curr].end - c->bsp + > c->rbs_area[c->rbs_curr].size) + { + unw_word_t old_base = (c->rbs_area[c->rbs_curr].end + - c->rbs_area[c->rbs_curr].size); + + /* # of register we were short on old rbs-area: */ + num_regs = ia64_rse_num_regs (c->bsp, old_base); + + c->rbs_curr = ((c->rbs_curr + NELEMS (c->rbs_area) - 1) + % NELEMS (c->rbs_area)); + c->bsp = ia64_rse_skip_regs (c->rbs_area[c->rbs_curr].end, -num_regs); + } +} + +HIDDEN int +rbs_find_stacked (struct cursor *c, unw_word_t regs_to_skip, + unw_word_t *locp, unw_word_t *rnat_locp) +{ + unw_word_t curr, nregs, bsp = c->bsp; + int i; + + curr = c->rbs_curr; + + for (i = 0; i < c->rbs_nvalid; ++i) + { + nregs = ia64_rse_num_regs (bsp, c->rbs_area[curr].end); + + if (regs_to_skip < nregs) + { + /* found it: */ + *locp = ia64_rse_skip_regs (bsp, regs_to_skip); + if (rnat_locp) + { + *rnat_locp = ia64_rse_rnat_addr (*locp); + if (*rnat_locp >= c->rbs_area[curr].end) + *rnat_locp = c->rbs_area[curr].rnat_loc; + } + return 0; + } + + regs_to_skip -= nregs; + + curr = (curr + 1) % NELEMS (c->rbs_area); + bsp = c->rbs_area[curr].end - c->rbs_area[curr].size; + } + debug (1, "%s: could not find register r%d!\n", + __FUNCTION__, 32 + regs_to_skip); + return -UNW_EINVAL; +} diff --git a/tests/test-resume-sig.c b/tests/test-resume-sig.c index e69de29b..d5da30aa 100644 --- a/tests/test-resume-sig.c +++ b/tests/test-resume-sig.c @@ -0,0 +1,63 @@ +/* Verify that unw_resume() restores the signal mask at proper time. */ + +#include +#include +#include +#include +#include + +#define panic(args...) \ + { fprintf (stderr, args); exit (-1); } + +int got_usr1, got_usr2; +char *sigusr1_sp; + +void +handler (int sig) +{ + sigset_t mask; + unw_context_t uc; + unw_cursor_t c; + unw_word_t ip; + char foo; + + if (sig == SIGUSR1) + { + ++got_usr1; + sigusr1_sp = &foo; + + sigemptyset (&mask); + sigaddset (&mask, SIGUSR2); + sigprocmask (SIG_BLOCK, &mask, NULL); + kill (getpid (), SIGUSR2); /* pend SIGUSR2 */ + + signal (SIGUSR1, SIG_IGN); + signal (SIGUSR2, handler); + + unw_getcontext(&uc); + unw_init_local(&c, &uc); + unw_step(&c); /* step to signal trampoline */ + unw_step(&c); /* step to signaller frame (main ()) */ + unw_get_reg(&c, UNW_REG_IP, &ip); + printf ("resuming at 0x%lx\n", ip); + unw_resume(&c); + } + else if (sig == SIGUSR2) + { + ++got_usr2; + if (got_usr1) + if (sigusr1_sp != &foo) + panic ("Stack pointer changed from %p to %p between signals\n", + sigusr1_sp, &foo); + signal (SIGUSR2, SIG_IGN); + } else + panic ("Got unexpected signal %d\n", sig); +} + +int +main (int argc, char **argv) +{ + signal (SIGUSR1, handler); + kill (getpid (), SIGUSR1); + return 0; +}