citus/src/backend/distributed/utils/backtrace.c

104 lines
2.1 KiB
C

/*
* backtrace.c
*
* Utilities related to backtrace
*
* Copyright (c) Citus Data, Inc.
*/
#include "postgres.h"
#include "backtrace.h"
#include "lib/stringinfo.h"
#include "distributed/backtrace.h"
#define BACKTRACE_HEADER "\nBACKTRACE:\n"
#define BACKTRACE_SKIP 2
static int BacktraceFullCallback(void *data, uintptr_t pc,
const char *filename, int lineno,
const char *function);
static void BacktraceErrorCallback(void *data, const char *msg, int errnum);
static void InitBackTrace(void);
static bool ShouldLogBacktrace(int elevel);
static char * GenerateBackTrace(int);
static struct backtrace_state *backTracestate;
static void
InitBackTrace(void)
{
const char *filename = NULL;
void *data = NULL;
backTracestate = backtrace_create_state(filename, 0,
BacktraceErrorCallback, data);
}
static bool
ShouldLogBacktrace(int elevel)
{
return elevel >= ERROR;
}
void
Backtrace(int elevel)
{
if (!ShouldLogBacktrace(elevel))
{
return;
}
errdetail("%s", GenerateBackTrace(BACKTRACE_SKIP));
}
void AssertBacktrace(void) {
const char * backtrace = GenerateBackTrace(BACKTRACE_SKIP);
ereport(ERROR, (errmsg("%s", backtrace)));
}
void SignalBacktrace(void) {
const char * backtrace = GenerateBackTrace(BACKTRACE_SKIP + 1);
ereport(WARNING, (errmsg("%s", backtrace)));
}
static char *
GenerateBackTrace(int skipAmount)
{
if (backTracestate == NULL)
{
InitBackTrace();
}
StringInfo msgWithBacktrace = makeStringInfo();
appendStringInfoString(msgWithBacktrace, BACKTRACE_HEADER);
backtrace_full(backTracestate, skipAmount, BacktraceFullCallback,
BacktraceErrorCallback, msgWithBacktrace);
return msgWithBacktrace->data;
}
static int
BacktraceFullCallback(void *data, uintptr_t pc, const char *filename, int lineno,
const char *function)
{
StringInfo str = (StringInfo) data;
if (function && filename)
{
appendStringInfo(str, "%s:%s:%d\n", filename, function, lineno);
}
/* returning 0 means we will continue the backtrace */
return 0;
}
static void
BacktraceErrorCallback(void *data, const char *msg, int errnum)
{
/* currently NO-OP */
}