* [PATCH] perf symbols: Follow .gnu_debuglink section to find separate symbols
@ 2012-06-20 22:22 Pierre-Loup A. Griffais
2012-06-21 17:28 ` Arnaldo Carvalho de Melo
0 siblings, 1 reply; 4+ messages in thread
From: Pierre-Loup A. Griffais @ 2012-06-20 22:22 UTC (permalink / raw)
To: linux-kernel; +Cc: a.p.zijlstra, paulus, mingo, acme, torvalds, Mike Sartain
The .gnu_debuglink section is specified to contain the filename of the
debug info file, as well as a CRC that can be used to validate it.
This doesn't currently use the checksum and relies on the usual build-id
matching for validation.
This provides more context:
http://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html
Signed-off-by: Pierre-Loup A. Griffais <pgriffais@nvidia.com>
Reported-by: Mike Sartain <mikesart@valvesoftware.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
---
tools/perf/util/symbol.c | 65 +++++++++++++++++++++++++++++++++++++++++++++-
tools/perf/util/symbol.h | 1 +
2 files changed, 65 insertions(+), 1 deletion(-)
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 3e2e5ea..4788092 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1590,11 +1590,62 @@ out:
return err;
}
+static int filename__read_debuglink(const char *filename,
+ char *path, size_t size)
+{
+ int fd, err = -1;
+ Elf *elf;
+ GElf_Ehdr ehdr;
+ GElf_Shdr shdr;
+ Elf_Data *data;
+ Elf_Scn *sec;
+ Elf_Kind ek;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ goto out;
+
+ elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
+ if (elf == NULL) {
+ pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
+ goto out_close;
+ }
+
+ ek = elf_kind(elf);
+ if (ek != ELF_K_ELF)
+ goto out_close;
+
+ if (gelf_getehdr(elf, &ehdr) == NULL) {
+ pr_err("%s: cannot get elf header.\n", __func__);
+ goto out_close;
+ }
+
+ sec = elf_section_by_name(elf, &ehdr, &shdr,
+ ".gnu_debuglink", NULL);
+ if (sec == NULL)
+ goto out_close;
+
+ data = elf_getdata(sec, NULL);
+ if (data == NULL)
+ goto out_close;
+
+ /* the start of this section is a zero-terminated string */
+ strncpy(path, data->d_buf, size);
+
+ elf_end(elf);
+
+out_close:
+ close(fd);
+out:
+ return err;
+}
+
char dso__symtab_origin(const struct dso *dso)
{
static const char origin[] = {
[SYMTAB__KALLSYMS] = 'k',
[SYMTAB__JAVA_JIT] = 'j',
+ [SYMTAB__DEBUGLINK] = 'l',
[SYMTAB__BUILD_ID_CACHE] = 'B',
[SYMTAB__FEDORA_DEBUGINFO] = 'f',
[SYMTAB__UBUNTU_DEBUGINFO] = 'u',
@@ -1662,10 +1713,22 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
*/
want_symtab = 1;
restart:
- for (dso->symtab_type = SYMTAB__BUILD_ID_CACHE;
+ for (dso->symtab_type = SYMTAB__DEBUGLINK;
dso->symtab_type != SYMTAB__NOT_FOUND;
dso->symtab_type++) {
switch (dso->symtab_type) {
+ case SYMTAB__DEBUGLINK: {
+ char *last_slash;
+ strncpy(name, dso->long_name, size);
+ last_slash = name + dso->long_name_len;
+ while (last_slash && *last_slash != '/')
+ last_slash--;
+ if (last_slash)
+ last_slash++;
+ filename__read_debuglink(dso->long_name, last_slash,
+ size - (last_slash - name));
+ }
+ break;
case SYMTAB__BUILD_ID_CACHE:
/* skip the locally configured cache if a symfs is given */
if (symbol_conf.symfs[0] ||
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index af0752b..a884b99 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -257,6 +257,7 @@ enum symtab_type {
SYMTAB__KALLSYMS = 0,
SYMTAB__GUEST_KALLSYMS,
SYMTAB__JAVA_JIT,
+ SYMTAB__DEBUGLINK,
SYMTAB__BUILD_ID_CACHE,
SYMTAB__FEDORA_DEBUGINFO,
SYMTAB__UBUNTU_DEBUGINFO,
--
1.7.9.5
^ permalink raw reply related [flat|nested] 4+ messages in thread* Re: [PATCH] perf symbols: Follow .gnu_debuglink section to find separate symbols
2012-06-20 22:22 [PATCH] perf symbols: Follow .gnu_debuglink section to find separate symbols Pierre-Loup A. Griffais
@ 2012-06-21 17:28 ` Arnaldo Carvalho de Melo
2012-06-21 18:41 ` Pierre-Loup A. Griffais
0 siblings, 1 reply; 4+ messages in thread
From: Arnaldo Carvalho de Melo @ 2012-06-21 17:28 UTC (permalink / raw)
To: Pierre-Loup A. Griffais
Cc: linux-kernel, a.p.zijlstra, paulus, mingo, torvalds, Mike Sartain
Em Wed, Jun 20, 2012 at 03:22:41PM -0700, Pierre-Loup A. Griffais escreveu:
> The .gnu_debuglink section is specified to contain the filename of the
> debug info file, as well as a CRC that can be used to validate it.
> This provides more context:
> http://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html
>
> +++ b/tools/perf/util/symbol.c
> +static int filename__read_debuglink(const char *filename,
> + char *path, size_t size)
> +{
Isn't there any other function that opens an ELF file, looks for an
specific session to then read its contents?
Couldn't it be reused here?
> + case SYMTAB__DEBUGLINK: {
> + char *last_slash;
> + strncpy(name, dso->long_name, size);
> + last_slash = name + dso->long_name_len;
> + while (last_slash && *last_slash != '/')
> + last_slash--;
Why the test for last_slash to be != NULL? How could it ever be? This is
an optimization since we have the dso->long_name_len so that we avoid
using strrchr that in turn would do an strlen?
So the test should be:
while (last_slash != name && *last_slash != '/')
To avoid underflowing, right?
> + if (last_slash)
> + last_slash++;
> + filename__read_debuglink(dso->long_name, last_slash,
How last_slash can point to the path? It looks like it points to the
basename, no?
Yeah, it is, and then your algorithm will work because last_slash
doesn't point to the _path_, but to a string _preceded_ by the path, so
for /bin/ls, the debuglink content would be ls.debug and that is what
will be stashed there, ending up with:
name = "/bin/\0"
last_slash---^
name = "/bin/ls.debug\0"
I.e. its not really the last slash, but where the debuglink content has
to be stashed, concatenating with the same dirname as the associated
binary.
Can you please rename "last_slash" to "debuglink"? And "path" to
"debuglink" as well in the routine that reads the debuglink.
> + size - (last_slash - name));
> + }
Other than that, thanks a lot for working on this, surely we have to
support this feature!
- ARnaldo
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [PATCH] perf symbols: Follow .gnu_debuglink section to find separate symbols
2012-06-21 17:28 ` Arnaldo Carvalho de Melo
@ 2012-06-21 18:41 ` Pierre-Loup A. Griffais
2012-06-22 12:39 ` Arnaldo Carvalho de Melo
0 siblings, 1 reply; 4+ messages in thread
From: Pierre-Loup A. Griffais @ 2012-06-21 18:41 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo
Cc: linux-kernel@vger.kernel.org, a.p.zijlstra@chello.nl,
paulus@samba.org, mingo@redhat.com, torvalds@linux-foundation.org,
Mike Sartain
Thanks a lot for taking a look, Arnaldo; inline:
On 06/21/2012 10:28 AM, Arnaldo Carvalho de Melo wrote:
> Em Wed, Jun 20, 2012 at 03:22:41PM -0700, Pierre-Loup A. Griffais escreveu:
>> The .gnu_debuglink section is specified to contain the filename of the
>> debug info file, as well as a CRC that can be used to validate it.
>
>> This provides more context:
>> http://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html
>>
>> +++ b/tools/perf/util/symbol.c
>> +static int filename__read_debuglink(const char *filename,
>> + char *path, size_t size)
>> +{
>
> Isn't there any other function that opens an ELF file, looks for an
> specific session to then read its contents?
>
> Couldn't it be reused here?
There are plenty, but they're all different enough that trying to fold
them into common code seemed involved and risky. The closest looks like
elf_read_build_id(), but in order to leverage that one the common
function would need to take a list of sections to try in sequence.
Unless you have strong feelings against using filename__read_debuglink()
as-is I would recommend that any such work happen outside of that patch
in the interest of minimizing risk.
>
>> + case SYMTAB__DEBUGLINK: {
>> + char *last_slash;
>> + strncpy(name, dso->long_name, size);
>> + last_slash = name + dso->long_name_len;
>> + while (last_slash && *last_slash != '/')
>> + last_slash--;
>
> Why the test for last_slash to be != NULL? How could it ever be? This is
> an optimization since we have the dso->long_name_len so that we avoid
> using strrchr that in turn would do an strlen?
>
> So the test should be:
>
> while (last_slash != name && *last_slash != '/')
>
> To avoid underflowing, right?
Oops, yeah; not what I had in mind. Thanks for catching that.
>> + if (last_slash)
>> + last_slash++;
>> + filename__read_debuglink(dso->long_name, last_slash,
>
> How last_slash can point to the path? It looks like it points to the
> basename, no?
>
> Yeah, it is, and then your algorithm will work because last_slash
> doesn't point to the _path_, but to a string _preceded_ by the path, so
> for /bin/ls, the debuglink content would be ls.debug and that is what
> will be stashed there, ending up with:
>
> name = "/bin/\0"
> last_slash---^
> name = "/bin/ls.debug\0"
>
> I.e. its not really the last slash, but where the debuglink content has
> to be stashed, concatenating with the same dirname as the associated
> binary.
Yes, that's correct; sorry for the ill-named variables.
>
> Can you please rename "last_slash" to "debuglink"? And "path" to
> "debuglink" as well in the routine that reads the debuglink.
Done. I'm proposing to resend with:
while (debuglink != name && *debuglink != '/')
debuglink--;
if (*debuglink == '/')
debuglink++;
The underflow and subsequent "*debuglink == '/'" checks are only there
to do the right thing in case dso->long_name happens to just be a local
filename without any slashes in it. I realize that's probably never
supposed to happen, so I could remove them if you want. I'd rather err
on the side of caution, though.
>
>> + size - (last_slash - name));
>> + }
>
> Other than that, thanks a lot for working on this, surely we have to
> support this feature!
Thanks a lot for walking through the logic. Looking forward to your
comments before I resend!
- Pierre-Loup
>
> - ARnaldo
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [PATCH] perf symbols: Follow .gnu_debuglink section to find separate symbols
2012-06-21 18:41 ` Pierre-Loup A. Griffais
@ 2012-06-22 12:39 ` Arnaldo Carvalho de Melo
0 siblings, 0 replies; 4+ messages in thread
From: Arnaldo Carvalho de Melo @ 2012-06-22 12:39 UTC (permalink / raw)
To: Pierre-Loup A. Griffais
Cc: linux-kernel@vger.kernel.org, a.p.zijlstra@chello.nl,
paulus@samba.org, mingo@redhat.com, torvalds@linux-foundation.org,
Mike Sartain
Em Thu, Jun 21, 2012 at 11:41:05AM -0700, Pierre-Loup A. Griffais escreveu:
> On 06/21/2012 10:28 AM, Arnaldo Carvalho de Melo wrote:
> > Em Wed, Jun 20, 2012 at 03:22:41PM -0700, Pierre-Loup A. Griffais escreveu:
> >> The .gnu_debuglink section is specified to contain the filename of the
> >> http://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html
> >> +static int filename__read_debuglink(const char *filename,
> > Isn't there any other function that opens an ELF file, looks for an
> > specific session to then read its contents?
> > Couldn't it be reused here?
> There are plenty, but they're all different enough that trying to fold
> them into common code seemed involved and risky. The closest looks like
> elf_read_build_id(), but in order to leverage that one the common
> function would need to take a list of sections to try in sequence.
But we can have helper routines to do what is done to open the elf file,
etc, right?
> Unless you have strong feelings against using filename__read_debuglink()
> as-is I would recommend that any such work happen outside of that patch
> in the interest of minimizing risk.
Agreed, that could be done later.
> >> + case SYMTAB__DEBUGLINK: {
> >> + char *last_slash;
> >> + strncpy(name, dso->long_name, size);
> >> + last_slash = name + dso->long_name_len;
> >> + while (last_slash && *last_slash != '/')
> >> + last_slash--;
> > Why the test for last_slash to be != NULL? How could it ever be? This is
> > an optimization since we have the dso->long_name_len so that we avoid
> > using strrchr that in turn would do an strlen?
> > So the test should be:
> > while (last_slash != name && *last_slash != '/')
> > To avoid underflowing, right?
>
> Oops, yeah; not what I had in mind. Thanks for catching that.
>
> >> + if (last_slash)
> >> + last_slash++;
> >> + filename__read_debuglink(dso->long_name, last_slash,
> > How last_slash can point to the path? It looks like it points to the
> > basename, no?
> >
> > Yeah, it is, and then your algorithm will work because last_slash
> > doesn't point to the _path_, but to a string _preceded_ by the path, so
> > for /bin/ls, the debuglink content would be ls.debug and that is what
> > will be stashed there, ending up with:
> >
> > name = "/bin/\0"
> > last_slash---^
> > name = "/bin/ls.debug\0"
> >
> > I.e. its not really the last slash, but where the debuglink content has
> > to be stashed, concatenating with the same dirname as the associated
> > binary.
>
> Yes, that's correct; sorry for the ill-named variables.
>
> > Can you please rename "last_slash" to "debuglink"? And "path" to
> > "debuglink" as well in the routine that reads the debuglink.
>
> Done. I'm proposing to resend with:
>
> while (debuglink != name && *debuglink != '/')
> debuglink--;
> if (*debuglink == '/')
> debuglink++;
>
> The underflow and subsequent "*debuglink == '/'" checks are only there
> to do the right thing in case dso->long_name happens to just be a local
> filename without any slashes in it. I realize that's probably never
> supposed to happen, so I could remove them if you want. I'd rather err
> on the side of caution, though.
That is the right mindset, code has to be robust.
> >> + size - (last_slash - name));
> >> + }
> >
> > Other than that, thanks a lot for working on this, surely we have to
> > support this feature!
>
> Thanks a lot for walking through the logic. Looking forward to your
> comments before I resend!
Please resend! :-)
- Arnaldo
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2012-06-22 12:39 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-06-20 22:22 [PATCH] perf symbols: Follow .gnu_debuglink section to find separate symbols Pierre-Loup A. Griffais
2012-06-21 17:28 ` Arnaldo Carvalho de Melo
2012-06-21 18:41 ` Pierre-Loup A. Griffais
2012-06-22 12:39 ` Arnaldo Carvalho de Melo
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).