diff -r 820b22e13ff1 -r 39c28ec933dd imgtools/romtools/rombuild/checkstubs.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/imgtools/romtools/rombuild/checkstubs.pl Mon May 10 19:54:49 2010 +0100 @@ -0,0 +1,298 @@ +# +# Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies). +# All rights reserved. +# This component and the accompanying materials are made available +# under the terms of the License "Eclipse Public License v1.0" +# which accompanies this distribution, and is available +# at the URL "http://www.eclipse.org/legal/epl-v10.html". +# +# Initial Contributors: +# Nokia Corporation - initial contribution. +# +# Contributors: +# +# Description: +# Perl script to check that import stubs go to the right place +# + +my $symbolfile="ba_001.engbuild.symbol"; +my $imagefile="ba_001.engbuild.img"; +my $imageoffset=0; # will be read from the image header + +die "Usage: checkstubs [imagefile]\n" if (@ARGV>1); +if (@ARGV==1) + { + $imagefile = @ARGV[0]; + $symbolfile = $imagefile; + $symbolfile =~ s/img$/symbol/i; + } + +# 1. Read in the SYMBOL information +# +# From \epoc32\release\ARM4\urel\netdial.agt +# 50989f5c 00c0 CImap4Utils::SendLogMessageL(int, TRequestStatus &) +# 5098a01c 000c stub UserSvr::DllGlobalAlloc(int, int) + +my %stubs; # stub names, by address +my %funcs; # function names, by address +my %knownfuncs; # function names which are reported in symbol file +my $line; + +open SYMBOL, "<$symbolfile" or die "Cannot open $symbolfile"; +while ($line=) + { + if ($line =~ /^([0-9a-f]{8})\s+[0-9a-f]+\s+(.*)$/i) + { + my $address = hex($1); + my $name = $2; + + $funcs{$address} = $name; + $knownfuncs{$name} = 1; + if ($name =~/^stub (.*)$/) + { + $stubs{$address} = $1; # lots of stubs, but only one address! + } + } + } +close SYMBOL; + +# 2. Understand the ROM structure +# + +open IMAGE, "<$imagefile" or die "Cannot open $imagefile"; +binmode IMAGE; + +my $stubaddress; +my $stubdata; +my $stubcount=0; +my $errors=0; +my $uncheckable=0; + +read IMAGE, $stubdata, 20; +if ($stubdata =~ /^EPOC....ROM/) + { + $imageoffset -= 256; # compensate for REPRO header + } + +# Read the image header to determine ROM linear address + +sub read_imageword + { + my $imagedata; + read IMAGE, $imagedata, 4; + return unpack "V", $imagedata; + } + +seek(IMAGE, 0x8c-$imageoffset, 0); +my $romlinearbase = read_imageword(); +my $romsize = read_imageword(); +$imageoffset += $romlinearbase; + +my %areas; +my %area_offsets; +$areas{$romlinearbase} = $romlinearbase+$romsize; +$area_offsets{$romlinearbase} = $imageoffset; + +# Check for the extension ROM + +if (seek(IMAGE, $romlinearbase+$romsize+0xC-$imageoffset,0)) + { + my $extensionlinearbase = read_imageword(); + my $extensionsize = read_imageword(); + + $areas{$extensionlinearbase} = $extensionlinearbase+$extensionsize; + $area_offsets{$extensionlinearbase} = + $imageoffset+($extensionlinearbase - $romlinearbase -$romsize); + } + +sub image_seek + { + my ($runaddress) = @_; + my $offset = 0; + + # Scan list of area mappings to determine correct offset + my $areabase; + foreach $areabase (keys %areas) + { + if ($areabase <= $runaddress && $areas{$areabase} > $runaddress) + { + $offset = $area_offsets{$areabase}; + last; + } + } + if ($offset==0) + { + printf "Can't find area for address 0x%x\n", $runaddress, $runaddress-$imageoffset; + $errors++; + return 0; + } + # + if (!seek(IMAGE, $runaddress-$offset, 0)) + { + printf "Can't seek to address 0x%x => offset 0x%x\n", $runaddress, $runaddress-$imageoffset; + $errors++; + return 0; + } + return 1; + } + +# Read the area relocation information (if any) + +image_seek($romlinearbase+0xd4); +my $areaptr = read_imageword(); +if ($areaptr != 0) + { + image_seek($areaptr); + my $areasize=0; + while ($areasize=read_imageword()) + { + my $srcbase=read_imageword(); + my $areabase=read_imageword(); + $areas{$areabase} = $areabase+$areasize; + $area_offsets{$areabase} = $imageoffset+($areabase-$srcbase); + } + } + +# 3. Scan the stubs +# + +foreach $stubaddress (sort keys %stubs) + { + my $stub = $stubs{$stubaddress}; + $stubcount++; + if (!image_seek($stubaddress)) + { + printf "Can't seek to %s at x%x\n", $stub, $stubaddress; + $errors++; + next; + } + read IMAGE, $stubdata, 20; + + my @arm_instructions = (unpack "V4", $stubdata); + my @thumb_instructions = (unpack "v6", $stubdata); + + my $address = $stubaddress; + my $indirections =-1; + my $finalbx = 1; + + if (@arm_instructions[0] == 0xe59fc000 && + @arm_instructions[1] == 0xe59cf000) + { + # arm4 stub + $indirections=2; + $address+=8; + $finalbx = 0; + } + if (@arm_instructions[0] == 0xe59fc004 && + @arm_instructions[1] == 0xe59cc000 && + @arm_instructions[2] == 0xe12fff1c) + { + # armi stub + $indirections=2; + $address+=12; + } + if (@arm_instructions[0] == 0xe59fc004 && + @arm_instructions[1] == 0xe12fff1c) + { + # fast armi stub + $indirections=1; + $address+=12; + } + if (@thumb_instructions[0] == 0xb440 && + @thumb_instructions[1] == 0x4e02 && + @thumb_instructions[2] == 0x6836 && + @thumb_instructions[3] == 0x46b4 && + @thumb_instructions[4] == 0xbc40 && + @thumb_instructions[5] == 0x4760) + { + # thumb stub + $indirections=2; + $address+=12; + } + if (@thumb_instructions[0] == 0xb440 && + @thumb_instructions[1] == 0x4e02 && + @thumb_instructions[2] == 0x46b4 && + @thumb_instructions[3] == 0xbc40 && + @thumb_instructions[4] == 0x4760) + { + # fast thumb stub + $indirections=1; + $address+=12; + } + if (@thumb_instructions[0] == 0x4b01 && + @thumb_instructions[1] == 0x681b && + @thumb_instructions[2] == 0x4718) + { + # thumb r3unused stub + $indirections=2; + $address+=8; + } + if (@thumb_instructions[0] == 0x4b01 && + @thumb_instructions[1] == 0x4718) + { + # fast thumb r3unused stub + $indirections=1; + $address+=8; + } + + if ($indirections < 0) + { + printf "At %08x unrecognised stub %s = %08x %08x %08x %08x\n", $stubaddress, $stub, + @arm_instructions[0], @arm_instructions[1], @arm_instructions[2], @arm_instructions[3]; + $errors++; + next; + } + + my $indirection_count = $indirections; + while ($indirection_count > 0) + { + if (!image_seek($address)) + { + printf "Failed to follow %s to address 0x%x\n", $stub, $address; + $errors++; + last; + } + my $data; + read IMAGE, $data, 4; + $address = unpack "V", $data; + $indirection_count -= 1; + } + next if ($indirection_count != 0); + + if ($finalbx) + { + $address &= 0xfffffffe; # clear THUMB mode indicator + } + + if (!defined($funcs{$address})) + { + if (!defined($knownfuncs{$stub})) + { + # we don't have a map file for the provider of this function anyway + $uncheckable++; + next; + } + printf "At %08x stub %s points to %08x, which is not a known function\n", $stubaddress, $stub, $address; + $errors++; + next; + } + if ($funcs{$address} ne $stub) + { + printf "At %08x stub %s points to %08x, which is %s\n", $stubaddress, $stub, $address, $funcs{$address}; + $errors++; + next; + } + # Hurrah - it goes to the right place... + } +close IMAGE; + +print "Checked $symbolfile and $imagefile\n"; +if ($errors==0 && $uncheckable==0) + { + print "All $stubcount stubs passed\n"; + } +else + { + print "Tested $stubcount stubs, $uncheckable couldn't be verified, found $errors errors\n"; + } +exit ($errors);