summaryrefslogtreecommitdiff
path: root/src/x86_64/Gstep.c
diff options
context:
space:
mode:
authorLassi Tuura <lat@iki.fi>2011-03-19 10:00:48 +0100
committerArun Sharma <asharma@fb.com>2011-03-24 22:33:17 -0700
commit9e98f15e9aee12e67cd5956d06ccb559f6a06213 (patch)
tree5131aa7120043dab6da38f6765514858d31f9b23 /src/x86_64/Gstep.c
parent6c1a58fd06eea3a45c6de38eb5d1f79f636bb8d5 (diff)
downloadlibunwind-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.c44
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;
}