Message ID | 1378317854-25965-4-git-send-email-jean.pihet@linaro.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Hi Jean, [adding Michael, since I know he was interested in this] On Wed, Sep 04, 2013 at 07:04:14PM +0100, Jean Pihet wrote: > On ARM the debug info is not present in the .eh_frame sections but > instead in .debug_frame. > Use libunwind to load and parse the debug info. How have you tested this? Regardless of whether or not I apply this patch, I get the same (broken/truncated) callchains for userspace in perf report. E.g. the following stupid program (built with -O0 -g): --->8 void bar(void) { int i; for (i = 0; i < 1000000; ++i) asm volatile("nop" ::: "memory"); } void foo(void) { bar(); } int main(void) { foo(); return 0; } 8<--- Gives me an incomplete callchain: # Overhead Command Shared Object Symbol # ........ ........ ................. ............................... # 0.00% unwindme unwindme [.] bar | --- bar This is the same with or without your patch. Will
Hi Will, On Thu, Sep 5, 2013 at 2:45 PM, Will Deacon <will.deacon@arm.com> wrote: > Hi Jean, > > [adding Michael, since I know he was interested in this] > > On Wed, Sep 04, 2013 at 07:04:14PM +0100, Jean Pihet wrote: >> On ARM the debug info is not present in the .eh_frame sections but >> instead in .debug_frame. >> Use libunwind to load and parse the debug info. > > How have you tested this? Regardless of whether or not I apply this patch, I > get the same (broken/truncated) callchains for userspace in perf report. Here are the commands I have been using: perf record -g dwarf -- <binary to profile> perf report --sort symbol --call-graph --stdio > > E.g. the following stupid program (built with -O0 -g): > > --->8 > > void bar(void) > { > int i; > for (i = 0; i < 1000000; ++i) > asm volatile("nop" ::: "memory"); > } > > void foo(void) > { > bar(); > } > > > int main(void) > { > foo(); > return 0; > } > > 8<--- > > Gives me an incomplete callchain: > > # Overhead Command Shared Object Symbol > # ........ ........ ................. ............................... > # > 0.00% unwindme unwindme [.] bar > | > --- bar I get the following with a simple stupid program with a long call chain: 0.57% stress_bt stress_bt [.] foo_115 | --- foo_115 foo_114 foo_113 ... foo_92 bar doit main __libc_start_main Things to check: - compile the binaries and libraries with -g (-dbg flavor of libs are usually ok), - use -g dwarf in perf record > This is the same with or without your patch. > > Will Thanks for testing! Jean > > _______________________________________________ > linux-arm-kernel mailing list > linux-arm-kernel@lists.infradead.org > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
On 5 September 2013 14:45, Will Deacon <will.deacon@arm.com> wrote: > Hi Jean, > > [adding Michael, since I know he was interested in this] > > On Wed, Sep 04, 2013 at 07:04:14PM +0100, Jean Pihet wrote: >> On ARM the debug info is not present in the .eh_frame sections but >> instead in .debug_frame. >> Use libunwind to load and parse the debug info. > > How have you tested this? Regardless of whether or not I apply this patch, I > get the same (broken/truncated) callchains for userspace in perf report. Same here: I have applied these patches against 3.11 running on a Calxeda Highbank, and I never get more than a single entry for the userland part of the call stack. > > E.g. the following stupid program (built with -O0 -g): > [...] > > Gives me an incomplete callchain: > > # Overhead Command Shared Object Symbol > # ........ ........ ................. ............................... > # > 0.00% unwindme unwindme [.] bar > | > --- bar > I get exactly the same results, just bar and nothing below.
On 5 September 2013 15:05, Jean Pihet <jean.pihet@newoldbits.com> wrote: [..] > Here are the commands I have been using: > perf record -g dwarf -- <binary to profile> > perf report --sort symbol --call-graph --stdio > Ah, I failed to add the 'dwarf' after -g, however, in that case, my perf report segfaults: #0 locate_debug_info (as=0xb6ea9144 <local_addr_space>, info=info@entry=0x83d6, addr=addr@entry=0, dlname=0x4a0000 <Address 0x4a0000 out of bounds>) at dwarf/Gfind_proc_info-lsb.c:295 #1 0xb6e9a9c6 in _Uarm_dwarf_find_debug_frame (found=found@entry=0, di_debug=di_debug@entry=0xbeff95b8, info=info@entry=0x83d6, ip=ip@entry=0) at dwarf/Gfind_proc_info-lsb.c:423 #2 0x0006f0e4 in find_proc_info (as=0x2c06a0, ip=33750, pi=0xbeffa8fc, need_unwind_info=1, arg=0xbeffe530) at util/unwind.c:339 #3 0xb6e98258 in fetch_proc_info (c=c@entry=0xbeffa4d4, ip=<optimised out>, need_unwind_info=need_unwind_info@entry=1) at dwarf/Gparser.c:422 #4 0xb6e99640 in uncached_dwarf_find_save_locs (c=0xbeffa4d4) at dwarf/Gparser.c:824 #5 _Uarm_dwarf_find_save_locs (c=c@entry=0xbeffa4d4) at dwarf/Gparser.c:849 #6 0xb6e9a034 in _Uarm_dwarf_step (c=c@entry=0xbeffa4d4) at dwarf/Gstep.c:34 #7 0xb6e95182 in _Uarm_step (cursor=cursor@entry=0xbeffa4d4) at arm/Gstep.c:177 #8 0x0006ed50 in get_entries (ui=ui@entry=0xbeffe530, cb=cb@entry=0x47599 <unwind_entry>, arg=arg@entry=0xb6b804c8) at util/unwind.c:573 #9 0x0006f324 in unwind__get_entries (cb=cb@entry=0x47599 <unwind_entry>, arg=0xb6b804c8, machine=machine@entry=0xf0544, thread=thread@entry=0x101860, sample_uregs=sample_uregs@entry=65535, data=data@entry=0xbeffe740) at util/unwind.c:608 #10 0x00049a96 in machine__resolve_callchain (machine=machine@entry=0xf0544, evsel=evsel@entry=0xf0b98, thread=0x101860, sample=sample@entry=0xbeffe740, parent=parent@entry=0xbeffe644) at util/machine.c:1262 #11 0x0001a43e in perf_evsel__add_hist_entry (machine=0xf0544, sample=0xbeffe740, al=0xbeffe640, evsel=0xf0b98) at builtin-report.c:256 #12 process_sample_event (tool=0xbeffeb68, event=0xb6b3c600, sample=0xbeffe740, evsel=0xf0b98, machine=0xf0544) at builtin-report.c:335 #13 0x0004b3ca in perf_session_deliver_event (session=session@entry=0xf0498, event=0xb6b3c600, sample=sample@entry=0xbeffe740, tool=tool@entry=0xbeffeb68, file_offset=file_offset@entry=161280) at util/session.c:873 #14 0x0004b8d0 in flush_sample_queue (s=s@entry=0xf0498, tool=tool@entry=0xbeffeb68) at util/session.c:521 #15 0x0004c974 in __perf_session__process_events (session=session@entry=0xf0498, data_offset=<optimised out>, data_size=data_size@entry=437976, file_size=438264, tool=tool@entry=0xbeffeb68) at util/session.c:1269 #16 0x0004cc5c in perf_session__process_events (self=self@entry=0xf0498, tool=tool@entry=0xbeffeb68) at util/session.c:1286 #17 0x0001b4b2 in __cmd_report (rep=0xbeffeb68) at builtin-report.c:513 #18 cmd_report (argc=0, argv=0xbefff6c8, prefix=<optimised out>) at builtin-report.c:957 #19 0x0000d80e in run_builtin (p=p@entry=0xaa548 <commands+84>, argc=argc@entry=2, argv=argv@entry=0xbefff6c8) at perf.c:319 #20 0x0000d28a in handle_internal_command (argv=0xbefff6c8, argc=2) at perf.c:376 #21 run_argv (argv=0xbefff4a8, argcp=0xbefff4ac) at perf.c:420 #22 main (argc=2, argv=0xbefff6c8) at perf.c:521
On Thu, Sep 05, 2013 at 02:17:30PM +0100, Ard Biesheuvel wrote: > On 5 September 2013 15:05, Jean Pihet <jean.pihet@newoldbits.com> wrote: > [..] > > Here are the commands I have been using: > > perf record -g dwarf -- <binary to profile> > > perf report --sort symbol --call-graph --stdio > > > > Ah, I failed to add the 'dwarf' after -g, however, in that case, my > perf report segfaults: Same SEGV here. Will
On 5 September 2013 15:19, Will Deacon <will.deacon@arm.com> wrote: > On Thu, Sep 05, 2013 at 02:17:30PM +0100, Ard Biesheuvel wrote: >> On 5 September 2013 15:05, Jean Pihet <jean.pihet@newoldbits.com> wrote: >> [..] >> > Here are the commands I have been using: >> > perf record -g dwarf -- <binary to profile> >> > perf report --sort symbol --call-graph --stdio >> > >> >> Ah, I failed to add the 'dwarf' after -g, however, in that case, my >> perf report segfaults: > > Same SEGV here. Ouch! I never got the segfault on my side. Here is the setup I am using: - OMAP4 Pandaboard, - 13.07 Ubuntu dist from http://www.linaro.org/downloads/, - 3.11 mainline kernel + 3 patches for unwinding info, - patched perf tool, - dbg flavor of the libs installed. Without them installed I do not get the address resolved but no segfaults Can you check if the linked libraries contain the .debug_frame sections? (ldd; readelf -S /lib/arm-linux-gnueabihf/libc-2.17.so|grep debug_frame; readelf -S /usr/lib/debug/lib/arm-linux-gnueabihf/libc-2.17.so|grep debug_frame)? > > Will Jean
Hi, On 5 September 2013 15:33, Jean Pihet <jean.pihet@linaro.org> wrote: > On 5 September 2013 15:19, Will Deacon <will.deacon@arm.com> wrote: >> On Thu, Sep 05, 2013 at 02:17:30PM +0100, Ard Biesheuvel wrote: >>> On 5 September 2013 15:05, Jean Pihet <jean.pihet@newoldbits.com> wrote: >>> [..] >>> > Here are the commands I have been using: >>> > perf record -g dwarf -- <binary to profile> >>> > perf report --sort symbol --call-graph --stdio >>> > >>> >>> Ah, I failed to add the 'dwarf' after -g, however, in that case, my >>> perf report segfaults: >> >> Same SEGV here. > Ouch! I never got the segfault on my side. The segfault is caused by libunwind. With the latest version [1], dwarf unwinding works fine. Investigation on-going, more to come! [1] git://git.sv.gnu.org/libunwind.git Regards, Jean > > Here is the setup I am using: > - OMAP4 Pandaboard, > - 13.07 Ubuntu dist from http://www.linaro.org/downloads/, > - 3.11 mainline kernel + 3 patches for unwinding info, > - patched perf tool, > - dbg flavor of the libs installed. Without them installed I do not > get the address resolved but no segfaults > > Can you check if the linked libraries contain the .debug_frame > sections? (ldd; readelf -S /lib/arm-linux-gnueabihf/libc-2.17.so|grep > debug_frame; readelf -S > /usr/lib/debug/lib/arm-linux-gnueabihf/libc-2.17.so|grep debug_frame)? > >> >> Will > > Jean
On 5 September 2013 17:29, Jean Pihet <jean.pihet@linaro.org> wrote: [...] > The segfault is caused by libunwind. With the latest version [1], > dwarf unwinding works fine. > Investigation on-going, more to come! > > [1] git://git.sv.gnu.org/libunwind.git > I managed to get it to work by upgrading to Ubuntu Saucy's libunwind8 on a Ubuntu Raring system (Calxeda Highbank) FWIW, for the series Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> # on ARM/Highbank/UbuntuSaucy
On Wed, Sep 04, 2013 at 08:04:14PM +0200, Jean Pihet wrote: > On ARM the debug info is not present in the .eh_frame sections but > instead in .debug_frame. > Use libunwind to load and parse the debug info. hum, cannot make final link: $ make LIBUNWIND_DIR=/opt/libunwind/ CHK -fstack-protector-all CHK -Wstack-protector CHK -Wvolatile-register-var CHK -D_FORTIFY_SOURCE=2 CHK bionic CHK libelf CHK libdw CHK -DLIBELF_MMAP CHK -DLIBELF_MMAP CHK libunwind CHK libaudit ... make[1]: `liblk.a' is up to date. SUBDIR /home/jolsa/linux-perf/tools/lib/traceevent/ LINK perf libperf.a(unwind.o): In function `find_proc_info': /home/jolsa/linux-perf/tools/perf/util/unwind.c:339: undefined reference to `_Ux86_64_dwarf_find_debug_frame' collect2: ld returned 1 exit status make: *** [perf] Error 1 I'm using the latest code from git://git.sv.gnu.org/libunwind.git Looks like dwarf_find_debug_frame is not exported, although it looks like it is based on what I see in libunwind sources ;-) What did I miss? Also few typo comments below.. thanks, jirka > > Signed-off-by: Jean Pihet <jean.pihet@linaro.org> > --- > tools/perf/util/unwind.c | 70 +++++++++++++++++++++++++++++++++++++----------- > 1 file changed, 54 insertions(+), 16 deletions(-) > > diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c > index 958723b..5353b32 100644 > --- a/tools/perf/util/unwind.c > +++ b/tools/perf/util/unwind.c > @@ -39,6 +39,14 @@ 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 +253,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 +264,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 +273,27 @@ 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; > } > > +static int read_unwind_spec_debug_frame(struct dso *dso, > + struct machine *machine, u64 *offset) > +{ some strange formatting issue ^^^ ;-) > + 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; > +} > + > static struct map *find_map(unw_word_t ip, struct unwind_info *ui) > { > struct addr_location al; > @@ -291,20 +318,31 @@ 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)) { ditto ^^^ > + 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); ditto ^^^ > + } > + > + /* 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); ditto ^^^ > + } > > - 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, > -- > 1.7.11.7 >
Hi Jiri, On 5 September 2013 18:30, Jiri Olsa <jolsa@redhat.com> wrote: > On Wed, Sep 04, 2013 at 08:04:14PM +0200, Jean Pihet wrote: >> On ARM the debug info is not present in the .eh_frame sections but >> instead in .debug_frame. >> Use libunwind to load and parse the debug info. > > hum, cannot make final link: > > $ make LIBUNWIND_DIR=/opt/libunwind/ > CHK -fstack-protector-all > CHK -Wstack-protector > CHK -Wvolatile-register-var > CHK -D_FORTIFY_SOURCE=2 > CHK bionic > CHK libelf > CHK libdw > CHK -DLIBELF_MMAP > CHK -DLIBELF_MMAP > CHK libunwind > CHK libaudit > > ... > > make[1]: `liblk.a' is up to date. > SUBDIR /home/jolsa/linux-perf/tools/lib/traceevent/ > LINK perf > libperf.a(unwind.o): In function `find_proc_info': > /home/jolsa/linux-perf/tools/perf/util/unwind.c:339: undefined reference to `_Ux86_64_dwarf_find_debug_frame' > collect2: ld returned 1 exit status > make: *** [perf] Error 1 > > > I'm using the latest code from git://git.sv.gnu.org/libunwind.git > > Looks like dwarf_find_debug_frame is not exported, although > it looks like it is based on what I see in libunwind sources ;-) > > What did I miss? Weird, I do not have the error on x86_64. I am investigating this and will come back to you asap. > > Also few typo comments below.. > > thanks, > jirka > >> >> Signed-off-by: Jean Pihet <jean.pihet@linaro.org> >> --- >> tools/perf/util/unwind.c | 70 +++++++++++++++++++++++++++++++++++++----------- >> 1 file changed, 54 insertions(+), 16 deletions(-) >> >> diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c >> index 958723b..5353b32 100644 >> --- a/tools/perf/util/unwind.c >> +++ b/tools/perf/util/unwind.c >> @@ -39,6 +39,14 @@ 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 +253,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 +264,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 +273,27 @@ 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; >> } >> >> +static int read_unwind_spec_debug_frame(struct dso *dso, >> + struct machine *machine, u64 *offset) >> +{ > > some strange formatting issue ^^^ ;-) I am using 4-spaces tabs. scripts/checkpatch.pl reported it to me in the form of too long lines. Should I change the code to 8-spaces tabs? Thx! Jean > > >> + 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; >> +} >> + >> static struct map *find_map(unw_word_t ip, struct unwind_info *ui) >> { >> struct addr_location al; >> @@ -291,20 +318,31 @@ 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)) { > > ditto ^^^ > >> + 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); > > ditto ^^^ > >> + } >> + >> + /* 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); > > ditto ^^^ > >> + } >> >> - 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, >> -- >> 1.7.11.7 >>
Hi Jiri, On 5 September 2013 18:30, Jiri Olsa <jolsa@redhat.com> wrote: > On Wed, Sep 04, 2013 at 08:04:14PM +0200, Jean Pihet wrote: >> On ARM the debug info is not present in the .eh_frame sections but >> instead in .debug_frame. >> Use libunwind to load and parse the debug info. > > hum, cannot make final link: > > $ make LIBUNWIND_DIR=/opt/libunwind/ > CHK -fstack-protector-all > CHK -Wstack-protector > CHK -Wvolatile-register-var > CHK -D_FORTIFY_SOURCE=2 > CHK bionic > CHK libelf > CHK libdw > CHK -DLIBELF_MMAP > CHK -DLIBELF_MMAP > CHK libunwind > CHK libaudit > > ... > > make[1]: `liblk.a' is up to date. > SUBDIR /home/jolsa/linux-perf/tools/lib/traceevent/ > LINK perf > libperf.a(unwind.o): In function `find_proc_info': > /home/jolsa/linux-perf/tools/perf/util/unwind.c:339: undefined reference to `_Ux86_64_dwarf_find_debug_frame' > collect2: ld returned 1 exit status > make: *** [perf] Error 1 > > > I'm using the latest code from git://git.sv.gnu.org/libunwind.git > > Looks like dwarf_find_debug_frame is not exported, although > it looks like it is based on what I see in libunwind sources ;-) > > What did I miss? libunwind needs to be configured with --enable-debug-frame for the debug_frame code to be included in the lib. On ARM the flag is always set while it isn't on x86. Here is the culprit below (lines from libunwind configure). Should that be changed in configure along with the changes in tools/perf? { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to load .debug_frame sections" >&5 $as_echo_n "checking whether to load .debug_frame sections... " >&6; } # Check whether --enable-debug_frame was given. if test "${enable_debug_frame+set}" = set; then : enableval=$enable_debug_frame; else case "${target_arch}" in (arm) enable_debug_frame=yes;; (*) enable_debug_frame=no;; esac fi if test x$enable_debug_frame = xyes; then $as_echo "#define CONFIG_DEBUG_FRAME /**/" >>confdefs.h fi Regards, Jean > > Also few typo comments below.. > > thanks, > jirka > >> >> Signed-off-by: Jean Pihet <jean.pihet@linaro.org> >> --- >> tools/perf/util/unwind.c | 70 +++++++++++++++++++++++++++++++++++++----------- >> 1 file changed, 54 insertions(+), 16 deletions(-) >> >> diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c >> index 958723b..5353b32 100644 >> --- a/tools/perf/util/unwind.c >> +++ b/tools/perf/util/unwind.c >> @@ -39,6 +39,14 @@ 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 +253,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 +264,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 +273,27 @@ 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; >> } >> >> +static int read_unwind_spec_debug_frame(struct dso *dso, >> + struct machine *machine, u64 *offset) >> +{ > > some strange formatting issue ^^^ ;-) > > >> + 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; >> +} >> + >> static struct map *find_map(unw_word_t ip, struct unwind_info *ui) >> { >> struct addr_location al; >> @@ -291,20 +318,31 @@ 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)) { > > ditto ^^^ > >> + 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); > > ditto ^^^ > >> + } >> + >> + /* 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); > > ditto ^^^ > >> + } >> >> - 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, >> -- >> 1.7.11.7 >>
On Thu, Sep 05, 2013 at 06:49:13PM +0200, Jean Pihet wrote: > Hi Jiri, > > On 5 September 2013 18:30, Jiri Olsa <jolsa@redhat.com> wrote: > > On Wed, Sep 04, 2013 at 08:04:14PM +0200, Jean Pihet wrote: > >> On ARM the debug info is not present in the .eh_frame sections but > >> instead in .debug_frame. > >> Use libunwind to load and parse the debug info. > > > > hum, cannot make final link: > > > > $ make LIBUNWIND_DIR=/opt/libunwind/ > > CHK -fstack-protector-all > > CHK -Wstack-protector > > CHK -Wvolatile-register-var > > CHK -D_FORTIFY_SOURCE=2 > > CHK bionic > > CHK libelf > > CHK libdw > > CHK -DLIBELF_MMAP > > CHK -DLIBELF_MMAP > > CHK libunwind > > CHK libaudit > > > > ... > > > > make[1]: `liblk.a' is up to date. > > SUBDIR /home/jolsa/linux-perf/tools/lib/traceevent/ > > LINK perf > > libperf.a(unwind.o): In function `find_proc_info': > > /home/jolsa/linux-perf/tools/perf/util/unwind.c:339: undefined reference to `_Ux86_64_dwarf_find_debug_frame' > > collect2: ld returned 1 exit status > > make: *** [perf] Error 1 > > > > > > I'm using the latest code from git://git.sv.gnu.org/libunwind.git > > > > Looks like dwarf_find_debug_frame is not exported, although > > it looks like it is based on what I see in libunwind sources ;-) > > > > What did I miss? > Weird, I do not have the error on x86_64. I am investigating this and > will come back to you asap. > > > > > Also few typo comments below.. > > > > thanks, > > jirka > > > >> > >> Signed-off-by: Jean Pihet <jean.pihet@linaro.org> > >> --- > >> tools/perf/util/unwind.c | 70 +++++++++++++++++++++++++++++++++++++----------- > >> 1 file changed, 54 insertions(+), 16 deletions(-) > >> > >> diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c > >> index 958723b..5353b32 100644 > >> --- a/tools/perf/util/unwind.c > >> +++ b/tools/perf/util/unwind.c > >> @@ -39,6 +39,14 @@ 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 +253,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 +264,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 +273,27 @@ 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; > >> } > >> > >> +static int read_unwind_spec_debug_frame(struct dso *dso, > >> + struct machine *machine, u64 *offset) > >> +{ > > > > some strange formatting issue ^^^ ;-) > I am using 4-spaces tabs. scripts/checkpatch.pl reported it to me in > the form of too long lines. > Should I change the code to 8-spaces tabs? > right, if I set tabs to 4 space then it's ok so I guess 8 is globally agreed ;-) jirka
On Fri, Sep 06, 2013 at 11:31:17AM +0200, Jean Pihet wrote: > Hi Jiri, > > On 5 September 2013 18:30, Jiri Olsa <jolsa@redhat.com> wrote: > > On Wed, Sep 04, 2013 at 08:04:14PM +0200, Jean Pihet wrote: > >> On ARM the debug info is not present in the .eh_frame sections but > >> instead in .debug_frame. > >> Use libunwind to load and parse the debug info. > > > > hum, cannot make final link: > > > > $ make LIBUNWIND_DIR=/opt/libunwind/ > > CHK -fstack-protector-all > > CHK -Wstack-protector > > CHK -Wvolatile-register-var > > CHK -D_FORTIFY_SOURCE=2 > > CHK bionic > > CHK libelf > > CHK libdw > > CHK -DLIBELF_MMAP > > CHK -DLIBELF_MMAP > > CHK libunwind > > CHK libaudit > > > > ... > > > > make[1]: `liblk.a' is up to date. > > SUBDIR /home/jolsa/linux-perf/tools/lib/traceevent/ > > LINK perf > > libperf.a(unwind.o): In function `find_proc_info': > > /home/jolsa/linux-perf/tools/perf/util/unwind.c:339: undefined reference to `_Ux86_64_dwarf_find_debug_frame' > > collect2: ld returned 1 exit status > > make: *** [perf] Error 1 > > > > > > I'm using the latest code from git://git.sv.gnu.org/libunwind.git > > > > Looks like dwarf_find_debug_frame is not exported, although > > it looks like it is based on what I see in libunwind sources ;-) > > > > What did I miss? > libunwind needs to be configured with --enable-debug-frame for the > debug_frame code to be included in the lib. > On ARM the flag is always set while it isn't on x86. Here is the > culprit below (lines from libunwind configure). yay, thats it! > > Should that be changed in configure along with the changes in tools/perf? I guess it's ok Other than that tabs misformating the 'perf tool' change looks ok. I tested the '.eh_frame' code and it's still working. Once I figure out how to create a x86 binary with .debug_frame data I'll test the code itself ;-) If you could think of any automated testcase for this that could be added under 'tests' that'd be nice (not necessarily) thanks, jirka
On 6 September 2013 12:17, Jiri Olsa <jolsa@redhat.com> wrote: > On Fri, Sep 06, 2013 at 11:31:17AM +0200, Jean Pihet wrote: >> Hi Jiri, >> >> On 5 September 2013 18:30, Jiri Olsa <jolsa@redhat.com> wrote: >> > On Wed, Sep 04, 2013 at 08:04:14PM +0200, Jean Pihet wrote: >> >> On ARM the debug info is not present in the .eh_frame sections but >> >> instead in .debug_frame. >> >> Use libunwind to load and parse the debug info. >> > >> > hum, cannot make final link: >> > >> > $ make LIBUNWIND_DIR=/opt/libunwind/ >> > CHK -fstack-protector-all >> > CHK -Wstack-protector >> > CHK -Wvolatile-register-var >> > CHK -D_FORTIFY_SOURCE=2 >> > CHK bionic >> > CHK libelf >> > CHK libdw >> > CHK -DLIBELF_MMAP >> > CHK -DLIBELF_MMAP >> > CHK libunwind >> > CHK libaudit >> > >> > ... >> > >> > make[1]: `liblk.a' is up to date. >> > SUBDIR /home/jolsa/linux-perf/tools/lib/traceevent/ >> > LINK perf >> > libperf.a(unwind.o): In function `find_proc_info': >> > /home/jolsa/linux-perf/tools/perf/util/unwind.c:339: undefined reference to `_Ux86_64_dwarf_find_debug_frame' >> > collect2: ld returned 1 exit status >> > make: *** [perf] Error 1 >> > >> > >> > I'm using the latest code from git://git.sv.gnu.org/libunwind.git >> > >> > Looks like dwarf_find_debug_frame is not exported, although >> > it looks like it is based on what I see in libunwind sources ;-) >> > >> > What did I miss? >> libunwind needs to be configured with --enable-debug-frame for the >> debug_frame code to be included in the lib. >> On ARM the flag is always set while it isn't on x86. Here is the >> culprit below (lines from libunwind configure). > > yay, thats it! > >> >> Should that be changed in configure along with the changes in tools/perf? > > I guess it's ok I wonder how to express the dependency between the perf changes and the libunwind version and configure flags. Is a note in the commit descritpion enough? I fear that the change can break many build systems... > > Other than that tabs misformating the 'perf tool' change looks ok. Ok I will respin the code with the typo and formatting changes. > > I tested the '.eh_frame' code and it's still working. Once > I figure out how to create a x86 binary with .debug_frame > data I'll test the code itself ;-) Great! > > If you could think of any automated testcase for this that could > be added under 'tests' that'd be nice (not necessarily) Ok will look at it. Linaro has automated tests that I need to write as well so rather do it in perf/tests directly ;-p > > thanks, > jirka Thanks! Jean
diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c index 958723b..5353b32 100644 --- a/tools/perf/util/unwind.c +++ b/tools/perf/util/unwind.c @@ -39,6 +39,14 @@ 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 +253,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 +264,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 +273,27 @@ 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; } +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; +} + static struct map *find_map(unw_word_t ip, struct unwind_info *ui) { struct addr_location al; @@ -291,20 +318,31 @@ 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); + } + + /* 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); + } - 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,
On ARM the debug info is not present in the .eh_frame sections but instead in .debug_frame. Use libunwind to load and parse the debug info. Signed-off-by: Jean Pihet <jean.pihet@linaro.org> --- tools/perf/util/unwind.c | 70 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 54 insertions(+), 16 deletions(-)