Support .debug_frame based unwinding in _UPTi_find_unwind_table()
Signed-off-by: Andris Zeila <andris.zeila@accenture.com>
diff --git a/include/libunwind-common.h.in b/include/libunwind-common.h.in
index 228460a..2fb78e8 100644
--- a/include/libunwind-common.h.in
+++ b/include/libunwind-common.h.in
@@ -119,6 +119,8 @@
/* Each target may define it's own set of flags, but bits 0-15 are
reserved for general libunwind-use. */
#define UNW_PI_FLAG_FIRST_TDEP_BIT 16
+/* The information comes from a .debug_frame section. */
+#define UNW_PI_FLAG_DEBUG_FRAME 32
typedef struct unw_proc_info
{
diff --git a/src/dwarf/Gfind_proc_info-lsb.c b/src/dwarf/Gfind_proc_info-lsb.c
index 9718260..d65342c 100644
--- a/src/dwarf/Gfind_proc_info-lsb.c
+++ b/src/dwarf/Gfind_proc_info-lsb.c
@@ -895,13 +895,11 @@
#ifndef UNW_REMOTE_ONLY
struct unw_debug_frame_list *fdesc = (void *) di->u.ti.table_data;
- /* UNW_INFO_FORMAT_TABLE (i.e. .debug_frame) is currently only
- supported for the local address space. Both the index and
- the unwind tables live in local memory, but the address space
- to check for properties like the address size and endianness
- is the target one. When the ptrace code adds support for
- .debug_frame something will have to change. */
- assert (as == unw_local_addr_space);
+ /* UNW_INFO_FORMAT_TABLE (i.e. .debug_frame) is read from local address
+ space. Both the index and the unwind tables live in local memory, but
+ the address space to check for properties like the address size and
+ endianness is the target one. */
+ as = unw_local_addr_space;
table = fdesc->index;
table_len = fdesc->index_size * sizeof (struct table_entry);
debug_frame_base = (uintptr_t) fdesc->debug_frame;
@@ -958,6 +956,7 @@
{
pi->start_ip += segbase;
pi->end_ip += segbase;
+ pi->flags = UNW_PI_FLAG_DEBUG_FRAME;
}
if (ip < pi->start_ip || ip >= pi->end_ip)
diff --git a/src/dwarf/Gparser.c b/src/dwarf/Gparser.c
index 3b1a2b4..13bd9a2 100644
--- a/src/dwarf/Gparser.c
+++ b/src/dwarf/Gparser.c
@@ -73,6 +73,12 @@
as = c->as;
arg = c->as_arg;
+ if (c->pi.flags & UNW_PI_FLAG_DEBUG_FRAME)
+ {
+ /* .debug_frame CFI is stored in local address space. */
+ as = unw_local_addr_space;
+ arg = NULL;
+ }
a = unw_get_accessors (as);
curr_ip = c->pi.start_ip;
diff --git a/src/ptrace/_UPT_find_proc_info.c b/src/ptrace/_UPT_find_proc_info.c
index a0bd52c..97bf9e2 100644
--- a/src/ptrace/_UPT_find_proc_info.c
+++ b/src/ptrace/_UPT_find_proc_info.c
@@ -210,7 +210,31 @@
}
}
if (!ptxt || !peh_hdr)
- return NULL;
+ {
+ /* No .eh_frame found, try .debug_frame. */
+ struct dl_phdr_info info;
+
+ info.dlpi_name = path;
+ info.dlpi_phdr = phdr;
+ info.dlpi_phnum = ehdr->e_phnum;
+
+ /* Fixup segbase to match correct base address. */
+ for (i = 0; i < info.dlpi_phnum; i++)
+ {
+ if (info.dlpi_phdr[i].p_type == PT_LOAD &&
+ info.dlpi_phdr[i].p_offset == 0)
+ {
+ segbase -= info.dlpi_phdr[i].p_vaddr;
+ break;
+ }
+ }
+ info.dlpi_addr = segbase;
+
+ if (dwarf_find_debug_frame (0, &ui->di_cache, &info, ip))
+ return &ui->di_cache;
+ else
+ return NULL;
+ }
if (pdyn)
{