Maurus Cuelenaere | e8f75ed | 2009-06-28 18:51:38 +0000 | [diff] [blame] | 1 | #!/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 | # |
| 20 | use String::Scanf; |
Maurus Cuelenaere | 1176553 | 2009-07-01 12:25:24 +0000 | [diff] [blame] | 21 | use Cwd; |
Maurus Cuelenaere | e8f75ed | 2009-06-28 18:51:38 +0000 | [diff] [blame] | 22 | |
| 23 | sub 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 Cuelenaere | 1176553 | 2009-07-01 12:25:24 +0000 | [diff] [blame] | 37 | sub 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 | |
Amaury Pouly | cc59ea4 | 2012-05-31 15:56:34 +0200 | [diff] [blame] | 56 | my $prefix; |
| 57 | if($space eq 'plugin') |
| 58 | { |
| 59 | $prefix = 'apps'; |
| 60 | } |
| 61 | else |
| 62 | { |
| 63 | $prefix = 'lib/rbcodec'; |
| 64 | } |
| 65 | my $file = sprintf("%s/%ss/%s", $prefix, $space, @$space_array[$sel - 1]); |
Maurus Cuelenaere | 1176553 | 2009-07-01 12:25:24 +0000 | [diff] [blame] | 66 | $ret{'library'} = sprintf("%s/%s", cwd(), $file); |
| 67 | open FILE, "$objdump -t $file |" or die "Can't open pipe: $!"; |
| 68 | while(<FILE>) |
| 69 | { |
| 70 | chomp($_); |
| 71 | if(/^([0-9a-fA-F]+).+\s([0-9a-fA-F]{3,})\s(?:[^\s]+\s)?(.+)$/) |
| 72 | { |
| 73 | (my $addr) = sscanf("%lx", $1); |
| 74 | (my $size) = sscanf("%lx", $2); |
| 75 | |
| 76 | if($lookaddr >= $addr && $lookaddr <= ($addr + $size)) |
| 77 | { |
| 78 | my $diff = abs($lookaddr - $addr); |
| 79 | if(!defined($ret{'diff'}) || $diff <= $ret{'diff'}) |
| 80 | { |
| 81 | $ret{'diff'} = $diff; |
| 82 | $ret{'function'} = $3; |
| 83 | } |
| 84 | } |
| 85 | } |
| 86 | } |
| 87 | close FILE; |
| 88 | |
| 89 | return %ret; |
| 90 | } |
| 91 | |
Maurus Cuelenaere | e8f75ed | 2009-06-28 18:51:38 +0000 | [diff] [blame] | 92 | ($lookaddr) = sscanf("0x%lx", $ARGV[0]); |
| 93 | ($context_size) = $#ARGV > 0 ? $ARGV[1] : 5; |
| 94 | |
| 95 | if($lookaddr != 0) |
| 96 | { |
| 97 | # Determine the used objdump utility |
Maurus Cuelenaere | e8f75ed | 2009-06-28 18:51:38 +0000 | [diff] [blame] | 98 | open MAKEFILE, "<Makefile" or die "Can't open Makefile: $!"; |
Maurus Cuelenaere | e8f75ed | 2009-06-28 18:51:38 +0000 | [diff] [blame] | 99 | while(<MAKEFILE>) |
| 100 | { |
| 101 | chomp($_); |
| 102 | |
| 103 | if(/^export OC=(.+)$/) |
| 104 | { |
| 105 | $objdump = $1; |
| 106 | $objdump =~ s/objcopy/objdump/; |
| 107 | } |
| 108 | } |
| 109 | close MAKEFILE; |
| 110 | |
Maurus Cuelenaere | 1176553 | 2009-07-01 12:25:24 +0000 | [diff] [blame] | 111 | # Generate a list of all codecs |
Sean Bartell | f40bfc9 | 2011-06-25 21:32:25 -0400 | [diff] [blame] | 112 | open FINDCODECS, "find lib/rbcodec/codecs/ -name '*.elf' 2>&1 |" or die "Can't open pipe: $!"; |
Maurus Cuelenaere | 1176553 | 2009-07-01 12:25:24 +0000 | [diff] [blame] | 113 | my @codecs; |
| 114 | while(<FINDCODECS>) |
| 115 | { |
| 116 | chomp($_); |
Sean Bartell | f40bfc9 | 2011-06-25 21:32:25 -0400 | [diff] [blame] | 117 | $_ =~ s/lib\/rbcodec\/codecs\///; |
Maurus Cuelenaere | 1176553 | 2009-07-01 12:25:24 +0000 | [diff] [blame] | 118 | push(@codecs, $_); |
| 119 | } |
| 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>) |
| 125 | { |
| 126 | chomp($_); |
| 127 | $_ =~ s/apps\/plugins\///; |
| 128 | push(@plugins, $_); |
| 129 | } |
| 130 | close FINDPLUGINS; |
| 131 | |
Maurus Cuelenaere | e8f75ed | 2009-06-28 18:51:38 +0000 | [diff] [blame] | 132 | open MAPFILE, "<rockbox.map" or die "Can't open rockbox.map: $!"; |
Maurus Cuelenaere | 1176553 | 2009-07-01 12:25:24 +0000 | [diff] [blame] | 133 | my $addr, $size, $library, $match, $prev_function, $codec_addr, $plugin_addr; |
Maurus Cuelenaere | e8f75ed | 2009-06-28 18:51:38 +0000 | [diff] [blame] | 134 | while(<MAPFILE>) |
| 135 | { |
| 136 | chomp($_); |
| 137 | |
| 138 | if(/^\s*\.text\.([^\s]+)$/) |
| 139 | { |
| 140 | $prev_function = $1; |
| 141 | } |
| 142 | |
Maurus Cuelenaere | 1176553 | 2009-07-01 12:25:24 +0000 | [diff] [blame] | 143 | if(/^\.([^\s]+)\s*(0x[0-9a-fA-F]+)/) |
| 144 | { |
| 145 | ($addr) = sscanf("0x%lx", $2); |
Maurus Cuelenaere | 0a59e04 | 2009-07-08 19:38:46 +0000 | [diff] [blame] | 146 | if($1 eq "plugin") |
Maurus Cuelenaere | 1176553 | 2009-07-01 12:25:24 +0000 | [diff] [blame] | 147 | { |
| 148 | $plugin_addr = $addr; |
| 149 | } |
| 150 | elsif($1 eq "codec") |
| 151 | { |
| 152 | $codec_addr = $addr; |
| 153 | } |
| 154 | } |
| 155 | |
| 156 | |
Maurus Cuelenaere | e8f75ed | 2009-06-28 18:51:38 +0000 | [diff] [blame] | 157 | if(/^.*?\s*(0x[0-9a-fA-F]+)\s*(0x[0-9a-fA-F]+)\s(.+)$/) |
| 158 | { |
| 159 | ($addr) = sscanf("0x%lx", $1); |
| 160 | ($size) = sscanf("0x%lx", $2); |
| 161 | $library = $3; |
| 162 | |
| 163 | if(check_boundaries($addr, $size) != 0 |
| 164 | && $lookaddr >= $addr && $lookaddr <= ($addr + $size)) |
| 165 | { |
| 166 | #printf "0x%x 0x%x %s %s\n", $addr, $size, $prev_function, $library; |
| 167 | |
| 168 | my $diff = abs($lookaddr - $addr); |
| 169 | if(!defined($match{'diff'}) || $diff <= $match{'diff'}) |
| 170 | { |
| 171 | $match{'diff'} = $diff; |
| 172 | $match{'library'} = $library; |
| 173 | $match{'function'} = $prev_function; |
| 174 | } |
| 175 | } |
| 176 | } |
| 177 | elsif(/^\s*(0x[0-9a-fA-F]+)\s*([^\s]+)$/) |
| 178 | { |
| 179 | ($addr) = sscanf("0x%lx", $1); |
| 180 | my $function = $2; |
| 181 | |
| 182 | if(check_boundaries($addr, 0) != 0 && $lookaddr >= $addr) |
| 183 | { |
| 184 | #printf "0x%x %s\n", $addr, $function; |
| 185 | |
| 186 | my $diff = abs($lookaddr - $addr); |
| 187 | if(!defined($match{'diff'}) || $diff <= $match{'diff'}) |
| 188 | { |
| 189 | $match{'diff'} = $diff; |
| 190 | $match{'library'} = $library; |
| 191 | $match{'function'} = $function; |
| 192 | } |
| 193 | } |
| 194 | } |
| 195 | elsif(/^(.RAM) *(0x[0-9a-fA-F]+) (0x[0-9a-fA-F]+)/) |
| 196 | { |
| 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 |
| 202 | }); |
| 203 | } |
| 204 | } |
| 205 | close MAPFILE; |
| 206 | |
Maurus Cuelenaere | e251df9 | 2009-08-17 13:42:52 +0000 | [diff] [blame] | 207 | if($lookaddr >= $codec_addr && $lookaddr < $plugin_addr |
| 208 | && $codec_addr != 0) |
Maurus Cuelenaere | 1176553 | 2009-07-01 12:25:24 +0000 | [diff] [blame] | 209 | { |
| 210 | # look for codec |
| 211 | %match = dynamic_space("codec", \@codecs); |
| 212 | } |
Maurus Cuelenaere | e251df9 | 2009-08-17 13:42:52 +0000 | [diff] [blame] | 213 | elsif($lookaddr >= $plugin_addr && $plugin_addr != 0) |
Maurus Cuelenaere | 1176553 | 2009-07-01 12:25:24 +0000 | [diff] [blame] | 214 | { |
| 215 | # look for plugin |
| 216 | %match = dynamic_space("plugin", \@plugins); |
| 217 | } |
| 218 | |
Maurus Cuelenaere | e8f75ed | 2009-06-28 18:51:38 +0000 | [diff] [blame] | 219 | printf "%s -> %s\n\n", $match{'library'}, $match{'function'}; |
| 220 | |
| 221 | # Replace path/libfoo.a(bar.o) with path/libfoo.a |
| 222 | $match{'library'} =~ s/\(.+\)//; |
| 223 | |
| 224 | open OBJDUMP, "$objdump -S $match{'library'} 2>&1 |" or die "Can't open pipe: $!"; |
| 225 | my $found = 0, $addr; |
| 226 | while(<OBJDUMP>) |
| 227 | { |
| 228 | chomp($_); |
| 229 | |
Maurus Cuelenaere | 1176553 | 2009-07-01 12:25:24 +0000 | [diff] [blame] | 230 | if(/^[0-9a-fA-F]+\s\<(.+)\>:$/) |
Maurus Cuelenaere | e8f75ed | 2009-06-28 18:51:38 +0000 | [diff] [blame] | 231 | { |
| 232 | $found = ($1 eq $match{'function'}); |
| 233 | } |
| 234 | elsif(/Disassembly of section/) |
| 235 | { |
| 236 | $found = 0; |
| 237 | } |
| 238 | elsif($found == 1) |
| 239 | { |
| 240 | if(/^\s*([0-9a-fA-F]+):\s*[0-9a-fA-F]+\s*.+$/) |
| 241 | { |
| 242 | ($addr) = sscanf("%lx", $1); |
| 243 | |
Maurus Cuelenaere | 1176553 | 2009-07-01 12:25:24 +0000 | [diff] [blame] | 244 | if($addr - $lookaddr > 0) |
| 245 | { |
| 246 | $addr -= $lookaddr; |
| 247 | } |
Maurus Cuelenaere | e8f75ed | 2009-06-28 18:51:38 +0000 | [diff] [blame] | 248 | if(abs($match{'diff'} - $addr) <= $context_size * 4) |
| 249 | { |
| 250 | printf "%s%s\n", ($addr == $match{'diff'} ? ">": " "), $_; |
| 251 | } |
| 252 | } |
| 253 | else |
| 254 | { |
| 255 | # TODO: be able to also show source code (within context_size) |
| 256 | # printf " %s\n", $_; |
| 257 | } |
| 258 | } |
| 259 | } |
| 260 | close OBJDUMP; |
| 261 | } |
| 262 | else |
| 263 | { |
| 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). |
| 268 | |
| 269 | Usage example: |
Maurus Cuelenaere | 1176553 | 2009-07-01 12:25:24 +0000 | [diff] [blame] | 270 | mcuelenaere\@wim2160:~/rockbox/build2\$ ../utils/analysis/find_addr.pl 0x8001a434 1 |
Maurus Cuelenaere | e8f75ed | 2009-06-28 18:51:38 +0000 | [diff] [blame] | 271 | /home/mcuelenaere/rockbox/build2/apps/screens.o -> id3_get_info |
| 272 | |
| 273 | 23c: 00601021 move v0,v1 |
| 274 | > 240: 80620000 lb v0,0(v1) |
| 275 | 244: 0002180a movz v1,zero,v0 |
| 276 | |
| 277 | |
| 278 | Don't forget to build with -g ! |
| 279 | EOF |
| 280 | ; |
Maurus Cuelenaere | e251df9 | 2009-08-17 13:42:52 +0000 | [diff] [blame] | 281 | } |