mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2024-12-12 10:04:14 +02:00
Improve libbacktrace implementation.
The libbacktrace feature has not been working since the move to meson because libbacktrace detection was not added to the meson build. Add libbacktrace to meson and improve the feature so that it can be compiled into release builds. The prior implementation fetched line numbers with each stack trace push. Not only was this slow but it missed any functions that were not being tracked on our stack. Instead just examine the backtrace when an error happens and merge it with the info we have on our stack. If the backtrace is not available then the output remains as before. Also remove --backtrace from test.pl since the library is now auto-detected. Leave this library out of the production build for now to give it a little time to shake out in testing.
This commit is contained in:
parent
0dd2997714
commit
c826429123
20
.github/workflows/symbol.out
vendored
20
.github/workflows/symbol.out
vendored
@ -9,6 +9,26 @@ _end
|
||||
_fini
|
||||
_init
|
||||
_start
|
||||
backtrace_alloc
|
||||
backtrace_close
|
||||
backtrace_create_state
|
||||
backtrace_dwarf_add
|
||||
backtrace_free
|
||||
backtrace_full
|
||||
backtrace_get_view
|
||||
backtrace_initialize
|
||||
backtrace_open
|
||||
backtrace_pcinfo
|
||||
backtrace_qsort
|
||||
backtrace_release_view
|
||||
backtrace_syminfo
|
||||
backtrace_syminfo_to_full_callback
|
||||
backtrace_syminfo_to_full_error_callback
|
||||
backtrace_uncompress_lzma
|
||||
backtrace_uncompress_zdebug
|
||||
backtrace_vector_finish
|
||||
backtrace_vector_grow
|
||||
backtrace_vector_release
|
||||
data_start
|
||||
environ@GLIBC_2.2.5
|
||||
main
|
||||
|
@ -133,6 +133,13 @@ add_project_arguments(cc.get_supported_arguments('-fmacro-prefix-map=@0@/test/sr
|
||||
####################################################################################################################################
|
||||
configuration = configuration_data()
|
||||
|
||||
# Find optional backtrace library
|
||||
lib_backtrace = cc.find_library('backtrace', required: false)
|
||||
|
||||
if lib_backtrace.found()
|
||||
configuration.set('HAVE_LIBBACKTRACE', true, description: 'Is libbacktrace present?')
|
||||
endif
|
||||
|
||||
# Find required bz2 library
|
||||
lib_bz2 = cc.find_library('bz2')
|
||||
|
||||
|
@ -7,7 +7,7 @@ Stack Trace Handler
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef WITH_BACKTRACE
|
||||
#ifdef HAVE_LIBBACKTRACE
|
||||
#include <backtrace.h>
|
||||
#include <backtrace-supported.h>
|
||||
#endif
|
||||
@ -45,46 +45,11 @@ static struct StackTraceLocal
|
||||
int stackSize; // Stack size
|
||||
StackTraceData stack[STACK_TRACE_MAX]; // Stack data
|
||||
char functionParamBuffer[32 * 1024]; // Buffer to hold function parameters
|
||||
} stackTraceLocal;
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
#ifdef WITH_BACKTRACE
|
||||
|
||||
static struct StackTraceBackLocal
|
||||
{
|
||||
#ifdef HAVE_LIBBACKTRACE
|
||||
struct backtrace_state *backTraceState; // Backtrace state struct
|
||||
} stackTraceBackLocal;
|
||||
|
||||
FN_EXTERN void
|
||||
stackTraceInit(const char *exe)
|
||||
{
|
||||
if (stackTraceBackLocal.backTraceState == NULL)
|
||||
stackTraceBackLocal.backTraceState = backtrace_create_state(exe, false, NULL, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
backTraceCallback(void *data, uintptr_t pc, const char *filename, int lineno, const char *function)
|
||||
{
|
||||
(void)(data);
|
||||
(void)(pc);
|
||||
(void)(filename);
|
||||
(void)(function);
|
||||
|
||||
if (stackTraceLocal.stackSize > 0)
|
||||
stackTraceLocal.stack[stackTraceLocal.stackSize - 1].fileLine = (unsigned int)lineno;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
backTraceCallbackError(void *data, const char *msg, int errnum)
|
||||
{
|
||||
(void)data;
|
||||
(void)msg;
|
||||
(void)errnum;
|
||||
}
|
||||
|
||||
#endif
|
||||
} stackTraceLocal;
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
#ifdef DEBUG
|
||||
@ -128,11 +93,6 @@ stackTracePush(const char *fileName, const char *functionName, LogLevel function
|
||||
{
|
||||
ASSERT(stackTraceLocal.stackSize < STACK_TRACE_MAX - 1);
|
||||
|
||||
// Get line number from backtrace if available
|
||||
#ifdef WITH_BACKTRACE
|
||||
backtrace_full(stackTraceBackLocal.backTraceState, 2, backTraceCallback, backTraceCallbackError, NULL);
|
||||
#endif
|
||||
|
||||
// Set function info
|
||||
StackTraceData *data = &stackTraceLocal.stack[stackTraceLocal.stackSize];
|
||||
|
||||
@ -303,16 +263,118 @@ stackTraceFmt(char *buffer, size_t bufferSize, size_t bufferUsed, const char *fo
|
||||
return (size_t)result;
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Helper to trim off extra path before the src path
|
||||
***********************************************************************************************************************************/
|
||||
static const char *
|
||||
stackTraceTrimSrc(const char *const fileName)
|
||||
{
|
||||
const char *const src = strstr(fileName, "src/");
|
||||
return src == NULL ? fileName : src + 4;
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
FN_EXTERN size_t
|
||||
stackTraceToZ(char *buffer, size_t bufferSize, const char *fileName, const char *functionName, unsigned int fileLine)
|
||||
#ifdef HAVE_LIBBACKTRACE
|
||||
|
||||
typedef struct StackTraceBackData
|
||||
{
|
||||
bool firstCall;
|
||||
bool firstLine;
|
||||
int stackIdx;
|
||||
size_t result;
|
||||
char *const buffer;
|
||||
const size_t bufferSize;
|
||||
} StackTraceBackData;
|
||||
|
||||
// Callback to add backtrace data when available
|
||||
static int
|
||||
stackTraceBackCallback(
|
||||
void *const dataVoid, const uintptr_t pc, const char *fileName, const int fileLine, const char *const functionName)
|
||||
{
|
||||
(void)(pc);
|
||||
StackTraceBackData *const data = dataVoid;
|
||||
|
||||
// Stop if the stack has been exhausted
|
||||
if (data->stackIdx < 0)
|
||||
return true;
|
||||
|
||||
// Catch any unset parameters which indicates the debug data is not available
|
||||
if (fileName == NULL || fileLine == 0 || functionName == NULL)
|
||||
{
|
||||
// If this is the first call then stop because the top of the backtrace must be one of our functions
|
||||
if (data->firstCall)
|
||||
return true;
|
||||
|
||||
// Else return but do not stop
|
||||
data->firstCall = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Reset first call
|
||||
data->firstCall = false;
|
||||
|
||||
// If the function name matches combine backtrace data with stack data
|
||||
const StackTraceData *const traceData = &stackTraceLocal.stack[data->stackIdx];
|
||||
|
||||
if (strcmp(functionName, traceData->functionName) == 0)
|
||||
{
|
||||
data->result += stackTraceFmt(
|
||||
data->buffer, data->bufferSize, data->result, "%s%s:%s:%d:(%s)", data->firstLine ? "" : "\n",
|
||||
stackTraceTrimSrc(traceData->fileName), functionName, fileLine, stackTraceParamIdx(data->stackIdx));
|
||||
|
||||
data->stackIdx--;
|
||||
}
|
||||
// Else just use stack data. Skip any functions in the error module since they are not useful for the user
|
||||
else
|
||||
{
|
||||
fileName = stackTraceTrimSrc(fileName);
|
||||
|
||||
if (strcmp(fileName, "common/error.c") == 0)
|
||||
return false;
|
||||
|
||||
data->result += stackTraceFmt(
|
||||
data->buffer, data->bufferSize, data->result, "%s%s:%s:%d:(no parameters available)", data->firstLine ? "" : "\n",
|
||||
fileName, functionName, fileLine);
|
||||
}
|
||||
|
||||
// Reset first line
|
||||
data->firstLine = false;
|
||||
|
||||
// Stop when the main function has been processed
|
||||
return strcmp(functionName, "main") == 0;
|
||||
}
|
||||
|
||||
// Dummy error callback. If there is an error just generate the default stack trace.
|
||||
static void
|
||||
stackTraceBackErrorCallback(void *data, const char *msg, int errnum)
|
||||
{
|
||||
(void)data;
|
||||
(void)msg;
|
||||
(void)errnum;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Helper to build stack trace when backtrace is not available
|
||||
#ifdef HAVE_LIBBACKTRACE
|
||||
static size_t
|
||||
stackTraceToZDefault(
|
||||
#else
|
||||
FN_EXTERN size_t
|
||||
stackTraceToZ(
|
||||
#endif // HAVE_LIBBACKTRACE
|
||||
|
||||
char *const buffer, const size_t bufferSize, const char *fileName, const char *const functionName,
|
||||
const unsigned int fileLine)
|
||||
{
|
||||
size_t result = 0;
|
||||
const char *param = "test build required for parameters";
|
||||
int stackIdx = stackTraceLocal.stackSize - 1;
|
||||
|
||||
// If the current function passed in is the same as the top function on the stack then use the parameters for that function
|
||||
if (stackTraceLocal.stackSize > 0 && strcmp(fileName, stackTraceLocal.stack[stackIdx].fileName) == 0 &&
|
||||
fileName = stackTraceTrimSrc(fileName);
|
||||
|
||||
if (stackTraceLocal.stackSize > 0 && strcmp(fileName, stackTraceTrimSrc(stackTraceLocal.stack[stackIdx].fileName)) == 0 &&
|
||||
strcmp(functionName, stackTraceLocal.stack[stackIdx].functionName) == 0)
|
||||
{
|
||||
param = stackTraceParamIdx(stackTraceLocal.stackSize - 1);
|
||||
@ -332,9 +394,9 @@ stackTraceToZ(char *buffer, size_t bufferSize, const char *fileName, const char
|
||||
// Output the rest of the stack
|
||||
for (; stackIdx >= 0; stackIdx--)
|
||||
{
|
||||
StackTraceData *data = &stackTraceLocal.stack[stackIdx];
|
||||
const StackTraceData *const data = &stackTraceLocal.stack[stackIdx];
|
||||
|
||||
result += stackTraceFmt(buffer, bufferSize, result, "\n%s:%s", data->fileName, data->functionName);
|
||||
result += stackTraceFmt(buffer, bufferSize, result, "\n%s:%s", stackTraceTrimSrc(data->fileName), data->functionName);
|
||||
|
||||
if (data->fileLine > 0)
|
||||
result += stackTraceFmt(buffer, bufferSize, result, ":%u", data->fileLine);
|
||||
@ -346,6 +408,38 @@ stackTraceToZ(char *buffer, size_t bufferSize, const char *fileName, const char
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBBACKTRACE
|
||||
|
||||
FN_EXTERN size_t
|
||||
stackTraceToZ(
|
||||
char *const buffer, const size_t bufferSize, const char *const fileName, const char *const functionName,
|
||||
const unsigned int fileLine)
|
||||
{
|
||||
// Attempt to use backtrace data
|
||||
StackTraceBackData data =
|
||||
{
|
||||
.firstCall = true,
|
||||
.firstLine = true,
|
||||
.stackIdx = stackTraceLocal.stackSize - 1,
|
||||
.result = 0,
|
||||
.buffer = buffer,
|
||||
.bufferSize = bufferSize,
|
||||
};
|
||||
|
||||
if (stackTraceLocal.backTraceState == NULL)
|
||||
stackTraceLocal.backTraceState = backtrace_create_state(NULL, false, NULL, NULL);
|
||||
|
||||
backtrace_full(stackTraceLocal.backTraceState, 2, stackTraceBackCallback, stackTraceBackErrorCallback, &data);
|
||||
|
||||
// If the backtrace was not available generate default stack trace
|
||||
if (data.result == 0)
|
||||
return stackTraceToZDefault(buffer, bufferSize, fileName, functionName, fileLine);
|
||||
|
||||
return data.result;
|
||||
}
|
||||
|
||||
#endif // HAVE_LIBBACKTRACE
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
FN_EXTERN void
|
||||
stackTraceClean(const unsigned int tryDepth, const bool fatal)
|
||||
|
@ -31,11 +31,6 @@ Macros to access internal functions
|
||||
/***********************************************************************************************************************************
|
||||
Internal Functions
|
||||
***********************************************************************************************************************************/
|
||||
// Backtrace init
|
||||
#ifdef WITH_BACKTRACE
|
||||
void stackTraceInit(const char *exe);
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
// Enable/disable test function logging
|
||||
FN_EXTERN void stackTraceTestStart(void);
|
||||
|
@ -73,10 +73,6 @@ main(int argListSize, const char *argList[])
|
||||
|
||||
storageHelperInit(storageHelperList);
|
||||
|
||||
#ifdef WITH_BACKTRACE
|
||||
stackTraceInit(argList[0]);
|
||||
#endif
|
||||
|
||||
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||
FUNCTION_LOG_PARAM(INT, argListSize);
|
||||
FUNCTION_LOG_PARAM(CHARPY, argList);
|
||||
|
@ -93,6 +93,7 @@ build_code = executable(
|
||||
src_common,
|
||||
src_build_code,
|
||||
dependencies: [
|
||||
lib_backtrace,
|
||||
lib_bz2,
|
||||
lib_xml,
|
||||
lib_yaml
|
||||
@ -253,6 +254,7 @@ executable(
|
||||
help_auto_c_inc,
|
||||
interface_auto_c_inc,
|
||||
dependencies : [
|
||||
lib_backtrace,
|
||||
lib_bz2,
|
||||
lib_openssl,
|
||||
lib_lz4,
|
||||
|
@ -69,7 +69,6 @@ sub new
|
||||
$self->{bCoverageUnit},
|
||||
$self->{bCoverageSummary},
|
||||
$self->{bOptimize},
|
||||
$self->{bBackTrace},
|
||||
$self->{bProfile},
|
||||
$self->{iScale},
|
||||
$self->{strTimeZone},
|
||||
@ -102,7 +101,6 @@ sub new
|
||||
{name => 'bCoverageUnit'},
|
||||
{name => 'bCoverageSummary'},
|
||||
{name => 'bOptimize'},
|
||||
{name => 'bBackTrace'},
|
||||
{name => 'bProfile'},
|
||||
{name => 'iScale'},
|
||||
{name => 'strTimeZone', required => false},
|
||||
|
@ -44,8 +44,6 @@ use constant VMDEF_PGSQL_BIN => 'psql-bin
|
||||
push @EXPORT, qw(VMDEF_PGSQL_BIN);
|
||||
use constant VMDEF_LCOV_VERSION => 'lcov-version';
|
||||
push @EXPORT, qw(VMDEF_LCOV_VERSION);
|
||||
use constant VMDEF_WITH_BACKTRACE => 'with-backtrace';
|
||||
push @EXPORT, qw(VMDEF_WITH_BACKTRACE);
|
||||
use constant VMDEF_WITH_LZ4 => 'with-lz4';
|
||||
push @EXPORT, qw(VMDEF_WITH_LZ4);
|
||||
use constant VMDEF_WITH_ZST => 'with-zst';
|
||||
@ -191,7 +189,6 @@ my $oyVm =
|
||||
&VM_ARCH => VM_ARCH_I386,
|
||||
&VMDEF_PGSQL_BIN => '/usr/lib/postgresql/{[version]}/bin',
|
||||
|
||||
&VMDEF_WITH_BACKTRACE => true,
|
||||
&VMDEF_WITH_ZST => true,
|
||||
|
||||
&VM_DB =>
|
||||
@ -218,7 +215,6 @@ my $oyVm =
|
||||
&VMDEF_COVERAGE_C => true,
|
||||
&VMDEF_PGSQL_BIN => '/usr/lib/postgresql/{[version]}/bin',
|
||||
|
||||
&VMDEF_WITH_BACKTRACE => true,
|
||||
&VMDEF_WITH_ZST => true,
|
||||
|
||||
&VM_DB =>
|
||||
@ -252,7 +248,6 @@ my $oyVm =
|
||||
&VMDEF_COVERAGE_C => true,
|
||||
&VMDEF_PGSQL_BIN => '/usr/lib/postgresql/{[version]}/bin',
|
||||
|
||||
&VMDEF_WITH_BACKTRACE => true,
|
||||
&VMDEF_WITH_ZST => true,
|
||||
|
||||
&VM_DB =>
|
||||
@ -433,18 +428,6 @@ sub hostArch
|
||||
|
||||
push @EXPORT, qw(hostArch);
|
||||
|
||||
####################################################################################################################################
|
||||
# Does the VM support libbacktrace?
|
||||
####################################################################################################################################
|
||||
sub vmWithBackTrace
|
||||
{
|
||||
my $strVm = shift;
|
||||
|
||||
return ($oyVm->{$strVm}{&VMDEF_WITH_BACKTRACE} ? true : false);
|
||||
}
|
||||
|
||||
push @EXPORT, qw(vmWithBackTrace);
|
||||
|
||||
####################################################################################################################################
|
||||
# Does the VM support liblz4?
|
||||
####################################################################################################################################
|
||||
|
@ -533,6 +533,7 @@ testBldUnit(TestBuild *const this)
|
||||
" '%s/test/src',\n"
|
||||
" ),\n"
|
||||
" dependencies: [\n"
|
||||
" lib_backtrace,\n"
|
||||
" lib_bz2,\n"
|
||||
" lib_openssl,\n"
|
||||
" lib_lz4,\n"
|
||||
|
@ -7,13 +7,6 @@ C Debug Harness
|
||||
#ifdef HRN_FEATURE_DEBUG
|
||||
#include "common/debug.h"
|
||||
|
||||
#ifdef WITH_BACKTRACE
|
||||
#define FUNCTION_HARNESS_INIT(exe) \
|
||||
stackTraceInit(exe)
|
||||
#else
|
||||
#define FUNCTION_HARNESS_INIT(exe)
|
||||
#endif
|
||||
|
||||
// Set line numer of the current function in the stack trace. This is used to give more detailed info about which test macro
|
||||
// caused an error.
|
||||
#ifdef DEBUG
|
||||
@ -61,7 +54,6 @@ C Debug Harness
|
||||
#define FUNCTION_HARNESS_RETURN_VOID() \
|
||||
STACK_TRACE_POP(false);
|
||||
#else
|
||||
#define FUNCTION_HARNESS_INIT(exe)
|
||||
#define FUNCTION_HARNESS_STACK_TRACE_LINE_SET(lineNo)
|
||||
#define FUNCTION_HARNESS_BEGIN()
|
||||
#define FUNCTION_HARNESS_PARAM(typeMacroPrefix, param)
|
||||
|
@ -64,6 +64,7 @@ executable(
|
||||
arg_unity,
|
||||
],
|
||||
dependencies: [
|
||||
lib_backtrace,
|
||||
lib_bz2,
|
||||
lib_yaml,
|
||||
],
|
||||
|
@ -253,7 +253,7 @@ testRun(void)
|
||||
assert(
|
||||
strcmp(
|
||||
errorStackTrace(),
|
||||
TEST_PGB_PATH "/test/src/module/common/errorTest.c:testTryRecurse:29:(test build required for parameters)")
|
||||
"module/common/errorTest.c:testTryRecurse:29:(test build required for parameters)")
|
||||
== 0);
|
||||
assert(strcmp(errorMessage(), "too many nested try blocks") == 0);
|
||||
assert(strcmp(errorName(), AssertError.name) == 0);
|
||||
|
@ -3,6 +3,43 @@ Test Stack Trace Handler
|
||||
***********************************************************************************************************************************/
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef HAVE_LIBBACKTRACE
|
||||
|
||||
FN_NO_RETURN void
|
||||
testStackTraceError3(void)
|
||||
{
|
||||
stackTracePush("module/common/stackTraceTest.c", "testStackTraceError3", logLevelTrace);
|
||||
THROW(FormatError, "test error");
|
||||
}
|
||||
|
||||
FN_NO_RETURN void
|
||||
testStackTraceError2(void)
|
||||
{
|
||||
testStackTraceError3();
|
||||
}
|
||||
|
||||
FN_NO_RETURN void
|
||||
testStackTraceError1(void)
|
||||
{
|
||||
stackTracePush("src/file1.c", "testStackTraceError1", logLevelDebug);
|
||||
testStackTraceError2();
|
||||
}
|
||||
|
||||
FN_NO_RETURN void
|
||||
testStackTraceError5(void)
|
||||
{
|
||||
THROW_FMT(FormatError, "test error fmt");
|
||||
}
|
||||
|
||||
FN_NO_RETURN void
|
||||
testStackTraceError4(void)
|
||||
{
|
||||
stackTracePush("file4.c", "testStackTraceError4", logLevelTrace);
|
||||
testStackTraceError5();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Test Run
|
||||
***********************************************************************************************************************************/
|
||||
@ -25,19 +62,107 @@ testRun(void)
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************************
|
||||
if (testBegin("stackTraceInit() and stackTraceError()"))
|
||||
if (testBegin("libBackTrace"))
|
||||
{
|
||||
#ifdef WITH_BACKTRACE
|
||||
stackTraceInit(BOGUS_STR);
|
||||
#ifdef HAVE_LIBBACKTRACE
|
||||
// *************************************************************************************************************************
|
||||
TEST_TITLE("empty error function");
|
||||
|
||||
// This time does nothing
|
||||
stackTraceInit(BOGUS_STR);
|
||||
TEST_RESULT_VOID(stackTraceBackErrorCallback(NULL, NULL, 0), "call error");
|
||||
|
||||
// This will call the error routine since we passed a bogus exe
|
||||
assert(stackTracePush("file1.c", "function1", logLevelDebug) == logLevelDebug);
|
||||
stackTracePop("file1.c", "function1", false);
|
||||
// *************************************************************************************************************************
|
||||
TEST_TITLE("missing backtrace data");
|
||||
|
||||
stackTraceLocal.backTraceState = NULL;
|
||||
StackTraceBackData data =
|
||||
{
|
||||
.firstCall = true,
|
||||
};
|
||||
|
||||
TEST_RESULT_INT(stackTraceBackCallback(&data, 0, NULL, 0, NULL), true, "all null, first call");
|
||||
|
||||
data.firstCall = false;
|
||||
|
||||
TEST_RESULT_INT(stackTraceBackCallback(&data, 0, "fileName", 0, NULL), false, "two null");
|
||||
TEST_RESULT_INT(stackTraceBackCallback(&data, 0, "fileName", 2, NULL), false, "one null");
|
||||
|
||||
// Note that it is possible for libbacktrace to be present but not have any debug symbols to work with so handle that by
|
||||
// looking for an alternative error. However this will not work when coverage is required.
|
||||
// *************************************************************************************************************************
|
||||
TEST_TITLE("backtrace data");
|
||||
|
||||
TRY_BEGIN()
|
||||
{
|
||||
testStackTraceError1();
|
||||
}
|
||||
CATCH_ANY()
|
||||
{
|
||||
TRY_BEGIN()
|
||||
{
|
||||
TEST_RESULT_Z(
|
||||
errorStackTrace(),
|
||||
"module/common/stackTraceTest.c:testStackTraceError3:12:(trace log level required for parameters)\n"
|
||||
"module/common/stackTraceTest.c:testStackTraceError2:18:(no parameters available)\n"
|
||||
"file1.c:testStackTraceError1:25:(debug log level required for parameters)",
|
||||
"check stack trace");
|
||||
}
|
||||
CATCH(TestError)
|
||||
{
|
||||
hrnTestResultEnd();
|
||||
|
||||
TRY_BEGIN()
|
||||
{
|
||||
testStackTraceError1();
|
||||
}
|
||||
CATCH_ANY()
|
||||
{
|
||||
TEST_RESULT_Z(
|
||||
errorStackTrace(),
|
||||
"module/common/stackTraceTest.c:testStackTraceError3:12:(trace log level required for parameters)\n"
|
||||
"file1.c:testStackTraceError1:(debug log level required for parameters)",
|
||||
"check stack trace");
|
||||
}
|
||||
TRY_END();
|
||||
}
|
||||
TRY_END();
|
||||
}
|
||||
TRY_END();
|
||||
|
||||
TRY_BEGIN()
|
||||
{
|
||||
testStackTraceError4();
|
||||
}
|
||||
CATCH_ANY()
|
||||
{
|
||||
TRY_BEGIN()
|
||||
{
|
||||
TEST_RESULT_Z(
|
||||
errorStackTrace(),
|
||||
"module/common/stackTraceTest.c:testStackTraceError5:31:(no parameters available)\n"
|
||||
"file4.c:testStackTraceError4:38:(trace log level required for parameters)",
|
||||
"check stack trace");
|
||||
}
|
||||
CATCH(TestError)
|
||||
{
|
||||
hrnTestResultEnd();
|
||||
|
||||
TRY_BEGIN()
|
||||
{
|
||||
testStackTraceError4();
|
||||
}
|
||||
CATCH_ANY()
|
||||
{
|
||||
TEST_RESULT_Z(
|
||||
errorStackTrace(),
|
||||
"module/common/stackTraceTest.c:testStackTraceError5:31:(test build required for parameters)\n"
|
||||
" ... function(s) omitted ...\n"
|
||||
"file4.c:testStackTraceError4:(trace log level required for parameters)",
|
||||
"check stack trace");
|
||||
}
|
||||
TRY_END();
|
||||
}
|
||||
TRY_END();
|
||||
}
|
||||
TRY_END();
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -65,9 +190,6 @@ testRun(void)
|
||||
{
|
||||
char buffer[4096];
|
||||
|
||||
#ifdef WITH_BACKTRACE
|
||||
stackTraceInit(testExe());
|
||||
#endif
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("check size of StackTraceData");
|
||||
|
||||
@ -94,7 +216,12 @@ testRun(void)
|
||||
stackTraceParamLog();
|
||||
assert(strcmp(stackTraceParam(), "void") == 0);
|
||||
|
||||
stackTraceToZ(buffer, sizeof(buffer), "file1.c", "function2", 99);
|
||||
#ifdef HAVE_LIBBACKTRACE
|
||||
stackTraceToZDefault(
|
||||
#else
|
||||
stackTraceToZ(
|
||||
#endif
|
||||
buffer, sizeof(buffer), "file1.c", "function2", 99);
|
||||
|
||||
TEST_RESULT_Z(
|
||||
buffer,
|
||||
@ -135,7 +262,7 @@ testRun(void)
|
||||
// Munge the previous previous param in the stack so that the next one will just barely fit
|
||||
stackTraceLocal.stack[stackTraceLocal.stackSize - 1].paramSize = bufferOverflow - 1;
|
||||
|
||||
assert(stackTracePush("file4.c", "function4", logLevelDebug) == logLevelTrace);
|
||||
assert(stackTracePush("src/file4.c", "function4", logLevelDebug) == logLevelTrace);
|
||||
stackTraceLocal.stack[stackTraceLocal.stackSize - 2].fileLine = 7777;
|
||||
stackTraceParamLog();
|
||||
assert(stackTraceLocal.stackSize == 5);
|
||||
@ -150,7 +277,12 @@ testRun(void)
|
||||
stackTraceParamAdd((size_t)snprintf(stackTraceParamBuffer("param1"), STACK_TRACE_PARAM_MAX, "value1"));
|
||||
assert(strcmp(stackTraceParam(), "buffer full - parameters not available") == 0);
|
||||
|
||||
stackTraceToZ(buffer, sizeof(buffer), "file4.c", "function4", 99);
|
||||
#ifdef HAVE_LIBBACKTRACE
|
||||
stackTraceToZDefault(
|
||||
#else
|
||||
stackTraceToZ(
|
||||
#endif
|
||||
buffer, sizeof(buffer), "../pgbackrest/src/file4.c", "function4", 99);
|
||||
|
||||
TEST_RESULT_Z(
|
||||
buffer,
|
||||
@ -161,7 +293,25 @@ testRun(void)
|
||||
"file1.c:function1:7777:(void)",
|
||||
"stack trace");
|
||||
|
||||
stackTracePop("file4.c", "function4", false);
|
||||
#ifdef HAVE_LIBBACKTRACE
|
||||
stackTraceToZDefault(
|
||||
#else
|
||||
stackTraceToZ(
|
||||
#endif
|
||||
buffer, sizeof(buffer), "file5.c", "function4", 99);
|
||||
|
||||
TEST_RESULT_Z(
|
||||
buffer,
|
||||
"file5.c:function4:99:(test build required for parameters)\n"
|
||||
" ... function(s) omitted ...\n"
|
||||
"file4.c:function4:(buffer full - parameters not available)\n"
|
||||
"file3.c:function3:7777:(param1: value1, param2: value2)\n"
|
||||
"file2.c:function2:7777:(param1: value1)\n"
|
||||
"file1.c:function2:7777:(debug log level required for parameters)\n"
|
||||
"file1.c:function1:7777:(void)",
|
||||
"stack trace");
|
||||
|
||||
stackTracePop("src/file4.c", "function4", false);
|
||||
assert(stackTraceLocal.stackSize == 4);
|
||||
|
||||
// Check that stackTracePop() works with test tracing
|
||||
|
@ -295,6 +295,7 @@ testRun(void)
|
||||
" '../../../repo/test/src',\n"
|
||||
" ),\n"
|
||||
" dependencies: [\n"
|
||||
" lib_backtrace,\n"
|
||||
" lib_bz2,\n"
|
||||
" lib_openssl,\n"
|
||||
" lib_lz4,\n"
|
||||
@ -399,6 +400,7 @@ testRun(void)
|
||||
" '../../../repo/test/src',\n"
|
||||
" ),\n"
|
||||
" dependencies: [\n"
|
||||
" lib_backtrace,\n"
|
||||
" lib_bz2,\n"
|
||||
" lib_openssl,\n"
|
||||
" lib_lz4,\n"
|
||||
@ -605,6 +607,7 @@ testRun(void)
|
||||
" '../../../repo/test/src',\n"
|
||||
" ),\n"
|
||||
" dependencies: [\n"
|
||||
" lib_backtrace,\n"
|
||||
" lib_bz2,\n"
|
||||
" lib_openssl,\n"
|
||||
" lib_lz4,\n"
|
||||
@ -764,6 +767,7 @@ testRun(void)
|
||||
" '../../../repo/test/src',\n"
|
||||
" ),\n"
|
||||
" dependencies: [\n"
|
||||
" lib_backtrace,\n"
|
||||
" lib_bz2,\n"
|
||||
" lib_openssl,\n"
|
||||
" lib_lz4,\n"
|
||||
|
@ -151,9 +151,6 @@ main(int argListSize, const char *argList[])
|
||||
exit(25);
|
||||
}
|
||||
|
||||
// Initialize stack trace for the harness
|
||||
FUNCTION_HARNESS_INIT(argList[0]);
|
||||
|
||||
FUNCTION_HARNESS_BEGIN();
|
||||
FUNCTION_HARNESS_PARAM(INT, argListSize);
|
||||
FUNCTION_HARNESS_PARAM(CHARPY, argList);
|
||||
|
15
test/test.pl
15
test/test.pl
@ -84,7 +84,6 @@ test.pl [options]
|
||||
--no-coverage don't run coverage on C unit tests (saves time)
|
||||
--no-coverage-report run coverage but don't generate coverage report (saves time)
|
||||
--no-optimize don't do compile optimization for C (saves compile time)
|
||||
--backtrace enable backtrace when available (adds stack trace line numbers -- very slow)
|
||||
--profile generate profile info
|
||||
--no-debug don't generate a debug build
|
||||
--scale scale performance tests
|
||||
@ -158,7 +157,6 @@ my $bGenOnly = false;
|
||||
my $bGenCheck = false;
|
||||
my $bMinGen = false;
|
||||
my $bCodeCount = false;
|
||||
my $bBackTrace = false;
|
||||
my $bProfile = false;
|
||||
my $bNoValgrind = false;
|
||||
my $bNoOptimize = false;
|
||||
@ -208,7 +206,6 @@ GetOptions ('q|quiet' => \$bQuiet,
|
||||
'gen-check' => \$bGenCheck,
|
||||
'min-gen' => \$bMinGen,
|
||||
'code-count' => \$bCodeCount,
|
||||
'backtrace' => \$bBackTrace,
|
||||
'profile' => \$bProfile,
|
||||
'no-valgrind' => \$bNoValgrind,
|
||||
'no-optimize' => \$bNoOptimize,
|
||||
@ -729,12 +726,9 @@ eval
|
||||
$rhBinBuild->{$strBuildVM} = false;
|
||||
|
||||
# Build configure/compile options and see if they have changed from the previous build
|
||||
my $strCFlags =
|
||||
(vmWithBackTrace($strBuildVM) && $bBackTrace ? ' -DWITH_BACKTRACE' : '') .
|
||||
($bDebugTestTrace ? ' -DDEBUG_TEST_TRACE' : '');
|
||||
my $strLdFlags = vmWithBackTrace($strBuildVM) && $bBackTrace ? '-lbacktrace' : '';
|
||||
my $strCFlags = ($bDebugTestTrace ? ' -DDEBUG_TEST_TRACE' : '');
|
||||
my $strConfigOptions = (vmDebugIntegration($strBuildVM) ? ' --enable-test' : '');
|
||||
my $strBuildFlags = "CFLAGS_EXTRA=${strCFlags}\nLDFLAGS_EXTRA=${strLdFlags}\nCONFIGURE=${strConfigOptions}";
|
||||
my $strBuildFlags = "CFLAGS_EXTRA=${strCFlags}\nCONFIGURE=${strConfigOptions}";
|
||||
my $strBuildFlagFile = "${strBinPath}/${strBuildVM}/build.flags";
|
||||
|
||||
my $bBuildOptionsDiffer = buildPutDiffers($oStorageBackRest, $strBuildFlagFile, $strBuildFlags);
|
||||
@ -760,8 +754,7 @@ eval
|
||||
executeTest(
|
||||
'docker exec -i -u ' . TEST_USER . ' test-build ' .
|
||||
"${strMakeCmd} -s -j ${iBuildMax}" . ($bLogDetail ? '' : ' --silent') .
|
||||
" --directory ${strBuildPath} CFLAGS_EXTRA='${strCFlags}'" .
|
||||
($strLdFlags ne '' ? " LDFLAGS_EXTRA='${strLdFlags}'" : ''),
|
||||
" --directory ${strBuildPath} CFLAGS_EXTRA='${strCFlags}'",
|
||||
{bShowOutputAsync => $bLogDetail});
|
||||
}
|
||||
}
|
||||
@ -1062,7 +1055,7 @@ eval
|
||||
$oStorageTest, $strBackRestBase, $strTestPath, $$oyTestRun[$iTestIdx], $bDryRun, $bVmOut, $iVmIdx, $iVmMax,
|
||||
$strMakeCmd, $iTestIdx, $iTestMax, $strLogLevel, $strLogLevelTest, $strLogLevelTestFile, !$bNoLogTimestamp,
|
||||
$bShowOutputAsync, $bNoCleanup, $iRetry, !$bNoValgrind, !$bNoCoverage, $bCoverageSummary, !$bNoOptimize,
|
||||
$bBackTrace, $bProfile, $iScale, $strTimeZone, !$bNoDebug, $bDebugTestTrace,
|
||||
$bProfile, $iScale, $strTimeZone, !$bNoDebug, $bDebugTestTrace,
|
||||
$iBuildMax / $iVmMax < 1 ? 1 : int($iBuildMax / $iVmMax));
|
||||
$iTestIdx++;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user