From 10dbcdb8b2e47cf4b23ef630a4ec9045bc08f089 Mon Sep 17 00:00:00 2001 From: Silvan Calarco Date: Sun, 14 Feb 2021 14:28:21 +0100 Subject: [PATCH] functions.c: backtraceHandler(): use libunwind and libelf-utils to provide stacktrace with source code line numbers --- src/CMakeLists.txt | 10 ++++-- src/distromatic.c | 4 +-- src/functions.c | 76 ++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 74 insertions(+), 16 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7869e53..d59b95e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,6 +4,8 @@ set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) pkg_check_modules(RPM REQUIRED rpm) pkg_check_modules(SQLITE3 REQUIRED sqlite3) +pkg_check_modules(LIBUNWIND REQUIRED libunwind) +pkg_check_modules(LIBDW REQUIRED libdw) find_library(LIBIBERTY NAMES iberty) include_directories(include) @@ -42,9 +44,11 @@ target_link_libraries(distromatic ${RPM_LIBRARIES} ${ZLIB_LIBRARIES} ${SQLITE3_LIBRARIES} + ${LIBUNWIND_LIBRARIES} + ${LIBDW_LIBRARIES} ${LIBIBERTY} ) -target_include_directories(distromatic PUBLIC ${RPM_INCLUDE_DIRS}) +target_include_directories(distromatic PUBLIC ${RPM_INCLUDE_DIRS} ${LIBUNWIND_INCLUDE_DIRS}) # # NOTE: -fno-toplevel-reorder required to prevent Sqlite3 weird problems # @@ -64,9 +68,11 @@ target_link_libraries(distroquery ${RPM_LIBRARIES} ${ZLIB_LIBRARIES} ${SQLITE3_LIBRARIES} + ${LIBUNWIND_LIBRARIES} + ${LIBDW_LIBRARIES} ${LIBIBERTY} ) -target_include_directories(distroquery PUBLIC ${RPM_INCLUDE_DIRS}) +target_include_directories(distroquery PUBLIC ${RPM_INCLUDE_DIRS} ${LIBUNWIND_INCLUDE_DIRS}) install( TARGETS distromatic diff --git a/src/distromatic.c b/src/distromatic.c index e9d41a3..86331e8 100644 --- a/src/distromatic.c +++ b/src/distromatic.c @@ -113,7 +113,7 @@ int handleObsoletedPackages(struct configTag *ct, int arch); static const char *copyright[] = { PACKAGE_NAME " version " PACKAGE_VERSION, -"Copyright (C) 2004-2020 by Silvan Calarco ", +"Copyright (C) 2004-2021 by Silvan Calarco ", "Copyright (C) 2006 by Davide Madrisan ", (char *)0 }; @@ -162,7 +162,7 @@ static const char *helpmsg[] = { " -v, --version display version and exit", "", "Examples:", -" distromatic -t devel --genhtml --deps-table", +" distromatic -t devel --genhtml --gendatatables", " distromatic -t stable/2.0 --changelogsince 010106", "", "Please report bugs to <"PACKAGE_BUGREPORT">.", diff --git a/src/functions.c b/src/functions.c index 3e51957..e863008 100644 --- a/src/functions.c +++ b/src/functions.c @@ -1,7 +1,7 @@ /* * distromatic - tool for RPM based repositories * - * Copyright (C) 2004-2020 by Silvan Calarco + * Copyright (C) 2004-2021 by Silvan Calarco * Copyright (C) 2006 by Davide Madrisan * * This program is free software; you can redistribute it and/or modify it under @@ -67,29 +67,81 @@ #include "functions.h" #include "changelog.h" -#include +#define UNW_LOCAL_ONLY +#include +#include +#include static int debug_log = 0; static struct configDefaults configdefaults; static struct configTag *firstconfigtag = NULL; /* Obtain a backtrace and print it to stdout. */ +static void debugInfo(FILE *out, const void* ip) +{ + char *debuginfo_path=NULL; + + Dwfl_Callbacks callbacks={ + .find_elf=dwfl_linux_proc_find_elf, + .find_debuginfo=dwfl_standard_find_debuginfo, + .debuginfo_path=&debuginfo_path, + }; + + Dwfl* dwfl=dwfl_begin(&callbacks); + assert(dwfl!=NULL); + + assert(dwfl_linux_proc_report (dwfl, getpid())==0); + assert(dwfl_report_end (dwfl, NULL, NULL)==0); + + Dwarf_Addr addr = (uintptr_t)ip; + + Dwfl_Module* module=dwfl_addrmodule (dwfl, addr); + + const char* function_name = dwfl_module_addrname(module, addr); + + fprintf(out, "%s(",function_name); + + Dwfl_Line *line=dwfl_getsrc (dwfl, addr); + if(line!=NULL) + { + int nline; + Dwarf_Addr addr; + const char* filename=dwfl_lineinfo (line, &addr,&nline,NULL,NULL,NULL); + fprintf(out, "%s:%d",strrchr(filename,'/')+1,nline); + } + else + { + const char *module_name = dwfl_module_info(module, + NULL, NULL, NULL, NULL, NULL, NULL, NULL); + fprintf(out, "in %s", module_name); + } +} + void backtraceHandler(int sig) { - void *array[10]; - size_t size; - char **strings; - size_t i; + unw_context_t uc; + unw_getcontext(&uc); - size = backtrace (array, 10); - strings = (char**)backtrace_symbols (array, size); + unw_cursor_t cursor; + unw_init_local(&cursor, &uc); - fprintf(stderr, "Obtained %zd stack frames.\n", size); + fprintf(stderr, "*** Received signal %d; stack trace: ***\n", sig); - for (i = 0; i < size; i++) - fprintf(stderr, "%s\n", strings[i]); + while(unw_step(&cursor)>0) { + unw_word_t ip; + unw_get_reg(&cursor, UNW_REG_IP, &ip); - free (strings); + unw_word_t offset; + char name[32]; + assert(unw_get_proc_name(&cursor, name,sizeof(name), &offset)==0); + + fprintf(stderr, "\tat "); + debugInfo(stderr, (void*)(ip-4)); + fprintf(stderr, ")\n"); + + if(strcmp(name,"main")==0) + break; + } exit(1); }