diff options
author | Lassi Tuura <lat@iki.fi> | 2011-03-19 10:00:48 +0100 |
---|---|---|
committer | Arun Sharma <asharma@fb.com> | 2011-03-24 22:33:17 -0700 |
commit | 9e98f15e9aee12e67cd5956d06ccb559f6a06213 (patch) | |
tree | 5131aa7120043dab6da38f6765514858d31f9b23 /src/x86_64/Gstep.c | |
parent | 6c1a58fd06eea3a45c6de38eb5d1f79f636bb8d5 (diff) | |
download | libunwind-9e98f15e9aee12e67cd5956d06ccb559f6a06213.tar.gz |
Fast back-trace for x86_64 for only collecting the call stack.
Adds new function to perform a pure stack walk without unwinding,
functionally similar to backtrace() but accelerated by an address
attribute cache the caller maintains across calls.
Diffstat (limited to 'src/x86_64/Gstep.c')
-rw-r--r-- | src/x86_64/Gstep.c | 44 |
1 files changed, 35 insertions, 9 deletions
diff --git a/src/x86_64/Gstep.c b/src/x86_64/Gstep.c index 85e3989a..0d2eef80 100644 --- a/src/x86_64/Gstep.c +++ b/src/x86_64/Gstep.c @@ -58,6 +58,11 @@ unw_step (unw_cursor_t *cursor) struct cursor *c = (struct cursor *) cursor; int ret, i; +#if CONSERVATIVE_CHECKS + int val = c->validate; + c->validate = 1; +#endif + Debug (1, "(cursor=%p, ip=0x%016lx, cfa=0x%016lx)\n", c, c->dwarf.ip, c->dwarf.cfa); @@ -65,6 +70,10 @@ unw_step (unw_cursor_t *cursor) c->sigcontext_format = X86_64_SCF_NONE; ret = dwarf_step (&c->dwarf); +#if CONSERVATIVE_CHECKS + c->validate = val; +#endif + if (ret < 0 && ret != -UNW_ENOINFO) { Debug (2, "returning %d\n", ret); @@ -112,7 +121,11 @@ unw_step (unw_cursor_t *cursor) } else if (is_plt_entry (&c->dwarf)) { + /* Like regular frame, CFA = RSP+8, RA = [CFA-8], no regs saved. */ Debug (2, "found plt entry\n"); + c->frame_info.cfa_reg_offset = 8; + c->frame_info.cfa_reg_rsp = -1; + c->frame_info.frame_type = UNW_X86_64_FRAME_STANDARD; c->dwarf.loc[RIP] = DWARF_LOC (c->dwarf.cfa, 0); c->dwarf.cfa += 8; } @@ -142,19 +155,32 @@ unw_step (unw_cursor_t *cursor) } else { - unw_word_t rbp1; - Debug (1, "[RBP=0x%Lx] = 0x%Lx (cfa = 0x%Lx)\n", - (unsigned long long) DWARF_GET_LOC (c->dwarf.loc[RBP]), - (unsigned long long) rbp, - (unsigned long long) c->dwarf.cfa); - + unw_word_t rbp1 = 0; rbp_loc = DWARF_LOC(rbp, 0); rsp_loc = DWARF_NULL_LOC; rip_loc = DWARF_LOC (rbp + 8, 0); - /* Heuristic to recognize a bogus frame pointer */ ret = dwarf_get (&c->dwarf, rbp_loc, &rbp1); - if (ret || ((rbp1 - rbp) > 0x4000)) - rbp_loc = DWARF_NULL_LOC; + Debug (1, "[RBP=0x%lx] = 0x%lx (cfa = 0x%lx) -> 0x%lx\n", + (unsigned long) DWARF_GET_LOC (c->dwarf.loc[RBP]), + rbp, c->dwarf.cfa, rbp1); + + /* Heuristic to determine incorrect guess. For RBP to be a + valid frame it needs to be above current CFA, but don't + let it go more than a little. Note that we can't deduce + anything about new RBP (rbp1) since it may not be a frame + pointer in the frame above. Just check we get the value. */ + if (ret < 0 + || rbp <= c->dwarf.cfa + || (rbp - c->dwarf.cfa) > 0x4000) + { + rip_loc = DWARF_NULL_LOC; + rbp_loc = DWARF_NULL_LOC; + } + + c->frame_info.frame_type = UNW_X86_64_FRAME_GUESSED; + c->frame_info.cfa_reg_rsp = 0; + c->frame_info.cfa_reg_offset = 16; + c->frame_info.rbp_cfa_offset = -16; c->dwarf.cfa += 16; } |