From a5ba7ad71203a7ff1b3a716e7171e919a2e2e5bb Mon Sep 17 00:00:00 2001 From: Alexander Golubev Date: Sun, 25 Aug 2013 14:46:19 +0200 Subject: Improved creation backtraces --- tdeio/tdeio/CMakeLists.txt | 6 - tdeio/tdeio/backtrace_symbols.c | 325 ---------------------------------------- tdeio/tdeio/slavebase.cpp | 46 ++---- 3 files changed, 14 insertions(+), 363 deletions(-) delete mode 100644 tdeio/tdeio/backtrace_symbols.c (limited to 'tdeio') diff --git a/tdeio/tdeio/CMakeLists.txt b/tdeio/tdeio/CMakeLists.txt index cf5c272a9..e2b96ebb1 100644 --- a/tdeio/tdeio/CMakeLists.txt +++ b/tdeio/tdeio/CMakeLists.txt @@ -84,15 +84,9 @@ set( ${target}_SRCS 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 SOURCES ${${target}_SRCS} DEPENDENCIES dcopidl - LINK ${BACKTRACE_LIBRARY} ) diff --git a/tdeio/tdeio/backtrace_symbols.c b/tdeio/tdeio/backtrace_symbols.c deleted file mode 100644 index 69aa2d740..000000000 --- a/tdeio/tdeio/backtrace_symbols.c +++ /dev/null @@ -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 - - 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 -#include -#include -#include -#include -#include -#include -#include -#include - - -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); -} - diff --git a/tdeio/tdeio/slavebase.cpp b/tdeio/tdeio/slavebase.cpp index 83b2a9889..e7989ec6b 100644 --- a/tdeio/tdeio/slavebase.cpp +++ b/tdeio/tdeio/slavebase.cpp @@ -60,35 +60,6 @@ #include "uiserver_stub.h" -#ifndef NDEBUG -#ifdef HAVE_BACKTRACE -#include -#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 ("[tdeioslave] Obtained %zd stack frames.\n\r", size); - - for (i = 0; i < size; i++) { - printf ("[tdeioslave] %s\n\r", strings[i]); - } - - free (strings); -#endif // defined(HAVE_BACKTRACE) && defined(HAVE_DEMANGLE_H) -} -#endif // NDEBUG - using namespace TDEIO; template class TQPtrList >; @@ -764,9 +735,20 @@ void SlaveBase::sigsegv_handler(int sig) char buffer[120]; snprintf(buffer, sizeof(buffer), "tdeioslave: ####### CRASH ###### protocol = %s pid = %d signal = %d\n", s_protocol, getpid(), sig); write(2, buffer, strlen(buffer)); -#ifndef NDEBUG - print_trace(); -#endif +#ifdef SECURE_DEBUG + kdBacktraceFD(); +#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); #endif } -- cgit v1.2.1