pstrace: initial commit

This commit is contained in:
2020-01-04 14:28:08 +04:00
parent 82c73720b1
commit 1f3a6237ac
13 changed files with 1391 additions and 0 deletions
+55
View File
@@ -0,0 +1,55 @@
#include "log.h"
#include <time.h>
#define LOG_BUFF_SIZE (1024*1024)
const char * const SC_LogBase::mSeverityStrings[] = {
" [DEBUG] : ",
" [INFO] : ",
" [WARNING]: ",
" [ERROR] : "
};
char SC_LogBase::mString[LOG_BUFF_SIZE];
uint32_t SC_LogBase::mStringSize = sizeof(SC_LogBase::mString);
SC_LogBase::SC_LogBase(uint32_t id, const char* source) : mID(id)
{
mStringLen = 0;
mCurrentSeverity = SEVERITY_DEBUG;
if(source) {
mSource = source;
}
}
SC_LogBase::~SC_LogBase()
{
Close();
}
void SC_LogBase::FormatString(const char* fmt, va_list args)
{
mStringLen += vsnprintf(mString + mStringLen, mStringSize - mStringLen, fmt, args);
}
void SC_LogBase::FormatPrefix(SC_LogSeverity severity)
{
time_t rawTime;
struct tm * timeinfo;
time(&rawTime);
timeinfo = gmtime(&rawTime);
mStringLen += strftime(mString, sizeof(mString), "%d-%m-%Y %H:%M:%S", timeinfo);
strncpy(mString + mStringLen, mSeverityStrings[(int)severity], strlen(mSeverityStrings[(int)severity]));
mStringLen += strlen(mSeverityStrings[(int)severity]);
}
void SC_LogBase::FormatPostfix()
{
if((mStringLen + 2) < mStringSize) {
mString[mStringLen++] = '\n';
mString[mStringLen++] = 0;
}
}
+148
View File
@@ -0,0 +1,148 @@
#ifndef LOG_H_
#define LOG_H_
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <string>
#include "mutex.h"
using std::string;
// Log message severity
enum SC_LogSeverity {
SEVERITY_DEBUG = 0,
SEVERITY_INFO,
SEVERITY_WARNING,
SEVERITY_ERROR,
//----------------
SEVERITY_MAX
};
class SC_LogBase
{
protected:
SC_LogBase(uint32_t id, const char* source);
public:
virtual ~SC_LogBase();
//variable argument number logging
inline virtual void Log(SC_LogSeverity severity, const char* fmt, ...)
{
if (severity < mCurrentSeverity)
return;
mLock.Lock();
if(!IsOpened())
{
//print header if present
if(Open() && mHeader.size())
{
SendMessage((char*)mHeader.c_str());
}
}
mStringLen = 0;
FormatPrefix(severity);
va_list args;
va_start(args, fmt);
FormatString(fmt, args);
va_end(args);
FormatPostfix();
SendMessage(mString);
mLock.Unlock();
}
//open source for send messages
virtual bool Open() = 0;
//close source
virtual void Close(){}
//whether source already opened
virtual bool IsOpened() = 0;
//returns source path
string& GetSource()
{
return mSource;
}
//assign source path
inline void SetSource(const char* source)
{
Close();
mSource = source;
}
void SetSource(string& source)
{
SetSource(source.c_str());
}
//assign Log header
inline void SetHeader(const char* header)
{
mHeader = string(header) + '\n';
}
//return Log ID
inline uint32_t GetID() const
{
return mID;
}
//set Log ID
inline void SetID(uint32_t id)
{
mID = id;
}
//return current severity threshold applied to the messages
inline SC_LogSeverity GetCurrentSeverity() const
{
return mCurrentSeverity;
}
//set severity threshold to be applied to the messages
inline void SetCurrentSeverity(SC_LogSeverity severity)
{
mCurrentSeverity = severity;
}
protected:
//actually sends message to the source
virtual void SendMessage(const char* msg) = 0;
//format message prefix
virtual void FormatPrefix(SC_LogSeverity severity);
//format message body
virtual void FormatString(const char* fmt, va_list args);
//format message postfix
virtual void FormatPostfix();
protected:
uint32_t mID; //log ID, associated with source
string mSource; //source for store log messages (file, IP address or sometsing else)
string mHeader; //header of the Log
static char mString[]; //formatted string to be printed
static uint32_t mStringSize; //size of the string buffer
uint32_t mStringLen; //length of the string
SC_LogSeverity mCurrentSeverity; //maximum severity value to be logged
static const char * const mSeverityStrings[];
SC_Mutex mLock;
};
#endif /* LOG_H_ */
+29
View File
@@ -0,0 +1,29 @@
#ifndef SC_LOGCONSOLE_H
#define SC_LOGCONSOLE_H
#include "log.h"
class SC_LogConsole : public SC_LogBase {
public:
SC_LogConsole(uint32_t id, const char* source) : SC_LogBase(id, source) { }
//open file for writing
inline virtual bool Open() {
return true;
}
//close file opened
inline virtual void Close() { }
//whether file already opened or not
inline virtual bool IsOpened() {
return true;
}
protected:
inline virtual void SendMessage(const char* msg) {
fprintf(stderr, "%s", msg);
}
};
#endif // SC_LOGCONSOLE_H
+108
View File
@@ -0,0 +1,108 @@
#ifndef LOG_FILE_H_
#define LOG_FILE_H_
//framework
#include "log.h"
#include <stdio.h>
#include <sys/types.h>
using std::string;
//=============================================================================================
// SWI Logger to file logging class declaration
//=============================================================================================
class SC_LogFile : public SC_LogBase
{
public:
SC_LogFile(uint32_t id, const char* source) : SC_LogBase(id, source)
{
mFile = 0;
//2GByte by default
mMaxFileSize = 0x0000000080000000ULL;
mBytesCount = 0;
}
//open file for writing
inline virtual bool Open()
{
if(!mFile) {
// extract log and path names
uint32_t namelen = mSource.size();
if(namelen) {
const char* ptr = strrchr(mSource.c_str(), '/');
uint32_t pathlen = 0;
if(ptr) {
pathlen = ptr - mSource.c_str() + 1;
namelen -= pathlen + 1;
}
mLogPath.append(mSource.c_str(), pathlen);
mLogName.append((mSource.c_str() + pathlen), namelen);
//open the file finally
mFile = fopen(mSource.c_str(), "a+");
}
}
return (mFile != 0);
}
//close file opened
inline virtual void Close()
{
if(mFile) {
fclose(mFile);
}
mFile = 0;
mBytesCount = 0;
}
//whether file already opened or not
inline virtual bool IsOpened()
{
return (mFile != 0);
}
inline void SetMaxFileSize(uint64_t size)
{
mMaxFileSize = size;
}
inline uint64_t GetMaxFileSize()
{
return mMaxFileSize;
}
inline FILE* GetLogFD()
{
return mFile;
}
protected:
inline virtual void SendMessage(const char* msg)
{
if(mFile && mBytesCount < mMaxFileSize) {
if(fputs(msg, mFile) >= 0) {
fflush(mFile);
mBytesCount += mStringLen;
} else {
fclose(mFile);
mFile = 0;
}
}
}
protected:
string mLogPath; //path to the log file
string mLogName; //name of the log file
FILE* mFile; //log file descriptor
uint64_t mMaxFileSize; //maximum number bytes allowed to be written to the file
uint64_t mBytesCount; //number of bytes actually written
};
#endif /* LOG_FILE_H_ */
+40
View File
@@ -0,0 +1,40 @@
#ifndef MUTEX_H_
#define MUTEX_H_
#include <pthread.h>
#include <sys/time.h>
class SC_Mutex {
public:
SC_Mutex() {
pthread_mutex_init(&m, NULL);
}
SC_Mutex(SC_Mutex const&) {
pthread_mutex_init(&m, NULL);
}
SC_Mutex& operator=(SC_Mutex const& rhs) {
if (&rhs != this) {
pthread_mutex_init(&m, NULL);
}
return *this;
}
~SC_Mutex() {
pthread_mutex_destroy(&m);
}
void Lock() {
pthread_mutex_lock(&m);
}
void Unlock() {
pthread_mutex_unlock(&m);
}
bool Trylock() {
return (pthread_mutex_trylock(&m) == 0);
}
private:
pthread_mutex_t m;
};
#endif /* MUTEX_H_ */
+509
View File
@@ -0,0 +1,509 @@
/*
* sysutils.cpp
*
* Created on: Dec 28, 2019
* Author: nnosov
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <limits.h>
#include <elfutils/libdwfl.h>
#include <cxxabi.h>
#include <execinfo.h>
#include <dwarf.h>
#include "logger/log.h"
#include "sysutils.h"
extern SC_LogBase* logger;
char __stack_trace[8192];
Dwarf_Frame* frame;
Dwfl_Module* module;
// dwfl_addrsegment() possibly can be used to check address validity
// dwarf_getattrs() allows to enumerate all DIE attributes
// dwarf_getfuncs() allows to enumerate functions within CU
static void print_detail (int result, const Dwarf_Op *ops, size_t nops, Dwarf_Addr bias, const char* prefix);
bool is_location_form(int form)
{
if (form == DW_FORM_block1 ||
form == DW_FORM_block2 ||
form == DW_FORM_block4 ||
form == DW_FORM_block ||
form == DW_FORM_data4 ||
form == DW_FORM_data8 ||
form == DW_FORM_sec_offset) {
return true;
}
return false;
}
char* GetExecutableName(char* path, uint32_t size)
{
char link[PATH_MAX];
snprintf(link, sizeof(link), "/proc/%d/exe", getpid());
int nret = readlink(link, path, size);
if (nret == -1) {
return NULL;
}
// trailing zero
path[nret] = 0;
return path;
}
#include <inttypes.h>
typedef struct __reginfo {
__reginfo() {
regname[0] = 0;
regno = -1;
}
char regname[1024];
int regno;
} reginfo;
int regname_callback (void *arg, int regno, const char *setname, const char *prefix, const char *regname, int bits, int type)
{
reginfo* info = (reginfo*)arg;
if(info->regno == regno) {
snprintf(info->regname, sizeof(info->regname), "%s %s%s", setname, prefix, regname);
}
return 0;
}
int reginfo_callback (void *arg, int regno, const char *setname, const char *prefix, const char *regname, int bits, int type)
{
reginfo* info = (reginfo*)arg;
//logger->Log(SEVERITY_DEBUG, "%s: info_reg = 0x%hhX, reg = 0x%hhX", __FUNCTION__, info->regno, regno);
if(info->regno == regno) {
snprintf(info->regname, sizeof(info->regname), "%s %s%s", setname, prefix, regname);
Dwarf_Op ops_mem[3];
Dwarf_Op* ops;
size_t nops;
int ret = dwarf_frame_register(frame, info->regno, ops_mem, &ops, &nops);
if(ret != 0) {
logger->Log(SEVERITY_DEBUG, "Failed to get CFI expression for register %s", info->regname);
return 0;
}
if(nops == 0 && ops == ops_mem) {
logger->Log(SEVERITY_DEBUG, "CFI expression for register %s is UNDEFINED", info->regname);
return 0;
}
if(nops == 0 && ops == NULL) {
logger->Log(SEVERITY_DEBUG, "CFI expression for register %s is SAME VALUE", info->regname);
return 0;
}
logger->Log(SEVERITY_DEBUG, "Found CFI expression for register %s, number of expressions: %d", info->regname, nops);
for(size_t i = 0; i < nops; ++i) {
logger->Log(SEVERITY_DEBUG, "\t[%d] operation: 0x%hhX, operand1: 0x%lX, operand2: 0x%lx, offset: 0x%lX", i, ops[i].atom, ops[i].number, ops[i].number2, ops[i].offset);
}
}
return 0;
}
void HandleType(Dwarf_Attribute* param, bool is_return = false)
{
Dwarf_Attribute attr_mem;
Dwarf_Attribute* attr;
// get DIE of return type
Dwarf_Die ret_die;
if(dwarf_formref_die(param, &ret_die)) {
switch (dwarf_tag(&ret_die)) {
case DW_TAG_base_type: {
// get Size attribute and it's value
Dwarf_Word size = 0;
attr = dwarf_attr(&ret_die, DW_AT_byte_size, &attr_mem);
if(attr) {
dwarf_formudata(attr, &size);
}
logger->Log(SEVERITY_INFO, "base type '%s'(%lu)", dwarf_diename(&ret_die), size);
break;
}
case DW_TAG_array_type:
logger->Log(SEVERITY_INFO, "array type");
break;
case DW_TAG_pointer_type:
logger->Log(SEVERITY_INFO, "pointer type");
break;
case DW_TAG_enumeration_type:
logger->Log(SEVERITY_INFO, "enumeration type");
break;
case DW_TAG_const_type:
logger->Log(SEVERITY_INFO, "constant type");
break;
case DW_TAG_subroutine_type:
logger->Log(SEVERITY_INFO, "subroutine type");
break;
case DW_TAG_typedef:
logger->Log(SEVERITY_INFO, "typedef '%s' type", dwarf_diename(&ret_die));
break;
default:
logger->Log(SEVERITY_INFO, "Unknown 0x%X tag type", dwarf_tag(&ret_die));
break;
}
attr = dwarf_attr(&ret_die, DW_AT_type, &attr_mem);
if(attr) {
HandleType(attr);
}
}
}
void
print_expr_block (Dwarf_Attribute *attr, Dwarf_Op *exprs, int len,
Dwarf_Addr addr, int depth)
{
printf ("{");
for (int i = 0; i < len; i++)
{
printf ("%s", (i + 1 < len ? ", " : ""));
}
printf ("}");
}
void HandleParameter(Dwarf_Die* result)
{
Dwarf_Attribute attr_mem;
Dwarf_Attribute* attr;
// Get reference to attribute type of the parameter/variable
attr = dwarf_attr(result, DW_AT_type, &attr_mem);
logger->Log(SEVERITY_INFO, "Handle '%s' %s", dwarf_diename(result), dwarf_tag(result) == DW_TAG_formal_parameter ? "parameter" : "variable");
if(attr) {
HandleType(attr);
}
// determine location of parameter in stack/heap or CPU registers
attr = dwarf_attr(result, DW_AT_location, &attr_mem);
if(attr) {
logger->Log(SEVERITY_DEBUG, "parameter location attribute form = 0x%X, code = 0x%X", attr->form, attr->code);
if(dwarf_hasform(attr, DW_FORM_exprloc)) {
Dwarf_Op *expr;
size_t exprlen;
if (dwarf_getlocation(attr, &expr, &exprlen) == 0) {
logger->Log(SEVERITY_DEBUG, "Found DW_AT_location expression");
print_detail(0, expr, exprlen, 0, "\tLocation ");
if(expr[0].atom >= DW_OP_reg0 && expr[0].atom <= DW_OP_bregx) {
Dwarf_Op ops_mem[3];
Dwarf_Op* ops;
size_t nops;
int ret = dwarf_frame_register(frame, expr[0].atom, ops_mem, &ops, &nops);
if(ret != 0) {
logger->Log(SEVERITY_DEBUG, "Failed to get CFI expression for register 0x%hhX", expr[0].atom);
return;
}
if(nops == 0 && ops == ops_mem) {
logger->Log(SEVERITY_DEBUG, "CFI expression for register 0x%hhX is UNDEFINED", expr[0].atom);
return;
}
if(nops == 0 && ops == NULL) {
logger->Log(SEVERITY_DEBUG, "CFI expression for register 0x%hhX is SAME VALUE", expr[0].atom);
return;
}
logger->Log(SEVERITY_DEBUG, "Found CFI expression for register 0x%hhX, number of expressions: %d", expr[0].atom, nops);
for(size_t i = 0; i < nops; ++i) {
logger->Log(SEVERITY_DEBUG, "\t[%d] operation: 0x%hhX, operand1: 0x%lX, operand2: 0x%lx, offset: 0x%lX", i, ops[i].atom, ops[i].number, ops[i].number2, ops[i].offset);
}
}
}
} else if(dwarf_hasform(attr, DW_FORM_sec_offset)) {
Dwarf_Addr base, start, end;
ptrdiff_t off = 0;
Dwarf_Op *fb_expr;
size_t fb_exprlen;
while ((off = dwarf_getlocations (attr, off, &base, &start, &end, &fb_expr, &fb_exprlen)) > 0) {
printf (" (%" PRIx64 ",%" PRIx64 ") ", start, end);
print_expr_block (attr, fb_expr, fb_exprlen, start, 0);
printf ("\n");
}
Dwarf_Word value;
int ret = dwarf_formudata(attr, &value);
if(ret >= 0) {
logger->Log(SEVERITY_DEBUG, "Found DW_AT_location offset = 0x%lX", value);
}
} else {
logger->Log(SEVERITY_WARNING, "Unknown attribute form = 0x%X, code = 0x%X", attr->form, attr->code);
}
}
}
void HandleFunction(Dwarf_Die* func, const char* fname)
{
if(!strcmp(fname, dwarf_diename(func))) {
logger->Log(SEVERITY_INFO, "Found function in debug info. DWARF tag: 0x%X, name = %s(...)", dwarf_tag(func), dwarf_diename(func));
Dwarf_Attribute attr_mem;
Dwarf_Attribute* attr;
// determine function's stack frame base
attr = dwarf_attr(func, DW_AT_frame_base, &attr_mem);
if(attr) {
if(dwarf_hasform(attr, DW_FORM_exprloc)) {
Dwarf_Op *expr;
size_t exprlen;
if (dwarf_getlocation (attr, &expr, &exprlen) == 0) {
logger->Log(SEVERITY_DEBUG, "Found DW_AT_framebase expression");
print_detail(0, expr, exprlen, 0, "\tLocation ");
} else {
logger->Log(SEVERITY_WARNING, "Unknown attribute form = 0x%X, code = 0x%X", attr->form, attr->code);
}
}
}
// Get reference to return attribute type of the function
// may be to use dwfl_module_return_value_location() instead
attr = dwarf_attr(func, DW_AT_type, &attr_mem);
if(attr) {
logger->Log(SEVERITY_INFO, "Handle return parameter");
HandleType(attr, true);
} else {
logger->Log(SEVERITY_DEBUG, "return attr name = 'void(0)'");
}
Dwarf_Die result;
if (dwarf_child(func, &result) != 0)
return;
// went through parameters and local variables of the function
do {
switch (dwarf_tag(&result)) {
case DW_TAG_formal_parameter:
case DW_TAG_variable:
HandleParameter(&result);
break;
// case DW_TAG_inlined_subroutine:
// /* Recurse further down */
// HandleFunction(&result, dwarf_diename(&result));
// break;
default:
break;
}
} while(dwarf_siblingof(&result, &result) == 0);
}
return;
}
static void print_detail (int result, const Dwarf_Op *ops, size_t nops, Dwarf_Addr bias, const char* prefix)
{
printf("\t%s ", prefix);
if (result < 0) {
printf("indeterminate (%s)\n", dwarf_errmsg (-1));
} else if (nops == 0) {
printf("%s\n", ops == NULL ? "same_value" : "undefined");
} else {
printf("%s expression:", result == 0 ? "location" : "value");
for (size_t i = 0; i < nops; ++i) {
printf (" 0x%X (offset: 0x%lX)", ops[i].atom, ops[i].offset);
if (ops[i].number2 == 0) {
if (ops[i].atom == DW_OP_addr) {
printf ("(%#" PRIx64 ")", ops[i].number + bias);
} else if (ops[i].number != 0) {
printf ("(%" PRIx64 ")", ops[i].number);
}
}
else {
printf ("(%" PRIx64 ",%" PRIx64 ")", ops[i].number, ops[i].number2);
}
}
puts("");
}
}
void HandleCompilationUnit(Dwfl_Module* module, Dwarf_Addr addr, const char* fname)
{
Dwarf_Addr mod_bias = 0;
// get function debug definition
Dwarf_Die* cdie = dwfl_module_addrdie(module, addr, &mod_bias);
logger->Log(SEVERITY_DEBUG, "Function bias in module is 0x%lX", mod_bias);
//Dwarf_Die* cdie = dwfl_addrdie(dwfl, addr, &mod_bias);
if(!cdie) {
logger->Log(SEVERITY_INFO, "Failed to find DWARF DIE for address %X", addr);
return;
}
// get CFI (Call Frame Information) for current module
// from handle_cfi()
Dwarf_CFI* cfi = dwfl_module_eh_cfi(module, &mod_bias);
if(cfi) {
// get frame of CFI for address
logger->Log(SEVERITY_INFO, "Found CFI for module %s", dwarf_diename(cdie));
int result = dwarf_cfi_addrframe (cfi, addr - mod_bias, &frame);
if (result == 0) {
// get frame information
logger->Log(SEVERITY_INFO, "Found CFI frame for module %s", dwarf_diename(cdie));
Dwarf_Addr start = addr;
Dwarf_Addr end = addr;
bool signalp;
int ra_regno = dwarf_frame_info (frame, &start, &end, &signalp);
if (ra_regno >= 0)
{
start += mod_bias;
end += mod_bias;
}
logger->Log(SEVERITY_DEBUG, "Per '.eh_frame' info has %#" PRIx64 " => [%#" PRIx64 ", %#" PRIx64 "] in_signal = %s", addr, start, end, signalp ? "true" : "false");
if (ra_regno < 0)
logger->Log(SEVERITY_DEBUG, "return address register unavailable (%s)", dwarf_errmsg (0));
else {
reginfo info; info.regno = ra_regno;
dwfl_module_register_names(module, regname_callback, &info);
logger->Log(SEVERITY_DEBUG, "return address in reg%u%s ==> %s", ra_regno, signalp ? " (signal frame)" : "", info.regname);
}
// finally get CFA (Canonical Frame Address)
// Point cfa_ops to dummy to match print_detail expectations.
// (nops == 0 && cfa_ops != NULL => "undefined")
Dwarf_Op dummy;
Dwarf_Op *cfa_ops = &dummy;
size_t cfa_nops;
result = dwarf_frame_cfa(frame, &cfa_ops, &cfa_nops);
print_detail (result, cfa_ops, cfa_nops, mod_bias, "\tCFA ");
}
}
if(dwarf_tag(cdie) != DW_TAG_compile_unit) {
logger->Log(SEVERITY_DEBUG, "Skipping non-cu die. DWARF tag: 0x%X, name = %s", dwarf_tag(cdie), dwarf_diename(cdie));
return;
}
logger->Log(SEVERITY_DEBUG, "Enumerating Compilation Unit '%s' to lookup for function %s()", dwarf_diename(cdie), fname);
Dwarf_Die result;
if(dwarf_child(cdie, &result)) {
logger->Log(SEVERITY_INFO, "No child DIE found for CU");
return;
}
do {
switch (dwarf_tag(&result)) {
case DW_TAG_subprogram:
case DW_TAG_entry_point:
case DW_TAG_inlined_subroutine:
HandleFunction(&result, fname);
break;
default:
//logger->Log(SEVERITY_INFO, "Unknown tag 0x%X for die '%s'", dwarf_tag(&result), dwarf_diename(&result));
break;
}
} while(dwarf_siblingof(&result, &result) == 0);
}
const char* LibdwTraceCallStack(ucontext_t* uctx)
{
void * caller_address = 0;
#ifdef REG_RIP // x86_64
caller_address = (void *) uctx->uc_mcontext.gregs[REG_RIP];
#elif defined(REG_EIP) // x86_32
caller_address = (void *) uctx->uc_mcontext.gregs[REG_EIP]);
#elif defined(__arm__)
caller_address = (void *) uctx->uc_mcontext.arm_pc);
#elif defined(__aarch64__)
caller_address = (void *) uctx->uc_mcontext.pc);
#elif defined(__ppc__) || defined(__powerpc) || defined(__powerpc__) || defined(__POWERPC__)
caller_address = (void *) uctx->uc_mcontext.regs->nip);
#elif defined(__s390x__)
caller_address = (void *) uctx->uc_mcontext.psw.addr);
#elif defined(__APPLE__) && defined(__x86_64__)
caller_address = (void *) uctx->uc_mcontext->__ss.__rip);
#else
# error "unknown architecture!"
#endif
void * array[50];
int size = backtrace(array, 50);
int skipped = 0;
for(int i = 0; i < size && array[i] != caller_address; ++i, ++skipped);
__stack_trace[0] = 0; uint32_t offset = 0;
offset += snprintf(__stack_trace + offset, sizeof(__stack_trace) - offset, "Stack trace(caller = %p. Total stack frames: %d, skipped: %d):\n",
caller_address, size, skipped);
char *debuginfo_path = NULL;
Dwfl_Callbacks callbacks = {
.find_elf = dwfl_linux_proc_find_elf,
.find_debuginfo = dwfl_standard_find_debuginfo,
.section_address = dwfl_offline_section_address,
.debuginfo_path = &debuginfo_path,
};
Dwfl* dwfl = dwfl_begin(&callbacks);
if(dwfl == NULL) {
offset += snprintf(__stack_trace + offset, sizeof(__stack_trace) - offset, "Failed to initialize libdw session for parse stack frames");
return __stack_trace;
}
if(dwfl_linux_proc_report(dwfl, getpid()) != 0 || dwfl_report_end(dwfl, NULL, NULL) !=0) {
offset += snprintf(__stack_trace + offset, sizeof(__stack_trace) - offset, "Failed to parse debug section of executable");
return __stack_trace;
}
for (int i = skipped, idx = 0; i < size ; ++i, ++idx) {
offset += snprintf(__stack_trace + offset, sizeof(__stack_trace) - offset, "[%-2d] ", idx);
Dwarf_Addr addr = (uintptr_t)array[i];
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);
if(filename) {
const char* str = strrchr(filename, '/');
if(str && *str != 0) {
str++;
} else {
str = filename;
}
offset += snprintf(__stack_trace + offset, sizeof(__stack_trace) - offset, "%s:%d", str, nline);
} else {
offset += snprintf(__stack_trace + offset, sizeof(__stack_trace) - offset, "%p", array[i]);
}
} else {
offset += snprintf(__stack_trace + offset, sizeof(__stack_trace) - offset, "%p", array[i]);
}
module = dwfl_addrmodule(dwfl, addr);
const char* addrname = dwfl_module_addrname(module, addr);
char* demangle_name = NULL;
if(addrname) {
int status;
demangle_name = abi::__cxa_demangle(addrname, NULL, NULL, &status);
char* function_name = NULL;
if(asprintf(&function_name, "%s%s", demangle_name ? demangle_name : addrname, demangle_name ? "" : "()") == -1) {
logger->Log(SEVERITY_ERROR, "Failed to allocate memory");
return __stack_trace;
}
offset += snprintf(__stack_trace + offset, sizeof(__stack_trace) - offset, " --> %s", function_name);
char* str = strchr(function_name, '(');
if(str) {
*str = 0;
}
HandleCompilationUnit(module, addr, function_name);
free(function_name);
}
if(demangle_name) {
free(demangle_name);
}
offset += snprintf(__stack_trace + offset, sizeof(__stack_trace) - offset, "\n");
}
return __stack_trace;
}
+30
View File
@@ -0,0 +1,30 @@
/*
* sysutils.h
*
* Created on: Dec 28, 2019
* Author: nnosov
*/
#ifndef SC_SYSUTILS_H_
#define SC_SYSUTILS_H_
//system
#include <string>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <ucontext.h>
using std::string;
// stack trace string buffer
extern char __stack_trace[8192];
// libdw-based trace call stack implementation
const char* LibdwTraceCallStack(ucontext_t* uctx);
char* GetExecutableName(char* path, uint32_t size);
#endif /* SC_SYSUTILS_H_ */