2011-02-04 14:45:46 +03:00
/*
* Copyright ( C ) 2011 , Red Hat Inc , Arnaldo Carvalho de Melo < acme @ redhat . com >
*
* Parts came from builtin - annotate . c , see those files for further
* copyright notes .
*
* Released under the GPL v2 . ( and only v2 , not any later version )
*/
# include "util.h"
# include "build-id.h"
# include "color.h"
# include "cache.h"
# include "symbol.h"
# include "debug.h"
# include "annotate.h"
2011-02-08 18:27:39 +03:00
# include <pthread.h>
2011-02-04 14:45:46 +03:00
2011-09-16 01:31:41 +04:00
const char * disassembler_style ;
2011-02-08 18:27:39 +03:00
int symbol__annotate_init ( struct map * map __used , struct symbol * sym )
2011-02-04 14:45:46 +03:00
{
struct annotation * notes = symbol__annotation ( sym ) ;
2011-02-08 18:27:39 +03:00
pthread_mutex_init ( & notes - > lock , NULL ) ;
return 0 ;
}
2011-02-04 14:45:46 +03:00
2011-11-12 04:17:32 +04:00
int symbol__alloc_hist ( struct symbol * sym )
2011-02-08 18:27:39 +03:00
{
struct annotation * notes = symbol__annotation ( sym ) ;
size_t sizeof_sym_hist = ( sizeof ( struct sym_hist ) +
2011-02-04 18:43:24 +03:00
( sym - > end - sym - > start ) * sizeof ( u64 ) ) ;
2011-02-08 18:27:39 +03:00
2011-11-12 04:17:32 +04:00
notes - > src = zalloc ( sizeof ( * notes - > src ) + symbol_conf . nr_events * sizeof_sym_hist ) ;
2011-02-08 18:27:39 +03:00
if ( notes - > src = = NULL )
return - 1 ;
notes - > src - > sizeof_sym_hist = sizeof_sym_hist ;
2011-11-12 04:17:32 +04:00
notes - > src - > nr_histograms = symbol_conf . nr_events ;
2011-02-08 18:27:39 +03:00
INIT_LIST_HEAD ( & notes - > src - > source ) ;
return 0 ;
2011-02-04 14:45:46 +03:00
}
2011-02-06 19:54:44 +03:00
void symbol__annotate_zero_histograms ( struct symbol * sym )
{
struct annotation * notes = symbol__annotation ( sym ) ;
2011-02-08 18:27:39 +03:00
pthread_mutex_lock ( & notes - > lock ) ;
if ( notes - > src ! = NULL )
memset ( notes - > src - > histograms , 0 ,
notes - > src - > nr_histograms * notes - > src - > sizeof_sym_hist ) ;
pthread_mutex_unlock ( & notes - > lock ) ;
2011-02-06 19:54:44 +03:00
}
2011-02-04 18:43:24 +03:00
int symbol__inc_addr_samples ( struct symbol * sym , struct map * map ,
int evidx , u64 addr )
2011-02-04 14:45:46 +03:00
{
2011-02-04 18:43:24 +03:00
unsigned offset ;
2011-02-04 14:45:46 +03:00
struct annotation * notes ;
struct sym_hist * h ;
notes = symbol__annotation ( sym ) ;
2011-02-08 18:27:39 +03:00
if ( notes - > src = = NULL )
2011-02-04 14:45:46 +03:00
return - ENOMEM ;
pr_debug3 ( " %s: addr=%# " PRIx64 " \n " , __func__ , map - > unmap_ip ( map , addr ) ) ;
2011-02-04 18:43:24 +03:00
if ( addr > = sym - > end )
2011-02-04 14:45:46 +03:00
return 0 ;
2011-02-04 18:43:24 +03:00
offset = addr - sym - > start ;
h = annotation__histogram ( notes , evidx ) ;
2011-02-04 14:45:46 +03:00
h - > sum + + ;
h - > addr [ offset ] + + ;
pr_debug3 ( " %# " PRIx64 " %s: period++ [addr: %# " PRIx64 " , %# " PRIx64
2011-02-04 18:43:24 +03:00
" , evidx=%d] => % " PRIu64 " \n " , sym - > start , sym - > name ,
addr , addr - sym - > start , evidx , h - > addr [ offset ] ) ;
2011-02-04 14:45:46 +03:00
return 0 ;
}
static struct objdump_line * objdump_line__new ( s64 offset , char * line , size_t privsize )
{
struct objdump_line * self = malloc ( sizeof ( * self ) + privsize ) ;
if ( self ! = NULL ) {
self - > offset = offset ;
self - > line = line ;
}
return self ;
}
void objdump_line__free ( struct objdump_line * self )
{
free ( self - > line ) ;
free ( self ) ;
}
static void objdump__add_line ( struct list_head * head , struct objdump_line * line )
{
list_add_tail ( & line - > node , head ) ;
}
struct objdump_line * objdump__get_next_ip_line ( struct list_head * head ,
struct objdump_line * pos )
{
list_for_each_entry_continue ( pos , head , node )
if ( pos - > offset > = 0 )
return pos ;
return NULL ;
}
2011-02-08 18:27:39 +03:00
static int objdump_line__print ( struct objdump_line * oline , struct symbol * sym ,
2011-02-06 19:54:44 +03:00
int evidx , u64 len , int min_pcnt ,
2011-02-08 20:29:25 +03:00
int printed , int max_lines ,
struct objdump_line * queue )
2011-02-04 14:45:46 +03:00
{
static const char * prev_line ;
static const char * prev_color ;
if ( oline - > offset ! = - 1 ) {
const char * path = NULL ;
unsigned int hits = 0 ;
double percent = 0.0 ;
const char * color ;
struct annotation * notes = symbol__annotation ( sym ) ;
2011-02-08 18:27:39 +03:00
struct source_line * src_line = notes - > src - > lines ;
2011-02-04 18:43:24 +03:00
struct sym_hist * h = annotation__histogram ( notes , evidx ) ;
2011-02-04 14:45:46 +03:00
s64 offset = oline - > offset ;
2011-02-08 18:27:39 +03:00
struct objdump_line * next ;
next = objdump__get_next_ip_line ( & notes - > src - > source , oline ) ;
2011-02-04 14:45:46 +03:00
while ( offset < ( s64 ) len & &
( next = = NULL | | offset < next - > offset ) ) {
if ( src_line ) {
if ( path = = NULL )
path = src_line [ offset ] . path ;
percent + = src_line [ offset ] . percent ;
} else
hits + = h - > addr [ offset ] ;
+ + offset ;
}
if ( src_line = = NULL & & h - > sum )
percent = 100.0 * hits / h - > sum ;
2011-02-05 20:37:31 +03:00
if ( percent < min_pcnt )
2011-02-06 19:54:44 +03:00
return - 1 ;
2011-02-08 20:01:39 +03:00
if ( max_lines & & printed > = max_lines )
2011-02-06 19:54:44 +03:00
return 1 ;
2011-02-05 20:37:31 +03:00
2011-02-08 20:29:25 +03:00
if ( queue ! = NULL ) {
list_for_each_entry_from ( queue , & notes - > src - > source , node ) {
if ( queue = = oline )
break ;
objdump_line__print ( queue , sym , evidx , len ,
0 , 0 , 1 , NULL ) ;
}
}
2011-02-04 14:45:46 +03:00
color = get_percent_color ( percent ) ;
/*
* Also color the filename and line if needed , with
* the same color than the percentage . Don ' t print it
* twice for close colored addr with the same filename : line
*/
if ( path ) {
if ( ! prev_line | | strcmp ( prev_line , path )
| | color ! = prev_color ) {
color_fprintf ( stdout , color , " %s " , path ) ;
prev_line = path ;
prev_color = color ;
}
}
color_fprintf ( stdout , color , " %7.2f " , percent ) ;
printf ( " : " ) ;
color_fprintf ( stdout , PERF_COLOR_BLUE , " %s \n " , oline - > line ) ;
2011-02-08 20:01:39 +03:00
} else if ( max_lines & & printed > = max_lines )
2011-02-06 19:54:44 +03:00
return 1 ;
else {
2011-02-08 20:29:25 +03:00
if ( queue )
return - 1 ;
2011-02-04 14:45:46 +03:00
if ( ! * oline - > line )
printf ( " : \n " ) ;
else
printf ( " : %s \n " , oline - > line ) ;
}
2011-02-06 19:54:44 +03:00
return 0 ;
2011-02-04 14:45:46 +03:00
}
2011-02-08 18:27:39 +03:00
static int symbol__parse_objdump_line ( struct symbol * sym , struct map * map ,
FILE * file , size_t privsize )
2011-02-04 14:45:46 +03:00
{
2011-02-08 18:27:39 +03:00
struct annotation * notes = symbol__annotation ( sym ) ;
2011-02-04 14:45:46 +03:00
struct objdump_line * objdump_line ;
char * line = NULL , * tmp , * tmp2 , * c ;
size_t line_len ;
s64 line_ip , offset = - 1 ;
if ( getline ( & line , & line_len , file ) < 0 )
return - 1 ;
if ( ! line )
return - 1 ;
while ( line_len ! = 0 & & isspace ( line [ line_len - 1 ] ) )
line [ - - line_len ] = ' \0 ' ;
c = strchr ( line , ' \n ' ) ;
if ( c )
* c = 0 ;
line_ip = - 1 ;
/*
* Strip leading spaces :
*/
tmp = line ;
while ( * tmp ) {
if ( * tmp ! = ' ' )
break ;
tmp + + ;
}
if ( * tmp ) {
/*
* Parse hexa addresses followed by ' : '
*/
line_ip = strtoull ( tmp , & tmp2 , 16 ) ;
if ( * tmp2 ! = ' : ' | | tmp = = tmp2 | | tmp2 [ 1 ] = = ' \0 ' )
line_ip = - 1 ;
}
if ( line_ip ! = - 1 ) {
u64 start = map__rip_2objdump ( map , sym - > start ) ,
end = map__rip_2objdump ( map , sym - > end ) ;
offset = line_ip - start ;
if ( offset < 0 | | ( u64 ) line_ip > end )
offset = - 1 ;
}
objdump_line = objdump_line__new ( offset , line , privsize ) ;
if ( objdump_line = = NULL ) {
free ( line ) ;
return - 1 ;
}
2011-02-08 18:27:39 +03:00
objdump__add_line ( & notes - > src - > source , objdump_line ) ;
2011-02-04 14:45:46 +03:00
return 0 ;
}
2011-02-08 18:27:39 +03:00
int symbol__annotate ( struct symbol * sym , struct map * map , size_t privsize )
2011-02-04 14:45:46 +03:00
{
struct dso * dso = map - > dso ;
char * filename = dso__build_id_filename ( dso , NULL , 0 ) ;
bool free_filename = true ;
char command [ PATH_MAX * 2 ] ;
FILE * file ;
int err = 0 ;
char symfs_filename [ PATH_MAX ] ;
if ( filename ) {
snprintf ( symfs_filename , sizeof ( symfs_filename ) , " %s%s " ,
symbol_conf . symfs , filename ) ;
}
if ( filename = = NULL ) {
if ( dso - > has_build_id ) {
pr_err ( " Can't annotate %s: not enough memory \n " ,
sym - > name ) ;
return - ENOMEM ;
}
goto fallback ;
} else if ( readlink ( symfs_filename , command , sizeof ( command ) ) < 0 | |
strstr ( command , " [kernel.kallsyms] " ) | |
access ( symfs_filename , R_OK ) ) {
free ( filename ) ;
fallback :
/*
* If we don ' t have build - ids or the build - id file isn ' t in the
* cache , or is just a kallsyms file , well , lets hope that this
* DSO is the same as when ' perf record ' ran .
*/
filename = dso - > long_name ;
snprintf ( symfs_filename , sizeof ( symfs_filename ) , " %s%s " ,
symbol_conf . symfs , filename ) ;
free_filename = false ;
}
2011-03-11 19:13:36 +03:00
if ( dso - > symtab_type = = SYMTAB__KALLSYMS ) {
2011-02-23 17:08:59 +03:00
char bf [ BUILD_ID_SIZE * 2 + 16 ] = " with build id " ;
char * build_id_msg = NULL ;
2011-02-04 14:45:46 +03:00
if ( dso - > annotate_warned )
goto out_free_filename ;
2011-02-23 17:08:59 +03:00
if ( dso - > has_build_id ) {
build_id__sprintf ( dso - > build_id ,
sizeof ( dso - > build_id ) , bf + 15 ) ;
build_id_msg = bf ;
}
2011-02-04 14:45:46 +03:00
err = - ENOENT ;
dso - > annotate_warned = 1 ;
2011-10-26 14:00:55 +04:00
pr_err ( " Can't annotate %s: \n \n "
" No vmlinux file%s \n was found in the path. \n \n "
" Please use: \n \n "
" perf buildid-cache -av vmlinux \n \n "
" or: \n \n "
2012-02-23 12:46:24 +04:00
" --vmlinux vmlinux \n " ,
2011-02-23 17:08:59 +03:00
sym - > name , build_id_msg ? : " " ) ;
2011-02-04 14:45:46 +03:00
goto out_free_filename ;
}
pr_debug ( " %s: filename=%s, sym=%s, start=%# " PRIx64 " , end=%# " PRIx64 " \n " , __func__ ,
filename , sym - > name , map - > unmap_ip ( map , sym - > start ) ,
map - > unmap_ip ( map , sym - > end ) ) ;
pr_debug ( " annotating [%p] %30s : [%p] %30s \n " ,
dso , dso - > long_name , sym , sym - > name ) ;
snprintf ( command , sizeof ( command ) ,
2011-09-16 01:31:41 +04:00
" objdump %s%s --start-address=0x%016 " PRIx64
2011-05-17 19:32:07 +04:00
" --stop-address=0x%016 " PRIx64
" -d %s %s -C %s|grep -v %s|expand " ,
2011-09-16 01:31:41 +04:00
disassembler_style ? " -M " : " " ,
disassembler_style ? disassembler_style : " " ,
2011-02-04 14:45:46 +03:00
map__rip_2objdump ( map , sym - > start ) ,
perf tools: Fix truncated annotation
I get such truncated annotation results in 'perf top':
: Disassembly of section .text: ▒
: ▒
: ffffffff810966a8 <nr_iowait_cpu>: ▒
4.94 : ffffffff810966a8: movslq %edi,%rdi ▒
3.70 : ffffffff810966ab: mov $0x13700,%rax ▒
0.00 : ffffffff810966b2: add -0x7e32cb00(,%rdi,8),%rax ▒
8.64 : ffffffff810966ba: mov 0x7e0(%rax),%eax ▒
82.72 : ffffffff810966c0: cltq ▒
Note the missing 'retq' which is there in the original function:
ffffffff810966a8 <nr_iowait_cpu>:
ffffffff810966a8: 48 63 ff movslq %edi,%rdi
ffffffff810966ab: 48 c7 c0 00 37 01 00 mov $0x13700,%rax
ffffffff810966b2: 48 03 04 fd 00 35 cd add -0x7e32cb00(,%rdi,8),%rax
ffffffff810966b9: 81
ffffffff810966ba: 8b 80 e0 07 00 00 mov 0x7e0(%rax),%eax
ffffffff810966c0: 48 98 cltq
ffffffff810966c2: c3 retq
ffffffff810966c3 <this_cpu_load>:
I'm using a fairly recent binutils:
GNU objdump version 2.21.51.0.6-2.fc16 20110118
AFAICS the bug is simply that sym->end points to the last byte
of the symbol in question - while objdump's --stop-address
expects the last byte plus 1 to disassemble the full range.
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/20111223130804.GA24305@elte.hu
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2011-12-23 17:08:04 +04:00
map__rip_2objdump ( map , sym - > end + 1 ) ,
2011-05-17 19:32:07 +04:00
symbol_conf . annotate_asm_raw ? " " : " --no-show-raw " ,
symbol_conf . annotate_src ? " -S " : " " ,
2011-02-04 14:45:46 +03:00
symfs_filename , filename ) ;
pr_debug ( " Executing: %s \n " , command ) ;
file = popen ( command , " r " ) ;
if ( ! file )
goto out_free_filename ;
while ( ! feof ( file ) )
2011-02-08 18:27:39 +03:00
if ( symbol__parse_objdump_line ( sym , map , file , privsize ) < 0 )
2011-02-04 14:45:46 +03:00
break ;
pclose ( file ) ;
out_free_filename :
if ( free_filename )
free ( filename ) ;
return err ;
}
static void insert_source_line ( struct rb_root * root , struct source_line * src_line )
{
struct source_line * iter ;
struct rb_node * * p = & root - > rb_node ;
struct rb_node * parent = NULL ;
while ( * p ! = NULL ) {
parent = * p ;
iter = rb_entry ( parent , struct source_line , node ) ;
if ( src_line - > percent > iter - > percent )
p = & ( * p ) - > rb_left ;
else
p = & ( * p ) - > rb_right ;
}
rb_link_node ( & src_line - > node , parent , p ) ;
rb_insert_color ( & src_line - > node , root ) ;
}
static void symbol__free_source_line ( struct symbol * sym , int len )
{
struct annotation * notes = symbol__annotation ( sym ) ;
2011-02-08 18:27:39 +03:00
struct source_line * src_line = notes - > src - > lines ;
2011-02-04 14:45:46 +03:00
int i ;
for ( i = 0 ; i < len ; i + + )
free ( src_line [ i ] . path ) ;
free ( src_line ) ;
2011-02-08 18:27:39 +03:00
notes - > src - > lines = NULL ;
2011-02-04 14:45:46 +03:00
}
/* Get the filename:line for the colored entries */
static int symbol__get_source_line ( struct symbol * sym , struct map * map ,
2011-02-04 18:43:24 +03:00
int evidx , struct rb_root * root , int len ,
2011-02-04 14:45:46 +03:00
const char * filename )
{
u64 start ;
int i ;
char cmd [ PATH_MAX * 2 ] ;
struct source_line * src_line ;
struct annotation * notes = symbol__annotation ( sym ) ;
2011-02-04 18:43:24 +03:00
struct sym_hist * h = annotation__histogram ( notes , evidx ) ;
2011-02-04 14:45:46 +03:00
if ( ! h - > sum )
return 0 ;
2011-02-08 18:27:39 +03:00
src_line = notes - > src - > lines = calloc ( len , sizeof ( struct source_line ) ) ;
if ( ! notes - > src - > lines )
2011-02-04 14:45:46 +03:00
return - 1 ;
start = map - > unmap_ip ( map , sym - > start ) ;
for ( i = 0 ; i < len ; i + + ) {
char * path = NULL ;
size_t line_len ;
u64 offset ;
FILE * fp ;
src_line [ i ] . percent = 100.0 * h - > addr [ i ] / h - > sum ;
if ( src_line [ i ] . percent < = 0.5 )
continue ;
offset = start + i ;
sprintf ( cmd , " addr2line -e %s %016 " PRIx64 , filename , offset ) ;
fp = popen ( cmd , " r " ) ;
if ( ! fp )
continue ;
if ( getline ( & path , & line_len , fp ) < 0 | | ! line_len )
goto next ;
src_line [ i ] . path = malloc ( sizeof ( char ) * line_len + 1 ) ;
if ( ! src_line [ i ] . path )
goto next ;
strcpy ( src_line [ i ] . path , path ) ;
insert_source_line ( root , & src_line [ i ] ) ;
next :
pclose ( fp ) ;
}
return 0 ;
}
static void print_summary ( struct rb_root * root , const char * filename )
{
struct source_line * src_line ;
struct rb_node * node ;
printf ( " \n Sorted summary for file %s \n " , filename ) ;
printf ( " ---------------------------------------------- \n \n " ) ;
if ( RB_EMPTY_ROOT ( root ) ) {
printf ( " Nothing higher than %1.1f%% \n " , MIN_GREEN ) ;
return ;
}
node = rb_first ( root ) ;
while ( node ) {
double percent ;
const char * color ;
char * path ;
src_line = rb_entry ( node , struct source_line , node ) ;
percent = src_line - > percent ;
color = get_percent_color ( percent ) ;
path = src_line - > path ;
color_fprintf ( stdout , color , " %7.2f %s " , percent , path ) ;
node = rb_next ( node ) ;
}
}
2011-02-04 18:43:24 +03:00
static void symbol__annotate_hits ( struct symbol * sym , int evidx )
2011-02-04 14:45:46 +03:00
{
struct annotation * notes = symbol__annotation ( sym ) ;
2011-02-04 18:43:24 +03:00
struct sym_hist * h = annotation__histogram ( notes , evidx ) ;
2011-02-04 14:45:46 +03:00
u64 len = sym - > end - sym - > start , offset ;
for ( offset = 0 ; offset < len ; + + offset )
if ( h - > addr [ offset ] ! = 0 )
printf ( " %* " PRIx64 " : % " PRIu64 " \n " , BITS_PER_LONG / 2 ,
sym - > start + offset , h - > addr [ offset ] ) ;
printf ( " %*s: % " PRIu64 " \n " , BITS_PER_LONG / 2 , " h->sum " , h - > sum ) ;
}
2011-02-08 18:27:39 +03:00
int symbol__annotate_printf ( struct symbol * sym , struct map * map , int evidx ,
2011-02-08 20:29:25 +03:00
bool full_paths , int min_pcnt , int max_lines ,
int context )
2011-02-04 14:45:46 +03:00
{
struct dso * dso = map - > dso ;
const char * filename = dso - > long_name , * d_filename ;
2011-02-08 18:27:39 +03:00
struct annotation * notes = symbol__annotation ( sym ) ;
2011-02-08 20:29:25 +03:00
struct objdump_line * pos , * queue = NULL ;
int printed = 2 , queue_len = 0 ;
2011-02-06 19:54:44 +03:00
int more = 0 ;
2011-02-04 14:45:46 +03:00
u64 len ;
if ( full_paths )
d_filename = filename ;
else
d_filename = basename ( filename ) ;
len = sym - > end - sym - > start ;
printf ( " Percent | Source code & Disassembly of %s \n " , d_filename ) ;
printf ( " ------------------------------------------------ \n " ) ;
if ( verbose )
2011-02-04 18:43:24 +03:00
symbol__annotate_hits ( sym , evidx ) ;
2011-02-04 14:45:46 +03:00
2011-02-08 18:27:39 +03:00
list_for_each_entry ( pos , & notes - > src - > source , node ) {
2011-02-08 20:29:25 +03:00
if ( context & & queue = = NULL ) {
queue = pos ;
queue_len = 0 ;
}
2011-02-08 18:27:39 +03:00
switch ( objdump_line__print ( pos , sym , evidx , len , min_pcnt ,
2011-02-08 20:29:25 +03:00
printed , max_lines , queue ) ) {
2011-02-06 19:54:44 +03:00
case 0 :
+ + printed ;
2011-02-08 20:29:25 +03:00
if ( context ) {
printed + = queue_len ;
queue = NULL ;
queue_len = 0 ;
}
2011-02-06 19:54:44 +03:00
break ;
case 1 :
/* filtered by max_lines */
+ + more ;
2011-02-05 20:37:31 +03:00
break ;
2011-02-06 19:54:44 +03:00
case - 1 :
default :
2011-02-08 20:29:25 +03:00
/*
* Filtered by min_pcnt or non IP lines when
* context ! = 0
*/
if ( ! context )
break ;
if ( queue_len = = context )
queue = list_entry ( queue - > node . next , typeof ( * queue ) , node ) ;
else
+ + queue_len ;
2011-02-06 19:54:44 +03:00
break ;
}
}
return more ;
}
2011-02-05 23:51:38 +03:00
2011-02-06 19:54:44 +03:00
void symbol__annotate_zero_histogram ( struct symbol * sym , int evidx )
{
struct annotation * notes = symbol__annotation ( sym ) ;
struct sym_hist * h = annotation__histogram ( notes , evidx ) ;
2011-02-08 18:27:39 +03:00
memset ( h , 0 , notes - > src - > sizeof_sym_hist ) ;
2011-02-06 19:54:44 +03:00
}
2011-02-08 18:27:39 +03:00
void symbol__annotate_decay_histogram ( struct symbol * sym , int evidx )
2011-02-06 19:54:44 +03:00
{
struct annotation * notes = symbol__annotation ( sym ) ;
struct sym_hist * h = annotation__histogram ( notes , evidx ) ;
struct objdump_line * pos ;
2011-02-09 18:56:28 +03:00
int len = sym - > end - sym - > start ;
2011-02-06 19:54:44 +03:00
h - > sum = 0 ;
2011-02-08 18:27:39 +03:00
list_for_each_entry ( pos , & notes - > src - > source , node ) {
2011-02-09 18:56:28 +03:00
if ( pos - > offset ! = - 1 & & pos - > offset < len ) {
2011-02-06 19:54:44 +03:00
h - > addr [ pos - > offset ] = h - > addr [ pos - > offset ] * 7 / 8 ;
h - > sum + = h - > addr [ pos - > offset ] ;
}
2011-02-05 23:51:38 +03:00
}
}
void objdump_line_list__purge ( struct list_head * head )
{
struct objdump_line * pos , * n ;
list_for_each_entry_safe ( pos , n , head , node ) {
list_del ( & pos - > node ) ;
objdump_line__free ( pos ) ;
}
}
int symbol__tty_annotate ( struct symbol * sym , struct map * map , int evidx ,
bool print_lines , bool full_paths , int min_pcnt ,
int max_lines )
{
struct dso * dso = map - > dso ;
const char * filename = dso - > long_name ;
struct rb_root source_line = RB_ROOT ;
u64 len ;
2011-02-08 18:27:39 +03:00
if ( symbol__annotate ( sym , map , 0 ) < 0 )
2011-02-05 23:51:38 +03:00
return - 1 ;
len = sym - > end - sym - > start ;
if ( print_lines ) {
symbol__get_source_line ( sym , map , evidx , & source_line ,
len , filename ) ;
print_summary ( & source_line , filename ) ;
2011-02-04 14:45:46 +03:00
}
2011-02-08 18:27:39 +03:00
symbol__annotate_printf ( sym , map , evidx , full_paths ,
2011-02-08 20:29:25 +03:00
min_pcnt , max_lines , 0 ) ;
2011-02-04 14:45:46 +03:00
if ( print_lines )
symbol__free_source_line ( sym , len ) ;
2011-02-08 18:27:39 +03:00
objdump_line_list__purge ( & symbol__annotation ( sym ) - > src - > source ) ;
2011-02-05 23:51:38 +03:00
2011-02-04 14:45:46 +03:00
return 0 ;
}