summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantin Belousov <kostik@pooma.home>2010-05-03 17:59:50 +0300
committerKonstantin Belousov <kostik@pooma.home>2010-05-03 17:59:50 +0300
commite1493dc011346ace15f15b19894f1d063de35f24 (patch)
treef637e7f76f528be2699a8458fc3854169f093097
parentc84005e9c8226917747c1e8ba31a13bff25b0c84 (diff)
parentaa3bb307a30a5b78bf1ae4ac843ae53e354736f5 (diff)
downloadlibunwind-e1493dc011346ace15f15b19894f1d063de35f24.tar.gz
Merge branch 'master' into freebsd
-rw-r--r--src/x86_64/Gos-linux.c1
-rw-r--r--src/x86_64/Gstep.c36
2 files changed, 34 insertions, 3 deletions
diff --git a/src/x86_64/Gos-linux.c b/src/x86_64/Gos-linux.c
index 957f3e30..b7f832ca 100644
--- a/src/x86_64/Gos-linux.c
+++ b/src/x86_64/Gos-linux.c
@@ -93,6 +93,7 @@ unw_handle_signal_frame (unw_cursor_t *cursor)
Hence dwarf_step() should never call this function. Maybe
restore old non-dwarf signal handling here, but then the
gating on unw_is_signal_frame() needs to be removed. */
+ struct cursor *c = (struct cursor *) cursor;
Debug(1, "old format signal frame? format=%d addr=0x%lx cfa=0x%lx\n",
c->sigcontext_format, c->sigcontext_addr, c->dwarf.cfa);
assert(c->sigcontext_format == X86_64_SCF_LINUX_RT_SIGFRAME);
diff --git a/src/x86_64/Gstep.c b/src/x86_64/Gstep.c
index 237811ce..85e3989a 100644
--- a/src/x86_64/Gstep.c
+++ b/src/x86_64/Gstep.c
@@ -28,14 +28,38 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unwind_i.h"
#include <signal.h>
+/* Recognise PLT entries such as:
+ 3bdf0: ff 25 e2 49 13 00 jmpq *0x1349e2(%rip)
+ 3bdf6: 68 ae 03 00 00 pushq $0x3ae
+ 3bdfb: e9 00 c5 ff ff jmpq 38300 <_init+0x18> */
+static int
+is_plt_entry (struct dwarf_cursor *c)
+{
+ unw_word_t w0, w1;
+ unw_accessors_t *a;
+ int ret;
+
+ a = unw_get_accessors (c->as);
+ if ((ret = (*a->access_mem) (c->as, c->ip, &w0, 0, c->as_arg)) < 0
+ || (ret = (*a->access_mem) (c->as, c->ip + 8, &w1, 0, c->as_arg)) < 0)
+ return 0;
+
+ ret = (((w0 & 0xffff) == 0x25ff)
+ && (((w0 >> 48) & 0xff) == 0x68)
+ && (((w1 >> 24) & 0xff) == 0xe9));
+
+ Debug (14, "ip=0x%lx => 0x%016lx 0x%016lx, ret = %d\n", c->ip, w0, w1, ret);
+ return ret;
+}
+
PROTECTED int
unw_step (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
int ret, i;
- Debug (1, "(cursor=%p, ip=0x%016llx)\n",
- c, (unsigned long long) c->dwarf.ip);
+ Debug (1, "(cursor=%p, ip=0x%016lx, cfa=0x%016lx)\n",
+ c, c->dwarf.ip, c->dwarf.cfa);
/* Try DWARF-based unwinding... */
c->sigcontext_format = X86_64_SCF_NONE;
@@ -86,6 +110,12 @@ unw_step (unw_cursor_t *cursor)
return 0;
}
}
+ else if (is_plt_entry (&c->dwarf))
+ {
+ Debug (2, "found plt entry\n");
+ c->dwarf.loc[RIP] = DWARF_LOC (c->dwarf.cfa, 0);
+ c->dwarf.cfa += 8;
+ }
else if (DWARF_IS_NULL_LOC (c->dwarf.loc[RBP]))
{
for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
@@ -139,7 +169,7 @@ unw_step (unw_cursor_t *cursor)
c->dwarf.ret_addr_column = RIP;
- if (!DWARF_IS_NULL_LOC (c->dwarf.loc[RBP]))
+ if (!DWARF_IS_NULL_LOC (c->dwarf.loc[RIP]))
{
ret = dwarf_get (&c->dwarf, c->dwarf.loc[RIP], &c->dwarf.ip);
Debug (1, "Frame Chain [RIP=0x%Lx] = 0x%Lx\n",