backtrace: Add ability to lookup function names via libbfd

dladdr() is not always able to determine the function names while
libbfd often can in such cases.
This commit is contained in:
Tobias Brunner
2022-12-02 14:57:47 +01:00
parent 02519ad60e
commit 21af89f941
+107 -40
View File
@@ -207,10 +207,16 @@ typedef struct {
bfd_entry_t *entry; bfd_entry_t *entry;
/** backtrace address */ /** backtrace address */
bfd_vma vma; bfd_vma vma;
/** stream to log to */ /** TRUE if address found */
FILE *file;
/** TRUE if complete */
bool found; bool found;
/** optional stream to log to */
FILE *file;
/** optional list of function names to match */
char **list;
/** optional number of names in list */
int count;
/** TRUE if found function name is in list */
bool in_list;
} bfd_find_data_t; } bfd_find_data_t;
/** /**
@@ -279,39 +285,56 @@ static void find_addr(bfd *abfd, asection *section, bfd_find_data_t *data)
const char *function; const char *function;
char fbuf[512] = "", sbuf[512] = ""; char fbuf[512] = "", sbuf[512] = "";
u_int line; u_int line;
int i;
if (!data->found || (get_section_flags(abfd, section) & SEC_ALLOC) != 0) if (data->found || (get_section_flags(abfd, section) & SEC_ALLOC) == 0)
{ {
vma = get_section_vma(abfd, section); return;
if (data->vma >= vma) }
vma = get_section_vma(abfd, section);
if (data->vma < vma)
{
return;
}
size = get_section_size(section);
if (data->vma >= vma + size)
{
return;
}
data->found = bfd_find_nearest_line(abfd, section, data->entry->syms,
data->vma - vma, &source, &function,
&line);
if (!data->found)
{
return;
}
if (data->count && function)
{
for (i = 0; i < data->count; i++)
{ {
size = get_section_size(section); if (streq(function, data->list[i]))
if (data->vma < vma + size)
{ {
data->found = bfd_find_nearest_line(abfd, section, data->in_list = TRUE;
data->entry->syms, data->vma - vma, break;
&source, &function, &line);
if (data->found)
{
if (source || function)
{
if (function)
{
snprintf(fbuf, sizeof(fbuf), "%s%s() ",
esc(data->file, TTY_FG_BLUE), function);
}
if (source)
{
snprintf(sbuf, sizeof(sbuf), "%s@ %s:%d",
esc(data->file, TTY_FG_GREEN), source, line);
}
println(data->file, " -> %s%s%s", fbuf, sbuf,
esc(data->file, TTY_FG_DEF));
}
}
} }
} }
} }
else if (data->file && (source || function))
{
if (function)
{
snprintf(fbuf, sizeof(fbuf), "%s%s() ",
esc(data->file, TTY_FG_BLUE), function);
}
if (source)
{
snprintf(sbuf, sizeof(sbuf), "%s@ %s:%d",
esc(data->file, TTY_FG_GREEN), source, line);
}
println(data->file, " -> %s%s%s", fbuf, sbuf,
esc(data->file, TTY_FG_DEF));
}
} }
/** /**
@@ -380,15 +403,11 @@ static bfd_entry_t *get_bfd_entry(char *filename)
} }
/** /**
* Print the source file with line number to file, libbfd variant * Lookup the given address
*/ */
static void print_sourceline(FILE *file, char *filename, void *ptr, void *base) static void lookup_addr(char *filename, bfd_find_data_t *data)
{ {
bfd_entry_t *entry; bfd_entry_t *entry;
bfd_find_data_t data = {
.file = file,
.vma = (uintptr_t)ptr,
};
bool old = FALSE; bool old = FALSE;
bfd_mutex->lock(bfd_mutex); bfd_mutex->lock(bfd_mutex);
@@ -399,8 +418,8 @@ static void print_sourceline(FILE *file, char *filename, void *ptr, void *base)
entry = get_bfd_entry(filename); entry = get_bfd_entry(filename);
if (entry) if (entry)
{ {
data.entry = entry; data->entry = entry;
bfd_map_over_sections(entry->abfd, (void*)find_addr, &data); bfd_map_over_sections(entry->abfd, (void*)find_addr, data);
} }
if (lib && lib->leak_detective) if (lib && lib->leak_detective)
{ {
@@ -409,6 +428,35 @@ static void print_sourceline(FILE *file, char *filename, void *ptr, void *base)
bfd_mutex->unlock(bfd_mutex); bfd_mutex->unlock(bfd_mutex);
} }
/**
* Print the source file with line number to file, libbfd variant
*/
static void print_sourceline(FILE *file, char *filename, void *ptr, void *base)
{
bfd_find_data_t data = {
.file = file,
.vma = (uintptr_t)ptr,
};
lookup_addr(filename, &data);
}
/**
* Check if the function name of the source line is in the given list
*/
static bool contains_function_bfd(char *filename, void *ptr, char *list[],
int count)
{
bfd_find_data_t data = {
.vma = (uintptr_t)ptr,
.list = list,
.count = count,
};
lookup_addr(filename, &data);
return data.in_list;
}
#else /* !HAVE_BFD_H */ #else /* !HAVE_BFD_H */
void backtrace_init() {} void backtrace_init() {}
@@ -619,15 +667,34 @@ METHOD(backtrace_t, contains_function, bool,
{ {
Dl_info info; Dl_info info;
if (dladdr(this->frames[i], &info) && info.dli_sname) if (dladdr(this->frames[i], &info))
{ {
for (j = 0; j < count; j++) if (info.dli_sname)
{ {
if (streq(info.dli_sname, function[j])) for (j = 0; j < count; j++)
{
if (streq(info.dli_sname, function[j]))
{
return TRUE;
}
}
}
#ifdef HAVE_BFD_H
else if (info.dli_fname[0])
{
void *ptr = this->frames[i];
if (strstr(info.dli_fname, ".so"))
{
ptr = (void*)(this->frames[i] - info.dli_fbase);
}
if (contains_function_bfd((char*)info.dli_fname, ptr,
function, count))
{ {
return TRUE; return TRUE;
} }
} }
#endif /* HAVE_BFD_H */
} }
} }
#elif defined(HAVE_DBGHELP) #elif defined(HAVE_DBGHELP)