Bump version numbers for 3.13
[maemo-rb.git] / utils / analysis / find_addr.pl
blobb66f35f48e8fd6fefee8cca21c884352316d15f8
1 #!/usr/bin/env perl
2 # __________ __ ___.
3 # Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 # Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 # Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 # Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 # \/ \/ \/ \/ \/
8 # $Id$
10 # Copyright (C) 2009 by Maurus Cuelenaere
12 # This program is free software; you can redistribute it and/or
13 # modify it under the terms of the GNU General Public License
14 # as published by the Free Software Foundation; either version 2
15 # of the License, or (at your option) any later version.
17 # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 # KIND, either express or implied.
20 use String::Scanf;
21 use Cwd;
23 sub check_boundaries
25 my $fits = 0, $start = $_[0], $end = $_[0] + $_[1];
26 foreach my $boundary (@ram_boundaries)
28 if(defined(@$boundary{'name'}) && $start >= @$boundary{'start'} && $end <= @$boundary{'end'})
30 return 1;
34 return 0;
37 sub dynamic_space
39 my $space = $_[0], $space_array = $_[1], $ret;
41 printf "This address is in %s space, please select the %s which was used with this address:\n", $space, $space;
42 $count = 1;
43 foreach my $el (@$space_array)
45 printf " [%d]: %s\n", $count++, $el;
48 print "\n";
49 my $sel = -1;
52 print "Selection: ";
53 $sel = <STDIN>;
54 } while($sel <= 0 || $sel > $count - 1 || !($sel =~ /^[+-]?\d+$/));
56 my $prefix;
57 if($space eq 'plugin')
59 $prefix = 'apps';
61 else
63 $prefix = 'lib/rbcodec';
65 my $file = sprintf("%s/%ss/%s", $prefix, $space, @$space_array[$sel - 1]);
66 $ret{'library'} = sprintf("%s/%s", cwd(), $file);
67 open FILE, "$objdump -t $file |" or die "Can't open pipe: $!";
68 while(<FILE>)
70 chomp($_);
71 if(/^([0-9a-fA-F]+).+\s([0-9a-fA-F]{3,})\s(?:[^\s]+\s)?(.+)$/)
73 (my $addr) = sscanf("%lx", $1);
74 (my $size) = sscanf("%lx", $2);
76 if($lookaddr >= $addr && $lookaddr <= ($addr + $size))
78 my $diff = abs($lookaddr - $addr);
79 if(!defined($ret{'diff'}) || $diff <= $ret{'diff'})
81 $ret{'diff'} = $diff;
82 $ret{'function'} = $3;
87 close FILE;
89 return %ret;
92 ($lookaddr) = sscanf("0x%lx", $ARGV[0]);
93 ($context_size) = $#ARGV > 0 ? $ARGV[1] : 5;
95 if($lookaddr != 0)
97 # Determine the used objdump utility
98 open MAKEFILE, "<Makefile" or die "Can't open Makefile: $!";
99 while(<MAKEFILE>)
101 chomp($_);
103 if(/^export OC=(.+)$/)
105 $objdump = $1;
106 $objdump =~ s/objcopy/objdump/;
109 close MAKEFILE;
111 # Generate a list of all codecs
112 open FINDCODECS, "find lib/rbcodec/codecs/ -name '*.elf' 2>&1 |" or die "Can't open pipe: $!";
113 my @codecs;
114 while(<FINDCODECS>)
116 chomp($_);
117 $_ =~ s/lib\/rbcodec\/codecs\///;
118 push(@codecs, $_);
120 close FINDCODECS;
121 # Generate a list of all plugins
122 open FINDPLUGINS, "find apps/plugins/ -name '*.elf' 2>&1 |" or die "Can't open pipe: $!";
123 my @plugins;
124 while(<FINDPLUGINS>)
126 chomp($_);
127 $_ =~ s/apps\/plugins\///;
128 push(@plugins, $_);
130 close FINDPLUGINS;
132 open MAPFILE, "<rockbox.map" or die "Can't open rockbox.map: $!";
133 my $addr, $size, $library, $match, $prev_function, $codec_addr, $plugin_addr;
134 while(<MAPFILE>)
136 chomp($_);
138 if(/^\s*\.text\.([^\s]+)$/)
140 $prev_function = $1;
143 if(/^\.([^\s]+)\s*(0x[0-9a-fA-F]+)/)
145 ($addr) = sscanf("0x%lx", $2);
146 if($1 eq "plugin")
148 $plugin_addr = $addr;
150 elsif($1 eq "codec")
152 $codec_addr = $addr;
157 if(/^.*?\s*(0x[0-9a-fA-F]+)\s*(0x[0-9a-fA-F]+)\s(.+)$/)
159 ($addr) = sscanf("0x%lx", $1);
160 ($size) = sscanf("0x%lx", $2);
161 $library = $3;
163 if(check_boundaries($addr, $size) != 0
164 && $lookaddr >= $addr && $lookaddr <= ($addr + $size))
166 #printf "0x%x 0x%x %s %s\n", $addr, $size, $prev_function, $library;
168 my $diff = abs($lookaddr - $addr);
169 if(!defined($match{'diff'}) || $diff <= $match{'diff'})
171 $match{'diff'} = $diff;
172 $match{'library'} = $library;
173 $match{'function'} = $prev_function;
177 elsif(/^\s*(0x[0-9a-fA-F]+)\s*([^\s]+)$/)
179 ($addr) = sscanf("0x%lx", $1);
180 my $function = $2;
182 if(check_boundaries($addr, 0) != 0 && $lookaddr >= $addr)
184 #printf "0x%x %s\n", $addr, $function;
186 my $diff = abs($lookaddr - $addr);
187 if(!defined($match{'diff'}) || $diff <= $match{'diff'})
189 $match{'diff'} = $diff;
190 $match{'library'} = $library;
191 $match{'function'} = $function;
195 elsif(/^(.RAM) *(0x[0-9a-fA-F]+) (0x[0-9a-fA-F]+)/)
197 (my $start_addr) = sscanf("0x%lx", $2);
198 (my $addr_length) = sscanf("0x%lx", $3);
199 push(@ram_boundaries, {"name", $1,
200 "start", $start_addr,
201 "end", $start_addr + $addr_length
205 close MAPFILE;
207 if($lookaddr >= $codec_addr && $lookaddr < $plugin_addr
208 && $codec_addr != 0)
210 # look for codec
211 %match = dynamic_space("codec", \@codecs);
213 elsif($lookaddr >= $plugin_addr && $plugin_addr != 0)
215 # look for plugin
216 %match = dynamic_space("plugin", \@plugins);
219 printf "%s -> %s\n\n", $match{'library'}, $match{'function'};
221 # Replace path/libfoo.a(bar.o) with path/libfoo.a
222 $match{'library'} =~ s/\(.+\)//;
224 open OBJDUMP, "$objdump -S $match{'library'} 2>&1 |" or die "Can't open pipe: $!";
225 my $found = 0, $addr;
226 while(<OBJDUMP>)
228 chomp($_);
230 if(/^[0-9a-fA-F]+\s\<(.+)\>:$/)
232 $found = ($1 eq $match{'function'});
234 elsif(/Disassembly of section/)
236 $found = 0;
238 elsif($found == 1)
240 if(/^\s*([0-9a-fA-F]+):\s*[0-9a-fA-F]+\s*.+$/)
242 ($addr) = sscanf("%lx", $1);
244 if($addr - $lookaddr > 0)
246 $addr -= $lookaddr;
248 if(abs($match{'diff'} - $addr) <= $context_size * 4)
250 printf "%s%s\n", ($addr == $match{'diff'} ? ">": " "), $_;
253 else
255 # TODO: be able to also show source code (within context_size)
256 # printf " %s\n", $_;
260 close OBJDUMP;
262 else
264 print "find_addr.pl 0xABCDEF [CONTEXT_SIZE]\n\n";
265 print <<EOF
266 This makes it possible to find the exact assembly instruction at the specified
267 memory location (depends on Makefile, rockbox.map and the object files).
269 Usage example:
270 mcuelenaere\@wim2160:~/rockbox/build2\$ ../utils/analysis/find_addr.pl 0x8001a434 1
271 /home/mcuelenaere/rockbox/build2/apps/screens.o -> id3_get_info
273 23c: 00601021 move v0,v1
274 > 240: 80620000 lb v0,0(v1)
275 244: 0002180a movz v1,zero,v0
278 Don't forget to build with -g !