Skip to content
3 changes: 3 additions & 0 deletions backtrace_filter.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
zlib
deflate
inflate
39 changes: 37 additions & 2 deletions src/cfg.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#define _GNU_SOURCE
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>

Expand Down Expand Up @@ -77,7 +78,8 @@ struct _config_t

custom_tag_t** tags;
unsigned max_tags;

cfg_backtrace_t backtrace_option;
char* backtrace_filter_file;
char* commanddir;
unsigned processstartmsg;
unsigned enhancefs;
Expand Down Expand Up @@ -163,7 +165,6 @@ static cfg_buffer_t bufDefault[] = {
DEFAULT_LS_BUF,
};


///////////////////////////////////
// Constructors Destructors
///////////////////////////////////
Expand Down Expand Up @@ -231,6 +232,7 @@ cfgCreateDefault()
c->commanddir = (DEFAULT_COMMAND_DIR) ? scope_strdup(DEFAULT_COMMAND_DIR) : NULL;
c->processstartmsg = DEFAULT_PROCESS_START_MSG;
c->enhancefs = DEFAULT_ENHANCE_FS;
c->backtrace_option = DEFAULT_BACKTRACE_OPTION;

c->logstream.enable = DEFAULT_LOGSTREAM_ENABLE;
c->logstream.cloud = DEFAULT_LOGSTREAM_CLOUD;
Expand Down Expand Up @@ -379,6 +381,18 @@ cfgEnhanceFs(config_t* cfg)
return (cfg) ? cfg->enhancefs : DEFAULT_ENHANCE_FS;
}

cfg_backtrace_t
cfgBacktrace(config_t* cfg)
{
return (cfg) ? cfg->backtrace_option : DEFAULT_BACKTRACE_OPTION;
}

const char*
cfgBacktraceFilterFile(config_t* cfg)
{
return (cfg) ? cfg->backtrace_filter_file : NULL;
}

const char*
cfgEvtFormatValueFilter(config_t* cfg, watch_t src)
{
Expand Down Expand Up @@ -977,6 +991,27 @@ cfgLogLevelSet(config_t* cfg, cfg_log_level_t level)
cfg->log.level = level;
}



void
cfgBacktraceSet(config_t* cfg, cfg_backtrace_t backtrace)
{
if (!cfg || backtrace < 0 || backtrace > CFG_BACKTRACE_NONE) return;
cfg->backtrace_option = backtrace;
}

void
cfgBacktraceFilterFileSet(config_t* cfg, const char* path)
{
if (!cfg) return;
if (cfg->backtrace_filter_file) scope_free(cfg->backtrace_filter_file);
if (!path || (path[0] == '\0')) {
return;
}

cfg->backtrace_filter_file = scope_strdup(path);
}

void
cfgPayEnableSet(config_t *cfg, unsigned int val)
{
Expand Down
4 changes: 4 additions & 0 deletions src/cfg.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ unsigned cfgEvtEnable(config_t*);
cfg_mtc_format_t cfgEventFormat(config_t*);
unsigned cfgEvtRateLimit(config_t*);
unsigned cfgEnhanceFs(config_t*);
cfg_backtrace_t cfgBacktrace(config_t*);
const char* cfgBacktraceFilterFile(config_t*);
const char* cfgEvtFormatValueFilter(config_t*, watch_t);
const char* cfgEvtFormatFieldFilter(config_t*, watch_t);
const char* cfgEvtFormatNameFilter(config_t*, watch_t);
Expand Down Expand Up @@ -81,6 +83,8 @@ void cfgTransportTlsValidateServerSet(config_t *, which_transport
void cfgTransportTlsCACertPathSet(config_t *, which_transport_t, const char *);
void cfgCustomTagAdd(config_t*, const char*, const char*);
void cfgLogLevelSet(config_t*, cfg_log_level_t);
void cfgBacktraceSet(config_t*, cfg_backtrace_t);
void cfgBacktraceFilterFileSet(config_t*, const char*);
void cfgPayEnableSet(config_t*, unsigned int);
void cfgPayDirSet(config_t*, const char *);
void cfgEvtFormatHeaderSet(config_t *, const char *);
Expand Down
28 changes: 28 additions & 0 deletions src/cfgutils.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,14 @@ enum_map_t logLevelMap[] = {
{NULL, -1}
};

enum_map_t backtraceLevel[] = {
{"full", CFG_BACKTRACE_FULL},
{"filter", CFG_BACKTRACE_FILTER},
{"openat", CFG_BACKTRACE_OPENAT},
{"none", CFG_BACKTRACE_NONE},
{NULL, -1}
};

enum_map_t bufferMap[] = {
{"line", CFG_BUFFER_LINE},
{"full", CFG_BUFFER_FULLY},
Expand Down Expand Up @@ -180,6 +188,8 @@ void cfgTransportTlsValidateServerSetFromStr(config_t *, which_transport_t, cons
void cfgTransportTlsCACertPathSetFromStr(config_t *, which_transport_t, const char *);
void cfgCustomTagAddFromStr(config_t*, const char*, const char*);
void cfgLogLevelSetFromStr(config_t*, const char*);
void cfgBacktraceSetFromStr(config_t*, const char*);
void cfgBacktraceFilterFileSetFromStr(config_t*, const char*);
void cfgPayEnableSetFromStr(config_t*, const char*);
void cfgPayDirSetFromStr(config_t*, const char*);
void cfgAuthTokenSetFromStr(config_t*, const char*);
Expand Down Expand Up @@ -479,6 +489,10 @@ processEnvStyleInput(config_t *cfg, const char *env_line)
cfgMtcVerbositySetFromStr(cfg, value);
} else if (!scope_strcmp(env_name, "SCOPE_LOG_LEVEL")) {
cfgLogLevelSetFromStr(cfg, value);
} else if (!scope_strcmp(env_name, "SCOPE_BACKTRACE")) {
cfgBacktraceSetFromStr(cfg, value);
} else if (!scope_strcmp(env_name, "SCOPE_BACKTRACE_FILTER")) {
cfgBacktraceFilterFileSetFromStr(cfg, value);
} else if (!scope_strcmp(env_name, "SCOPE_METRIC_DEST")) {
cfgTransportSetFromStr(cfg, CFG_MTC, value);
} else if (!scope_strcmp(env_name, "SCOPE_METRIC_TLS_ENABLE")) {
Expand Down Expand Up @@ -894,6 +908,20 @@ cfgLogLevelSetFromStr(config_t* cfg, const char* value)
cfgLogLevelSet(cfg, strToVal(logLevelMap, value));
}

void
cfgBacktraceSetFromStr(config_t* cfg, const char* value)
{
if (!cfg || !value) return;
cfgBacktraceSet(cfg, strToVal(backtraceLevel, value));
}

void
cfgBacktraceFilterFileSetFromStr(config_t* cfg, const char* value)
{
if (!cfg || !value) return;
cfgBacktraceFilterFileSet(cfg, value);
}

void
cfgPayEnableSetFromStr(config_t* cfg, const char* value)
{
Expand Down
141 changes: 141 additions & 0 deletions src/dbg.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "dbg.h"
#include "utils.h"
#include "scopestdlib.h"
#include "uthash.h"

#define UNW_LOCAL_ONLY
#include "libunwind.h"
Expand Down Expand Up @@ -275,6 +276,146 @@ scopeLog(cfg_log_level_t level, const char *format, ...)
return;
}


struct b_hash_struct {
uint64_t ip;
char *name;
UT_hash_handle hh; /* makes this structure hashable */
};

struct b_hash_struct *backtrace_hash = NULL;

static void add_backtrace_hash(uint64_t ip, const char* name) {
struct b_hash_struct* bh = (struct b_hash_struct*)scope_malloc(sizeof(struct b_hash_struct));
bh->ip = ip;
bh->name = scope_strdup(name);
HASH_ADD_INT(backtrace_hash, ip, bh);
}

static struct b_hash_struct *find_backtrace_hash(uint64_t ip) {
struct b_hash_struct *s;

HASH_FIND_INT(backtrace_hash, &ip, s);
return s;
}

void
scopeBacktraceOp(const char* func, const char* path) {
unw_cursor_t cursor;
unw_context_t uc;
unw_word_t ip;
unw_getcontext(&uc);
unw_init_local(&cursor, &uc);
unw_step(&cursor); //skip first frame
scopeLogError("%s begin", __FUNCTION__);
while(unw_step(&cursor) > 0) {
char symbol[SYMBOL_BT_NAME_LEN];
unw_word_t offset;

int ret = unw_get_reg(&cursor, UNW_REG_IP, &ip);
if (ret) {
continue;
}
struct b_hash_struct *test = find_backtrace_hash(ip);
if(test) {
scopeLogError("func symbol: %s, fun: %s, arg %s", test->name, func, path);
} else {
ret = unw_get_proc_name(&cursor, symbol, SYMBOL_BT_NAME_LEN, &offset);
if (!ret) {
scopeLogError("func symbol: %s, fun: %s, arg %s", symbol, func, path);
add_backtrace_hash(ip, symbol);
} else {
scopeLogError("func symbol: unknown, fun: %s, arg %s", func, path);
add_backtrace_hash(ip, "unknown");
}
}
}
scopeLogError("%s end\n", __FUNCTION__);
}

void
scopeBacktraceFull(long long size, const char* alloc_fun, size_t total_size) {
unw_cursor_t cursor;
unw_context_t uc;
unw_word_t ip;
unw_getcontext(&uc);
unw_init_local(&cursor, &uc);
unw_step(&cursor); //skip first frame
scopeLogError("%s begin", __FUNCTION__);
while(unw_step(&cursor) > 0) {
char symbol[SYMBOL_BT_NAME_LEN];
unw_word_t offset;

int ret = unw_get_reg(&cursor, UNW_REG_IP, &ip);
if (ret) {
continue;
}
struct b_hash_struct *test = find_backtrace_hash(ip);
if(test) {
scopeLogError("func symbol: %s, malloc_fun: %s, size allocated: %lld, total size allocated: %zu", test->name, alloc_fun, size, total_size);
} else {
ret = unw_get_proc_name(&cursor, symbol, SYMBOL_BT_NAME_LEN, &offset);
if (!ret) {
scopeLogError("func symbol: %s, malloc_fun: %s, size allocated: %lld, total size allocated: %zu", symbol, alloc_fun, size, total_size);
add_backtrace_hash(ip, symbol);
} else {
scopeLogError("func symbol: unknown, malloc_fun: %s, size allocated: %lld, total size allocated: %zu", alloc_fun, size, total_size);
add_backtrace_hash(ip, "unknown");
}
}
}
scopeLogError("%s end\n", __FUNCTION__);
}

// Dl_info info = {};
// if (dladdr((void *)ip, &info))
// scopeLogError(" %s:%s", info.dli_fname, info.dli_sname ? info.dli_sname : "");

void
scopeBacktraceFilter(const char** str, int str_size, long long size, const char* alloc_fun, size_t total_size) {
unw_cursor_t cursor;
unw_context_t uc;
unw_word_t ip;
unw_getcontext(&uc);
unw_init_local(&cursor, &uc);
unw_step(&cursor); //skip first frame
while(unw_step(&cursor) > 0) {
char symbol[SYMBOL_BT_NAME_LEN];
unw_word_t offset;

int ret = unw_get_reg(&cursor, UNW_REG_IP, &ip);
if (ret) {
continue;
}
struct b_hash_struct *test = find_backtrace_hash(ip);
if(test) {
for (int i=0; i < str_size; ++i) {
if(scope_strstr(test->name, str[i])) {
scopeLogError("%s begin", __FUNCTION__);
scopeLogError("func symbol: %s, malloc_fun: %s, size allocated: %lld, total size allocated: %zu", test->name, alloc_fun, size, total_size);
scopeLogError("%s end\n", __FUNCTION__);
return;
}
}
} else {
ret = unw_get_proc_name(&cursor, symbol, SYMBOL_BT_NAME_LEN, &offset);
if (!ret) {
add_backtrace_hash(ip, symbol);
for (int i=0; i < str_size; ++i) {
if(scope_strstr(symbol, str[i])) {
scopeLogError("%s begin", __FUNCTION__);
scopeLogError("func symbol: %s, malloc_fun: %s, size allocated: %lld, total size allocated: %zu", symbol, alloc_fun, size, total_size);
scopeLogError("%s end\n", __FUNCTION__);
return;
}
}
} else {
add_backtrace_hash(ip, "unknown");
}
}
}
}

void
scopeBacktrace(cfg_log_level_t level)
{
Expand Down
3 changes: 3 additions & 0 deletions src/dbg.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ extern bool g_ismusl;
void scopeLog(cfg_log_level_t, const char *, ...) PRINTF_FORMAT(2,3);
void scopeLogHex(cfg_log_level_t, const void *, size_t, const char *, ...) PRINTF_FORMAT(4,5);
void scopeBacktrace(cfg_log_level_t);
void scopeBacktraceOp(const char*, const char*);
void scopeBacktraceFull(long long, const char*, size_t);
void scopeBacktraceFilter(const char**, int, long long, const char*, size_t);

#define scopeLogError(...) scopeLog(CFG_LOG_ERROR, __VA_ARGS__)
#define scopeLogWarn(...) scopeLog(CFG_LOG_WARN, __VA_ARGS__)
Expand Down
13 changes: 13 additions & 0 deletions src/fn.h
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,19 @@ typedef struct {
DIR *(*opendir)(const char *);
int (*closedir)(DIR *);
struct dirent *(*readdir)(DIR *);
void *(*malloc)(size_t);
void (*free)(void *);
void *(*calloc)(size_t, size_t);
void *(*realloc)(void *, size_t);
int (*posix_memalign)(void **, size_t, size_t);
void *(*aligned_alloc)(size_t, size_t);
void *(*valloc)(size_t);
void *(*memalign)(size_t, size_t);
void *(*pvalloc)(size_t);
size_t (*malloc_usable_size)(void *);
char *(*strdup)(const char *);
void *(*mmap)(void *, size_t, int, int, int, off_t);
int (*munmap)(void *, size_t);
#endif // __linux__

#if defined(__linux__) && defined(__STATX__)
Expand Down
7 changes: 6 additions & 1 deletion src/scopetypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ typedef enum {CFG_LOG_TRACE,
CFG_LOG_WARN,
CFG_LOG_ERROR,
CFG_LOG_NONE} cfg_log_level_t;
typedef enum {CFG_BACKTRACE_FULL,
CFG_BACKTRACE_FILTER,
CFG_BACKTRACE_OPENAT,
CFG_BACKTRACE_NONE} cfg_backtrace_t;
typedef enum {CFG_BUFFER_FULLY, CFG_BUFFER_LINE} cfg_buffer_t;
typedef enum {CFG_SRC_FILE,
CFG_SRC_CONSOLE,
Expand Down Expand Up @@ -125,6 +129,7 @@ typedef unsigned int bool;

#define DEFAULT_MAXEVENTSPERSEC 10000
#define DEFAULT_ENHANCE_FS TRUE
#define DEFAULT_BACKTRACE_OPTION CFG_BACKTRACE_NONE
#define DEFAULT_PORTBLOCK 0
#define DEFAULT_METRIC_CBUF_SIZE 50 * 1024
#define DEFAULT_PROCESS_START_MSG TRUE
Expand Down Expand Up @@ -184,7 +189,7 @@ typedef unsigned int bool;
// SCOPE_PID provided by library
// SCOPE_PAYLOAD_HEADER write payload headers to files
// SCOPE_ALLOW_CONSTRUCT_DBG allows debug inside the constructor
// SCOPE_ERROR_SIGNAL_HANDLER allows to register SIGSEGV&SIGBUS handler
// SCOPE_ERROR_SIGNAL_HANDLER allows to register SIGSEGV&SIGBUS&SIGABRT handler
// SCOPE_QUEUE_LENGTH override default circular buffer sizes
// SCOPE_ALLOW_BINARY_CONSOLE "true" outputs all console data, always

Expand Down
Loading