imgtools/romtools/rombuild/checkstubs.pl
author timothy.murphy@nokia.com
Sun, 28 Feb 2010 21:18:07 +0200
branchfix
changeset 279 733464eaac50
parent 0 044383f39525
permissions -rw-r--r--
fix: make sure host attribute is set rather than blank in logs on windows by using the env var 'COMPUTERNAME' instead of 'HOSTNAME'. Thus make it less difficult to order recipes in the log by time.

#
# 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);