Remove BFD-based debugging code, to avoid the runtime dependency on binutils.
Fixes #581. This was SVN commit r8271.
This commit is contained in:
parent
caba7cbe8f
commit
6b5b35c245
@ -227,10 +227,6 @@ function package_set_build_flags()
|
||||
"/usr/X11R6/lib"
|
||||
}
|
||||
|
||||
if OS == "linux" and options["icc"] then
|
||||
tinsert(package.libpaths, "/usr/i686-pc-linux-gnu/lib") -- needed for ICC to find libbfd
|
||||
end
|
||||
|
||||
if options["bindir"] then
|
||||
tinsert(package.defines, "INSTALLED_BINDIR=" .. options["bindir"])
|
||||
end
|
||||
@ -679,8 +675,6 @@ function setup_main_exe ()
|
||||
"fam",
|
||||
-- Utilities
|
||||
"rt",
|
||||
-- Debugging
|
||||
"bfd", "iberty",
|
||||
-- Dynamic libraries (needed for linking for gold)
|
||||
"dl",
|
||||
})
|
||||
@ -1085,8 +1079,6 @@ function setup_tests()
|
||||
"fam",
|
||||
-- Utilities
|
||||
"rt",
|
||||
-- Debugging
|
||||
"bfd", "iberty",
|
||||
-- Dynamic libraries (needed for linking for gold)
|
||||
"dl",
|
||||
})
|
||||
|
@ -20,68 +20,21 @@
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// note: the BFD stuff *could* be used on other platforms, if we saw the
|
||||
// need for it.
|
||||
// Note: This used to use BFD to get more useful debugging information.
|
||||
// (See SVN r8270 if you want that code.)
|
||||
// That requires binutils at runtime, which hits some bugs and library versioning
|
||||
// issues on some Linux distros.
|
||||
// The debugging info reported by this code with BFD wasn't especially useful,
|
||||
// and it's easy enough to get people to run in gdb if we want a proper backtrace.
|
||||
// So we now go with the simple approach of not using BFD.
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "lib/timer.h"
|
||||
#include "lib/utf8.h"
|
||||
#include "lib/sysdep/sysdep.h"
|
||||
#include "lib/debug.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <cassert>
|
||||
|
||||
#include <bfd.h>
|
||||
#include <cxxabi.h>
|
||||
|
||||
#ifndef bfd_get_section_size
|
||||
#define bfd_get_section_size bfd_get_section_size_before_reloc
|
||||
#endif
|
||||
|
||||
#define GNU_SOURCE
|
||||
#include <dlfcn.h>
|
||||
#include <execinfo.h>
|
||||
|
||||
// Hard-coded - yuck :P
|
||||
// These should only be used as fallbacks
|
||||
#if defined(TESTING)
|
||||
#define EXE_NAME "pyrogenesis_test"
|
||||
#elif defined(NDEBUG)
|
||||
#define EXE_NAME "pyrogenesis"
|
||||
#else
|
||||
#define EXE_NAME "pyrogenesis_dbg"
|
||||
#endif
|
||||
|
||||
#define PROFILE_RESOLVE_SYMBOL 0
|
||||
|
||||
struct symbol_file_context
|
||||
{
|
||||
asymbol **syms;
|
||||
bfd *abfd;
|
||||
};
|
||||
symbol_file_context ps_dbg_context;
|
||||
bool udbg_initialized=false;
|
||||
|
||||
struct symbol_lookup_context
|
||||
{
|
||||
symbol_file_context *file_ctx;
|
||||
|
||||
bfd_vma address;
|
||||
const char* symbol;
|
||||
const char* filename;
|
||||
uint line;
|
||||
|
||||
bool found;
|
||||
};
|
||||
|
||||
void* debug_GetCaller(void* UNUSED(context), const wchar_t* UNUSED(lastFuncToSkip))
|
||||
{
|
||||
// bt[0] == this function
|
||||
@ -100,16 +53,16 @@ LibError debug_DumpStack(wchar_t* buf, size_t max_chars, void* UNUSED(context),
|
||||
{
|
||||
static const size_t N_FRAMES = 16;
|
||||
void *bt[N_FRAMES];
|
||||
int bt_size=0;
|
||||
int bt_size = 0;
|
||||
wchar_t *bufpos = buf;
|
||||
wchar_t *bufend = buf + max_chars;
|
||||
|
||||
bt_size=backtrace(bt, ARRAY_SIZE(bt));
|
||||
bt_size = backtrace(bt, ARRAY_SIZE(bt));
|
||||
|
||||
// Assumed max length of a single print-out
|
||||
static const size_t MAX_OUT_CHARS=1024;
|
||||
static const size_t MAX_OUT_CHARS = 1024;
|
||||
|
||||
for (size_t i=0;(int)i<bt_size && bufpos+MAX_OUT_CHARS < bufend;i++)
|
||||
for (size_t i = 0; (int)i < bt_size && bufpos+MAX_OUT_CHARS < bufend; i++)
|
||||
{
|
||||
wchar_t file[DBG_FILE_LEN];
|
||||
wchar_t symbol[DBG_SYMBOL_LEN];
|
||||
@ -117,9 +70,16 @@ LibError debug_DumpStack(wchar_t* buf, size_t max_chars, void* UNUSED(context),
|
||||
int len;
|
||||
|
||||
if (debug_ResolveSymbol(bt[i], symbol, file, &line) == 0)
|
||||
len = swprintf(bufpos, MAX_OUT_CHARS, L"(%p) %ls:%d %ls\n", bt[i], file, line, symbol);
|
||||
{
|
||||
if (file[0])
|
||||
len = swprintf(bufpos, MAX_OUT_CHARS, L"(%p) %ls:%d %ls\n", bt[i], file, line, symbol);
|
||||
else
|
||||
len = swprintf(bufpos, MAX_OUT_CHARS, L"(%p) %ls\n", bt[i], symbol);
|
||||
}
|
||||
else
|
||||
{
|
||||
len = swprintf(bufpos, MAX_OUT_CHARS, L"(%p)\n", bt[i]);
|
||||
}
|
||||
|
||||
if (len < 0)
|
||||
{
|
||||
@ -136,264 +96,31 @@ LibError debug_DumpStack(wchar_t* buf, size_t max_chars, void* UNUSED(context),
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
static int slurp_symtab(symbol_file_context *ctx)
|
||||
{
|
||||
bfd *abfd=ctx->abfd;
|
||||
asymbol ***syms=&ctx->syms;
|
||||
long symcount;
|
||||
int size=0;
|
||||
|
||||
if ((bfd_get_file_flags (abfd) & HAS_SYMS) == 0)
|
||||
{
|
||||
printf("slurp_symtab(): Huh? Has no symbols...\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
size = bfd_get_symtab_upper_bound(abfd);
|
||||
if (size < 0)
|
||||
{
|
||||
bfd_perror("symtab_upper_bound");
|
||||
return -1;
|
||||
}
|
||||
*syms = (asymbol **)malloc(size);
|
||||
if (!syms)
|
||||
return -1;
|
||||
symcount = bfd_canonicalize_symtab(abfd, *syms);
|
||||
|
||||
if (symcount == 0)
|
||||
symcount = bfd_read_minisymbols (abfd, FALSE, (void **)syms, (unsigned*)&size);
|
||||
if (symcount == 0)
|
||||
symcount = bfd_read_minisymbols (abfd, TRUE /* dynamic */, (void **)syms, (unsigned*)&size);
|
||||
|
||||
if (symcount < 0)
|
||||
{
|
||||
bfd_perror("slurp_symtab");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_symbols(const char *file_name, symbol_file_context *ctx)
|
||||
{
|
||||
char **matching=NULL;
|
||||
|
||||
ONCE(bfd_init());
|
||||
|
||||
ctx->abfd = bfd_openr (file_name, NULL);
|
||||
if (ctx->abfd == NULL)
|
||||
{
|
||||
bfd_perror("udbg.cpp: bfd_openr");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (! bfd_check_format_matches (ctx->abfd, bfd_object, &matching))
|
||||
{
|
||||
if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
|
||||
{
|
||||
printf("Error reading symbols from %s: ambiguous format\n", file_name);
|
||||
while (*matching)
|
||||
printf("\tPotential matching format: %s\n", *matching++);
|
||||
free(matching);
|
||||
}
|
||||
else
|
||||
{
|
||||
bfd_perror("bfd_check_format_matches");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int res=slurp_symtab(ctx);
|
||||
if (res == 0)
|
||||
return res;
|
||||
else
|
||||
{
|
||||
bfd_perror("udbg.cpp: slurp_symtab");
|
||||
bfd_close(ctx->abfd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void udbg_bfd_init(void)
|
||||
{
|
||||
fs::wpath path;
|
||||
std::string exename;
|
||||
if (sys_get_executable_name(path) == INFO::OK)
|
||||
{
|
||||
exename = utf8_from_wstring(path.string());
|
||||
}
|
||||
else
|
||||
{
|
||||
debug_printf(L"sys_get_executable_name didn't work, using hard-coded guess %hs.\n", EXE_NAME);
|
||||
exename = EXE_NAME;
|
||||
}
|
||||
|
||||
debug_printf(L"udbg_bfd_init: loading symbols from %hs.\n", exename.c_str());
|
||||
|
||||
if (read_symbols(exename.c_str(), &ps_dbg_context)==0)
|
||||
udbg_initialized=true;
|
||||
|
||||
#if PROFILE_RESOLVE_SYMBOL
|
||||
{
|
||||
TIMER(udbg_init_benchmark)
|
||||
char symbol[DBG_SYMBOL_LEN];
|
||||
char file[DBG_FILE_LEN];
|
||||
int line;
|
||||
debug_ResolveSymbol(debug_get_nth_caller(3), symbol, file, &line);
|
||||
printf("%s (%s:%d)\n", symbol, file, line);
|
||||
for (int i=0;i<1000000;i++)
|
||||
{
|
||||
debug_ResolveSymbol(debug_get_nth_caller(1), symbol, file, &line);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void find_address_in_section (bfd *abfd, asection *section, void *data)
|
||||
{
|
||||
symbol_lookup_context *ctx=(symbol_lookup_context *)data;
|
||||
asymbol **syms=ctx->file_ctx->syms;
|
||||
|
||||
bfd_vma pc=ctx->address;
|
||||
bfd_vma vma;
|
||||
bfd_size_type size;
|
||||
|
||||
if (ctx->found) return;
|
||||
|
||||
if ((bfd_get_section_flags (abfd, section) & SEC_ALLOC) == 0)
|
||||
return;
|
||||
|
||||
vma = bfd_get_section_vma (abfd, section);
|
||||
if (pc < vma)
|
||||
return;
|
||||
|
||||
size = bfd_get_section_size (section);
|
||||
if (pc >= vma + size)
|
||||
return;
|
||||
|
||||
ctx->found = bfd_find_nearest_line (abfd, section, syms,
|
||||
pc - vma, &ctx->filename, &ctx->symbol, &ctx->line);
|
||||
}
|
||||
|
||||
// BFD functions perform allocs with real malloc - we need to free that data
|
||||
void demangle_buf(char *buf, const char *symbol, size_t n)
|
||||
{
|
||||
int status=0;
|
||||
char *alloc=NULL;
|
||||
if (symbol == NULL || *symbol == '\0')
|
||||
{
|
||||
symbol = "??";
|
||||
status = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
alloc=abi::__cxa_demangle(symbol, NULL, NULL, &status);
|
||||
}
|
||||
// status is 0 on success and a negative value on failure
|
||||
if (status == 0)
|
||||
symbol=alloc;
|
||||
strncpy(buf, symbol, n);
|
||||
buf[n-1]=0;
|
||||
if (alloc)
|
||||
free(alloc);
|
||||
}
|
||||
|
||||
static LibError debug_resolve_symbol_dladdr(void *ptr, wchar_t* sym_name, wchar_t* file, int* line)
|
||||
{
|
||||
Dl_info syminfo;
|
||||
|
||||
int res=dladdr(ptr, &syminfo);
|
||||
if (res == 0)
|
||||
WARN_RETURN(ERR::FAIL);
|
||||
|
||||
if (sym_name)
|
||||
{
|
||||
if (syminfo.dli_sname)
|
||||
{
|
||||
char sym_name_buf[DBG_SYMBOL_LEN];
|
||||
demangle_buf(sym_name_buf, syminfo.dli_sname, DBG_SYMBOL_LEN);
|
||||
wcscpy_s(sym_name, DBG_SYMBOL_LEN, wstring_from_utf8(sym_name_buf).c_str());
|
||||
}
|
||||
else
|
||||
swprintf_s(sym_name, DBG_SYMBOL_LEN, L"%p", ptr);
|
||||
}
|
||||
|
||||
if (file)
|
||||
{
|
||||
wcscpy_s(file, DBG_FILE_LEN, wstring_from_utf8(syminfo.dli_fname).c_str());
|
||||
}
|
||||
|
||||
if (line)
|
||||
{
|
||||
*line=0;
|
||||
}
|
||||
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
LibError debug_ResolveSymbol(void* ptr_of_interest, wchar_t* sym_name, wchar_t* file, int* line)
|
||||
{
|
||||
ONCE(udbg_bfd_init());
|
||||
|
||||
// We use our default context - in the future we could do something like
|
||||
// mapping library -> file context to support more detailed reporting on
|
||||
// external libraries
|
||||
symbol_file_context *file_ctx=&ps_dbg_context;
|
||||
bfd *abfd=file_ctx->abfd;
|
||||
|
||||
// Reset here if we fail later on
|
||||
if (sym_name)
|
||||
*sym_name=0;
|
||||
*sym_name = 0;
|
||||
if (file)
|
||||
*file=0;
|
||||
*file = 0;
|
||||
if (line)
|
||||
*line=0;
|
||||
*line = 0;
|
||||
|
||||
if (!udbg_initialized)
|
||||
return debug_resolve_symbol_dladdr(ptr_of_interest, sym_name, file, line);
|
||||
|
||||
symbol_lookup_context ctx;
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
ctx.address=reinterpret_cast<bfd_vma>(ptr_of_interest);
|
||||
ctx.file_ctx=file_ctx;
|
||||
|
||||
bfd_map_over_sections (abfd, find_address_in_section, &ctx);
|
||||
|
||||
// This will happen for addresses in external files. What one *could* do
|
||||
// here is to figure out the originating library file and load that through
|
||||
// BFD... but how often will external libraries have debugging info? really?
|
||||
// At least attempt to find out the symbol name through dladdr.
|
||||
if (!ctx.found)
|
||||
return debug_resolve_symbol_dladdr(ptr_of_interest, sym_name, file, line);
|
||||
|
||||
if (sym_name)
|
||||
char** symbols = backtrace_symbols(&ptr_of_interest, 1);
|
||||
if (symbols)
|
||||
{
|
||||
char sym_name_buf[DBG_SYMBOL_LEN];
|
||||
demangle_buf(sym_name_buf, ctx.symbol, DBG_SYMBOL_LEN);
|
||||
wcscpy_s(sym_name, DBG_SYMBOL_LEN, wstring_from_utf8(sym_name_buf).c_str());
|
||||
}
|
||||
swprintf_s(sym_name, DBG_SYMBOL_LEN, L"%s", symbols[0]);
|
||||
free(symbols);
|
||||
|
||||
if (file)
|
||||
{
|
||||
if (ctx.filename != NULL)
|
||||
{
|
||||
const char *h;
|
||||
h = strrchr (ctx.filename, '/');
|
||||
if (h != NULL)
|
||||
ctx.filename = h + 1;
|
||||
|
||||
wcscpy_s(file, DBG_FILE_LEN, wstring_from_utf8(ctx.filename).c_str());
|
||||
}
|
||||
else
|
||||
wcscpy_s(file, DBG_FILE_LEN, L"none");
|
||||
// (Note that this will usually return a pretty useless string,
|
||||
// because we compile with -fvisibility=hidden and there won't be
|
||||
// any exposed symbols for backtrace_symbols to report.)
|
||||
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
if (line)
|
||||
else
|
||||
{
|
||||
*line = ctx.line;
|
||||
return ERR::FAIL;
|
||||
}
|
||||
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
void debug_SetThreadName(char const* UNUSED(name))
|
||||
|
Loading…
Reference in New Issue
Block a user