2013-07-23 00:11:35 -07:00
/*
* Copyright ( c ) 2013 Luca Clementi < luca . clementi @ gmail . com >
2018-02-13 22:00:00 +00:00
* Copyright ( c ) 2013 - 2018 The strace developers .
2013-07-23 00:11:35 -07:00
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ` ` AS IS ' ' AND ANY EXPRESS OR
* IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED .
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
* INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
* NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
# include "defs.h"
2018-03-14 02:28:10 +09:00
# include "unwind.h"
2013-07-23 00:11:35 -07:00
2017-12-18 13:24:55 +09:00
# ifdef USE_DEMANGLE
2018-01-09 20:23:01 +01:00
# if defined HAVE_DEMANGLE_H
# include <demangle.h>
# elif defined HAVE_LIBIBERTY_DEMANGLE_H
# include <libiberty / demangle.h>
# endif
2017-12-18 13:24:55 +09:00
# endif
2014-04-16 15:33:06 +09:00
/*
* Type used in stacktrace capturing
*/
struct call_t {
2017-06-17 22:23:09 +00:00
struct call_t * next ;
char * output_line ;
2014-04-16 15:33:06 +09:00
} ;
2018-03-14 02:28:07 +09:00
struct unwind_queue_t {
2017-06-17 22:23:09 +00:00
struct call_t * tail ;
struct call_t * head ;
2014-04-16 15:33:06 +09:00
} ;
2014-04-16 15:33:07 +09:00
2018-03-14 02:28:07 +09:00
static void queue_print ( struct unwind_queue_t * queue ) ;
2014-04-16 15:33:04 +09:00
2017-08-04 08:43:16 +02:00
static const char asprintf_error_str [ ] = " ??? " ;
2013-07-23 00:11:35 -07:00
void
2014-04-16 15:33:02 +09:00
unwind_init ( void )
2013-07-23 00:11:35 -07:00
{
2018-03-14 02:28:10 +09:00
if ( unwinder . init )
unwinder . init ( ) ;
2013-07-23 00:11:35 -07:00
}
void
2014-04-16 15:33:02 +09:00
unwind_tcb_init ( struct tcb * tcp )
2013-07-23 00:11:35 -07:00
{
2018-03-14 02:28:10 +09:00
if ( tcp - > unwind_queue )
2016-12-08 09:54:24 -10:00
return ;
2018-03-14 02:28:07 +09:00
tcp - > unwind_queue = xmalloc ( sizeof ( * tcp - > unwind_queue ) ) ;
tcp - > unwind_queue - > head = NULL ;
tcp - > unwind_queue - > tail = NULL ;
2018-03-14 02:28:10 +09:00
tcp - > unwind_ctx = unwinder . tcb_init ( tcp ) ;
2013-07-23 00:11:35 -07:00
}
void
2014-04-16 15:33:02 +09:00
unwind_tcb_fin ( struct tcb * tcp )
2013-07-23 00:11:35 -07:00
{
2018-04-19 18:03:58 +00:00
if ( ! tcp - > unwind_queue )
return ;
2018-03-14 02:28:07 +09:00
queue_print ( tcp - > unwind_queue ) ;
free ( tcp - > unwind_queue ) ;
tcp - > unwind_queue = NULL ;
2014-04-16 15:33:06 +09:00
2018-03-14 02:28:10 +09:00
unwinder . tcb_fin ( tcp ) ;
2018-03-14 02:28:06 +09:00
tcp - > unwind_ctx = NULL ;
2013-07-23 00:11:35 -07:00
}
2014-04-16 15:33:04 +09:00
/*
2014-04-16 15:33:06 +09:00
* printing an entry in stack to stream or buffer
2014-04-16 15:33:04 +09:00
*/
/*
* we want to keep the format used by backtrace_symbols from the glibc
*
* . / a . out ( ) [ 0x40063d ]
* . / a . out ( ) [ 0x4006bb ]
* . / a . out ( ) [ 0x4006c6 ]
* / lib64 / libc . so .6 ( __libc_start_main + 0xed ) [ 0x7fa2f8a5976d ]
* . / a . out ( ) [ 0x400569 ]
*/
2018-03-14 02:28:10 +09:00
# define STACK_ENTRY_SYMBOL_FMT(SYM) \
2014-04-16 15:33:04 +09:00
" > %s(%s+0x%lx) [0x%lx] \n " , \
binary_filename , \
2018-03-14 02:28:10 +09:00
( SYM ) , \
2014-06-05 21:44:40 +00:00
( unsigned long ) function_offset , \
2014-04-16 15:33:04 +09:00
true_offset
# define STACK_ENTRY_NOSYMBOL_FMT \
" > %s() [0x%lx] \n " , \
binary_filename , true_offset
# define STACK_ENTRY_BUG_FMT \
" > BUG IN %s \n "
# define STACK_ENTRY_ERROR_WITH_OFFSET_FMT \
" > %s [0x%lx] \n " , error , true_offset
# define STACK_ENTRY_ERROR_FMT \
" > %s \n " , error
static void
print_call_cb ( void * dummy ,
2014-06-05 22:37:09 +00:00
const char * binary_filename ,
const char * symbol_name ,
2018-03-14 02:28:10 +09:00
unwind_function_offset_t function_offset ,
2014-04-16 15:33:04 +09:00
unsigned long true_offset )
{
2018-03-14 02:28:10 +09:00
if ( symbol_name & & ( symbol_name [ 0 ] ! = ' \0 ' ) ) {
# ifdef USE_DEMANGLE
char * demangled_name =
cplus_demangle ( symbol_name ,
DMGL_AUTO | DMGL_PARAMS ) ;
# endif
tprintf ( STACK_ENTRY_SYMBOL_FMT (
# ifdef USE_DEMANGLE
demangled_name ? demangled_name :
# endif
symbol_name ) ) ;
# ifdef USE_DEMANGLE
free ( demangled_name ) ;
# endif
}
2014-04-16 15:33:04 +09:00
else if ( binary_filename )
tprintf ( STACK_ENTRY_NOSYMBOL_FMT ) ;
else
2017-06-17 20:39:26 +00:00
tprintf ( STACK_ENTRY_BUG_FMT , __func__ ) ;
2014-04-16 15:33:04 +09:00
line_ended ( ) ;
}
static void
print_error_cb ( void * dummy ,
const char * error ,
unsigned long true_offset )
{
if ( true_offset )
tprintf ( STACK_ENTRY_ERROR_WITH_OFFSET_FMT ) ;
else
tprintf ( STACK_ENTRY_ERROR_FMT ) ;
line_ended ( ) ;
}
2014-04-16 15:33:06 +09:00
static char *
2014-06-05 22:37:09 +00:00
sprint_call_or_error ( const char * binary_filename ,
const char * symbol_name ,
2018-03-14 02:28:10 +09:00
unwind_function_offset_t function_offset ,
2014-04-16 15:33:06 +09:00
unsigned long true_offset ,
const char * error )
{
2017-06-17 22:23:09 +00:00
char * output_line = NULL ;
int n ;
2018-03-14 02:28:10 +09:00
if ( symbol_name ) {
# ifdef USE_DEMANGLE
char * demangled_name =
cplus_demangle ( symbol_name ,
DMGL_AUTO | DMGL_PARAMS ) ;
# endif
n = asprintf ( & output_line ,
STACK_ENTRY_SYMBOL_FMT (
# ifdef USE_DEMANGLE
demangled_name ? demangled_name :
# endif
symbol_name ) ) ;
# ifdef USE_DEMANGLE
free ( demangled_name ) ;
# endif
}
2017-06-17 22:23:09 +00:00
else if ( binary_filename )
n = asprintf ( & output_line , STACK_ENTRY_NOSYMBOL_FMT ) ;
else if ( error )
n = true_offset
? asprintf ( & output_line , STACK_ENTRY_ERROR_WITH_OFFSET_FMT )
: asprintf ( & output_line , STACK_ENTRY_ERROR_FMT ) ;
else
n = asprintf ( & output_line , STACK_ENTRY_BUG_FMT , __func__ ) ;
2017-08-04 08:43:16 +02:00
if ( n < 0 ) {
perror_func_msg ( " asprintf " ) ;
output_line = ( char * ) asprintf_error_str ;
}
2017-06-17 22:23:09 +00:00
return output_line ;
2014-04-16 15:33:06 +09:00
}
/*
* queue manipulators
*/
static void
2018-03-14 02:28:07 +09:00
queue_put ( struct unwind_queue_t * queue ,
2014-06-05 22:37:09 +00:00
const char * binary_filename ,
const char * symbol_name ,
2018-03-14 02:28:10 +09:00
unwind_function_offset_t function_offset ,
2014-04-16 15:33:06 +09:00
unsigned long true_offset ,
const char * error )
{
struct call_t * call ;
Introduce memory allocation wrappers
Introduce wrappers to the following functions that do memory allocation:
malloc, calloc, realloc, strdup.
This commit is a follow-up to the related discussions in strace-devel ML:
http://sourceforge.net/p/strace/mailman/message/33618180/
http://sourceforge.net/p/strace/mailman/message/33733470/
* defs.h (xmalloc, xcalloc, xreallocarray, xstrdup): New prototypes.
* xmalloc.c: New file.
* Makefile.am (strace_SOURCES): Add it.
* count.c (count_syscall, call_summary_pers): Use xcalloc.
* desc.c (decode_select): Use xmalloc.
* dirent.c (sys_getdents, sys_getdents64): Likewise.
* net.c (sys_recvmmsg): Use xstrdup.
* pathtrace.c (storepath): Use xreallocarray.
(pathtrace_match): Use xmalloc.
* strace.c (die_out_of_memory): Move to xmalloc.c.
(expand_tcbtab): Use xcalloc and xreallocarray.
(startup_child): Use xstrdup.
(init): Use xmalloc, xcalloc, and xstrdup.
* syscall.c (reallocate_qual): Use xreallocarray.
(qualify): Use xstrdup.
* unwind.c (unwind_tcb_init): Use xmalloc.
(build_mmap_cache): Use xcalloc, xreallocarray, and xstrdup.
(get_symbol_name): Use xreallocarray.
(stacktrace_walk, queue_put): Use xmalloc.
* util.c (printstr): Use xmalloc.
* vsprintf.c (strace_vfprintf): Likewise.
2015-05-25 20:41:02 +00:00
call = xmalloc ( sizeof ( * call ) ) ;
2014-04-16 15:33:06 +09:00
call - > output_line = sprint_call_or_error ( binary_filename ,
symbol_name ,
2014-06-05 21:44:40 +00:00
function_offset ,
2014-04-16 15:33:06 +09:00
true_offset ,
error ) ;
call - > next = NULL ;
if ( ! queue - > head ) {
queue - > head = call ;
queue - > tail = call ;
} else {
queue - > tail - > next = call ;
queue - > tail = call ;
}
}
static void
queue_put_call ( void * queue ,
2014-06-05 22:37:09 +00:00
const char * binary_filename ,
const char * symbol_name ,
2018-03-14 02:28:10 +09:00
unwind_function_offset_t function_offset ,
2014-04-16 15:33:06 +09:00
unsigned long true_offset )
{
queue_put ( queue ,
binary_filename ,
symbol_name ,
2014-06-05 21:44:40 +00:00
function_offset ,
2014-04-16 15:33:06 +09:00
true_offset ,
NULL ) ;
}
static void
queue_put_error ( void * queue ,
const char * error ,
2014-06-05 14:37:04 +00:00
unsigned long ip )
2014-04-16 15:33:06 +09:00
{
queue_put ( queue , NULL , NULL , 0 , ip , error ) ;
}
static void
2018-03-14 02:28:07 +09:00
queue_print ( struct unwind_queue_t * queue )
2014-04-16 15:33:06 +09:00
{
struct call_t * call , * tmp ;
queue - > tail = NULL ;
call = queue - > head ;
queue - > head = NULL ;
while ( call ) {
tmp = call ;
call = call - > next ;
tprints ( tmp - > output_line ) ;
line_ended ( ) ;
2017-08-04 08:43:16 +02:00
if ( tmp - > output_line ! = asprintf_error_str )
free ( tmp - > output_line ) ;
2014-04-16 15:33:06 +09:00
tmp - > output_line = NULL ;
tmp - > next = NULL ;
free ( tmp ) ;
}
}
2014-04-16 15:33:04 +09:00
/*
* printing stack
*/
void
2018-03-14 02:28:09 +09:00
unwind_tcb_print ( struct tcb * tcp )
2014-04-16 15:33:04 +09:00
{
2014-06-09 22:05:38 -07:00
# if SUPPORTED_PERSONALITIES > 1
if ( tcp - > currpers ! = DEFAULT_PERSONALITY ) {
2017-08-04 08:36:22 +02:00
/* disable stack trace */
2014-06-09 22:05:38 -07:00
return ;
}
# endif
2018-03-14 02:28:07 +09:00
if ( tcp - > unwind_queue - > head ) {
debug_func_msg ( " head: tcp=%p, queue=%p " ,
tcp , tcp - > unwind_queue - > head ) ;
queue_print ( tcp - > unwind_queue ) ;
2018-04-30 06:45:40 +09:00
} else
unwinder . tcb_walk ( tcp , print_call_cb , print_error_cb , NULL ) ;
2014-04-16 15:33:06 +09:00
}
/*
* capturing stack
*/
void
2018-03-14 02:28:09 +09:00
unwind_tcb_capture ( struct tcb * tcp )
2014-04-16 15:33:06 +09:00
{
2014-06-09 22:05:38 -07:00
# if SUPPORTED_PERSONALITIES > 1
if ( tcp - > currpers ! = DEFAULT_PERSONALITY ) {
2017-08-04 08:36:22 +02:00
/* disable stack trace */
2014-06-09 22:05:38 -07:00
return ;
}
# endif
2018-03-14 02:28:07 +09:00
if ( tcp - > unwind_queue - > head )
2014-04-16 15:33:06 +09:00
error_msg_and_die ( " bug: unprinted entries in queue " ) ;
2018-04-30 06:45:40 +09:00
else {
debug_func_msg ( " walk: tcp=%p, queue=%p " ,
2018-03-14 02:28:07 +09:00
tcp , tcp - > unwind_queue - > head ) ;
2018-04-30 06:45:40 +09:00
unwinder . tcb_walk ( tcp , queue_put_call , queue_put_error ,
tcp - > unwind_queue ) ;
2014-04-16 15:33:07 +09:00
}
2014-04-16 15:33:04 +09:00
}