2016-02-17 19:58:59 -08:00
/* Copyright (c) 2016 Facebook
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation .
*/
# include <stdio.h>
# include <unistd.h>
# include <stdlib.h>
# include <signal.h>
# include <linux/bpf.h>
# include <string.h>
# include <linux/perf_event.h>
# include <errno.h>
# include <assert.h>
# include <stdbool.h>
# include <sys/resource.h>
# include "libbpf.h"
# include "bpf_load.h"
# define PRINT_RAW_ADDR 0
static void print_ksym ( __u64 addr )
{
struct ksym * sym ;
if ( ! addr )
return ;
2016-03-07 21:57:19 -08:00
sym = ksym_search ( addr ) ;
2016-02-17 19:58:59 -08:00
if ( PRINT_RAW_ADDR )
printf ( " %s/%llx; " , sym - > name , addr ) ;
else
printf ( " %s; " , sym - > name ) ;
}
# define TASK_COMM_LEN 16
struct key_t {
char waker [ TASK_COMM_LEN ] ;
char target [ TASK_COMM_LEN ] ;
__u32 wret ;
__u32 tret ;
} ;
static void print_stack ( struct key_t * key , __u64 count )
{
__u64 ip [ PERF_MAX_STACK_DEPTH ] = { } ;
static bool warned ;
int i ;
printf ( " %s; " , key - > target ) ;
if ( bpf_lookup_elem ( map_fd [ 3 ] , & key - > tret , ip ) ! = 0 ) {
printf ( " ---; " ) ;
} else {
for ( i = PERF_MAX_STACK_DEPTH - 1 ; i > = 0 ; i - - )
print_ksym ( ip [ i ] ) ;
}
printf ( " -; " ) ;
if ( bpf_lookup_elem ( map_fd [ 3 ] , & key - > wret , ip ) ! = 0 ) {
printf ( " ---; " ) ;
} else {
for ( i = 0 ; i < PERF_MAX_STACK_DEPTH ; i + + )
print_ksym ( ip [ i ] ) ;
}
printf ( " ;%s %lld \n " , key - > waker , count ) ;
if ( ( key - > tret = = - EEXIST | | key - > wret = = - EEXIST ) & & ! warned ) {
printf ( " stackmap collisions seen. Consider increasing size \n " ) ;
warned = true ;
} else if ( ( ( int ) ( key - > tret ) < 0 | | ( int ) ( key - > wret ) < 0 ) ) {
printf ( " err stackid %d %d \n " , key - > tret , key - > wret ) ;
}
}
static void print_stacks ( int fd )
{
struct key_t key = { } , next_key ;
__u64 value ;
while ( bpf_get_next_key ( fd , & key , & next_key ) = = 0 ) {
bpf_lookup_elem ( fd , & next_key , & value ) ;
print_stack ( & next_key , value ) ;
key = next_key ;
}
}
static void int_exit ( int sig )
{
print_stacks ( map_fd [ 0 ] ) ;
exit ( 0 ) ;
}
int main ( int argc , char * * argv )
{
struct rlimit r = { RLIM_INFINITY , RLIM_INFINITY } ;
char filename [ 256 ] ;
int delay = 1 ;
snprintf ( filename , sizeof ( filename ) , " %s_kern.o " , argv [ 0 ] ) ;
setrlimit ( RLIMIT_MEMLOCK , & r ) ;
signal ( SIGINT , int_exit ) ;
if ( load_kallsyms ( ) ) {
printf ( " failed to process /proc/kallsyms \n " ) ;
return 2 ;
}
if ( load_bpf_file ( filename ) ) {
printf ( " %s " , bpf_log_buf ) ;
return 1 ;
}
if ( argc > 1 )
delay = atoi ( argv [ 1 ] ) ;
sleep ( delay ) ;
print_stacks ( map_fd [ 0 ] ) ;
return 0 ;
}