@ -62,6 +62,9 @@
# ifdef HAVE_SYSLOG
# include <syslog.h>
# endif
# ifdef HAVE_EXECINFO_H
# include <execinfo.h>
# endif
# include "access/transam.h"
# include "access/xact.h"
@ -167,6 +170,7 @@ static char formatted_log_time[FORMATTED_TS_LEN];
static const char * err_gettext ( const char * str ) pg_attribute_format_arg ( 1 ) ;
static pg_noinline void set_backtrace ( ErrorData * edata , int num_skip ) ;
static void set_errdata_field ( MemoryContextData * cxt , char * * ptr , const char * str ) ;
static void write_console ( const char * line , int len ) ;
static void setup_formatted_log_time ( void ) ;
@ -398,6 +402,32 @@ errstart(int elevel, const char *filename, int lineno,
return true ;
}
/*
* Checks whether the given funcname matches backtrace_functions ; see
* check_backtrace_functions .
*/
static bool
matches_backtrace_functions ( const char * funcname )
{
char * p ;
if ( ! backtrace_symbol_list | | funcname = = NULL | | funcname [ 0 ] = = ' \0 ' )
return false ;
p = backtrace_symbol_list ;
for ( ; ; )
{
if ( * p = = ' \0 ' ) /* end of backtrace_symbol_list */
break ;
if ( strcmp ( funcname , p ) = = 0 )
return true ;
p + = strlen ( p ) + 1 ;
}
return false ;
}
/*
* errfinish - - - end an error - reporting cycle
*
@ -424,6 +454,12 @@ errfinish(int dummy,...)
*/
oldcontext = MemoryContextSwitchTo ( ErrorContext ) ;
if ( ! edata - > backtrace & &
edata - > funcname & &
backtrace_functions & &
matches_backtrace_functions ( edata - > funcname ) )
set_backtrace ( edata , 2 ) ;
/*
* Call any context callback functions . Errors occurring in callback
* functions will be treated as recursive errors - - - this ensures we will
@ -488,6 +524,8 @@ errfinish(int dummy,...)
pfree ( edata - > hint ) ;
if ( edata - > context )
pfree ( edata - > context ) ;
if ( edata - > backtrace )
pfree ( edata - > backtrace ) ;
if ( edata - > schema_name )
pfree ( edata - > schema_name ) ;
if ( edata - > table_name )
@ -798,6 +836,65 @@ errmsg(const char *fmt,...)
return 0 ; /* return value does not matter */
}
/*
* Add a backtrace to the containing ereport ( ) call . This is intended to be
* added temporarily during debugging .
*/
int
errbacktrace ( void )
{
ErrorData * edata = & errordata [ errordata_stack_depth ] ;
MemoryContext oldcontext ;
Assert ( false ) ;
recursion_depth + + ;
CHECK_STACK_DEPTH ( ) ;
oldcontext = MemoryContextSwitchTo ( edata - > assoc_context ) ;
set_backtrace ( edata , 1 ) ;
MemoryContextSwitchTo ( oldcontext ) ;
recursion_depth - - ;
return 0 ;
}
/*
* Compute backtrace data and add it to the supplied ErrorData . num_skip
* specifies how many inner frames to skip . Use this to avoid showing the
* internal backtrace support functions in the backtrace . This requires that
* this and related functions are not inlined .
*/
static void
set_backtrace ( ErrorData * edata , int num_skip )
{
StringInfoData errtrace ;
initStringInfo ( & errtrace ) ;
# ifdef HAVE_BACKTRACE_SYMBOLS
{
void * buf [ 100 ] ;
int nframes ;
char * * strfrms ;
nframes = backtrace ( buf , lengthof ( buf ) ) ;
strfrms = backtrace_symbols ( buf , nframes ) ;
if ( strfrms = = NULL )
return ;
for ( int i = num_skip ; i < nframes ; i + + )
appendStringInfo ( & errtrace , " \n %s " , strfrms [ i ] ) ;
free ( strfrms ) ;
}
# else
appendStringInfoString ( & errtrace ,
" backtrace generation is not supported by this installation " ) ;
# endif
edata - > backtrace = errtrace . data ;
}
/*
* errmsg_internal - - - add a primary error message text to the current error
@ -1353,6 +1450,11 @@ elog_finish(int elevel, const char *fmt,...)
recursion_depth + + ;
oldcontext = MemoryContextSwitchTo ( edata - > assoc_context ) ;
if ( ! edata - > backtrace & &
edata - > funcname & &
matches_backtrace_functions ( edata - > funcname ) )
set_backtrace ( edata , 2 ) ;
edata - > message_id = fmt ;
EVALUATE_MESSAGE ( edata - > domain , message , false , false ) ;
@ -1509,6 +1611,8 @@ CopyErrorData(void)
newedata - > hint = pstrdup ( newedata - > hint ) ;
if ( newedata - > context )
newedata - > context = pstrdup ( newedata - > context ) ;
if ( newedata - > backtrace )
newedata - > backtrace = pstrdup ( newedata - > backtrace ) ;
if ( newedata - > schema_name )
newedata - > schema_name = pstrdup ( newedata - > schema_name ) ;
if ( newedata - > table_name )
@ -1547,6 +1651,8 @@ FreeErrorData(ErrorData *edata)
pfree ( edata - > hint ) ;
if ( edata - > context )
pfree ( edata - > context ) ;
if ( edata - > backtrace )
pfree ( edata - > backtrace ) ;
if ( edata - > schema_name )
pfree ( edata - > schema_name ) ;
if ( edata - > table_name )
@ -1622,6 +1728,8 @@ ThrowErrorData(ErrorData *edata)
newedata - > hint = pstrdup ( edata - > hint ) ;
if ( edata - > context )
newedata - > context = pstrdup ( edata - > context ) ;
if ( edata - > backtrace )
newedata - > backtrace = pstrdup ( edata - > backtrace ) ;
/* assume message_id is not available */
if ( edata - > schema_name )
newedata - > schema_name = pstrdup ( edata - > schema_name ) ;
@ -1689,6 +1797,8 @@ ReThrowError(ErrorData *edata)
newedata - > hint = pstrdup ( newedata - > hint ) ;
if ( newedata - > context )
newedata - > context = pstrdup ( newedata - > context ) ;
if ( newedata - > backtrace )
newedata - > backtrace = pstrdup ( newedata - > backtrace ) ;
if ( newedata - > schema_name )
newedata - > schema_name = pstrdup ( newedata - > schema_name ) ;
if ( newedata - > table_name )
@ -2914,6 +3024,13 @@ send_message_to_server_log(ErrorData *edata)
append_with_tabs ( & buf , edata - > context ) ;
appendStringInfoChar ( & buf , ' \n ' ) ;
}
if ( edata - > backtrace )
{
log_line_prefix ( & buf , edata ) ;
appendStringInfoString ( & buf , _ ( " BACKTRACE: " ) ) ;
append_with_tabs ( & buf , edata - > backtrace ) ;
appendStringInfoChar ( & buf , ' \n ' ) ;
}
if ( Log_error_verbosity > = PGERROR_VERBOSE )
{
/* assume no newlines in funcname or filename... */