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:
59
config.lib
59
config.lib
@@ -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
|
||||
|
45
src/crashlog_bfd.h
Normal file
45
src/crashlog_bfd.h
Normal file
@@ -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");
|
||||
}
|
||||
|
Reference in New Issue
Block a user