summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Byrd <jbyrd@allinea.com>2016-11-15 12:45:30 +0000
committerDave Watson <davejwatson@fb.com>2017-08-18 09:55:49 -0700
commit1c190a8f9eb88578388340c5b14b2d683856c9c9 (patch)
treeb3580bf38abd1fed804026e320c054a0b60507e5
parent819bf51bbd2da462c2ec3401e8ac9153b6e725e3 (diff)
downloadlibunwind-1c190a8f9eb88578388340c5b14b2d683856c9c9.tar.gz
aarch64: PLT entry recognition & fixes
Attached is a corrected version of my previous patch for aarch64 PLT entry recognition. The comparison in the is_plt_entry function should have been: ret = (((w0 & 0xff0000009f000000) == 0xf900000090000000) && ((w1 & 0xffffffffff000000) == 0xd61f022091000000));
-rw-r--r--src/aarch64/Gstep.c60
-rw-r--r--src/dwarf/Gfde.c2
-rw-r--r--src/dwarf/Gfind_proc_info-lsb.c14
3 files changed, 67 insertions, 9 deletions
diff --git a/src/aarch64/Gstep.c b/src/aarch64/Gstep.c
index 44fbb04c..e38ff979 100644
--- a/src/aarch64/Gstep.c
+++ b/src/aarch64/Gstep.c
@@ -27,6 +27,30 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unwind_i.h"
#include "offsets.h"
+/* Recognise PLT entries such as:
+ 40ddf0: b0000570 adrp x16, 4ba000 <_GLOBAL_OFFSET_TABLE_+0x2a8>
+ 40ddf4: f9433611 ldr x17, [x16,#1640]
+ 40ddf8: 9119a210 add x16, x16, #0x668
+ 40ddfc: d61f0220 br x17 */
+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 & 0xff0000009f000000) == 0xf900000090000000)
+ && ((w1 & 0xffffffffff000000) == 0xd61f022091000000));
+
+ Debug (14, "ip=0x%lx => 0x%016lx 0x%016lx, ret = %d\n", c->ip, w0, w1, ret);
+ return ret;
+}
+
PROTECTED int
unw_handle_signal_frame (unw_cursor_t *cursor)
{
@@ -101,6 +125,7 @@ unw_handle_signal_frame (unw_cursor_t *cursor)
dwarf_get (&c->dwarf, c->dwarf.loc[UNW_AARCH64_PC], &c->dwarf.ip);
c->dwarf.pi_valid = 0;
+ c->dwarf.use_prev_instr = 0;
return 1;
}
@@ -125,7 +150,40 @@ unw_step (unw_cursor_t *cursor)
return ret;
if (unlikely (ret < 0))
- return 0;
+ {
+ /* DWARF failed. */
+ if (is_plt_entry (&c->dwarf))
+ {
+ Debug (2, "found plt entry\n");
+ c->frame_info.frame_type = UNW_AARCH64_FRAME_STANDARD;
+ }
+ else
+ {
+ Debug (2, "fallback\n");
+ c->frame_info.frame_type = UNW_AARCH64_FRAME_GUESSED;
+ }
+ /* Use link register (X30). */
+ c->frame_info.cfa_reg_offset = 0;
+ c->frame_info.cfa_reg_sp = 0;
+ c->frame_info.fp_cfa_offset = -1;
+ c->frame_info.lr_cfa_offset = -1;
+ c->frame_info.sp_cfa_offset = -1;
+ c->dwarf.loc[UNW_AARCH64_PC] = c->dwarf.loc[UNW_AARCH64_X30];
+ c->dwarf.loc[UNW_AARCH64_X30] = DWARF_NULL_LOC;
+ if (!DWARF_IS_NULL_LOC (c->dwarf.loc[UNW_AARCH64_PC]))
+ {
+ ret = dwarf_get (&c->dwarf, c->dwarf.loc[UNW_AARCH64_PC], &c->dwarf.ip);
+ if (ret < 0)
+ {
+ Debug (2, "failed to get pc from link register: %d\n", ret);
+ return ret;
+ }
+ Debug (2, "link register (x30) = 0x%016lx\n", c->dwarf.ip);
+ ret = 1;
+ }
+ else
+ c->dwarf.ip = 0;
+ }
return (c->dwarf.ip == 0) ? 0 : 1;
}
diff --git a/src/dwarf/Gfde.c b/src/dwarf/Gfde.c
index 55d8da84..49484eee 100644
--- a/src/dwarf/Gfde.c
+++ b/src/dwarf/Gfde.c
@@ -32,7 +32,7 @@ is_cie_id (unw_word_t val, int is_debug_frame)
0xffffffffffffffff (for 64-bit ELF). However, .eh_frame
uses 0. */
if (is_debug_frame)
- return (val == - (uint32_t) 1 || val == - (uint64_t) 1);
+ return (val == (uint32_t)(-1) || val == (uint64_t)(-1));
else
return (val == 0);
}
diff --git a/src/dwarf/Gfind_proc_info-lsb.c b/src/dwarf/Gfind_proc_info-lsb.c
index 30f8b68f..d8cbc3e0 100644
--- a/src/dwarf/Gfind_proc_info-lsb.c
+++ b/src/dwarf/Gfind_proc_info-lsb.c
@@ -199,7 +199,7 @@ locate_debug_info (unw_addr_space_t as, unw_word_t addr, const char *dlname,
name = (char*) dlname;
err = load_debug_frame (name, &buf, &bufsize, as == unw_local_addr_space);
-
+
if (!err)
{
fdesc = malloc (sizeof (struct unw_debug_frame_list));
@@ -210,10 +210,10 @@ locate_debug_info (unw_addr_space_t as, unw_word_t addr, const char *dlname,
fdesc->debug_frame_size = bufsize;
fdesc->index = NULL;
fdesc->next = as->debug_frames;
-
+
as->debug_frames = fdesc;
}
-
+
return fdesc;
}
@@ -235,10 +235,10 @@ debug_frame_tab_append (struct debug_frame_tab *tab,
tab->size *= 2;
tab->tab = realloc (tab->tab, sizeof (struct table_entry) * tab->size);
}
-
+
tab->tab[length].fde_offset = fde_offset;
tab->tab[length].start_ip_offset = start_ip;
-
+
tab->length = length + 1;
}
@@ -256,7 +256,7 @@ static int
debug_frame_tab_compare (const void *a, const void *b)
{
const struct table_entry *fa = a, *fb = b;
-
+
if (fa->start_ip_offset > fb->start_ip_offset)
return 1;
else if (fa->start_ip_offset < fb->start_ip_offset)
@@ -522,7 +522,7 @@ dwarf_callback (struct dl_phdr_info *info, size_t size, void *ptr)
else if (phdr->p_type == PT_DYNAMIC)
p_dynamic = phdr;
}
-
+
if (!p_text)
return 0;