|
@@ -39,6 +39,15 @@ UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
|
|
|
|
|
|
#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table)
|
|
|
|
|
|
+extern int
|
|
|
+UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug,
|
|
|
+ unw_word_t ip,
|
|
|
+ unw_word_t segbase,
|
|
|
+ const char *obj_name, unw_word_t start,
|
|
|
+ unw_word_t end);
|
|
|
+
|
|
|
+#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame)
|
|
|
+
|
|
|
#define DW_EH_PE_FORMAT_MASK 0x0f /* format of the encoded value */
|
|
|
#define DW_EH_PE_APPL_MASK 0x70 /* how the value is to be applied */
|
|
|
|
|
@@ -245,8 +254,9 @@ static int unwind_spec_ehframe(struct dso *dso, struct machine *machine,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int read_unwind_spec(struct dso *dso, struct machine *machine,
|
|
|
- u64 *table_data, u64 *segbase, u64 *fde_count)
|
|
|
+static int read_unwind_spec_eh_frame(struct dso *dso, struct machine *machine,
|
|
|
+ u64 *table_data, u64 *segbase,
|
|
|
+ u64 *fde_count)
|
|
|
{
|
|
|
int ret = -EINVAL, fd;
|
|
|
u64 offset;
|
|
@@ -255,6 +265,7 @@ static int read_unwind_spec(struct dso *dso, struct machine *machine,
|
|
|
if (fd < 0)
|
|
|
return -EINVAL;
|
|
|
|
|
|
+ /* Check the .eh_frame section for unwinding info */
|
|
|
offset = elf_section_offset(fd, ".eh_frame_hdr");
|
|
|
close(fd);
|
|
|
|
|
@@ -263,10 +274,29 @@ static int read_unwind_spec(struct dso *dso, struct machine *machine,
|
|
|
table_data, segbase,
|
|
|
fde_count);
|
|
|
|
|
|
- /* TODO .debug_frame check if eh_frame_hdr fails */
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+#ifndef NO_LIBUNWIND_DEBUG_FRAME
|
|
|
+static int read_unwind_spec_debug_frame(struct dso *dso,
|
|
|
+ struct machine *machine, u64 *offset)
|
|
|
+{
|
|
|
+ int fd = dso__data_fd(dso, machine);
|
|
|
+
|
|
|
+ if (fd < 0)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ /* Check the .debug_frame section for unwinding info */
|
|
|
+ *offset = elf_section_offset(fd, ".debug_frame");
|
|
|
+ close(fd);
|
|
|
+
|
|
|
+ if (*offset)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ return -EINVAL;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
static struct map *find_map(unw_word_t ip, struct unwind_info *ui)
|
|
|
{
|
|
|
struct addr_location al;
|
|
@@ -291,20 +321,33 @@ find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
|
|
|
|
|
|
pr_debug("unwind: find_proc_info dso %s\n", map->dso->name);
|
|
|
|
|
|
- if (read_unwind_spec(map->dso, ui->machine,
|
|
|
- &table_data, &segbase, &fde_count))
|
|
|
- return -EINVAL;
|
|
|
+ /* Check the .eh_frame section for unwinding info */
|
|
|
+ if (!read_unwind_spec_eh_frame(map->dso, ui->machine,
|
|
|
+ &table_data, &segbase, &fde_count)) {
|
|
|
+ memset(&di, 0, sizeof(di));
|
|
|
+ di.format = UNW_INFO_FORMAT_REMOTE_TABLE;
|
|
|
+ di.start_ip = map->start;
|
|
|
+ di.end_ip = map->end;
|
|
|
+ di.u.rti.segbase = map->start + segbase;
|
|
|
+ di.u.rti.table_data = map->start + table_data;
|
|
|
+ di.u.rti.table_len = fde_count * sizeof(struct table_entry)
|
|
|
+ / sizeof(unw_word_t);
|
|
|
+ return dwarf_search_unwind_table(as, ip, &di, pi,
|
|
|
+ need_unwind_info, arg);
|
|
|
+ }
|
|
|
+
|
|
|
+#ifndef NO_LIBUNWIND_DEBUG_FRAME
|
|
|
+ /* Check the .debug_frame section for unwinding info */
|
|
|
+ if (!read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) {
|
|
|
+ memset(&di, 0, sizeof(di));
|
|
|
+ dwarf_find_debug_frame(0, &di, ip, 0, map->dso->name,
|
|
|
+ map->start, map->end);
|
|
|
+ return dwarf_search_unwind_table(as, ip, &di, pi,
|
|
|
+ need_unwind_info, arg);
|
|
|
+ }
|
|
|
+#endif
|
|
|
|
|
|
- memset(&di, 0, sizeof(di));
|
|
|
- di.format = UNW_INFO_FORMAT_REMOTE_TABLE;
|
|
|
- di.start_ip = map->start;
|
|
|
- di.end_ip = map->end;
|
|
|
- di.u.rti.segbase = map->start + segbase;
|
|
|
- di.u.rti.table_data = map->start + table_data;
|
|
|
- di.u.rti.table_len = fde_count * sizeof(struct table_entry)
|
|
|
- / sizeof(unw_word_t);
|
|
|
- return dwarf_search_unwind_table(as, ip, &di, pi,
|
|
|
- need_unwind_info, arg);
|
|
|
+ return -EINVAL;
|
|
|
}
|
|
|
|
|
|
static int access_fpreg(unw_addr_space_t __maybe_unused as,
|