Use libbfd as a fallback for backtrace symbol lookup on MinGW.

This will try to demangle.
If bfd_find_nearest_line returns a file name but nothing else
(debugging info is turned off), scan the symbol table for the previous
symbol and use it if it looks OKish.
This commit is contained in:
Jonathan G Rennison
2015-09-09 02:14:06 +01:00
parent 99d8d1afa6
commit 3a093c4b63
6 changed files with 196 additions and 84 deletions

View File

@@ -11,6 +11,7 @@
#include "../../stdafx.h"
#include "../../crashlog.h"
#include "../../crashlog_bfd.h"
#include "../../string_func.h"
#include "../../gamelog.h"
#include "../../saveload/saveload.h"
@@ -42,73 +43,6 @@
#include "../../safeguards.h"
#if defined(WITH_BFD)
struct line_info {
bfd_vma addr;
bfd *abfd;
asymbol **syms;
long sym_count;
const char *file_name;
const char *function_name;
bfd_vma function_addr;
unsigned int line;
bool found;
line_info(bfd_vma addr_) : addr(addr_), abfd(NULL), syms(NULL), sym_count(0),
file_name(NULL), function_name(NULL), function_addr(0), line(0), found(false) {}
~line_info()
{
free(syms);
if (abfd != NULL) bfd_close(abfd);
}
};
static void find_address_in_section(bfd *abfd, asection *section, void *data)
{
line_info *info = static_cast<line_info *>(data);
if (info->found) return;
if ((bfd_get_section_flags(abfd, section) & SEC_ALLOC) == 0) return;
bfd_vma vma = bfd_get_section_vma(abfd, section);
if (info->addr < vma) return;
bfd_size_type size = bfd_section_size(abfd, section);
if (info->addr >= vma + size) return;
info->found = bfd_find_nearest_line(abfd, section, info->syms, info->addr - vma,
&(info->file_name), &(info->function_name), &(info->line));
if (info->found) {
for (long i = 0; i < info->sym_count; i++) {
asymbol *sym = info->syms[i];
if (sym->flags & (BSF_LOCAL | BSF_GLOBAL) && strcmp(sym->name, info->function_name) == 0) {
info->function_addr = sym->value + vma;
}
}
}
}
void lookup_addr_bfd(const char *obj_file_name, line_info &info)
{
info.abfd = bfd_openr(obj_file_name, NULL);
if (info.abfd == NULL) return;
if (!bfd_check_format(info.abfd, bfd_object) || (bfd_get_file_flags(info.abfd) & HAS_SYMS) == 0) return;
unsigned int size;
info.sym_count = bfd_read_minisymbols(info.abfd, false, (void**) &(info.syms), &size);
if (info.sym_count <= 0) {
info.sym_count = bfd_read_minisymbols(info.abfd, true, (void**) &(info.syms), &size);
}
if (info.sym_count <= 0) return;
bfd_map_over_sections(info.abfd, find_address_in_section, &info);
}
#endif
/**
* Unix implementation for the crash logger.
*/
@@ -202,7 +136,7 @@ class CrashLogUnix : public CrashLog {
unsigned int line_num = 0;
#if defined(WITH_BFD)
/* subtract one to get the line before the return address, i.e. the function call line */
line_info bfd_info(reinterpret_cast<bfd_vma>(trace[i]) - 1);
sym_info_bfd bfd_info(reinterpret_cast<bfd_vma>(trace[i]) - 1);
if (dladdr_result && info.dli_fname) {
lookup_addr_bfd(info.dli_fname, bfd_info);
if (bfd_info.file_name != NULL) file_name = bfd_info.file_name;