diff mbox

[4/4] perf: parse the .debug_frame section in case .eh_frame is not present

Message ID 1380195398-4402-5-git-send-email-jean.pihet@linaro.org (mailing list archive)
State New, archived
Headers show

Commit Message

Jean Pihet Sept. 26, 2013, 11:36 a.m. UTC
On ARM the debug info is not present in the .eh_frame sections but
in .debug_frame instead, in dwarf format.
Use libunwind to load and parse the debug info.

Dependencies:
 . if present, libunwind >= 1.1 is needed to prevent a segfault when
   parsing the dwarf info,
 . libunwind needs to be configured with --enable-debug-frame. Note:
   --enable-debug-frame is automatically selected on ARM.

Signed-off-by: Jean Pihet <jean.pihet@linaro.org>
---
 tools/perf/util/unwind.c | 75 +++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 59 insertions(+), 16 deletions(-)

Comments

Jiri Olsa Sept. 26, 2013, 12:49 p.m. UTC | #1
On Thu, Sep 26, 2013 at 01:36:38PM +0200, Jean Pihet wrote:
> On ARM the debug info is not present in the .eh_frame sections but
> in .debug_frame instead, in dwarf format.
> Use libunwind to load and parse the debug info.
> 
> Dependencies:
>  . if present, libunwind >= 1.1 is needed to prevent a segfault when
>    parsing the dwarf info,
>  . libunwind needs to be configured with --enable-debug-frame. Note:
>    --enable-debug-frame is automatically selected on ARM.

Acked-by: Jiri Olsa <jolsa@redhat.com>

thanks,
jirka
Jean Pihet Oct. 8, 2013, 10:44 a.m. UTC | #2
Hi,

On 26 September 2013 14:49, Jiri Olsa <jolsa@redhat.com> wrote:
> On Thu, Sep 26, 2013 at 01:36:38PM +0200, Jean Pihet wrote:
>> On ARM the debug info is not present in the .eh_frame sections but
>> in .debug_frame instead, in dwarf format.
>> Use libunwind to load and parse the debug info.
>>
>> Dependencies:
>>  . if present, libunwind >= 1.1 is needed to prevent a segfault when
>>    parsing the dwarf info,
>>  . libunwind needs to be configured with --enable-debug-frame. Note:
>>    --enable-debug-frame is automatically selected on ARM.
>
> Acked-by: Jiri Olsa <jolsa@redhat.com>
>
> thanks,
> jirka


Thanks for the ack!

Is it possible to get an ack from the perf core maintainers?
Also, is the patch going in Will's tree?

Regards,
Jean
diff mbox

Patch

diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c
index 2f891f7..5390d0b 100644
--- a/tools/perf/util/unwind.c
+++ b/tools/perf/util/unwind.c
@@ -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,