blob: dd42ef6dd80dccb6bf1263e5c61ac0d46b18ae03 [file] [log] [blame]
Maurus Cuelenaeree8f75ed2009-06-28 18:51:38 +00001#!/usr/bin/env perl
2# __________ __ ___.
3# Open \______ \ ____ ____ | | _\_ |__ _______ ___
4# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7# \/ \/ \/ \/ \/
8# $Id$
9#
10# Copyright (C) 2009 by Maurus Cuelenaere
11#
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.
16#
17# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18# KIND, either express or implied.
19#
20use String::Scanf;
Maurus Cuelenaere11765532009-07-01 12:25:24 +000021use Cwd;
Maurus Cuelenaeree8f75ed2009-06-28 18:51:38 +000022
23sub check_boundaries
24{
25 my $fits = 0, $start = $_[0], $end = $_[0] + $_[1];
26 foreach my $boundary (@ram_boundaries)
27 {
28 if(defined(@$boundary{'name'}) && $start >= @$boundary{'start'} && $end <= @$boundary{'end'})
29 {
30 return 1;
31 }
32 }
33
34 return 0;
35}
36
Maurus Cuelenaere11765532009-07-01 12:25:24 +000037sub dynamic_space
38{
39 my $space = $_[0], $space_array = $_[1], $ret;
40
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)
44 {
45 printf " [%d]: %s\n", $count++, $el;
46 }
47
48 print "\n";
49 my $sel = -1;
50 do
51 {
52 print "Selection: ";
53 $sel = <STDIN>;
54 } while($sel <= 0 || $sel > $count - 1 || !($sel =~ /^[+-]?\d+$/));
55
56 my $file = sprintf("apps/%ss/%s", $space, @$space_array[$sel - 1]);
57 $ret{'library'} = sprintf("%s/%s", cwd(), $file);
58 open FILE, "$objdump -t $file |" or die "Can't open pipe: $!";
59 while(<FILE>)
60 {
61 chomp($_);
62 if(/^([0-9a-fA-F]+).+\s([0-9a-fA-F]{3,})\s(?:[^\s]+\s)?(.+)$/)
63 {
64 (my $addr) = sscanf("%lx", $1);
65 (my $size) = sscanf("%lx", $2);
66
67 if($lookaddr >= $addr && $lookaddr <= ($addr + $size))
68 {
69 my $diff = abs($lookaddr - $addr);
70 if(!defined($ret{'diff'}) || $diff <= $ret{'diff'})
71 {
72 $ret{'diff'} = $diff;
73 $ret{'function'} = $3;
74 }
75 }
76 }
77 }
78 close FILE;
79
80 return %ret;
81}
82
Maurus Cuelenaeree8f75ed2009-06-28 18:51:38 +000083($lookaddr) = sscanf("0x%lx", $ARGV[0]);
84($context_size) = $#ARGV > 0 ? $ARGV[1] : 5;
85
86if($lookaddr != 0)
87{
88 # Determine the used objdump utility
Maurus Cuelenaeree8f75ed2009-06-28 18:51:38 +000089 open MAKEFILE, "<Makefile" or die "Can't open Makefile: $!";
Maurus Cuelenaeree8f75ed2009-06-28 18:51:38 +000090 while(<MAKEFILE>)
91 {
92 chomp($_);
93
94 if(/^export OC=(.+)$/)
95 {
96 $objdump = $1;
97 $objdump =~ s/objcopy/objdump/;
98 }
99 }
100 close MAKEFILE;
101
Maurus Cuelenaere11765532009-07-01 12:25:24 +0000102 # Generate a list of all codecs
103 open FINDCODECS, "find apps/codecs/ -name '*.elf' 2>&1 |" or die "Can't open pipe: $!";
104 my @codecs;
105 while(<FINDCODECS>)
106 {
107 chomp($_);
108 $_ =~ s/apps\/codecs\///;
109 push(@codecs, $_);
110 }
111 close FINDCODECS;
112 # Generate a list of all plugins
113 open FINDPLUGINS, "find apps/plugins/ -name '*.elf' 2>&1 |" or die "Can't open pipe: $!";
114 my @plugins;
115 while(<FINDPLUGINS>)
116 {
117 chomp($_);
118 $_ =~ s/apps\/plugins\///;
119 push(@plugins, $_);
120 }
121 close FINDPLUGINS;
122
Maurus Cuelenaeree8f75ed2009-06-28 18:51:38 +0000123 open MAPFILE, "<rockbox.map" or die "Can't open rockbox.map: $!";
Maurus Cuelenaere11765532009-07-01 12:25:24 +0000124 my $addr, $size, $library, $match, $prev_function, $codec_addr, $plugin_addr;
Maurus Cuelenaeree8f75ed2009-06-28 18:51:38 +0000125 while(<MAPFILE>)
126 {
127 chomp($_);
128
129 if(/^\s*\.text\.([^\s]+)$/)
130 {
131 $prev_function = $1;
132 }
133
Maurus Cuelenaere11765532009-07-01 12:25:24 +0000134 if(/^\.([^\s]+)\s*(0x[0-9a-fA-F]+)/)
135 {
136 ($addr) = sscanf("0x%lx", $2);
Maurus Cuelenaere0a59e042009-07-08 19:38:46 +0000137 if($1 eq "plugin")
Maurus Cuelenaere11765532009-07-01 12:25:24 +0000138 {
139 $plugin_addr = $addr;
140 }
141 elsif($1 eq "codec")
142 {
143 $codec_addr = $addr;
144 }
145 }
146
147
Maurus Cuelenaeree8f75ed2009-06-28 18:51:38 +0000148 if(/^.*?\s*(0x[0-9a-fA-F]+)\s*(0x[0-9a-fA-F]+)\s(.+)$/)
149 {
150 ($addr) = sscanf("0x%lx", $1);
151 ($size) = sscanf("0x%lx", $2);
152 $library = $3;
153
154 if(check_boundaries($addr, $size) != 0
155 && $lookaddr >= $addr && $lookaddr <= ($addr + $size))
156 {
157 #printf "0x%x 0x%x %s %s\n", $addr, $size, $prev_function, $library;
158
159 my $diff = abs($lookaddr - $addr);
160 if(!defined($match{'diff'}) || $diff <= $match{'diff'})
161 {
162 $match{'diff'} = $diff;
163 $match{'library'} = $library;
164 $match{'function'} = $prev_function;
165 }
166 }
167 }
168 elsif(/^\s*(0x[0-9a-fA-F]+)\s*([^\s]+)$/)
169 {
170 ($addr) = sscanf("0x%lx", $1);
171 my $function = $2;
172
173 if(check_boundaries($addr, 0) != 0 && $lookaddr >= $addr)
174 {
175 #printf "0x%x %s\n", $addr, $function;
176
177 my $diff = abs($lookaddr - $addr);
178 if(!defined($match{'diff'}) || $diff <= $match{'diff'})
179 {
180 $match{'diff'} = $diff;
181 $match{'library'} = $library;
182 $match{'function'} = $function;
183 }
184 }
185 }
186 elsif(/^(.RAM) *(0x[0-9a-fA-F]+) (0x[0-9a-fA-F]+)/)
187 {
188 (my $start_addr) = sscanf("0x%lx", $2);
189 (my $addr_length) = sscanf("0x%lx", $3);
190 push(@ram_boundaries, {"name", $1,
191 "start", $start_addr,
192 "end", $start_addr + $addr_length
193 });
194 }
195 }
196 close MAPFILE;
197
Maurus Cuelenaeree251df92009-08-17 13:42:52 +0000198 if($lookaddr >= $codec_addr && $lookaddr < $plugin_addr
199 && $codec_addr != 0)
Maurus Cuelenaere11765532009-07-01 12:25:24 +0000200 {
201 # look for codec
202 %match = dynamic_space("codec", \@codecs);
203 }
Maurus Cuelenaeree251df92009-08-17 13:42:52 +0000204 elsif($lookaddr >= $plugin_addr && $plugin_addr != 0)
Maurus Cuelenaere11765532009-07-01 12:25:24 +0000205 {
206 # look for plugin
207 %match = dynamic_space("plugin", \@plugins);
208 }
209
Maurus Cuelenaeree8f75ed2009-06-28 18:51:38 +0000210 printf "%s -> %s\n\n", $match{'library'}, $match{'function'};
211
212 # Replace path/libfoo.a(bar.o) with path/libfoo.a
213 $match{'library'} =~ s/\(.+\)//;
214
215 open OBJDUMP, "$objdump -S $match{'library'} 2>&1 |" or die "Can't open pipe: $!";
216 my $found = 0, $addr;
217 while(<OBJDUMP>)
218 {
219 chomp($_);
220
Maurus Cuelenaere11765532009-07-01 12:25:24 +0000221 if(/^[0-9a-fA-F]+\s\<(.+)\>:$/)
Maurus Cuelenaeree8f75ed2009-06-28 18:51:38 +0000222 {
223 $found = ($1 eq $match{'function'});
224 }
225 elsif(/Disassembly of section/)
226 {
227 $found = 0;
228 }
229 elsif($found == 1)
230 {
231 if(/^\s*([0-9a-fA-F]+):\s*[0-9a-fA-F]+\s*.+$/)
232 {
233 ($addr) = sscanf("%lx", $1);
234
Maurus Cuelenaere11765532009-07-01 12:25:24 +0000235 if($addr - $lookaddr > 0)
236 {
237 $addr -= $lookaddr;
238 }
Maurus Cuelenaeree8f75ed2009-06-28 18:51:38 +0000239 if(abs($match{'diff'} - $addr) <= $context_size * 4)
240 {
241 printf "%s%s\n", ($addr == $match{'diff'} ? ">": " "), $_;
242 }
243 }
244 else
245 {
246 # TODO: be able to also show source code (within context_size)
247 # printf " %s\n", $_;
248 }
249 }
250 }
251 close OBJDUMP;
252}
253else
254{
255 print "find_addr.pl 0xABCDEF [CONTEXT_SIZE]\n\n";
256 print <<EOF
257This makes it possible to find the exact assembly instruction at the specified
258memory location (depends on Makefile, rockbox.map and the object files).
259
260Usage example:
Maurus Cuelenaere11765532009-07-01 12:25:24 +0000261 mcuelenaere\@wim2160:~/rockbox/build2\$ ../utils/analysis/find_addr.pl 0x8001a434 1
Maurus Cuelenaeree8f75ed2009-06-28 18:51:38 +0000262 /home/mcuelenaere/rockbox/build2/apps/screens.o -> id3_get_info
263
264 23c: 00601021 move v0,v1
265 > 240: 80620000 lb v0,0(v1)
266 244: 0002180a movz v1,zero,v0
267
268
269Don't forget to build with -g !
270EOF
271;
Maurus Cuelenaeree251df92009-08-17 13:42:52 +0000272}