Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

i#4123: Look for symbols in special build-id subdir #4133

Merged
merged 3 commits into from
Feb 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 58 additions & 1 deletion ext/drsyms/drsyms_elf.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* **********************************************************
* Copyright (c) 2011-2015 Google, Inc. All rights reserved.
* Copyright (c) 2011-2020 Google, Inc. All rights reserved.
* **********************************************************/

/*
Expand Down Expand Up @@ -126,6 +126,8 @@ typedef struct _elf_info_t {
byte *map_base;
ptr_uint_t load_base;
drsym_debug_kind_t debug_kind;
#define MAX_BUILD_ID_LENGTH 128
char build_id[MAX_BUILD_ID_LENGTH];
} elf_info_t;

/* Looks for a section with real data, not just a section with a header */
Expand Down Expand Up @@ -166,6 +168,52 @@ find_elf_section_by_name(Elf *elf, const char *match_name)
return NULL;
}

/* Reads the build id into mod->build_id. */
static void
read_build_id(Elf *elf, elf_info_t *mod)
{
Elf_Scn *scn;
for (scn = elf_getscn(elf, 0); scn != NULL; scn = elf_nextscn(elf, scn)) {
Elf_Shdr *section_header = elf_getshdr(scn);
if (section_header == NULL || section_header->sh_type != SHT_NOTE)
continue;
Elf_Data *data = elf_getdata(scn, NULL);
Elf_Note *note = (Elf_Note *)data->d_buf;
if (note->n_type == NT_GNU_BUILD_ID) {
/* Following the note are the name and value. */
byte *src = ((byte *)(note + 1)) + note->n_namesz;
size_t size = note->n_descsz;
if ((byte *)data->d_buf + data->d_size < src + note->n_descsz) {
NOTIFY_ELF("note data is shorter than specified length");
size = (byte *)data->d_buf + data->d_size - src;
}
char *dst = mod->build_id;
for (int i = 0; i < size; i++) {
derekbruening marked this conversation as resolved.
Show resolved Hide resolved
/* We're writing 3 chars at a time (2 digits + newline). */
if (dst + 3 > mod->build_id + MAX_BUILD_ID_LENGTH) {
NOTIFY_ELF("build id is too long");
/* It is already null-terminated from the prior write. Return
* the truncated id. It will likely still work for buildid-dir
* purposes where we only need the 1st 2 chars, and the rest
* come from the debuglink name.
*/
return;
}
unsigned int val = (unsigned int)*src;
int len = dr_snprintf(dst, 3, "%02x", val);
if (len < 0) {
NOTIFY_ELF("malformed build id");
mod->build_id[0] = '\0';
return;
}
dst += len;
src++;
}
return;
}
}
}

/* Iterates the program headers for an ELF object and returns the minimum
* segment load address. For executables this is generally a well-known
* address. For PIC shared libraries this is usually 0. For DR clients this is
Expand Down Expand Up @@ -260,6 +308,8 @@ drsym_obj_mod_init_pre(byte *map_base, size_t map_size)
mod->debug_kind |= DRSYM_LINE_NUMS | DRSYM_DWARF_LINE;
}

read_build_id(mod->elf, mod);

return (void *)mod;
}

Expand Down Expand Up @@ -431,6 +481,13 @@ drsym_obj_addrsearch_symtab(void *mod_in, size_t modoffs, uint *idx OUT)
return DRSYM_ERROR_SYMBOL_NOT_FOUND;
}

const char *
drsym_obj_build_id(void *mod_in)
{
elf_info_t *mod = (elf_info_t *)mod_in;
return mod->build_id;
}

/******************************************************************************
* Linux-specific helpers
*/
Expand Down
7 changes: 7 additions & 0 deletions ext/drsyms/drsyms_macho.c
Original file line number Diff line number Diff line change
Expand Up @@ -645,3 +645,10 @@ drsym_obj_debug_path(void)
{
return "/usr/lib/debug";
}

const char *
drsym_obj_build_id(void *mod_in)
{
/* NYI. Are build id-based dirs used on Mac? */
return NULL;
}
5 changes: 4 additions & 1 deletion ext/drsyms/drsyms_obj.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* **********************************************************
* Copyright (c) 2011-2014 Google, Inc. All rights reserved.
* Copyright (c) 2011-2020 Google, Inc. All rights reserved.
* **********************************************************/

/*
Expand Down Expand Up @@ -101,6 +101,9 @@ drsym_obj_same_file(const char *path1, const char *path2);
const char *
drsym_obj_debug_path(void);

const char *
drsym_obj_build_id(void *mod_in);

/***************************************************************************
* DWARF
*/
Expand Down
9 changes: 8 additions & 1 deletion ext/drsyms/drsyms_pecoff.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* **********************************************************
* Copyright (c) 2012-2017 Google, Inc. All rights reserved.
* Copyright (c) 2012-2020 Google, Inc. All rights reserved.
* **********************************************************/

/*
Expand Down Expand Up @@ -664,3 +664,10 @@ drsym_obj_debug_path(void)
/* XXX: also search mingw debug path */
return "c:\\cygwin\\lib\\debug";
}

const char *
drsym_obj_build_id(void *mod_in)
{
/* NYI. Are build id-based dirs used on cygwin? */
return NULL;
}
20 changes: 16 additions & 4 deletions ext/drsyms/drsyms_unix_common.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* **********************************************************
* Copyright (c) 2011-2014 Google, Inc. All rights reserved.
* Copyright (c) 2011-2020 Google, Inc. All rights reserved.
* **********************************************************/

/*
Expand Down Expand Up @@ -253,7 +253,19 @@ follow_debuglink(const char *modpath, dbg_module_t *mod, const char *debuglink,
if (last_slash != NULL)
*last_slash = '\0';

/* 1. Check $mod_dir/$debuglink */
/* 1. Check /usr/lib/debug/.build-id/xx/$debuglink */
const char *build_id = drsym_obj_build_id(mod->obj_info);
NOTIFY("%s: build id is %s\n", __FUNCTION__, build_id == NULL ? "<null>" : build_id);
if (build_id != NULL && build_id[0] != '\0') {
dr_snprintf(debug_modpath, MAXIMUM_PATH, "%s/.build-id/%c%c/%s",
drsym_obj_debug_path(), build_id[0], build_id[1], debuglink);
debug_modpath[MAXIMUM_PATH - 1] = '\0';
NOTIFY("%s: looking for %s\n", __FUNCTION__, debug_modpath);
if (dr_file_exists(debug_modpath))
return true;
}

/* 2. Check $mod_dir/$debuglink */
dr_snprintf(debug_modpath, MAXIMUM_PATH, "%s/%s", mod_dir, debuglink);
debug_modpath[MAXIMUM_PATH - 1] = '\0';
NOTIFY("%s: looking for %s\n", __FUNCTION__, debug_modpath);
Expand All @@ -265,14 +277,14 @@ follow_debuglink(const char *modpath, dbg_module_t *mod, const char *debuglink,
if (dr_file_exists(debug_modpath) && !drsym_obj_same_file(modpath, debug_modpath))
return true;

/* 2. Check $mod_dir/.debug/$debuglink */
/* 3. Check $mod_dir/.debug/$debuglink */
dr_snprintf(debug_modpath, MAXIMUM_PATH, "%s/.debug/%s", mod_dir, debuglink);
debug_modpath[MAXIMUM_PATH - 1] = '\0';
NOTIFY("%s: looking for %s\n", __FUNCTION__, debug_modpath);
if (dr_file_exists(debug_modpath))
return true;

/* 3. Check /usr/lib/debug/$mod_dir/$debuglink */
/* 4. Check /usr/lib/debug/$mod_dir/$debuglink */
dr_snprintf(debug_modpath, MAXIMUM_PATH, "%s/%s/%s", drsym_obj_debug_path(), mod_dir,
debuglink);
debug_modpath[MAXIMUM_PATH - 1] = '\0';
Expand Down