#!/usr/bin/env perl # __________ __ ___. # Open \______ \ ____ ____ | | _\_ |__ _______ ___ # Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / # Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < # Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ # \/ \/ \/ \/ \/ # $Id$ # # Copyright (C) 2009 by Maurus Cuelenaere # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # KIND, either express or implied. # use String::Scanf; use Cwd; sub check_boundaries { my $fits = 0, $start = $_[0], $end = $_[0] + $_[1]; foreach my $boundary (@ram_boundaries) { if(defined(@$boundary{'name'}) && $start >= @$boundary{'start'} && $end <= @$boundary{'end'}) { return 1; } } return 0; } sub dynamic_space { my $space = $_[0], $space_array = $_[1], $ret; printf "This address is in %s space, please select the %s which was used with this address:\n", $space, $space; $count = 1; foreach my $el (@$space_array) { printf " [%d]: %s\n", $count++, $el; } print "\n"; my $sel = -1; do { print "Selection: "; $sel = ; } while($sel <= 0 || $sel > $count - 1 || !($sel =~ /^[+-]?\d+$/)); my $prefix; if($space eq 'plugin') { $prefix = 'apps'; } else { $prefix = 'lib/rbcodec'; } my $file = sprintf("%s/%ss/%s", $prefix, $space, @$space_array[$sel - 1]); $ret{'library'} = sprintf("%s/%s", cwd(), $file); open FILE, "$objdump -t $file |" or die "Can't open pipe: $!"; while() { chomp($_); if(/^([0-9a-fA-F]+).+\s([0-9a-fA-F]{3,})\s(?:[^\s]+\s)?(.+)$/) { (my $addr) = sscanf("%lx", $1); (my $size) = sscanf("%lx", $2); if($lookaddr >= $addr && $lookaddr <= ($addr + $size)) { my $diff = abs($lookaddr - $addr); if(!defined($ret{'diff'}) || $diff <= $ret{'diff'}) { $ret{'diff'} = $diff; $ret{'function'} = $3; } } } } close FILE; return %ret; } ($lookaddr) = sscanf("0x%lx", $ARGV[0]); ($context_size) = $#ARGV > 0 ? $ARGV[1] : 5; if($lookaddr != 0) { # Determine the used objdump utility open MAKEFILE, ") { chomp($_); if(/^export OC=(.+)$/) { $objdump = $1; $objdump =~ s/objcopy/objdump/; } } close MAKEFILE; # Generate a list of all codecs open FINDCODECS, "find lib/rbcodec/codecs/ -name '*.elf' 2>&1 |" or die "Can't open pipe: $!"; my @codecs; while() { chomp($_); $_ =~ s/lib\/rbcodec\/codecs\///; push(@codecs, $_); } close FINDCODECS; # Generate a list of all plugins open FINDPLUGINS, "find apps/plugins/ -name '*.elf' 2>&1 |" or die "Can't open pipe: $!"; my @plugins; while() { chomp($_); $_ =~ s/apps\/plugins\///; push(@plugins, $_); } close FINDPLUGINS; open MAPFILE, ") { chomp($_); if(/^\s*\.text\.([^\s]+)$/) { $prev_function = $1; } if(/^\.([^\s]+)\s*(0x[0-9a-fA-F]+)/) { ($addr) = sscanf("0x%lx", $2); if($1 eq "plugin") { $plugin_addr = $addr; } elsif($1 eq "codec") { $codec_addr = $addr; } } if(/^.*?\s*(0x[0-9a-fA-F]+)\s*(0x[0-9a-fA-F]+)\s(.+)$/) { ($addr) = sscanf("0x%lx", $1); ($size) = sscanf("0x%lx", $2); $library = $3; if(check_boundaries($addr, $size) != 0 && $lookaddr >= $addr && $lookaddr <= ($addr + $size)) { #printf "0x%x 0x%x %s %s\n", $addr, $size, $prev_function, $library; my $diff = abs($lookaddr - $addr); if(!defined($match{'diff'}) || $diff <= $match{'diff'}) { $match{'diff'} = $diff; $match{'library'} = $library; $match{'function'} = $prev_function; } } } elsif(/^\s*(0x[0-9a-fA-F]+)\s*([^\s]+)$/) { ($addr) = sscanf("0x%lx", $1); my $function = $2; if(check_boundaries($addr, 0) != 0 && $lookaddr >= $addr) { #printf "0x%x %s\n", $addr, $function; my $diff = abs($lookaddr - $addr); if(!defined($match{'diff'}) || $diff <= $match{'diff'}) { $match{'diff'} = $diff; $match{'library'} = $library; $match{'function'} = $function; } } } elsif(/^(.RAM) *(0x[0-9a-fA-F]+) (0x[0-9a-fA-F]+)/) { (my $start_addr) = sscanf("0x%lx", $2); (my $addr_length) = sscanf("0x%lx", $3); push(@ram_boundaries, {"name", $1, "start", $start_addr, "end", $start_addr + $addr_length }); } } close MAPFILE; if($lookaddr >= $codec_addr && $lookaddr < $plugin_addr && $codec_addr != 0) { # look for codec %match = dynamic_space("codec", \@codecs); } elsif($lookaddr >= $plugin_addr && $plugin_addr != 0) { # look for plugin %match = dynamic_space("plugin", \@plugins); } printf "%s -> %s\n\n", $match{'library'}, $match{'function'}; # Replace path/libfoo.a(bar.o) with path/libfoo.a $match{'library'} =~ s/\(.+\)//; open OBJDUMP, "$objdump -S $match{'library'} 2>&1 |" or die "Can't open pipe: $!"; my $found = 0, $addr; while() { chomp($_); if(/^[0-9a-fA-F]+\s\<(.+)\>:$/) { $found = ($1 eq $match{'function'}); } elsif(/Disassembly of section/) { $found = 0; } elsif($found == 1) { if(/^\s*([0-9a-fA-F]+):\s*[0-9a-fA-F]+\s*.+$/) { ($addr) = sscanf("%lx", $1); if($addr - $lookaddr > 0) { $addr -= $lookaddr; } if(abs($match{'diff'} - $addr) <= $context_size * 4) { printf "%s%s\n", ($addr == $match{'diff'} ? ">": " "), $_; } } else { # TODO: be able to also show source code (within context_size) # printf " %s\n", $_; } } } close OBJDUMP; } else { print "find_addr.pl 0xABCDEF [CONTEXT_SIZE]\n\n"; print < id3_get_info 23c: 00601021 move v0,v1 > 240: 80620000 lb v0,0(v1) 244: 0002180a movz v1,zero,v0 Don't forget to build with -g ! EOF ; }