18 if (!defined($ARGV[0])) {
19 print "No log file specified\n";
20 print "Usage: leak_finder.pl <debug_file> [--option]\n";
21 print " --by_func show leak logs by function name in ascending order.\n";
22 print " --summary implies --by_func, print a summary report by \n";
23 print " the number of total leak bytes of each function \n";
24 print " in ascending order in YAML format.\n";
28 open(INFILE, $ARGV[0]);
29 while ($line = <INFILE>) {
30 if ($line =~ m/^(.*)\((.*):(\d+):(.*)\(\)\)/) {
31 @parsed = split(":", $1);
32 if (substr ($parsed[2], -1, 1) eq "F") {
36 if (!defined($cpu{$parsed[2]})) {
37 $cpu{$parsed[2]} = $parsed[3];
43 foreach $time (values %cpu) {
44 if ($start_time < $time) {
49 print "Starting analysis since $start_time\n";
52 while ($line = <INFILE>) {
54 my ($file, $func, $lno, $name, $size, $addr, $type);
55 # message format here needs to match OBD_ALLOC_POST()/OBD_FREE_PRE()
56 # mask:subs:cpu:epoch second.usec:?:pid:?:(filename:line:function_name())
57 # alloc-type 'var_name': size at memory_address.
58 if ($line =~ m/^(.*)\((.*):(\d+):(.*)\(\)\) (k[m]?|v[m]?|slab-|)(alloc(ed)?|free[d]?(_rcu)?) '(.*)': (\d+) at ([\da-f]+)/) {
59 @parsed = split(":", $1);
60 if ($parsed[3] <= $start_time) {
72 # we can't dump the log after portals has exited, so skip "leaks"
73 # from memory freed in the portals module unloading.
74 if ($func eq 'portals_handle_init') {
77 printf("%8s %6d bytes at %s called %s (%s:%s:%d)\n", $type, $size,
78 $addr, $name, $file, $func, $lno);
79 } elsif ($line =~ m/(alloc(ed)?|free[d]?).*at [0-9a-f]*/) {
80 # alloc/free line that didn't match regexp, notify user of missed line
81 print STDERR "Couldn't parse line $debug_line, script needs to be fixed:\n$line";
84 # line not related to alloc/free, skip it silently
85 #print STDERR "Couldn't parse $line";
89 if (index($type, 'alloc') >= 0) {
90 if (defined($memory->{$addr})) {
91 print STDOUT "*** Two allocs with the same address ($size bytes at $addr, $file:$func:$lno)\n";
92 print STDOUT " first malloc at $memory->{$addr}->{file}:$memory->{$addr}->{func}:$memory->{$addr}->{lno}, second at $file:$func:$lno\n";
96 $memory->{$addr}->{name} = $name;
97 $memory->{$addr}->{size} = $size;
98 $memory->{$addr}->{file} = $file;
99 $memory->{$addr}->{func} = $func;
100 $memory->{$addr}->{lno} = $lno;
101 $memory->{$addr}->{debug_line} = $debug_line;
108 if (!defined($memory->{$addr})) {
109 print STDOUT "*** Free without malloc ($size bytes at $addr, $file:$func:$lno)\n";
112 my ($oldname, $oldsize, $oldfile, $oldfunc, $oldlno) = $memory->{$addr};
114 if ($memory->{$addr}->{size} != $size) {
115 print STDOUT "*** Free different size ($memory->{$addr}->{size} alloced, $size freed).\n";
116 print STDOUT " malloc at $memory->{$addr}->{file}:$memory->{$addr}->{func}:$memory->{$addr}->{lno}, free at $file:$func:$lno\n";
120 delete $memory->{$addr};
129 if (defined($ARGV[1])) {
130 if ($ARGV[1] eq "--by_func" or $ARGV[1] eq "--summary") {
131 # Sort leak output by source code position
132 $aa = "$memory->{$a}->{func}:$memory->{$a}->{lno}:$memory->{$a}->{name}:$memory->{$a}->{size}";
133 $bb = "$memory->{$b}->{func}:$memory->{$b}->{lno}:$memory->{$b}->{name}:$memory->{$b}->{size}";
137 # Sort leak output by allocation time
138 $memory->{$a}->{debug_line} <=> $memory->{$b}->{debug_line};
150 foreach $key (@sorted) {
151 if (defined($ARGV[1]) and $ARGV[1] eq "--summary") {
152 $aa = "$memory->{$key}->{func}:$memory->{$key}->{lno}:$memory->{$key}->{name}:$memory->{$key}->{size}";
156 $records[$i]->{func} = $leak_func;
157 $records[$i]->{size} = $leak_size;
158 $records[$i]->{count} = $leak_count;
159 $records[$i]->{total} = $leak_count * $leak_size;;
166 $leak_func = "$memory->{$key}->{func}:$memory->{$key}->{lno}:$memory->{$key}->{name}";
167 $leak_size = $memory->{$key}->{size};
169 print STDOUT "*** Leak: $memory->{$key}->{size} bytes allocated at $key ($memory->{$key}->{file}:$memory->{$key}->{func}:$memory->{$key}->{lno}:$memory->{$key}->{name}, debug file line $memory->{$key}->{debug_line})\n";
173 if (defined($ARGV[1]) and $ARGV[1] eq "--summary") {
174 # print a summary report by total leak bytes in ASC order
175 my @sorted_records = sort {
176 $a->{total} <=> $b->{total};
178 foreach $key (@sorted_records) {
179 printf("- { func: %-58s, alloc_bytes: %-8d, leak_count: %-6d, leak_bytes: %-8d },\n",
180 $key->{func}, $key->{size}, $key->{count}, $key->{total});
183 print STDOUT "maximum used: $max, amount leaked: $total\n";