lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <521CCFD8.90201@gmail.com>
Date:	Tue, 27 Aug 2013 10:12:08 -0600
From:	David Ahern <dsahern@...il.com>
To:	Jean Pihet <jean.pihet@...aro.org>, Jiri Olsa <jolsa@...hat.com>
CC:	linux-kernel@...r.kernel.org
Subject: Re: Fwd: perf: callchain feature on ARM - question about libunwind
 API

[Added Jiri who added the feature to perf]

On 8/27/13 5:58 AM, Jean Pihet wrote:
> Hi!
>
> I am looking for info and help on the libunwind API.
>
> What I am trying to achieve is to allow the callchain feature on perf
> for ARM (v7 to start with, then ARMv8), from the DWARF info found in
> the .debug_frame section.
>
>  From the source code in tools/perf I have added the call to
> dwarf_find_debug_frame to load and parse the debug info from
> .debug_frame. This works correctly, all IP ranges are found from the
> debug code (test program and libraries). Then at some point I get an
> assertion: 'perf: dwarf/Gparser.c:459: fetch_proc_info: Assertion
> `c->pi.unwind_info' failed.' At that point c->pi is NULL. Cf. below
> for more info.
>
> It looks like I am not using the libunwind API as it should, so that
> the perf code apparently builds a list of IP ranges to resolve but
> cannot use it later on to gather statistics on the runtime info.
>
> Any idea on how to progress? I am also looking at the *_proc_info API
> of libunwind.
>
> Here is the patch I am using below.
>
> Cheers,
> Jean
>
> ---
> Debug log:
>
> perf report --sort symbol --call-graph --stdio
>
> _Uarm_step: calling dwarf_step(ip=0x8464, c->dwarf@...ee150f8,
> c->dwarf.pi@...2bc0008)
> unwind: find_proc_info dso /home/linaro/perf-libunwind/
> test_app/stress_bt
> read_unwind_spec_debug_frame: .debug_frame offset=9304
> opened file '/home/linaro/perf-libunwind/test_app/stress_bt'. Section
> header at offset 18152
> read 3160 bytes of .debug_frame from offset 9304
> ...
> _ULarm_step: calling dwarf_step(ip=0xb6e6e764, c->dwarf@...ee07508,
> c->dwarf.pi@...6e955c0)
> _ULarm_find_proc_info: looking for IP=0xb6e6e763
> opened file '/usr/lib/arm-linux-gnueabihf/libunwind.so.8'. Section
> header at offset 513260
> read 17072 bytes of .debug_frame from offset 451836
> _ULarm_dwarf_search_unwind_table: looking for IP=0xb6e6e763
> _ULarm_find_proc_info returns 0
> ...
> perf: dwarf/Gparser.c:459: fetch_proc_info: Assertion
> `c->pi.unwind_info' failed.
>
>
> ---
> Patch to the kernel source:
>
> diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c
> index 958723b..dd97688 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,18 +264,40 @@ 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);
>
> -   if (offset)
> +   if (offset) {
> +       fprintf(stderr, "%s: .eh_frame offset=%llu\n", __func__, offset);
>          ret = unwind_spec_ehframe(dso, machine, offset,
>                        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 *segbase)
> +{
> +   int fd = dso__data_fd(dso, machine);
> +   if (fd < 0)
> +       return -EINVAL;
> +
> +   /* Check the .debug_frame section for unwinding info */
> +   *segbase = elf_section_offset(fd, ".debug_frame");
> +   close(fd);
> +
> +   fprintf(stderr, "%s: .debug_frame offset=%llu\n", __func__, *segbase);
> +
> +   if (!segbase)
> +       return -EINVAL;
> +
> +   return 0;
> +}
> +
>   static struct map *find_map(unw_word_t ip, struct unwind_info *ui)
>   {
>      struct addr_location al;
> @@ -289,22 +320,32 @@ find_proc_info(unw_addr_space_t as, unw_word_t
> ip,        unw_proc_info_t *pi,
>      if (!map || !map->dso)
>          return -EINVAL;
>
> -   pr_debug("unwind: find_proc_info dso %s\n", map->dso->name);
> +   fprintf(stderr, "unwind: find_proc_info dso %s\n", map->dso->name);
> +
> +   /* 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);
> +   }
>
> -   if (read_unwind_spec(map->dso, ui->machine,
> -                &table_data, &segbase, &fde_count))
> -       return -EINVAL;
> +   /* Check the .debug_frame section for unwinding info */
> +   if (!read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) {
> +       memset(&di, 0, sizeof(di));
> +       if (dwarf_find_debug_frame(0, &di, ip, segbase, map->dso->name,
> +                      map->start, map->end))
> +           return 0;
> +   }
>
> -   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,
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@...r.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
>

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ