On 06/24/2013 09:18 AM, Luca Clementi wrote:
> This patch prints the stack trace of the traced process after
> each system call when using -k flag. It uses libunwind to
> unwind the stack and to obtain the function name pointed by
> the IP.
>
> Tested on Ubuntu 12.04 64 with the distribution version of
> libunwind (0.99-0.3ubuntu1) and on CentOS 6.3 with libunwind
> form the source code. On Ubuntu you need the libunwind and
> libunwind-dev package to compile the stack trace feature in
> the code.
> 
> This is still a development patch, please let me know if you
> would consider pulling this patch and if so what do you think
> should be modified (I will also write man page and better
> autoconf script).

> +#ifdef LIB_UNWIND
> +#include <libunwind-ptrace.h>
> +#include <libunwind.h>
> +
> +/* keep a sorted array of cache entries, so that we can binary search
> + * through it
> + */
> +struct mmap_cache_t {
> +     // example entry:
> +     // 7fabbb09b000-7fabbb09f000 r--p 00179000 fc:00 1180246 
> /lib/libc-2.11.1.so
> +     //
> +     // start_addr  is 0x7fabbb09b000
> +     // end_addr    is 0x7fabbb09f000
> +     // mmap_offset is 0x179000
> +     // binary_filename is "/lib/libc-2.11.1.so"
> +     unsigned long start_addr;
> +     unsigned long end_addr;
> +     unsigned long mmap_offset;
> +     char* binary_filename;
> +};
> +#endif
> +
>  /* Trace Control Block */
>  struct tcb {
>       int flags;              /* See below for TCB_ values */
> @@ -417,6 +440,13 @@ struct tcb {
>       struct timeval etime;   /* Syscall entry time */
>                               /* Support for tracing forked processes: */
>       long inst[2];           /* Saved clone args (badly named) */
> +
> +#ifdef LIB_UNWIND
> +     // keep a cache of /proc/<pid>/mmap contents to avoid unnecessary file 
> reads
> +     struct mmap_cache_t* mmap_cache;
> +     int mmap_cache_size;
> +     struct UPT_info* libunwind_ui;
> +#endif
>  };
>  
>  /* TCB flags */
> @@ -710,6 +740,14 @@ extern void tv_sub(struct timeval *, struct timeval *, 
> struct timeval *);
>  extern void tv_mul(struct timeval *, struct timeval *, int);
>  extern void tv_div(struct timeval *, struct timeval *, int);
>  
> +#ifdef LIB_UNWIND
> +/**
> + * print stack (-k flag) memory allocation and deallocation
> + */
> +extern void alloc_mmap_cache(struct tcb* tcp);
> +extern void delete_mmap_cache(struct tcb* tcp);


#else
# define alloc_mmap_cache(tcp) ((void)0)
# define delete_mmap_cache(tcp) ((void)0)

> +#endif



>  print_mmap(struct tcb *tcp, long *u_arg, unsigned long long offset)
>  {
>       if (entering(tcp)) {
> +#ifdef LIB_UNWIND
> +             /* clean the cache */
> +             delete_mmap_cache(tcp);
> +#endif

If you add above defines, you can lose #ifdef here.
Comment is redundant - function name is good enough.


> +#ifdef LIB_UNWIND
> +/* if this is 1, then do the stack trace for every system call
> + */
> +int use_libunwind = 0;

Maybe bool?

> @@ -685,6 +698,15 @@ alloctcb(int pid)
>  #if SUPPORTED_PERSONALITIES > 1
>                       tcp->currpers = current_personality;
>  #endif
> +
> +#ifdef LIB_UNWIND
> +                     tcp->mmap_cache = NULL;
> +                     tcp->mmap_cache_size = 0;

tcp was memset to 0 a few lines above. These assignment are redundant.


> +#ifdef LIB_UNWIND
> +     if (use_libunwind) {
> +             libunwind_as = unw_create_addr_space (&_UPT_accessors, 0);

The rest of strace source uses a style with no space: "func(...)",
not "func (...)". Follow the style.


> +             if (!libunwind_as) {
> +                     error_msg_and_die("Fatal error: unable to create 
> address space for stack tracing\n");

Just call die_out_of_memory().

> +void alloc_mmap_cache(struct tcb* tcp) {
> +
> +     if ( tcp->mmap_cache)
> +             perror_msg_and_die("Memory map cache is empty");
> +     if ( tcp->mmap_cache_size)
> +             perror_msg_and_die("Memory map cache is empty");

?? please explain the code above.

> +     /* start with a small dynamically-allocated array and then expand it */
> +     int cur_array_size = 10;
> +     struct mmap_cache_t* cache_head = malloc(cur_array_size * 
> sizeof(*cache_head));
> +     char filename[sizeof ("/proc/0123456789/maps")];
> +
> +     sprintf(filename, "/proc/%d/maps", tcp->pid);
> +
> +     FILE* f = fopen(filename, "r");
> +     if ( ! f )
> +             perror_msg_and_die("Unable to open %s", filename);

"Unable to" => "Can't". It's the same but shorter :)

> +     char s[300];
> +     while (fgets(s, sizeof(s), f) != NULL) {
> +             unsigned long start_addr, end_addr, mmap_offset;
> +             char binary_path[512];
> +             binary_path[0] = '\0'; // 'reset' it just to be paranoid
> +
> +             sscanf(s, "%lx-%lx %*c%*c%*c%*c %lx %*x:%*x %*d %[^\n]", 
> &start_addr,
> +                     &end_addr, &mmap_offset, binary_path);
> +
> +             /* ignore special 'fake files' like "[vdso]", "[heap]", 
> "[stack]", */
> +             if (binary_path[0] == '[' && binary_path[strlen(binary_path) - 
> 1] == ']') {
> +                     continue;
> +             }

I would drop the check for closing ']' - strlen is a bit expensive,
and all legal files are going to start with '/', not '[', anyway.

> +             /* resize doubling its size */
> +             if (tcp->mmap_cache_size >= cur_array_size) {
> +                     cur_array_size *= 2;
> +                     cache_head = realloc(cache_head, cur_array_size * 
> sizeof(*cache_head));

Please, die_out_of_memory() if realloc returns NULL.


> +void delete_mmap_cache(struct tcb* tcp) {

The { should be on the next line, as the rest of the strace source does.

> +#ifdef LIB_UNWIND
> +     extern int use_libunwind;

Move this extern to defs.h

> +     if (use_libunwind) {
> +             // caching for efficiency ...
> +             if (!tcp->mmap_cache) {
> +                     alloc_mmap_cache(tcp);
> +             }
> +             // use libunwind to unwind the stack, which works even for code 
> compiled

I don't understand what "which works even for code compiled"
tries to say.

> +             print_libunwind_backtrace(tcp);
> +     }


-- 
vda



------------------------------------------------------------------------------
This SF.net email is sponsored by Windows:

Build for Windows Store.

http://p.sf.net/sfu/windows-dev2dev
_______________________________________________
Strace-devel mailing list
Strace-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/strace-devel

Reply via email to