Hello,
The attached patch adds support for unwinding the vsyscall region and
adds more generic support for frameless functions.
Regards,
Jonathan Byrd
Senior Application Developer
Allinea Software Ltd.
diff --git a/src/x86_64/Gstep.c b/src/x86_64/Gstep.c
index 84b3728..29bd56a 100644
--- a/src/x86_64/Gstep.c
+++ b/src/x86_64/Gstep.c
@@ -27,6 +27,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unwind_i.h"
#include <signal.h>
+#include <asm/vsyscall.h>
/* Recognise PLT entries such as:
3bdf0: ff 25 e2 49 13 00 jmpq *0x1349e2(%rip)
@@ -52,6 +53,18 @@ is_plt_entry (struct dwarf_cursor *c)
return ret;
}
+static int
+is_vsyscall (struct dwarf_cursor *c)
+{
+#if defined(VSYSCALL_START) && defined(VSYSCALL_END)
+ return c->ip >= VSYSCALL_START && c->ip < VSYSCALL_END;
+#else
+ /* Linux 3.16 removes `VSYSCALL_START` and `VSYSCALL_END`. Assume
+ * that no-one is using vsyscall on newer systems. */
+ return 0;
+#endif
+}
+
PROTECTED int
unw_step (unw_cursor_t *cursor)
{
@@ -106,7 +119,6 @@ unw_step (unw_cursor_t *cursor)
code. */
unw_word_t prev_ip = c->dwarf.ip, prev_cfa = c->dwarf.cfa;
- struct dwarf_loc rbp_loc, rsp_loc, rip_loc;
/* We could get here because of missing/bad unwind information.
Validate all addresses before dereferencing. */
@@ -133,6 +145,40 @@ unw_step (unw_cursor_t *cursor)
c->dwarf.loc[RIP] = DWARF_LOC (c->dwarf.cfa, 0);
c->dwarf.cfa += 8;
}
+ else if (is_vsyscall (&c->dwarf))
+ {
+ int frameless;
+ unw_word_t rbp;
+ Debug (2, "in vsyscall region\n");
+ ret = dwarf_get (&c->dwarf, c->dwarf.loc[RBP], &rbp);
+ frameless = (ret < 0) || (rbp != c->dwarf.cfa);
+ Debug (1, "[RBP=0x%lx] = 0x%lx (cfa = 0x%lx) frameless = %d\n",
+ (unsigned long) DWARF_GET_LOC (c->dwarf.loc[RBP]),
+ rbp, c->dwarf.cfa, frameless);
+ if (frameless)
+ {
+ c->frame_info.cfa_reg_offset = 8;
+ c->frame_info.cfa_reg_rsp = -1;
+ c->frame_info.frame_type = UNW_X86_64_FRAME_GUESSED;
+ c->dwarf.loc[RIP] = DWARF_LOC (c->dwarf.cfa, 0);
+ c->dwarf.cfa += 8;
+ }
+ else
+ {
+ 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;
+
+ /* Mark all registers unsaved */
+ for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
+ c->dwarf.loc[i] = DWARF_NULL_LOC;
+ c->dwarf.loc[RBP] = DWARF_LOC(rbp, 0);
+ c->dwarf.loc[RSP] = DWARF_NULL_LOC;
+ c->dwarf.loc[RIP] = DWARF_LOC (rbp + 8, 0);
+ }
+ }
else if (DWARF_IS_NULL_LOC (c->dwarf.loc[RBP]))
{
for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
@@ -140,62 +186,67 @@ unw_step (unw_cursor_t *cursor)
}
else
{
+ int frameless;
unw_word_t rbp;
ret = dwarf_get (&c->dwarf, c->dwarf.loc[RBP], &rbp);
- if (ret < 0)
+ if (is_vsyscall (&c->dwarf))
{
- Debug (2, "returning %d [RBP=0x%lx]\n", ret,
- DWARF_GET_LOC (c->dwarf.loc[RBP]));
- return ret;
- }
-
+ Debug (2, "in vsyscall region\n");
+ /* The vsyscalls don't use the stack so we can use a stricter check. */
+ frameless = (ret < 0) || (rbp != c->dwarf.cfa);
+ }
+ else
+ {
+ /* 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. */
+ frameless = (ret < 0) || (rbp < c->dwarf.cfa) || ((rbp - c->dwarf.cfa) > 0x4000);
+ }
if (!rbp)
{
- /* Looks like we may have reached the end of the call-chain. */
- rbp_loc = DWARF_NULL_LOC;
- rsp_loc = DWARF_NULL_LOC;
- rip_loc = DWARF_NULL_LOC;
+ /* Looks like we may have reached the end of the call-chain. */
+ /* Mark all registers unsaved */
+ for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
+ c->dwarf.loc[i] = DWARF_NULL_LOC;
}
+ else if (frameless)
+ {
+ Debug (1, "[RBP=0x%lx] = 0x%lx (cfa = 0x%lx) (frameless)\n",
+ (unsigned long) DWARF_GET_LOC (c->dwarf.loc[RBP]),
+ rbp, c->dwarf.cfa);
+
+ c->frame_info.cfa_reg_offset = 8;
+ c->frame_info.cfa_reg_rsp = -1;
+ c->frame_info.frame_type = UNW_X86_64_FRAME_GUESSED;
+ c->dwarf.loc[RIP] = DWARF_LOC (c->dwarf.cfa, 0);
+ c->dwarf.cfa += 8;
+ }
else
- {
- unw_word_t rbp1 = 0;
- rbp_loc = DWARF_LOC(rbp, 0);
- rsp_loc = DWARF_NULL_LOC;
- rip_loc = DWARF_LOC (rbp + 8, 0);
- ret = dwarf_get (&c->dwarf, rbp_loc, &rbp1);
- 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;
- }
-
- /* Mark all registers unsaved */
- for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
- c->dwarf.loc[i] = DWARF_NULL_LOC;
-
- c->dwarf.loc[RBP] = rbp_loc;
- c->dwarf.loc[RSP] = rsp_loc;
- c->dwarf.loc[RIP] = rip_loc;
- c->dwarf.use_prev_instr = 1;
+ {
+ unw_word_t rbp1 = 0;
+ struct dwarf_loc rbp_loc = DWARF_LOC(rbp, 0);
+ ret = dwarf_get (&c->dwarf, rbp_loc, &rbp1);
+ 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);
+
+ 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;
+ c->dwarf.use_prev_instr = 1;
+ /* Mark all registers unsaved */
+ for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
+ c->dwarf.loc[i] = DWARF_NULL_LOC;
+
+ c->dwarf.loc[RBP] = rbp_loc;
+ c->dwarf.loc[RSP] = DWARF_NULL_LOC;
+ c->dwarf.loc[RIP] = DWARF_LOC (rbp + 8, 0);
+ }
}
c->dwarf.ret_addr_column = RIP;
_______________________________________________
Libunwind-devel mailing list
[email protected]
https://lists.nongnu.org/mailman/listinfo/libunwind-devel