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)
     {