commit 72b70a14c147b7ae8a8c45ea83b87790ef0d1d05
Author: Keno Fischer <kfischer@college.harvard.edu>
Date:   Tue Oct 6 23:20:42 2015 +0000

    Add an option to have start_ip_offset be relative to start_ip
    
    By default, the start_ip_offset in libunwind's table_entry struct is
    relative to the unw_dyn_info_t's segbase. This presents a problem
    for us in conjunction with using LLVM's MCJIT because it likes to
    spread text sections and the corresponding eh_frame sections quite
    far apart. This represents my attempt to support this use case in the
    simplest manner that is backwards compatible, by adding a new format
    kind (UNW_INFO_FORMAT_REMOTE_TABLE2) that indicates that the
    `start_ip_offset` should be interpreted as relative to `start_ip`
    rather than segbase.

diff --git a/include/libunwind-dynamic.h b/include/libunwind-dynamic.h
index 8feb9de..edb0bbd 100644
--- a/include/libunwind-dynamic.h
+++ b/include/libunwind-dynamic.h
@@ -76,7 +76,11 @@ typedef enum
     UNW_INFO_FORMAT_DYNAMIC,            /* unw_dyn_proc_info_t */
     UNW_INFO_FORMAT_TABLE,              /* unw_dyn_table_t */
     UNW_INFO_FORMAT_REMOTE_TABLE,       /* unw_dyn_remote_table_t */
-    UNW_INFO_FORMAT_ARM_EXIDX           /* ARM specific unwind info */
+    UNW_INFO_FORMAT_ARM_EXIDX,          /* ARM specific unwind info */
+    UNW_INFO_FORMAT_IP_OFFSET,          /* Like UNW_INFO_FORMAT_REMOTE_TABLE, but
+                                           table entries are considered
+                                           relative to di->start_ip, rather
+                                           than di->segbase */
   }
 unw_dyn_info_format_t;
 
diff --git a/src/dwarf/Gfind_proc_info-lsb.c b/src/dwarf/Gfind_proc_info-lsb.c
index af4546d..61c7599 100644
--- a/src/dwarf/Gfind_proc_info-lsb.c
+++ b/src/dwarf/Gfind_proc_info-lsb.c
@@ -819,13 +819,18 @@ remote_lookup (unw_addr_space_t as,
 
 #endif /* !UNW_LOCAL_ONLY */
 
+static int is_remote_table(int format) {
+  return (format == UNW_INFO_FORMAT_REMOTE_TABLE ||
+	  format == UNW_INFO_FORMAT_IP_OFFSET);
+}
+
 PROTECTED int
 dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
                            unw_dyn_info_t *di, unw_proc_info_t *pi,
                            int need_unwind_info, void *arg)
 {
   const struct table_entry *e = NULL, *table;
-  unw_word_t segbase = 0, fde_addr;
+  unw_word_t ip_base = 0, segbase = 0, fde_addr;
   unw_accessors_t *a;
 #ifndef UNW_LOCAL_ONLY
   struct table_entry ent;
@@ -835,14 +840,14 @@ dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
   size_t table_len;
 
 #ifdef UNW_REMOTE_ONLY
-  assert (di->format == UNW_INFO_FORMAT_REMOTE_TABLE);
+  assert (is_remote_table(di->format));
 #else
-  assert (di->format == UNW_INFO_FORMAT_REMOTE_TABLE
+  assert (is_remote_table(di->format)
           || di->format == UNW_INFO_FORMAT_TABLE);
 #endif
   assert (ip >= di->start_ip && ip < di->end_ip);
 
-  if (di->format == UNW_INFO_FORMAT_REMOTE_TABLE)
+  if (is_remote_table(di->format))
     {
       table = (const struct table_entry *) (uintptr_t) di->u.rti.table_data;
       table_len = di->u.rti.table_len * sizeof (unw_word_t);
@@ -850,6 +855,7 @@ dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
     }
   else
     {
+      assert(di->format == UNW_INFO_FORMAT_TABLE);
 #ifndef UNW_REMOTE_ONLY
       struct unw_debug_frame_list *fdesc = (void *) di->u.ti.table_data;
 
@@ -866,11 +872,17 @@ dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
 
   a = unw_get_accessors (as);
 
+  segbase = di->u.rti.segbase;
+  if (di->format == UNW_INFO_FORMAT_IP_OFFSET) {
+    ip_base = di->start_ip;
+  } else {
+    ip_base = segbase;
+  }
+
 #ifndef UNW_REMOTE_ONLY
   if (as == unw_local_addr_space)
     {
-      segbase = di->u.rti.segbase;
-      e = lookup (table, table_len, ip - segbase);
+      e = lookup (table, table_len, ip - ip_base);
     }
   else
 #endif
@@ -878,7 +890,7 @@ dwarf_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
 #ifndef UNW_LOCAL_ONLY
       segbase = di->u.rti.segbase;
       if ((ret = remote_lookup (as, (uintptr_t) table, table_len,
-                                ip - segbase, &ent, arg)) < 0)
+                                ip - ip_base, &ent, arg)) < 0)
         return ret;
       if (ret)
         e = &ent;
diff --git a/src/mi/Gdyn-extract.c b/src/mi/Gdyn-extract.c
index a083350..c8ae7a0 100644
--- a/src/mi/Gdyn-extract.c
+++ b/src/mi/Gdyn-extract.c
@@ -49,6 +49,7 @@ unwi_extract_dynamic_proc_info (unw_addr_space_t as, unw_word_t ip,
 
     case UNW_INFO_FORMAT_TABLE:
     case UNW_INFO_FORMAT_REMOTE_TABLE:
+    case UNW_INFO_FORMAT_IP_OFFSET:
 #ifdef tdep_search_unwind_table
       /* call platform-specific search routine: */
       return tdep_search_unwind_table (as, ip, di, pi, need_unwind_info, arg);
diff --git a/src/x86_64/Ginit.c b/src/x86_64/Ginit.c
index 480d470..6e9d4fe 100644
--- a/src/x86_64/Ginit.c
+++ b/src/x86_64/Ginit.c
@@ -168,8 +168,10 @@ access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write,
       /* validate address */
       const struct cursor *c = (const struct cursor *)arg;
       if (likely (c != NULL) && unlikely (c->validate)
-          && unlikely (validate_mem (addr)))
+          && unlikely (validate_mem (addr))) {
+        Debug (16, "mem[%016lx] -> invalid\n", addr);
         return -1;
+      }
       *val = *(unw_word_t *) addr;
       Debug (16, "mem[%016lx] -> %lx\n", addr, *val);
     }
