functions.c: backtraceHandler(): use libunwind and libelf-utils to provide stacktrace with source code line numbers

This commit is contained in:
Silvan Calarco 2021-02-14 14:28:21 +01:00
parent 88887423f4
commit 10dbcdb8b2
3 changed files with 74 additions and 16 deletions

View File

@ -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

View File

@ -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 <silvan.calarco@mambasoft.it>",
"Copyright (C) 2004-2021 by Silvan Calarco <silvan.calarco@mambasoft.it>",
"Copyright (C) 2006 by Davide Madrisan <davide.madrisan@gmail.com>",
(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">.",

View File

@ -1,7 +1,7 @@
/*
* distromatic - tool for RPM based repositories
*
* Copyright (C) 2004-2020 by Silvan Calarco <silvan.calarco@mambasoft.it>
* Copyright (C) 2004-2021 by Silvan Calarco <silvan.calarco@mambasoft.it>
* Copyright (C) 2006 by Davide Madrisan <davide.madrisan@gmail.com>
*
* 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 <execinfo.h>
#define UNW_LOCAL_ONLY
#include <elfutils/libdwfl.h>
#include <libunwind.h>
#include <assert.h>
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);
}