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 | |
| 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 Cuelenaere | e8f75ed | 2009-06-28 18:51:38 +0000 | [diff] [blame] | 83 | ($lookaddr) = sscanf("0x%lx", $ARGV[0]); |
| 84 | ($context_size) = $#ARGV > 0 ? $ARGV[1] : 5; |
| 85 | |
| 86 | if($lookaddr != 0) |
| 87 | { |
| 88 | # Determine the used objdump utility |
Maurus Cuelenaere | e8f75ed | 2009-06-28 18:51:38 +0000 | [diff] [blame] | 89 | open MAKEFILE, "<Makefile" or die "Can't open Makefile: $!"; |
Maurus Cuelenaere | e8f75ed | 2009-06-28 18:51:38 +0000 | [diff] [blame] | 90 | 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 Cuelenaere | 1176553 | 2009-07-01 12:25:24 +0000 | [diff] [blame] | 102 | # 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 Cuelenaere | e8f75ed | 2009-06-28 18:51:38 +0000 | [diff] [blame] | 123 | open MAPFILE, "<rockbox.map" or die "Can't open rockbox.map: $!"; |
Maurus Cuelenaere | 1176553 | 2009-07-01 12:25:24 +0000 | [diff] [blame] | 124 | my $addr, $size, $library, $match, $prev_function, $codec_addr, $plugin_addr; |
Maurus Cuelenaere | e8f75ed | 2009-06-28 18:51:38 +0000 | [diff] [blame] | 125 | while(<MAPFILE>) |
| 126 | { |
| 127 | chomp($_); |
| 128 | |
| 129 | if(/^\s*\.text\.([^\s]+)$/) |
| 130 | { |
| 131 | $prev_function = $1; |
| 132 | } |
| 133 | |
Maurus Cuelenaere | 1176553 | 2009-07-01 12:25:24 +0000 | [diff] [blame] | 134 | if(/^\.([^\s]+)\s*(0x[0-9a-fA-F]+)/) |
| 135 | { |
| 136 | ($addr) = sscanf("0x%lx", $2); |
Maurus Cuelenaere | 0a59e04 | 2009-07-08 19:38:46 +0000 | [diff] [blame] | 137 | if($1 eq "plugin") |
Maurus Cuelenaere | 1176553 | 2009-07-01 12:25:24 +0000 | [diff] [blame] | 138 | { |
| 139 | $plugin_addr = $addr; |
| 140 | } |
| 141 | elsif($1 eq "codec") |
| 142 | { |
| 143 | $codec_addr = $addr; |
| 144 | } |
| 145 | } |
| 146 | |
| 147 | |
Maurus Cuelenaere | e8f75ed | 2009-06-28 18:51:38 +0000 | [diff] [blame] | 148 | 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 Cuelenaere | e251df9 | 2009-08-17 13:42:52 +0000 | [diff] [blame] | 198 | if($lookaddr >= $codec_addr && $lookaddr < $plugin_addr |
| 199 | && $codec_addr != 0) |
Maurus Cuelenaere | 1176553 | 2009-07-01 12:25:24 +0000 | [diff] [blame] | 200 | { |
| 201 | # look for codec |
| 202 | %match = dynamic_space("codec", \@codecs); |
| 203 | } |
Maurus Cuelenaere | e251df9 | 2009-08-17 13:42:52 +0000 | [diff] [blame] | 204 | elsif($lookaddr >= $plugin_addr && $plugin_addr != 0) |
Maurus Cuelenaere | 1176553 | 2009-07-01 12:25:24 +0000 | [diff] [blame] | 205 | { |
| 206 | # look for plugin |
| 207 | %match = dynamic_space("plugin", \@plugins); |
| 208 | } |
| 209 | |
Maurus Cuelenaere | e8f75ed | 2009-06-28 18:51:38 +0000 | [diff] [blame] | 210 | 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 Cuelenaere | 1176553 | 2009-07-01 12:25:24 +0000 | [diff] [blame] | 221 | if(/^[0-9a-fA-F]+\s\<(.+)\>:$/) |
Maurus Cuelenaere | e8f75ed | 2009-06-28 18:51:38 +0000 | [diff] [blame] | 222 | { |
| 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 Cuelenaere | 1176553 | 2009-07-01 12:25:24 +0000 | [diff] [blame] | 235 | if($addr - $lookaddr > 0) |
| 236 | { |
| 237 | $addr -= $lookaddr; |
| 238 | } |
Maurus Cuelenaere | e8f75ed | 2009-06-28 18:51:38 +0000 | [diff] [blame] | 239 | 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 | } |
| 253 | else |
| 254 | { |
| 255 | print "find_addr.pl 0xABCDEF [CONTEXT_SIZE]\n\n"; |
| 256 | print <<EOF |
| 257 | This makes it possible to find the exact assembly instruction at the specified |
| 258 | memory location (depends on Makefile, rockbox.map and the object files). |
| 259 | |
| 260 | Usage example: |
Maurus Cuelenaere | 1176553 | 2009-07-01 12:25:24 +0000 | [diff] [blame] | 261 | mcuelenaere\@wim2160:~/rockbox/build2\$ ../utils/analysis/find_addr.pl 0x8001a434 1 |
Maurus Cuelenaere | e8f75ed | 2009-06-28 18:51:38 +0000 | [diff] [blame] | 262 | /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 | |
| 269 | Don't forget to build with -g ! |
| 270 | EOF |
| 271 | ; |
Maurus Cuelenaere | e251df9 | 2009-08-17 13:42:52 +0000 | [diff] [blame] | 272 | } |