summaryrefslogtreecommitdiffstats
path: root/libdw/libdw_findcu.c
diff options
context:
space:
mode:
authorMark Wielaard <[email protected]>2018-05-29 23:49:21 +0200
committerMark Wielaard <[email protected]>2018-05-31 17:03:19 +0200
commit7d6fe0a39f6ae5c516ffd63558e12b24297bf982 (patch)
tree30469e6da3f107797bb69a1d0a480eafc4ba50fd /libdw/libdw_findcu.c
parentb37feac1a8ceebb0748cb28d219aa8387d0885dd (diff)
libdw: Handle split Dwarf Dies in dwarf_die_addr_die.
dwarf_die_addr_die can be used to turn an Dwarf_Die addr back into a full Dwarf_Die, just given the original Dwarf debug handle. This now also works for Dwarf_Dies which originated from a split Dwarf. Whenever a split Dwarf_CU is found the Dwarf it originated from is registered with the Dwarf that the skeleton Dwarf_CU came from. All registered split Dwarfs are then searched by dwarf_die_addr_die if the addr didn't match the main Dwarf or the alt Dwarf. One limitation in this implementation is that only DIEs that come from the main .debug_info in the .dwo are supported. Theoretically there could also be DIEs in an .debug_type or from other/multiple (comdat) sections. New tests are added for dwarf-4, dwarf-5, split-dwarf-4, split-dwarf-5 and version 4 and 5 dwo files. Signed-off-by: Mark Wielaard <[email protected]>
Diffstat (limited to 'libdw/libdw_findcu.c')
-rw-r--r--libdw/libdw_findcu.c49
1 files changed, 49 insertions, 0 deletions
diff --git a/libdw/libdw_findcu.c b/libdw/libdw_findcu.c
index 9d231999..2f5c6c42 100644
--- a/libdw/libdw_findcu.c
+++ b/libdw/libdw_findcu.c
@@ -61,6 +61,40 @@ findcu_cb (const void *arg1, const void *arg2)
return 0;
}
+int
+__libdw_finddbg_cb (const void *arg1, const void *arg2)
+{
+ Dwarf *dbg1 = (Dwarf *) arg1;
+ Dwarf *dbg2 = (Dwarf *) arg2;
+
+ Elf_Data *dbg1_data = dbg1->sectiondata[IDX_debug_info];
+ unsigned char *dbg1_start = dbg1_data->d_buf;
+ size_t dbg1_size = dbg1_data->d_size;
+
+ Elf_Data *dbg2_data = dbg2->sectiondata[IDX_debug_info];
+ unsigned char *dbg2_start = dbg2_data->d_buf;
+ size_t dbg2_size = dbg2_data->d_size;
+
+ /* Find out which of the two arguments is the search value. It has
+ a size of 0. */
+ if (dbg1_size == 0)
+ {
+ if (dbg1_start < dbg2_start)
+ return -1;
+ if (dbg1_start >= dbg2_start + dbg2_size)
+ return 1;
+ }
+ else
+ {
+ if (dbg2_start < dbg1_start)
+ return 1;
+ if (dbg2_start >= dbg1_start + dbg1_size)
+ return -1;
+ }
+
+ return 0;
+}
+
struct Dwarf_CU *
internal_function
__libdw_intern_next_unit (Dwarf *dbg, bool debug_types)
@@ -247,3 +281,18 @@ __libdw_findcu_addr (Dwarf *dbg, void *addr)
return NULL;
}
+
+Dwarf *
+internal_function
+__libdw_find_split_dbg_addr (Dwarf *dbg, void *addr)
+{
+ /* XXX Assumes split DWARF only has CUs in main IDX_debug_info. */
+ Elf_Data fake_data = { .d_buf = addr, .d_size = 0 };
+ Dwarf fake = { .sectiondata[IDX_debug_info] = &fake_data };
+ Dwarf **found = tfind (&fake, &dbg->split_tree, __libdw_finddbg_cb);
+
+ if (found != NULL)
+ return *found;
+
+ return NULL;
+}