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.
pull/3/head
Jonathan G Rennison 9 years ago
parent 99d8d1afa6
commit 3a093c4b63

@ -1571,22 +1571,6 @@ EOL
fi
rm tmp.config.libdl
"$cc_host" $CFLAGS $LDFLAGS -o tmp.config.demangle -x c++ - -lstdc++ 2> /dev/null << EOL
#include <cxxabi.h>
int main() {
int status = -1;
char *demangled = abi::__cxa_demangle("test", 0, 0, &status);
return 0;
}
EOL
if [ $? -ne 0 ]; then
log 1 "checking abi::__cxa_demangle... no"
else
log 1 "checking abi::__cxa_demangle... found"
CFLAGS="$CFLAGS -DWITH_DEMANGLE"
fi
rm tmp.config.demangle
"$cc_host" $CFLAGS $LDFLAGS -o tmp.config.bfd -x c++ - -lbfd 2> /dev/null << EOL
#define PACKAGE 1
#define PACKAGE_VERSION 1
@ -1629,10 +1613,53 @@ EOL
else
log 1 "checking dbghelp... found"
CFLAGS="$CFLAGS -DWITH_DBGHELP"
"$cc_host" $CFLAGS $LDFLAGS -o tmp.config.bfd -x c++ - -lbfd -liberty -lintl 2> /dev/null << EOL
#define PACKAGE 1
#define PACKAGE_VERSION 1
#include <bfd.h>
int main() {
bfd_init();
unsigned int size;
asymbol *syms = 0;
long symcount = bfd_read_minisymbols((bfd *) 0, false, (void**) &syms, &size);
return 0;
}
EOL
if [ $? -ne 0 ]; then
log 1 "checking libbfd... no"
else
log 1 "checking libbfd... found"
LIBS="$LIBS -lbfd -liberty -lintl"
CFLAGS="$CFLAGS -DWITH_BFD"
if [ $enable_debug -lt 1 ]; then
CFLAGS="$CFLAGS -g1"
fi
fi
rm -f tmp.config.bfd
fi
rm -f tmp.config.dbghelp
fi
if [ "$os" != "CYGWIN" ] && [ "$os" != "HAIKU" ] && [ "$os" != "MORPHOS" ] && [ "$os" != "OSX" ] && [ "$os" != "DOS" ] && [ "$os" != "WINCE" ] && [ "$os" != "PSP" ] && [ "$os" != "OS2" ]; then
"$cc_host" $CFLAGS $LDFLAGS -o tmp.config.demangle -x c++ - -lstdc++ 2> /dev/null << EOL
#include <cxxabi.h>
int main() {
int status = -1;
char *demangled = abi::__cxa_demangle("test", 0, 0, &status);
return 0;
}
EOL
if [ $? -ne 0 ]; then
log 1 "checking abi::__cxa_demangle... no"
else
log 1 "checking abi::__cxa_demangle... found"
CFLAGS="$CFLAGS -DWITH_DEMANGLE"
fi
rm tmp.config.demangle
fi
if [ "$os" != "CYGWIN" ] && [ "$os" != "HAIKU" ] && [ "$os" != "MINGW" ] && [ "$os" != "DOS" ] && [ "$os" != "WINCE" ]; then
LIBS="$LIBS -lc"
fi

@ -165,6 +165,7 @@ console_internal.h
console_type.h
cpu.h
crashlog.h
crashlog_bfd.h
currency.h
date_func.h
date_gui.h

@ -11,6 +11,7 @@
#include "stdafx.h"
#include "crashlog.h"
#include "crashlog_bfd.h"
#include "gamelog.h"
#include "date_func.h"
#include "map_func.h"
@ -493,3 +494,72 @@ bool CrashLog::MakeCrashLog() const
if (SoundDriver::GetInstance() != NULL) SoundDriver::GetInstance()->Stop();
if (VideoDriver::GetInstance() != NULL) VideoDriver::GetInstance()->Stop();
}
#if defined(WITH_BFD)
sym_info_bfd::sym_info_bfd(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) {}
sym_info_bfd::~sym_info_bfd()
{
free(syms);
if (abfd != NULL) bfd_close(abfd);
}
static void find_address_in_section(bfd *abfd, asection *section, void *data)
{
sym_info_bfd *info = static_cast<sym_info_bfd *>(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 && info->function_name) {
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;
}
}
} else if (info->found) {
bfd_vma target = info->addr - vma;
bfd_vma best_diff = size;
for (long i = 0; i < info->sym_count; i++) {
asymbol *sym = info->syms[i];
if (!(sym->flags & (BSF_LOCAL | BSF_GLOBAL))) continue;
if (sym->value > target) continue;
bfd_vma diff = target - sym->value;
if (diff < best_diff) {
best_diff = diff;
info->function_name = sym->name;
info->function_addr = sym->value + vma;
}
}
}
}
void lookup_addr_bfd(const char *obj_file_name, sym_info_bfd &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

@ -0,0 +1,45 @@
/* $Id$ */
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file crashlog_bfd.h Definitions for utility functions for using libbfd as part of logging a crash */
#ifndef CRASHLOG_BFD_H
#define CRASHLOG_BFD_H
#if defined(WITH_BFD)
/* this is because newer versions of libbfd insist on seeing these, even though they aren't used for anything */
#define PACKAGE 1
#define PACKAGE_VERSION 1
#include <bfd.h>
#undef PACKAGE
#undef PACKAGE_VERSION
#endif
#if defined(WITH_BFD)
struct sym_info_bfd;
void lookup_addr_bfd(const char *obj_file_name, sym_info_bfd &info);
struct sym_info_bfd {
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;
sym_info_bfd(bfd_vma addr_);
~sym_info_bfd();
};
#endif
#endif /* CRASHLOG_BFD_H */

@ -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;

@ -11,6 +11,7 @@
#include "../../stdafx.h"
#include "../../crashlog.h"
#include "../../crashlog_bfd.h"
#include "win32.h"
#include "../../core/alloc_func.hpp"
#include "../../core/math_func.hpp"
@ -20,6 +21,9 @@
#include "../../gamelog.h"
#include "../../saveload/saveload.h"
#include "../../video/video_driver.hpp"
#if defined(WITH_DEMANGLE)
#include <cxxabi.h>
#endif
#include <windows.h>
#include <signal.h>
@ -413,11 +417,13 @@ char *CrashLogWindows::AppendDecodedStacktrace(char *buffer, const char *last) c
/* Get module name. */
const char *mod_name = "???";
const char *image_name = NULL;
IMAGEHLP_MODULE64 module;
module.SizeOfStruct = sizeof(module);
if (proc.pSymGetModuleInfo64(hCur, frame.AddrPC.Offset, &module)) {
mod_name = module.ModuleName;
image_name = module.ImageName;
}
/* Print module and instruction pointer. */
@ -434,6 +440,35 @@ char *CrashLogWindows::AppendDecodedStacktrace(char *buffer, const char *last) c
if (proc.pSymGetLineFromAddr64(hCur, frame.AddrPC.Offset, &line_offs, &line)) {
buffer += seprintf(buffer, last, " (%s:%d)", line.FileName, line.LineNumber);
}
} else if (image_name != NULL) {
#if defined (WITH_BFD)
/* subtract one to get the line before the return address, i.e. the function call line */
sym_info_bfd bfd_info(reinterpret_cast<bfd_vma>(frame.AddrPC.Offset) - 1);
lookup_addr_bfd(image_name, bfd_info);
if (bfd_info.function_name != NULL) {
const char *func_name = bfd_info.function_name;
#if defined(WITH_DEMANGLE)
int status = -1;
char *demangled = abi::__cxa_demangle(func_name, NULL, 0, &status);
if (demangled != NULL && status == 0) {
func_name = demangled;
}
#endif
bool symbol_ok = strncmp(func_name, ".rdata$", 7) != 0 && strncmp(func_name, ".debug_loc", 10) != 0;
if (symbol_ok) {
buffer += seprintf(buffer, last, " %s", func_name);
}
#if defined(WITH_DEMANGLE)
free(demangled);
#endif
if (symbol_ok && bfd_info.function_addr) {
buffer += seprintf(buffer, last, " + %I64u", reinterpret_cast<bfd_vma>(frame.AddrPC.Offset) - bfd_info.function_addr);
}
}
if (bfd_info.file_name != NULL) {
buffer += seprintf(buffer, last, " (%s:%d)", bfd_info.file_name, bfd_info.line);
}
#endif
}
buffer += seprintf(buffer, last, "\n");
}

Loading…
Cancel
Save