imgtools/romtools/rombuild/checkstubs.pl
author raptorbot <raptorbot@systemstesthead.symbian.intra>
Fri, 18 Dec 2009 19:57:42 +0000
branchwip
changeset 117 ecf683438dc6
parent 0 044383f39525
permissions -rw-r--r--
Don't mess around with EPOCROOT until actually entering raptor so we know what the original was Put the original epocroot back on the front of the whatcomp output. This allows what output to be either relative or absolute depending on what your epocroot is.

#
# 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=<SYMBOL>)
	{
	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);