2018-02-16 22:37:09 +03:00
/*
* Copyright ( c ) 2013 Luca Clementi < luca . clementi @ gmail . com >
* Copyright ( c ) 2013 - 2018 The strace developers .
*
2018-12-10 03:00:00 +03:00
* SPDX - License - Identifier : LGPL - 2.1 - or - later
2018-02-16 22:37:09 +03:00
*/
# include "defs.h"
# include <limits.h>
2018-02-27 02:22:24 +03:00
# include "largefile_wrappers.h"
2018-02-27 02:22:24 +03:00
# include "mmap_cache.h"
2018-04-30 00:45:37 +03:00
# include "mmap_notify.h"
2018-02-16 22:37:09 +03:00
# include "xstring.h"
static unsigned int mmap_cache_generation ;
2018-02-16 22:37:13 +03:00
2018-04-30 00:45:37 +03:00
static void
mmap_cache_invalidate ( struct tcb * tcp , void * unused )
{
# if SUPPORTED_PERSONALITIES > 1
if ( tcp - > currpers ! = DEFAULT_PERSONALITY ) {
/* disable stack trace */
return ;
}
# endif
mmap_cache_generation + + ;
debug_func_msg ( " tgen=%u, ggen=%u, tcp=%p, cache=%p " ,
2018-05-04 17:45:44 +03:00
tcp - > mmap_cache ? tcp - > mmap_cache - > generation : 0 ,
mmap_cache_generation , tcp ,
tcp - > mmap_cache ? tcp - > mmap_cache - > entry : 0 ) ;
2018-04-30 00:45:37 +03:00
}
void
mmap_cache_enable ( void )
2018-02-16 22:37:13 +03:00
{
2018-05-04 02:43:38 +03:00
static bool use_mmap_cache ;
2018-04-30 00:45:37 +03:00
if ( ! use_mmap_cache ) {
mmap_notify_register_client ( mmap_cache_invalidate , NULL ) ;
use_mmap_cache = true ;
}
2018-02-16 22:37:13 +03:00
}
2018-05-04 17:45:44 +03:00
/* deleting the cache */
static void
delete_mmap_cache ( struct tcb * tcp , const char * caller )
{
debug_func_msg ( " tgen=%u, ggen=%u, tcp=%p, cache=%p, caller=%s " ,
tcp - > mmap_cache ? tcp - > mmap_cache - > generation : 0 ,
mmap_cache_generation , tcp ,
tcp - > mmap_cache ? tcp - > mmap_cache - > entry : 0 , caller ) ;
if ( ! tcp - > mmap_cache )
return ;
while ( tcp - > mmap_cache - > size ) {
unsigned int i = - - tcp - > mmap_cache - > size ;
free ( tcp - > mmap_cache - > entry [ i ] . binary_filename ) ;
tcp - > mmap_cache - > entry [ i ] . binary_filename = NULL ;
}
free ( tcp - > mmap_cache - > entry ) ;
tcp - > mmap_cache - > entry = NULL ;
free ( tcp - > mmap_cache ) ;
tcp - > mmap_cache = NULL ;
}
2018-02-16 22:37:09 +03:00
/*
* caching of / proc / ID / maps for each process to speed up stack tracing
*
* The cache must be refreshed after syscalls that affect memory mappings ,
* e . g . mmap , mprotect , munmap , execve .
*/
2018-05-04 17:45:44 +03:00
extern enum mmap_cache_rebuild_result
mmap_cache_rebuild_if_invalid ( struct tcb * tcp , const char * caller )
2018-02-16 22:37:09 +03:00
{
2018-05-04 17:45:44 +03:00
if ( tcp - > mmap_cache
& & tcp - > mmap_cache - > generation ! = mmap_cache_generation )
delete_mmap_cache ( tcp , caller ) ;
2018-02-16 22:37:09 +03:00
2018-05-04 17:45:44 +03:00
if ( tcp - > mmap_cache )
return MMAP_CACHE_REBUILD_READY ;
char filename [ sizeof ( " /proc/4294967296/maps " ) ] ;
2018-02-16 22:37:09 +03:00
xsprintf ( filename , " /proc/%u/maps " , tcp - > pid ) ;
2018-05-04 17:45:44 +03:00
FILE * fp = fopen_stream ( filename , " r " ) ;
2018-02-16 22:37:09 +03:00
if ( ! fp ) {
perror_msg ( " fopen: %s " , filename ) ;
2018-05-04 17:45:44 +03:00
return MMAP_CACHE_REBUILD_NOCACHE ;
2018-02-16 22:37:09 +03:00
}
2018-05-04 17:45:44 +03:00
struct mmap_cache_t cache = {
. free_fn = delete_mmap_cache ,
. generation = mmap_cache_generation
} ;
/* start with a small dynamically-allocated array and then expand it */
size_t allocated = 0 ;
char buffer [ PATH_MAX + 80 ] ;
2018-05-02 21:20:38 +03:00
2018-02-16 22:37:09 +03:00
while ( fgets ( buffer , sizeof ( buffer ) , fp ) ! = NULL ) {
unsigned long start_addr , end_addr , mmap_offset ;
2018-02-16 22:37:11 +03:00
char read_bit ;
char write_bit ;
2018-02-16 22:37:09 +03:00
char exec_bit ;
2018-02-16 22:37:11 +03:00
char shared_bit ;
2018-02-16 22:37:14 +03:00
unsigned long major , minor ;
2018-02-16 22:37:09 +03:00
char binary_path [ sizeof ( buffer ) ] ;
2018-02-16 22:37:14 +03:00
if ( sscanf ( buffer , " %lx-%lx %c%c%c%c %lx %lx:%lx %*d %[^ \n ] " ,
2018-02-16 22:37:11 +03:00
& start_addr , & end_addr ,
& read_bit , & write_bit , & exec_bit , & shared_bit ,
2018-02-16 22:37:14 +03:00
& mmap_offset ,
& major , & minor ,
binary_path ) ! = 10 )
2018-02-16 22:37:09 +03:00
continue ;
2018-02-16 22:37:11 +03:00
/* skip mappings that have unknown protection */
if ( ! ( read_bit = = ' - ' | | read_bit = = ' r ' ) )
continue ;
if ( ! ( write_bit = = ' - ' | | write_bit = = ' w ' ) )
continue ;
if ( ! ( exec_bit = = ' - ' | | exec_bit = = ' x ' ) )
continue ;
if ( ! ( shared_bit = = ' p ' | | shared_bit = = ' s ' ) )
2018-02-16 22:37:09 +03:00
continue ;
if ( end_addr < start_addr ) {
error_msg ( " %s: unrecognized file format " , filename ) ;
break ;
}
2018-05-04 17:45:44 +03:00
struct mmap_cache_entry_t * entry ;
2018-02-16 22:37:09 +03:00
/*
* sanity check to make sure that we ' re storing
* non - overlapping regions in ascending order
*/
2018-05-04 17:45:44 +03:00
if ( cache . size > 0 ) {
entry = & cache . entry [ cache . size - 1 ] ;
2018-02-16 22:37:09 +03:00
if ( entry - > start_addr = = start_addr & &
entry - > end_addr = = end_addr ) {
/* duplicate entry, e.g. [vsyscall] */
continue ;
}
if ( start_addr < = entry - > start_addr | |
start_addr < entry - > end_addr ) {
debug_msg ( " %s: overlapping memory region: "
" \" %s \" [%08lx-%08lx] overlaps with "
" \" %s \" [%08lx-%08lx] " ,
filename , binary_path , start_addr ,
end_addr , entry - > binary_filename ,
entry - > start_addr , entry - > end_addr ) ;
continue ;
}
}
2018-05-04 17:45:44 +03:00
if ( cache . size > = allocated )
cache . entry = xgrowarray ( cache . entry , & allocated ,
sizeof ( * cache . entry ) ) ;
2018-02-16 22:37:09 +03:00
2018-05-04 17:45:44 +03:00
entry = & cache . entry [ cache . size ] ;
2018-02-16 22:37:09 +03:00
entry - > start_addr = start_addr ;
entry - > end_addr = end_addr ;
entry - > mmap_offset = mmap_offset ;
2018-02-16 22:37:11 +03:00
entry - > protections = (
0
| ( ( read_bit = = ' r ' ) ? MMAP_CACHE_PROT_READABLE : 0 )
| ( ( write_bit = = ' w ' ) ? MMAP_CACHE_PROT_WRITABLE : 0 )
| ( ( exec_bit = = ' x ' ) ? MMAP_CACHE_PROT_EXECUTABLE : 0 )
| ( ( shared_bit = = ' s ' ) ? MMAP_CACHE_PROT_SHARED : 0 )
) ;
2018-02-16 22:37:14 +03:00
entry - > major = major ;
entry - > minor = minor ;
2018-02-16 22:37:09 +03:00
entry - > binary_filename = xstrdup ( binary_path ) ;
2018-05-04 17:45:44 +03:00
cache . size + + ;
2018-02-16 22:37:09 +03:00
}
fclose ( fp ) ;
2018-05-04 17:45:44 +03:00
if ( ! cache . size )
return MMAP_CACHE_REBUILD_NOCACHE ;
2018-02-16 22:37:09 +03:00
2018-05-04 17:45:44 +03:00
tcp - > mmap_cache = xmalloc ( sizeof ( * tcp - > mmap_cache ) ) ;
memcpy ( tcp - > mmap_cache , & cache , sizeof ( cache ) ) ;
2018-02-16 22:37:09 +03:00
debug_func_msg ( " tgen=%u, ggen=%u, tcp=%p, cache=%p, caller=%s " ,
2018-05-04 17:45:44 +03:00
tcp - > mmap_cache - > generation , mmap_cache_generation ,
tcp , tcp - > mmap_cache - > entry , caller ) ;
2018-02-16 22:37:09 +03:00
2018-05-04 17:45:44 +03:00
return MMAP_CACHE_REBUILD_RENEWED ;
2018-02-16 22:37:09 +03:00
}
2018-05-04 17:45:44 +03:00
struct mmap_cache_entry_t *
2018-02-16 22:37:10 +03:00
mmap_cache_search ( struct tcb * tcp , unsigned long ip )
{
2018-05-04 17:45:44 +03:00
if ( ! tcp - > mmap_cache )
return NULL ;
2018-02-16 22:37:10 +03:00
int lower = 0 ;
2018-05-04 17:45:44 +03:00
int upper = ( int ) tcp - > mmap_cache - > size - 1 ;
2018-02-16 22:37:10 +03:00
while ( lower < = upper ) {
int mid = ( upper + lower ) / 2 ;
2018-05-04 17:45:44 +03:00
struct mmap_cache_entry_t * entry = & tcp - > mmap_cache - > entry [ mid ] ;
2018-02-16 22:37:10 +03:00
2018-05-04 17:45:44 +03:00
if ( ip > = entry - > start_addr & &
ip < entry - > end_addr )
return entry ;
else if ( ip < entry - > start_addr )
2018-02-16 22:37:10 +03:00
upper = mid - 1 ;
else
lower = mid + 1 ;
}
return NULL ;
}
2018-07-07 10:49:10 +03:00
struct mmap_cache_entry_t *
mmap_cache_search_custom ( struct tcb * tcp , mmap_cache_search_fn fn , void * data )
{
for ( unsigned int i = 0 ; i < tcp - > mmap_cache - > size ; i + + ) {
if ( fn ( tcp - > mmap_cache - > entry + i , data ) )
return tcp - > mmap_cache - > entry + i ;
}
return NULL ;
}