Improved creation backtraces

(cherry picked from commit a5ba7ad712)
v3.5.13-sru
Alexander Golubev 11 years ago committed by Slávek Banko
parent 5bb41966db
commit 918ff4b4ae

@ -84,6 +84,7 @@ OPTION( WITH_INOTIFY "Enable inotify support for kio" ON )
OPTION( WITH_GAMIN "Enable FAM/GAMIN support" ${WITH_ALL_OPTIONS} ) OPTION( WITH_GAMIN "Enable FAM/GAMIN support" ${WITH_ALL_OPTIONS} )
OPTION( WITH_SUDO_KDESU_BACKEND "Use sudo as backend for kdesu (default is su)" OFF ) OPTION( WITH_SUDO_KDESU_BACKEND "Use sudo as backend for kdesu (default is su)" OFF )
OPTION( WITH_LZMA "Enable support for LZMA/XZ" ${WITH_ALL_OPTIONS} ) OPTION( WITH_LZMA "Enable support for LZMA/XZ" ${WITH_ALL_OPTIONS} )
OPTION( WITH_LIBBFD "Enable pretty backtraces with libbfd from GNU binutils" OFF )
OPTION( WITH_XRANDR "Build the krandr library" ON ) OPTION( WITH_XRANDR "Build the krandr library" ON )
OPTION( WITH_ASPELL "Enable aspell support" ${WITH_ALL_OPTIONS} ) OPTION( WITH_ASPELL "Enable aspell support" ${WITH_ALL_OPTIONS} )
@ -196,7 +197,6 @@ check_include_file( "termio.h" HAVE_TERMIO_H )
check_include_file( "unistd.h" HAVE_UNISTD_H ) check_include_file( "unistd.h" HAVE_UNISTD_H )
check_include_file( "util.h" HAVE_UTIL_H ) check_include_file( "util.h" HAVE_UTIL_H )
check_include_file( "values.h" HAVE_VALUES_H ) check_include_file( "values.h" HAVE_VALUES_H )
check_include_file( "demangle.h" HAVE_DEMANGLE_H )
# FIXME I'm not sure if test TIME_WITH_SYS_TIME are correct # FIXME I'm not sure if test TIME_WITH_SYS_TIME are correct
check_include_file( "sys/time.h" HAVE_SYS_TIME_H ) check_include_file( "sys/time.h" HAVE_SYS_TIME_H )
@ -264,10 +264,33 @@ check_symbol_exists( gethostbyname_r "netdb.h" HAVE_GETHOSTBYNAME_R )
check_symbol_exists( gai_strerror "sys/types.h;sys/socket.h;netdb.h" HAVE_GAI_STRERROR ) check_symbol_exists( gai_strerror "sys/types.h;sys/socket.h;netdb.h" HAVE_GAI_STRERROR )
check_symbol_exists( getaddrinfo "sys/types.h;sys/socket.h;netdb.h" HAVE_GETADDRINFO ) check_symbol_exists( getaddrinfo "sys/types.h;sys/socket.h;netdb.h" HAVE_GETADDRINFO )
check_symbol_exists( backtrace "execinfo.h" HAVE_BACKTRACE ) check_symbol_exists( backtrace "execinfo.h" HAVE_BACKTRACE )
check_cxx_source_compiles( "#include <cxxabi.h>
int main() { abi::__cxa_demangle(0, 0, 0, 0); return 0; }"
HAVE_ABI_CXA_DEMANGLE )
# Some declarations are needed by demangle.h (libiberty.h) and/or bfd.h but we
# will check them uncondionally
# See WITH_LIBBFD also see binutils bugs 14243 and 14072
# NOTE: those headers use HAVE_DECL_* names but we would follow our macro
# naming style
check_symbol_exists( basename "libgen.h" HAVE_BASENAME_PROTO )
check_symbol_exists( ffs "string.h" HAVE_FFS_PROTO )
check_symbol_exists( asprintf "stdio.h" HAVE_ASPRINTF_PROTO )
check_symbol_exists( vasprintf "stdio.h" HAVE_VASPRINTF_PROTO )
check_symbol_exists( snprintf "stdio.h" HAVE_SNPRINTF_PROTO )
check_symbol_exists( vsnprintf "stdarg.h" HAVE_VSNPRINTF_PROTO )
check_symbol_exists( strvercmp "string.h" HAVE_STRVERCMP_PROTO )
check_function_exists( usleep HAVE_USLEEP ) check_function_exists( usleep HAVE_USLEEP )
check_symbol_exists( usleep "unistd.h" HAVE_USLEEP_PROTO ) check_symbol_exists( usleep "unistd.h" HAVE_USLEEP_PROTO )
if (HAVE_ALLOCA_H )
check_symbol_exists( alloca "alloca.h" HAVE_ALLOCA )
else (HAVE_ALLOCA_H )
check_symbol_exists( alloca "stdlib.h" HAVE_ALLOCA )
endif (HAVE_ALLOCA_H )
check_function_exists( getmntinfo HAVE_GETMNTINFO ) check_function_exists( getmntinfo HAVE_GETMNTINFO )
check_function_exists( getnameinfo HAVE_GETNAMEINFO ) check_function_exists( getnameinfo HAVE_GETNAMEINFO )
check_function_exists( getpagesize HAVE_GETPAGESIZE ) check_function_exists( getpagesize HAVE_GETPAGESIZE )
@ -323,7 +346,6 @@ check_function_exists( getcwd HAVE_GETCWD )
check_function_exists( dlerror HAVE_DLERROR ) check_function_exists( dlerror HAVE_DLERROR )
check_function_exists( crypt HAVE_CRYPT ) check_function_exists( crypt HAVE_CRYPT )
check_function_exists( bcopy HAVE_BCOPY ) check_function_exists( bcopy HAVE_BCOPY )
check_function_exists( alloca HAVE_ALLOCA )
check_function_exists( mmap HAVE_MMAP ) check_function_exists( mmap HAVE_MMAP )
check_function_exists( munmap HAVE_MUNMAP ) check_function_exists( munmap HAVE_MUNMAP )
@ -699,6 +721,17 @@ if( WITH_LIBIDN )
check_include_file( "stringprep.h" HAVE_STRINGPREP_H ) check_include_file( "stringprep.h" HAVE_STRINGPREP_H )
endif( WITH_LIBIDN ) endif( WITH_LIBIDN )
##### check for libbfq ##########################
if( WITH_LIBBFD )
check_library_exists( bfd bfd_init "" HAVE_LIBBFD )
if( NOT HAVE_LIBBFD )
tde_message_fatal( "libbfd support is requested, but not found on your system" )
endif( NOT HAVE_LIBBFD )
set( LIBBFD_LIBRARIES bfd )
check_include_file( "demangle.h" HAVE_DEMANGLE_H )
endif( WITH_LIBBFD )
##### check for openssl ######################### ##### check for openssl #########################

@ -47,9 +47,74 @@
/* Define to 1 if you have the <awe_voice.h> header file. */ /* Define to 1 if you have the <awe_voice.h> header file. */
#cmakedefine HAVE_AWE_VOICE_H 1 #cmakedefine HAVE_AWE_VOICE_H 1
/* Define if execinfo.h exists and defines backtrace (GLIBC >= 2.1) */ /* Define if you have basename prototype */
#cmakedefine HAVE_BASENAME_PROTO 1
/* Define if you have ffs prototype */
#cmakedefine HAVE_FFS_PROTO 1
/* Define if you have asprintf prototype */
#cmakedefine HAVE_ASPRINTF_PROTO 1
/* Define if you have vasprintf prototype */
#cmakedefine HAVE_VASPRINTF_PROTO 1
/* Define if you have snsprintf prototype */
#cmakedefine HAVE_SNPRINTF_PROTO 1
/* Define if you have vsnsprintf prototype */
#cmakedefine HAVE_VSNPRINTF_PROTO 1
/* Define if you have strvercmp prototype */
#cmakedefine HAVE_STRVERCMP_PROTO 1
/* Define to 1 if execinfo.h exists and defines backtrace (GLIBC >= 2.1) */
#cmakedefine HAVE_BACKTRACE 1 #cmakedefine HAVE_BACKTRACE 1
/* Define to 1 if gcc (or may be some over compiller) provides abi::__cxa_demangle() */
#cmakedefine HAVE_ABI_CXA_DEMANGLE 1
/* Define to 1 if compiled with libbfd support */
#cmakedefine WITH_LIBBFD 1
#ifdef WITH_LIBBFD
#cmakedefine HAVE_DECL_BASENAME 1
/* Some declarations are needed by demangle.h (libiberty.h) and/or bfd.h */
/* those heders use HAVE_DECL_* format but we decided to follow our macro style */
#ifdef HAVE_BASENAME_PROTO
#define HAVE_DECL_BASENAME 1
#endif /* HAVE_BASENAME_PROTO */
#ifdef HAVE_FFS_PROTO
#define HAVE_DECL_FFS 1
#endif /* HAVE_FFS_PROTO */
#ifdef HAVE_ASPRINTF_PROTO
#define HAVE_DECL_ASPRINTF 1
#endif /* HAVE_ASPRINTF_PROTO */
#ifdef HAVE_VASPRINTF_PROTO
#define HAVE_DECL_VASPRINTF 1
#endif /* HAVE_VASPRINTF_PROTO */
#ifdef HAVE_SNPRINTF_PROTO
#define HAVE_DECL_SNPRINTF 1
#endif /* HAVE_SNPRINTF_PROTO */
#ifdef HAVE_VSNPRINTF_PROTO
#define HAVE_DECL_VSNPRINTF 1
#endif /* HAVE_VSNPRINTF_PROTO */
#ifdef HAVE_STRVERCMP_PROTO
#define HAVE_DECL_STRVERCMP 1
#endif /* HAVE_STRVERCMP_PROTO */
#endif /* HAVE_BASENAME_PROTO */
/* Define to 1 if libbfd provides demangle.h header */
#cmakedefine HAVE_DEMANGLE_H 1
/* Define to 1 if you have the `bcopy' function. */ /* Define to 1 if you have the `bcopy' function. */
#cmakedefine HAVE_BCOPY 1 #cmakedefine HAVE_BCOPY 1

@ -131,6 +131,7 @@ tde_add_library( ${target} SHARED AUTOMOC
VERSION 4.2.0 VERSION 4.2.0
EMBED kdecorenetwork-static EMBED kdecorenetwork-static
LINK ltdlc-static ${KDESVGICONS} DCOP-shared kdefx-shared ${ZLIB_LIBRARIES} ${LIBIDN_LIBRARIES} ${XCOMPOSITE_LIBRARIES} ICE SM LINK ltdlc-static ${KDESVGICONS} DCOP-shared kdefx-shared ${ZLIB_LIBRARIES} ${LIBIDN_LIBRARIES} ${XCOMPOSITE_LIBRARIES} ICE SM
${LIBBFD_LIBRARIES}
DEPENDENCIES dcopidl dcopidl2cpp DEPENDENCIES dcopidl dcopidl2cpp
DESTINATION ${LIB_INSTALL_DIR} DESTINATION ${LIB_INSTALL_DIR}
) )

@ -22,7 +22,6 @@
#ifdef NDEBUG #ifdef NDEBUG
#undef kdDebug #undef kdDebug
#undef kdBacktrace
#endif #endif
#include "kdebugdcopiface.h" #include "kdebugdcopiface.h"
@ -54,15 +53,42 @@
#include <ctype.h> // isprint #include <ctype.h> // isprint
#include <syslog.h> #include <syslog.h>
#include <errno.h> #include <errno.h>
#include <string.h> #include <cstring>
#include <kconfig.h> #include <kconfig.h>
#include "kstaticdeleter.h" #include "kstaticdeleter.h"
#include <config.h> #include <config.h>
#ifdef HAVE_BACKTRACE #ifdef HAVE_BACKTRACE
#include <execinfo.h> #include <execinfo.h>
#ifdef HAVE_ABI_CXA_DEMANGLE
#include <cxxabi.h>
#endif #endif
#include <link.h>
#ifdef WITH_LIBBFD
/* newer versions of libbfd require some autotools-specific macros to be defined */
/* see binutils Bug 14243 and 14072 */
#define PACKAGE kdelibs
#define PACKAGE_VERSION KDE_VERSION
#include <bfd.h>
#ifdef HAVE_DEMANGLE_H
#include <demangle.h>
#endif // HAVE_DEMANGLE_H
#endif // WITH_LIBBFD
#endif // HAVE_BACKTRACE
#ifdef HAVE_ALLOCA_H
#include <alloca.h>
#endif // HAVE_ALLOCA_H
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif // HAVE_STDINT_H
class KDebugEntry; class KDebugEntry;
class KDebugEntry class KDebugEntry
@ -554,36 +580,247 @@ kdbgstream& kdbgstream::operator<<( const TQByteArray& data) {
return *this; return *this;
} }
#ifdef HAVE_BACKTRACE
struct BacktraceFunctionInfo {
const void *addr; //< the address of function returned by backtrace()
const char* fileName; //< the file of binary owning the function (e.g. shared library or current header)
const void *base; //< the base address there the binary is loaded to
uintptr_t offset; //< offset of the function in binary (base - address)
TQString functionName; //< mangled name of function
TQString prettyName; //< demangled name of function
TQString sourceName; //< name of source file function declared in
unsigned sourceLine; //< line where function defined
};
#ifdef WITH_LIBBFD
// load symbol table from file
asymbol** bfdLoadSymtab (bfd *abfd) {
long symCount; // count of entries in symbol table
long symtab_sz; // size of the table
asymbol** rv;
bfd_boolean dynamic = FALSE;
// make shure the file has symbol table
if ((bfd_get_file_flags (abfd) & HAS_SYMS) == 0){
return 0;
}
// determin the amount of space we'll need to store the table
symtab_sz = bfd_get_symtab_upper_bound (abfd);
if (symtab_sz == 0) {
symtab_sz = bfd_get_dynamic_symtab_upper_bound (abfd);
dynamic = TRUE;
}
if (symtab_sz < 0) {
return 0;
}
// allocate memory
rv = (asymbol **) malloc(symtab_sz); // dunno, why not malloc
if ( !rv ) {
return 0;
}
// actually load the table
if (dynamic) {
symCount = bfd_canonicalize_dynamic_symtab (abfd, rv);
} else {
symCount = bfd_canonicalize_symtab (abfd, rv);
}
if (symCount < 0) {
if (rv) {
free(rv);
}
return 0;
}
return rv;
}
void bfdFillAdditionalFunctionsInfo(BacktraceFunctionInfo &func) {
static bool inited=0;
if (!inited) {
bfd_init();
inited=1;
}
bfd *abfd = bfd_openr(func.fileName, 0); // a bfd object
if( !abfd ) {
return;
}
// check format of the object
if( !bfd_check_format(abfd, bfd_object) ) {
bfd_close(abfd);
return;
}
// load symbol table
asymbol **syms= bfdLoadSymtab(abfd);
if(!syms) {
bfd_close(abfd);
return;
}
// found source file and line for given address
for (asection *sect = abfd->sections; sect != NULL; sect = sect->next) {
if (bfd_get_section_flags(abfd, sect) & SEC_ALLOC) {
bfd_vma sectStart = bfd_get_section_vma(abfd, sect);
bfd_vma sectEnd = sectStart + bfd_section_size(abfd, sect);
if (sectStart <= func.offset && func.offset < sectEnd) {
bfd_vma sectOffset = func.offset - sectStart;
const char* functionName;
const char* sourceName;
unsigned sourceLine;
if (bfd_find_nearest_line(abfd, sect, syms, sectOffset,
&sourceName, &functionName, &sourceLine))
{
func.sourceName = sourceName;
func.sourceLine = sourceLine;
if(func.functionName.isEmpty()) {
func.functionName = TQString::fromAscii(functionName);
}
break;
}
}
}
}
#ifdef HAVE_DEMANGLE_H
if(func.prettyName.isEmpty() && !func.functionName.isEmpty()) {
char *demangled = bfd_demangle(abfd, func.functionName.ascii(), DMGL_AUTO | DMGL_PARAMS);
if (demangled) {
func.prettyName = demangled;
free(demangled);
}
}
#endif // HAVE_DEMANGLE_H
if( syms ) {
free(syms);
}
bfd_close(abfd);
}
#endif // WITH_LIBBFD
void fillAdditionalFunctionsInfo(BacktraceFunctionInfo &func) {
#ifdef WITH_LIBBFD
bfdFillAdditionalFunctionsInfo(func);
#endif // WITH_LIBBFD
#ifdef HAVE_ABI_CXA_DEMANGLE
if(func.prettyName.isEmpty() && !func.functionName.isEmpty()) {
int status=0;
char *demangled = abi::__cxa_demangle(func.functionName.ascii(), 0, 0, &status);
if (demangled) {
func.prettyName = demangled;
free(demangled);
}
}
#endif // HAVE_ABI_CXA_DEMANGLE
}
TQString formatBacktrace(void *addr) {
TQString rv;
BacktraceFunctionInfo func;
func.addr = addr;
// NOTE: if somebody would compile for some non-linux-glibc platform
// check if dladdr function is avalible there
Dl_info info;
dladdr(func.addr, &info); // obtain information about the function.
func.fileName = info.dli_fname;
func.base = info.dli_fbase;
func.offset = (uintptr_t)func.addr - (uintptr_t)func.base;
func.functionName = TQString::fromAscii(info.dli_sname);
func.sourceLine = 0;
fillAdditionalFunctionsInfo(func);
rv.sprintf("0x%0*lx", (int) sizeof(void*)*2, (uintptr_t) func.addr);
rv += " in ";
if (!func.prettyName.isEmpty()) {
rv += func.prettyName;
} else if (!func.functionName.isEmpty()) {
rv += func.functionName;
} else {
rv += "??";
}
if (!func.sourceName.isEmpty()) {
rv += " in ";
rv += func.sourceName;
rv += ":";
rv += func.sourceLine ? TQString::number(func.sourceLine) : "??";
} else if (func.fileName && func.fileName[0]) {
rv += TQString().sprintf(" from %s:0x%08lx",func.fileName, func.offset);
} else {
rv += " from ??";
}
return rv;
}
#endif // HAVE_BACKTRACE
TQString kdBacktrace(int levels) TQString kdBacktrace(int levels)
{ {
TQString s; TQString rv;
#ifdef HAVE_BACKTRACE #ifdef HAVE_BACKTRACE
void* trace[256]; if (levels < 0 || levels > 256 ) {
int n = backtrace(trace, 256); levels = 256;
if (!n) }
return s;
char** strings = backtrace_symbols (trace, n); rv = "[\n";
if ( levels != -1 ) if (levels) {
n = QMIN( n, levels ); #ifdef HAVE_ALLOCA
s = "[\n"; void** trace = (void**)alloca(levels * sizeof(void*));
#else // HAVE_ALLOCA
for (int i = 0; i < n; ++i) void* trace[256];
s += TQString::number(i) + #endif // HAVE_ALLOCA
TQString::fromLatin1(": ") + levels = backtrace(trace, levels);
TQString::fromLatin1(strings[i]) + TQString::fromLatin1("\n");
s += "]\n"; if (levels) {
if (strings) for (int i = 0; i < levels; ++i) {
free (strings); rv += QString().sprintf("#%-2d ", i);
#endif rv += formatBacktrace(trace[i]);
return s; rv += '\n';
}
} else {
rv += "backtrace() failed\n";
}
}
rv += "]\n";
#endif // HAVE_BACKTRACE
return rv;
} }
// Keep for ABI compatability for some time
// FIXME remove this (2013-08-18, 18:09, Fat-Zer)
TQString kdBacktrace() TQString kdBacktrace()
{ {
return kdBacktrace(-1 /*all*/); return kdBacktrace(-1 /*all*/);
} }
void kdBacktraceFD(int fd) {
#ifdef HAVE_BACKTRACE
void *trace[256];
int levels;
levels = backtrace(trace, 256);
if (levels) {
backtrace_symbols_fd(trace, levels, fd);
}
#endif // HAVE_BACKTRACE
}
void kdClearDebugConfig() void kdClearDebugConfig()
{ {
if (kDebug_data) { if (kDebug_data) {

@ -601,17 +601,21 @@ KDECORE_EXPORT kdbgstream kdDebug(bool cond, int area = 0);
/** /**
* \relates KGlobal * \relates KGlobal
* Returns a backtrace. * Returns a backtrace.
* @param levels the number of levels of the backtrace. Defauls to -1 (as much as avalible).
* @return a backtrace * @return a backtrace
* @since 3.1
*/ */
KDECORE_EXPORT TQString kdBacktrace(); KDECORE_EXPORT TQString kdBacktrace(int levels=-1);
/** /**
* \relates KGlobal * \relates KGlobal
* Returns a backtrace. * Writes a backtrace to the given file descriptor. In contrast to
* @param levels the number of levels of the backtrace * kdBacktrace, this function doesn't call any malloc(). So it supposed to be
* @return a backtrace * used in situations than any extra memmmory allocation may lead to yet
* @since 3.1 * another crash. As a limitation it doesn't produce any symbol demangling.
* @param fd a file descriptor to write to. Defaults to 2 (stderr)
* @since 14.0
*/ */
KDECORE_EXPORT TQString kdBacktrace(int levels); KDECORE_EXPORT void kdBacktraceFD(int fd=2);
/** /**
* Returns a dummy debug stream. The stream does not print anything. * Returns a dummy debug stream. The stream does not print anything.
* @param area an id to identify the output, 0 for default * @param area an id to identify the output, 0 for default
@ -619,9 +623,6 @@ KDECORE_EXPORT TQString kdBacktrace(int levels);
*/ */
inline kndbgstream kndDebug(int area = 0) { Q_UNUSED(area); return kndbgstream(); } inline kndbgstream kndDebug(int area = 0) { Q_UNUSED(area); return kndbgstream(); }
inline kndbgstream kndDebug(bool , int = 0) { return kndbgstream(); } inline kndbgstream kndDebug(bool , int = 0) { return kndbgstream(); }
inline TQString kndBacktrace() { return TQString::null; }
inline TQString kndBacktrace(int) { return TQString::null; }
/** /**
* \relates KGlobal * \relates KGlobal
* Returns a warning stream. You can use it to print warning * Returns a warning stream. You can use it to print warning
@ -658,7 +659,6 @@ KDECORE_EXPORT void kdClearDebugConfig();
#ifdef NDEBUG #ifdef NDEBUG
#define kdDebug kndDebug #define kdDebug kndDebug
#define kdBacktrace kndBacktrace
#endif #endif
#endif #endif

@ -83,15 +83,9 @@ set( ${target}_SRCS
kmimetypechooser.cpp kmimetypechooser.cpp
) )
if( HAVE_BACKTRACE AND HAVE_DEMANGLE_H )
list( APPEND ${target}_SRCS backtrace_symbols.c )
set( BACKTRACE_LIBRARY bfd )
endif( )
tde_add_library( ${target} STATIC_PIC AUTOMOC tde_add_library( ${target} STATIC_PIC AUTOMOC
SOURCES ${${target}_SRCS} SOURCES ${${target}_SRCS}
DEPENDENCIES dcopidl DEPENDENCIES dcopidl
LINK ${BACKTRACE_LIBRARY}
) )

@ -1,325 +0,0 @@
/*
A hacky replacement for backtrace_symbols in glibc
backtrace_symbols in glibc looks up symbols using dladdr which is limited in
the symbols that it sees. libbacktracesymbols opens the executable and shared
libraries using libbfd and will look up backtrace information using the symbol
table and the dwarf line information.
It may make more sense for this program to use libelf instead of libbfd.
However, I have not investigated that yet.
Derived from addr2line.c from GNU Binutils by Jeff Muizelaar
Copyright 2007 Jeff Muizelaar
Copyright 2012 Timothy Pearson
*/
/* addr2line.c -- convert addresses to line number and function name
Copyright 1997, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
Contributed by Ulrich Lauther <Ulrich.Lauther@mchp.siemens.de>
This file was part of GNU Binutils.
This program 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; either version 2, or (at your option)
any later version.
This program 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 this program; if not, write to the Free Software
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#define fatal(a, b) exit(1)
#define bfd_fatal(a) exit(1)
#define bfd_nonfatal(a) exit(1)
#define list_matching_formats(a) exit(1)
/* 2 characters for each byte, plus 1 each for 0, x, and NULL */
#define PTRSTR_LEN (sizeof(void *) * 2 + 3)
#define true 1
#define false 0
#define _GNU_SOURCE
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <execinfo.h>
#include <bfd.h>
#include <libiberty.h>
#include <dlfcn.h>
#include <link.h>
#include <demangle.h>
static asymbol **syms; /* Symbol table. */
/* 150 isn't special; it's just an arbitrary non-ASCII char value. */
#define OPTION_DEMANGLER (150)
static void slurp_symtab(bfd * abfd);
static void find_address_in_section(bfd *abfd, asection *section, void *data);
/* Read in the symbol table. */
static void slurp_symtab(bfd * abfd)
{
long symcount;
unsigned int size;
if ((bfd_get_file_flags(abfd) & HAS_SYMS) == 0)
return;
symcount = (long)bfd_read_minisymbols(abfd, false, (void**) & syms, &size);
if (symcount == 0)
symcount = bfd_read_minisymbols(abfd, true /* dynamic */ ,
(void**) & syms, &size);
if (symcount < 0)
bfd_fatal(bfd_get_filename(abfd));
}
/* These global variables are used to pass information between
translate_addresses and find_address_in_section. */
static bfd_vma pc;
static const char *filename;
static const char *functionname;
static unsigned int line;
static int found;
/* Look for an address in a section. This is called via
bfd_map_over_sections. */
static void find_address_in_section(bfd *abfd, asection *section, void *data __attribute__ ((__unused__)) )
{
bfd_vma vma;
bfd_size_type size;
if (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_section_size(abfd, section);
if (pc >= vma + size)
return;
found = bfd_find_nearest_line(abfd, section, syms, pc - vma,
&filename, &functionname, &line);
}
/* Read hexadecimal addresses from stdin, translate into
file_name:line_number and optionally function name. */
enum { Count, Print };
static char** translate_addresses_buf(bfd * abfd, bfd_vma *addr, int naddr)
{
int naddr_orig = naddr;
char b;
int total = 0;
int state;
char *buf = &b;
int len = 0;
char **ret_buf = NULL;
/* iterate over the formating twice.
* the first time we count how much space we need
* the second time we do the actual printing */
for (state=Count; state<=Print; state++) {
if (state == Print) {
ret_buf = (char**)malloc(total + sizeof(char*)*naddr);
buf = (char*)(ret_buf + naddr);
len = total;
}
while (naddr) {
if (state == Print)
ret_buf[naddr-1] = buf;
pc = addr[naddr-1];
found = false;
bfd_map_over_sections(abfd, find_address_in_section,
(PTR) NULL);
if (!found) {
total += snprintf(buf, len, "[0x%llx] \?\?() \?\?:0",(long long unsigned int) addr[naddr-1]) + 1;
} else {
const char *name;
name = functionname;
if (name == NULL || *name == '\0')
name = "??";
if (filename != NULL) {
const char *h;
h = strrchr(filename, '/');
if (h != NULL)
filename = h + 1;
}
char* funcname = cplus_demangle(name, DMGL_AUTO);
if (funcname) {
// demangling succeeded
total += snprintf(buf, len, "%s:%u\t%s()", filename ? filename : "??", line, funcname) + 1;
}
else {
// demangling failed
total += snprintf(buf, len, "%s:%u\t%s()", filename ? filename : "??", line, name) + 1;
}
}
if (state == Print) {
/* set buf just past the end of string */
buf = buf + total + 1;
}
naddr--;
}
naddr = naddr_orig;
}
return ret_buf;
}
/* Process a file. */
static char **process_file(const char *file_name, bfd_vma *addr, int naddr)
{
bfd *abfd;
char **matching;
char **ret_buf;
abfd = bfd_openr(file_name, NULL);
if (abfd == NULL)
bfd_fatal(file_name);
if (bfd_check_format(abfd, bfd_archive))
fatal("%s: can not get addresses from archive", file_name);
if (!bfd_check_format_matches(abfd, bfd_object, &matching)) {
bfd_nonfatal(bfd_get_filename(abfd));
if (bfd_get_error() ==
bfd_error_file_ambiguously_recognized) {
list_matching_formats(matching);
free(matching);
}
xexit(1);
}
slurp_symtab(abfd);
ret_buf = translate_addresses_buf(abfd, addr, naddr);
if (syms != NULL) {
free(syms);
syms = NULL;
}
bfd_close(abfd);
return ret_buf;
}
#define MAX_DEPTH 16
struct file_match {
const char *file;
void *address;
void *base;
void *hdr;
};
static int find_matching_file(struct dl_phdr_info *info,
size_t size, void *data)
{
struct file_match *match = data;
/* This code is modeled from Gfind_proc_info-lsb.c:callback() from libunwind */
long n;
const ElfW(Phdr) *phdr;
ElfW(Addr) load_base = info->dlpi_addr;
phdr = info->dlpi_phdr;
for (n = info->dlpi_phnum; --n >= 0; phdr++) {
if (phdr->p_type == PT_LOAD) {
ElfW(Addr) vaddr = phdr->p_vaddr + load_base;
if (match->address >= (void*)vaddr && match->address < (void*)(vaddr + phdr->p_memsz)) {
/* we found a match */
match->file = info->dlpi_name;
match->base = (void*)info->dlpi_addr;
}
}
}
return 0;
}
char **backtrace_symbols(void *const *buffer, int size)
{
int stack_depth = size - 1;
int x,y;
/* discard calling function */
int total = 0;
char ***locations;
char **final;
char *f_strings;
locations = (char***)malloc(sizeof(char**) * (stack_depth+1));
bfd_init();
for(x=stack_depth, y=0; x>=0; x--, y++){
struct file_match match = { .address = buffer[x] };
char **ret_buf;
bfd_vma addr;
dl_iterate_phdr(find_matching_file, &match);
addr = buffer[x] - match.base;
if (match.file && strlen(match.file))
ret_buf = process_file(match.file, &addr, 1);
else
ret_buf = process_file("/proc/self/exe", &addr, 1);
locations[x] = ret_buf;
total += strlen(ret_buf[0]) + 1;
}
/* allocate the array of char* we are going to return and extra space for
* all of the strings */
final = (char**)malloc(total + (stack_depth + 1) * sizeof(char*));
/* get a pointer to the extra space */
f_strings = (char*)(final + stack_depth + 1);
/* fill in all of strings and pointers */
for(x=stack_depth; x>=0; x--){
strcpy(f_strings, locations[x][0]);
free(locations[x]);
final[x] = f_strings;
f_strings += strlen(f_strings) + 1;
}
free(locations);
return final;
}
void
backtrace_symbols_fd(void *const *buffer, int size, int fd)
{
int j;
char **strings;
strings = backtrace_symbols(buffer, size);
if (strings == NULL) {
perror("backtrace_symbols");
exit(EXIT_FAILURE);
}
for (j = 0; j < size; j++)
printf("%s\n", strings[j]);
free(strings);
}

@ -60,35 +60,6 @@
#include "uiserver_stub.h" #include "uiserver_stub.h"
#ifndef NDEBUG
#ifdef HAVE_BACKTRACE
#include <execinfo.h>
#endif
#endif
#ifndef NDEBUG
void print_trace()
{
#if defined(HAVE_BACKTRACE) && defined(HAVE_DEMANGLE_H)
void *array[10];
size_t size;
char **strings;
size_t i;
size = backtrace (array, 10);
strings = backtrace_symbols (array, size);
printf ("[kioslave] Obtained %zd stack frames.\n\r", size);
for (i = 0; i < size; i++) {
printf ("[kioslave] %s\n\r", strings[i]);
}
free (strings);
#endif // defined(HAVE_BACKTRACE) && defined(HAVE_DEMANGLE_H)
}
#endif // NDEBUG
using namespace KIO; using namespace KIO;
template class TQPtrList<TQValueList<UDSAtom> >; template class TQPtrList<TQValueList<UDSAtom> >;
@ -764,9 +735,20 @@ void SlaveBase::sigsegv_handler(int sig)
char buffer[120]; char buffer[120];
snprintf(buffer, sizeof(buffer), "kioslave: ####### CRASH ###### protocol = %s pid = %d signal = %d\n", s_protocol, getpid(), sig); snprintf(buffer, sizeof(buffer), "kioslave: ####### CRASH ###### protocol = %s pid = %d signal = %d\n", s_protocol, getpid(), sig);
write(2, buffer, strlen(buffer)); write(2, buffer, strlen(buffer));
#ifndef NDEBUG #ifdef SECURE_DEBUG
print_trace(); kdBacktraceFD();
#endif #else // SECURE_DEBUG
// Screw the malloc issue! We want nice demangled backtrace!
// Anyway we are not supposed to go into infinite loop because next signal
// will kill us. If you are unlucky and there is a second crash during
// backtrase in your system, you can define SECURE_DEBUG to avoid it
// Extra sync here so we are sure even if the backtrace will fail
// we will pass at least some crash message.
fsync(2);
TQString backtrace = kdBacktrace();
write(2, backtrace.ascii(), backtrace.length());
#endif // SECURE_DEBUG
::exit(1); ::exit(1);
#endif #endif
} }

Loading…
Cancel
Save