linuxdcpp-team team mailing list archive
-
linuxdcpp-team team
-
Mailing list archive
-
Message #04270
[Branch ~dcplusplus-team/dcplusplus/trunk] Rev 2564: crash logger: get rid of bfd; use libdwarf instead (see launchpad bug 189241 for details)
------------------------------------------------------------
revno: 2564
committer: poy <poy@xxxxxxxxxx>
branch nick: trunk
timestamp: Fri 2011-06-24 18:08:35 +0200
message:
crash logger: get rid of bfd; use libdwarf instead (see launchpad bug 189241 for details)
modified:
SConstruct
ThirdPartyLicenses.txt
win32/AboutDlg.cpp
win32/CrashLogger.cpp
win32/HubFrame.cpp
win32/SConscript
--
lp:dcplusplus
https://code.launchpad.net/~dcplusplus-team/dcplusplus/trunk
Your team Dcplusplus-team is subscribed to branch lp:dcplusplus.
To unsubscribe from this branch go to https://code.launchpad.net/~dcplusplus-team/dcplusplus/trunk/+edit-subscription
=== modified file 'SConstruct'
--- SConstruct 2011-06-12 22:41:02 +0000
+++ SConstruct 2011-06-24 16:08:35 +0000
@@ -245,11 +245,10 @@
conf.env.Append(CPPDEFINES='HAVE_HTMLHELP_H')
if conf.CheckCXXHeader('natupnp.h', '<>'):
conf.env.Append(CPPDEFINES='HAVE_NATUPNP_H')
-if 'gcc' in env['TOOLS'] and conf.CheckCXXHeader('bfd.h', '<>'):
- conf.env.Append(CPPDEFINES='HAVE_BFD_H')
env = conf.Finish()
dev.boost = dev.build('boost/')
+dev.dwarf = dev.build('dwarf/')
dev.zlib = dev.build('zlib/')
dev.bzip2 = dev.build('bzip2/')
dev.intl = dev.build('intl/')
=== modified file 'ThirdPartyLicenses.txt'
--- ThirdPartyLicenses.txt 2011-06-12 22:41:02 +0000
+++ ThirdPartyLicenses.txt 2011-06-24 16:08:35 +0000
@@ -1,13 +1,3 @@
---- backtrace-mingw license ---
-
- Copyright (c) 2010 ,
- Cloud Wu . All rights reserved.
-
- http://www.codingnow.com
-
- Use, modification and distribution are subject to the "New BSD License"
- as listed at <url: http://www.opensource.org/licenses/bsd-license.php >.
-
--- GeoIP license ---
There are two licenses, one for the C library software, and one for
=== modified file 'win32/AboutDlg.cpp'
--- win32/AboutDlg.cpp 2011-05-04 19:32:00 +0000
+++ win32/AboutDlg.cpp 2011-06-24 16:08:35 +0000
@@ -37,11 +37,12 @@
static const char thanks[] = "Big thanks to all donators and people who have contributed with ideas "
"and code! Thanks go out to sourceforge.net for hosting the project. "
-"This product uses bzip2 (www.bzip.org), thanks to Julian Seward and team for providing it. "
-"This product uses zlib (www.zlib.net), thanks to Jean-loup Gailly and Mark Adler for providing it. "
-"This product includes GeoIP data created by MaxMind, available from http://maxmind.com/. "
-"This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit. (http://www.openssl.org/). "
-"This product uses the MiniUPnP client library (http://miniupnp.tuxfamily.org) and libnatpmp by Thomas Bernard. "
+"This product uses bzip2 <www.bzip.org>, thanks to Julian Seward and team for providing it. "
+"This product uses zlib <www.zlib.net>, thanks to Jean-loup Gailly and Mark Adler for providing it. "
+"This product includes GeoIP data created by MaxMind, available from <http://maxmind.com/>. "
+"This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <http://www.openssl.org/>. "
+"This product uses the MiniUPnP client library <http://miniupnp.tuxfamily.org> and libnatpmp by Thomas Bernard. "
+"This product uses libdwarf <http://reality.sgiweb.org/davea/dwarf.html> by SGI & David Anderson. "
"The following people have contributed code to DC++ (I hope I haven't missed someone, they're "
"roughly in chronological order...=):\r\n"
"geoff, carxor, luca rota, dan kline, mike, anton, zc, sarf, farcry, kyrre aalerud, opera, "
=== modified file 'win32/CrashLogger.cpp'
--- win32/CrashLogger.cpp 2011-06-14 20:44:55 +0000
+++ win32/CrashLogger.cpp 2011-06-24 16:08:35 +0000
@@ -27,160 +27,222 @@
FILE* f;
-#if defined(__MINGW32__) && defined(HAVE_BFD_H) && !defined(_WIN64)
-
-/* This backtrace writer for MinGW comes from the backtrace-mingw project by Cloud Wu:
-<http://code.google.com/p/backtrace-mingw/> */
-
-/*
- Copyright (c) 2010 ,
- Cloud Wu . All rights reserved.
-
- http://www.codingnow.com
-
- Use, modification and distribution are subject to the "New BSD License"
- as listed at <url: http://www.opensource.org/licenses/bsd-license.php >.
-*/
-
-#include <bfd.h>
+#if defined(__MINGW32__) && !defined(_WIN64)
+
#include <imagehlp.h>
-struct bfd_ctx {
- bfd * handle;
- asymbol ** symbol;
-};
-
-struct bfd_set {
- char * name;
- bfd_ctx * bc;
- bfd_set *next;
-};
-
-struct find_info {
- asymbol **symbol;
- bfd_vma counter;
- const char *file;
- const char *func;
- unsigned line;
-};
-
-void lookup_section(bfd *abfd, asection *sec, void *opaque_data)
-{
- find_info *data = reinterpret_cast<find_info*>(opaque_data);
-
- if (data->func)
- return;
-
- if (!(bfd_get_section_flags(abfd, sec) & SEC_ALLOC))
- return;
-
- bfd_vma vma = bfd_get_section_vma(abfd, sec);
- if (data->counter < vma || vma + bfd_get_section_size(sec) <= data->counter)
- return;
-
- bfd_find_nearest_line(abfd, sec, data->symbol, data->counter - vma, &(data->file), &(data->func), &(data->line));
-}
-
-void find(bfd_ctx * b, DWORD offset, const char **file, const char **func, unsigned *line)
-{
- find_info data = { b->symbol, offset };
-
- bfd_map_over_sections(b->handle, &lookup_section, &data);
-
- *file = data.file;
- *func = data.func;
- *line = data.line;
-}
-
-bool init_bfd_ctx(bfd_ctx *bc, const char * procname)
-{
- bc->handle = 0;
- bc->symbol = 0;
-
- bfd *b = bfd_openr(procname, 0);
- if (!b) {
- fprintf(f, "Failed to open bfd from %s\n", procname);
- return false;
- }
-
- int r1 = bfd_check_format(b, bfd_object);
- int r2 = bfd_check_format_matches(b, bfd_object, 0);
- int r3 = bfd_get_file_flags(b) & HAS_SYMS;
-
- if (!(r1 && r2 && r3)) {
- bfd_close(b);
- fprintf(f, "Failed to init bfd from %s\n", procname);
- return false;
- }
-
- void *symbol_table;
-
- unsigned dummy = 0;
- if (bfd_read_minisymbols(b, FALSE, &symbol_table, &dummy) == 0) {
- if (bfd_read_minisymbols(b, TRUE, &symbol_table, &dummy) < 0) {
- free(symbol_table);
- bfd_close(b);
- fprintf(f, "Failed to read symbols from %s\n", procname);
- return false;
- }
- }
-
- bc->handle = b;
- bc->symbol = reinterpret_cast<asymbol**>(symbol_table);
-
- return true;
-}
-
-void close_bfd_ctx(bfd_ctx *bc)
-{
- if (bc) {
- if (bc->symbol) {
- free(bc->symbol);
- }
- if (bc->handle) {
- bfd_close(bc->handle);
- }
- }
-}
-
-bfd_ctx * get_bc(bfd_set *set, const char *procname)
-{
- while(set->name) {
- if (strcmp(set->name, procname) == 0) {
- return set->bc;
- }
- set = set->next;
- }
- bfd_ctx bc;
- if(!init_bfd_ctx(&bc, procname)) {
- return 0;
- }
- set->next = reinterpret_cast<bfd_set*>(calloc(1, sizeof(*set)));
- set->bc = reinterpret_cast<bfd_ctx*>(malloc(sizeof(bfd_ctx)));
- memcpy(set->bc, &bc, sizeof(bc));
- set->name = strdup(procname);
-
- return set->bc;
-}
-
-void release_set(bfd_set *set)
-{
- while(set) {
- bfd_set * temp = set->next;
- free(set->name);
- close_bfd_ctx(set->bc);
- free(set);
- set = temp;
+#include <dwarf.h>
+#include <libdwarf.h>
+
+/* The following functions are called by libdwarf to get information about the sections in our
+file. libdwarf was originally designed for ELF, but it fortunately provides abstract methods one
+can use to load sections in a different format, such as PE/COFF in our case.
+Section indexes are offset to 1 because the first section (index 0) is reserved in libdwarf.
+The "obj" parameter passed to our callbacks is a PLOADED_IMAGE. */
+
+int get_section_info(void* obj, Dwarf_Half section_index, Dwarf_Obj_Access_Section* return_section, int* error) {
+ if(section_index == 0) {
+ // simulate the ELF empty section at index 0, as recommended in various comments in dwarf_init_finish.c.
+ return_section->addr = 0;
+ return_section->size = 0;
+ static char emptyStr = '\0';
+ return_section->name = &emptyStr;
+ return_section->link = 0;
+ return DW_DLV_OK;
+ }
+
+ auto image = reinterpret_cast<PLOADED_IMAGE>(obj);
+ auto section = image->Sections + section_index - 1;
+ if(!section) {
+ return DW_DLV_ERROR;
+ };
+
+ return_section->addr = 0; // 0 is ok for non-ELF as per the comments in dwarf_opaque.h.
+ return_section->size = section->SizeOfRawData;
+ return_section->name = reinterpret_cast<const char*>(section->Name);
+ if(return_section->name[0] == '/') {
+ /* This is a long string (> 8 characters) in the format "/x", where "x" is an offset of the
+ actual string in the COFF string table. As documented in the PE/COFF doc, the COFF string
+ table is immediately following the COFF symbol table.
+ The "18" multiplier is the size of a COFF symbol. */
+ auto& header = image->FileHeader->FileHeader;
+ return_section->name = reinterpret_cast<const char*>(image->MappedAddress +
+ header.PointerToSymbolTable + header.NumberOfSymbols * 18 + atoi(return_section->name + 1));
+ }
+ return_section->link = 0;
+ return DW_DLV_OK;
+}
+
+Dwarf_Endianness get_byte_order(void*) {
+ return DW_OBJECT_LSB; // always little-endian on Windows
+}
+
+Dwarf_Small get_length_size(void*) {
+ return 4;
+}
+
+Dwarf_Small get_pointer_size(void*) {
+ return 4;
+}
+
+Dwarf_Unsigned get_section_count(void* obj) {
+ return reinterpret_cast<PLOADED_IMAGE>(obj)->NumberOfSections + 1;
+}
+
+int load_section(void* obj, Dwarf_Half section_index, Dwarf_Small** return_data, int* error) {
+ if(section_index == 0) {
+ return DW_DLV_NO_ENTRY;
+ }
+
+ auto image = reinterpret_cast<PLOADED_IMAGE>(obj);
+ auto section = image->Sections + section_index - 1;
+ if(!section) {
+ return DW_DLV_ERROR;
+ };
+
+ *return_data = image->MappedAddress + section->PointerToRawData;
+ return DW_DLV_OK;
+}
+
+void getDebugInfo(string path, DWORD addr, string& file, int& line, int& column) {
+ if(path.empty())
+ return;
+ // replace the extension by "pdb".
+ auto dot = path.rfind('.');
+ if(dot != string::npos)
+ path.replace(dot, path.size() - dot, ".pdb");
+
+ auto image = ImageLoad(&path[0], 0);
+ if(!image) {
+ fprintf(f, "[Failed to load the debugging data into memory (error: %d)] ", GetLastError());
+ return;
+ }
+
+ Dwarf_Debug dbg;
+ Dwarf_Error error = 0;
+
+ /* initialize libdwarf using the "custom" interface that allows one to read the DWARF
+ information contained in non-ELF files (PE/COFF in our case). */
+ Dwarf_Obj_Access_Methods methods = {
+ get_section_info,
+ get_byte_order,
+ get_length_size,
+ get_pointer_size,
+ get_section_count,
+ load_section
+ };
+ Dwarf_Obj_Access_Interface access = { image, &methods };
+ if(dwarf_object_init(&access, 0, 0, &dbg, &error) == DW_DLV_OK) {
+
+ /* use the ".debug_aranges" DWARF section to pinpoint the CU (Compilation Unit) that
+ corresponds to the address we want to find information about. */
+ Dwarf_Arange* aranges;
+ Dwarf_Signed arange_count;
+ if(dwarf_get_aranges(dbg, &aranges, &arange_count, &error) == DW_DLV_OK) {
+
+ Dwarf_Arange arange;
+ if(dwarf_get_arange(aranges, arange_count, addr, &arange, &error) == DW_DLV_OK) {
+
+ /* great, got a range that matches. let's find the CU it describes, and the DIE
+ (Debugging Information Entry) related to that CU. */
+ Dwarf_Off die_offset;
+ if(dwarf_get_cu_die_offset(arange, &die_offset, &error) == DW_DLV_OK) {
+
+ Dwarf_Die die;
+ if(dwarf_offdie(dbg, die_offset, &die, &error) == DW_DLV_OK) {
+
+ /* inside this CU, find the exact statement (DWARF calls it a "line") that
+ corresponds to the address we want to find information about. */
+ Dwarf_Line* lines;
+ Dwarf_Signed line_count;
+ if(dwarf_srclines(die, &lines, &line_count, &error) == DW_DLV_OK) {
+
+ /* skim through all available statements to find the one that fits best
+ (with an address <= "addr", as close as possible to "addr"). */
+ Dwarf_Line best = 0;
+
+ int delta = 65;
+ for(Dwarf_Signed i = 0; i < line_count; ++i) {
+ auto& l = lines[i];
+ Dwarf_Addr lineaddr;
+ if(dwarf_lineaddr(l, &lineaddr, &error) == DW_DLV_OK) {
+ int d = addr - lineaddr;
+ if(d >= 0 && d < delta) {
+ best = l;
+ delta = d;
+ }
+ }
+ }
+
+ if(best) {
+ // get the source file behind this statement.
+ char* linesrc;
+ if(dwarf_linesrc(best, &linesrc, &error) == DW_DLV_OK) {
+ file = linesrc;
+ dwarf_dealloc(dbg, linesrc, DW_DLA_STRING);
+
+ // get the line number inside that source file.
+ Dwarf_Unsigned lineno;
+ if(dwarf_lineno(best, &lineno, &error) == DW_DLV_OK) {
+ line = lineno;
+
+ // get the column number as well if available.
+ Dwarf_Signed lineoff;
+ if(dwarf_lineoff(best, &lineoff, &error) == DW_DLV_OK) {
+ column = lineoff;
+ }
+ }
+ }
+ }
+
+ dwarf_srclines_dealloc(dbg, lines, line_count);
+ }
+
+ if(file.empty()) {
+ /* could not get a precise statement within this CU; resort to showing
+ the global name of this CU's DIE which, according to section 3.1 of the
+ DWARF 2 spec, is almost what we want. */
+ char* name;
+ if(dwarf_diename(die, &name, &error) == DW_DLV_OK) {
+ file = name;
+ dwarf_dealloc(dbg, name, DW_DLA_STRING);
+ }
+ }
+
+ dwarf_dealloc(dbg, die, DW_DLA_DIE);
+ }
+
+ }
+
+ }
+
+ for(Dwarf_Signed i = 0; i < arange_count; ++i) {
+ dwarf_dealloc(dbg, aranges[i], DW_DLA_ARANGE);
+ }
+ dwarf_dealloc(dbg, aranges, DW_DLA_LIST);
+ }
+
+ dwarf_object_finish(dbg, &error);
+ }
+
+ ImageUnload(image);
+
+ if(error) {
+ fprintf(f, "[libdwarf error: %s] ", dwarf_errmsg(error));
}
}
// add some x64 defs that MinGW is missing.
#define DWORD64 DWORD
+#define IMAGEHLP_LINE64 IMAGEHLP_LINE
+#define IMAGEHLP_MODULE64 IMAGEHLP_MODULE
+#define IMAGEHLP_SYMBOL64 IMAGEHLP_SYMBOL
#define STACKFRAME64 STACKFRAME
-#define IMAGEHLP_SYMBOL64 IMAGEHLP_SYMBOL
#define StackWalk64 StackWalk
#define SymFunctionTableAccess64 SymFunctionTableAccess
+#define SymGetLineFromAddr64 SymGetLineFromAddr
#define SymGetModuleBase64 SymGetModuleBase
+#define SymGetModuleInfo64 SymGetModuleInfo
#define SymGetSymFromAddr64 SymGetSymFromAddr
#elif defined(_MSC_VER)
@@ -242,8 +304,8 @@
inline void writeBacktrace(LPCONTEXT context)
{
- HANDLE process = GetCurrentProcess();
- HANDLE thread = GetCurrentThread();
+ HANDLE const process = GetCurrentProcess();
+ HANDLE const thread = GetCurrentThread();
#ifdef __MINGW32__
SymSetOptions(SYMOPT_DEFERRED_LOADS);
@@ -252,17 +314,10 @@
#endif
if(!SymInitialize(process, 0, TRUE)) {
- fputs("Failed to init symbol context\n", f);
+ fprintf(f, "Failed to initialize the symbol handler (error: %d)\n", GetLastError());
return;
}
-#ifdef __MINGW32__
- bfd_init();
- bfd_set *set = reinterpret_cast<bfd_set*>(calloc(1, sizeof(*set)));
-
- bfd_ctx *bc = 0;
-#endif
-
STACKFRAME64 frame;
memset(&frame, 0, sizeof(frame));
@@ -286,78 +341,64 @@
#endif
- char symbol_buffer[sizeof(IMAGEHLP_SYMBOL64) + 255];
- char module_name_raw[MAX_PATH];
-
- // get the current module address.
- HMODULE module = ::GetModuleHandle(0);
-
- for(uint8_t depth = 0; depth <= 128; ++depth) {
+ char symbolBuf[sizeof(IMAGEHLP_SYMBOL64) + 255];
+
+ for(uint8_t step = 0; step < 128; ++step) { // 128 steps max to avoid too long traces
+
+ /* in case something unexpected happens when reading the next address, we want to at least
+ record the information that has been gathered so far. */
+ fflush(f);
if(!StackWalk64(WALK_ARCH, process, thread, &frame, context,
0, SymFunctionTableAccess64, SymGetModuleBase64, 0)) { break; }
- HMODULE module_base = reinterpret_cast<HMODULE>(SymGetModuleBase64(process, frame.AddrPC.Offset));
-
- const char * module_name = 0;
- if(module_base) {
- if(module_base == module) {
- module_name = "DCPlusPlus.pdb";
- } else if(GetModuleFileNameA(module_base, module_name_raw, MAX_PATH)) {
- module_name = module_name_raw;
- }
- }
- if(module_name) {
-#ifdef __MINGW32__
- bc = get_bc(set, module_name);
-#endif
- } else {
- module_name = "[unknown module]";
- }
-
- const char* file = 0;
- const char* func = 0;
- unsigned line = 0;
-
-#ifdef __MINGW32__
- if(bc) {
- find(bc, frame.AddrPC.Offset, &file, &func, &line);
- }
-#endif
-
- if(file == 0) {
- DWORD64 dummy = 0;
- IMAGEHLP_SYMBOL64* symbol = reinterpret_cast<IMAGEHLP_SYMBOL64*>(symbol_buffer);
- symbol->SizeOfStruct = (sizeof *symbol) + 255;
+ string file;
+ int line = -1;
+ int column = -1;
+
+ IMAGEHLP_MODULE64 module = { sizeof(IMAGEHLP_MODULE64) };
+ if(!SymGetModuleInfo64(process, frame.AddrPC.Offset, &module))
+ continue;
+ fprintf(f, "%s: ", module.ModuleName);
+
+#ifdef __MINGW32__
+ // read DWARF debugging info if available.
+ getDebugInfo(module.LoadedImageName, frame.AddrPC.Offset, file, line, column);
+#endif
+
+ /* this is the usual Windows PDB reading method. we try it on MinGW too if reading DWARF
+ data has failed, just in case Windows can extract some information. */
+ if(file.empty()) {
+ IMAGEHLP_SYMBOL64* symbol = reinterpret_cast<IMAGEHLP_SYMBOL64*>(symbolBuf);
+ symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
symbol->MaxNameLength = 254;
- if(SymGetSymFromAddr64(process, frame.AddrPC.Offset, &dummy, symbol)) {
+ if(SymGetSymFromAddr64(process, frame.AddrPC.Offset, 0, symbol)) {
file = symbol->Name;
} else {
- file = "[unknown file]";
- }
- }
-
-#ifdef _MSC_VER
- IMAGEHLP_LINE64 info = { sizeof(IMAGEHLP_LINE64) };
- DWORD dummy = 0;
- if(SymGetLineFromAddr64(process, frame.AddrPC.Offset, &dummy, &info)) {
- func = file;
- file = info.FileName;
- line = info.LineNumber;
- }
-#endif
-
- if(func == 0) {
- fprintf(f, "%s - %s\n", module_name, file);
- } else {
- fprintf(f, "%s - %s (%d) - in function %s\n", module_name, file, line, func);
- }
+ file = "?";
+ }
+
+ IMAGEHLP_LINE64 info = { sizeof(IMAGEHLP_LINE64) };
+ DWORD col;
+ if(SymGetLineFromAddr64(process, frame.AddrPC.Offset, &col, &info)) {
+ file = info.FileName;
+ line = info.LineNumber;
+ column = col;
+ }
+ }
+
+ // write the data collected about this frame to the file.
+ fprintf(f, "%s", file.c_str());
+ if(line >= 0) {
+ fprintf(f, " (%d", line);
+ if(column >= 0) {
+ fprintf(f, ":%d", column);
+ }
+ fputs(")", f);
+ }
+ fputs("\n", f);
}
-#ifdef __MINGW32__
- release_set(set);
-#endif
-
SymCleanup(process);
}
=== modified file 'win32/HubFrame.cpp'
--- win32/HubFrame.cpp 2011-06-22 11:35:35 +0000
+++ win32/HubFrame.cpp 2011-06-24 16:08:35 +0000
@@ -155,6 +155,7 @@
inTabComplete(false)
{
paned = addChild(SplitterContainer::Seed(0.7));
+ int* x=0; *x=2;
createChat(paned);
chat->setHelpId(IDH_HUB_CHAT);
=== modified file 'win32/SConscript'
--- win32/SConscript 2011-06-12 22:41:02 +0000
+++ win32/SConscript 2011-06-24 16:08:35 +0000
@@ -18,9 +18,9 @@
env.Append(LIBS = ['comctl32', 'ws2_32', 'ole32', 'gdi32', 'comdlg32', 'iphlpapi', 'winmm', 'shlwapi', 'oleaut32', 'uuid'])
# add libs for the crash logger.
-if env['LINK'] == 'g++': # MinGW
- if 'HAVE_BFD_H' in env['CPPDEFINES']:
- env.Append(LIBS = ['bfd', 'iberty', 'imagehlp'])
+if 'g++' in env['LINK']: # MinGW
+ env.Append(CPPPATH = ['#/dwarf'])
+ env.Append(LIBS = ['imagehlp'])
elif env['LINK'] == 'link': # MSVC
env.Append(LIBS = ['dbghelp'])
@@ -44,7 +44,7 @@
headers=dev.get_sources(source_path, "*.h")
dev.i18n(source_path, env, [sources,headers], 'dcpp-win32')
-ret = env.Program(target, [sources, res, dev.client, dev.zlib, dev.boost, dev.bzip2, dev.miniupnpc, dev.natpmp, dev.dwt, dev.intl])
+ret = env.Program(target, [sources, res, dev.client, dev.dwarf, dev.zlib, dev.boost, dev.bzip2, dev.miniupnpc, dev.natpmp, dev.dwt, dev.intl])
if 'gcc' in env['TOOLS']:
# strip debug info to a separate PDB file