external tools cannot specify path.
#
# Copyright (c) 1999-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:
# Relinks the debug exe/dlls in a ROM if the make file is present
#
require 5.003_07;
use strict;
no strict 'vars';
use English;
use Cwd;
use FindBin; # for FindBin::Bin
my $PerlLibPath;
BEGIN {
# check user has a version of perl that will cope
require 5.005_03;
$PerlLibPath = $FindBin::Bin;
}
use lib $PerlLibPath;
use romutl;
# Version
my $MajorVersion = 1;
my $MinorVersion = 1;
my $PatchVersion = 1;
# Globals
my $debug = 0;
my $rombuild;
my @executables = ( 'euser' );
cwd =~ /^(.:)/o;
my $drive = $1;
# get EPOCROOT for searching directories
my $epocroot = lc &get_epocroot;
&args;
&main;
exit 0;
#
# main
#
sub main
{
my $file;
my $text;
my $data;
my $bss;
my $textlen;
my $datalen;
my $bsslen;
open (ROM, "<$rombuild")
or die "ERROR: Can't open rombuild log file \"$rombuild\"\n";
die "ERROR: \"$rombuild\" isn't a rombuild log file\n"
unless ((<ROM> =~ /^ROMBUILD/) || (<ROM> =~ /^ROMBUILD/));
# build up a hash of all the make files indexed by build and exe name
#
# do this in a more directed way based on the map files for the
# executables we are interested in.
%map = ();
&dirsearch($epocroot . "EPOC32\\", "BUILD");
while (<ROM>)
{
if (/^Writing Rom image/)
{
# stop at end of first ROM, ignoring any extension ROMs
# This is necessary because the same file could appear
# at different places in different extensions.
#
last;
}
if (/^Processing file (.*)/)
{
my $datalen;
my $skip;
$file = lc $1;
$text = $bss = $data = $datalen = 0;
# Work out final addresses of sections
while (defined($_=<ROM>) && !/^$/)
{
if (/^Code start addr:\s+(\w+)/)
{
$text = hex($1);
}
elsif (/^DataBssLinearBase:\s+(\w+)/)
{
$data = hex($1);
}
elsif (/^Code size:\s+(\w+)/)
{
$textlen = hex($1);
}
elsif (/^Data size:\s+(\w+)/)
{
$datalen = hex($1);
$bss = $data + $datalen;
}
elsif (/^BssSize:\s+(\w+)/)
{
$bsslen = hex($1);
}
}
# Sanity check - text section can't be zero (other sections may be)
die "ERROR: Can't find rombuild info for \"$file\"\n"
if (!$text);
# get the build and exe name
# protect $epocroot with \Q and \E to stop it
# using \ as a special character
if ($file =~ /^\Q$epocroot\Eepoc32\\release\\(.*)\\(.*)\\(.*)$/o)
{
$build = lc $1;
$debrel = uc $2;
$executablefile = lc $3;
}
# Only relink this file if it's kernel-side or matches the regexp
if ($build =~ /^(M|S)/i)
{
$skip = 0;
}
else
{
$skip = 1;
foreach $re (@executables)
{
$skip = 0 if ($file =~ /$re/i);
}
}
print "$file - skipped\n" if ($skip && $debug);
next if ($skip);
if (! defined $map{"$build $executablefile"})
{
print "$file - no makefile\n";
next;
}
if ($debrel ne "UDEB")
{
print "$file - can't fixup $debrel\n";
next;
}
# relink this file
print "$file";
# lookup the makefile name
($makepath, $workdir) = @{$map{"$build $executablefile"}};
# only relink if we have a makefile
if ($makepath && $workdir)
{
# optimisation: don't relink if already at correct address
$file =~ /(.+\.)[^\.]+/;
my $symfile = $drive.$1."sym";
my $buf;
my $elffile;
open SYMFILE, $symfile or print"\nCannot open $symfile\n";
read SYMFILE, $buf, 4;
if ($buf =~/^\x7F\x45\x4C\x46/){
$elffile = $buf;
}
close SYMFILE;
if ($elffile){
if ((-e $file) && (-e $symfile) &&
open (CHILD, "fromelf -v $symfile |"))
{
my $oldtext;
my $olddata;
my $foundcode = 0;
my $founddata = 0;
while (<CHILD>)
{
if (/ER_RO/)
{
$foundcode = 1;
}
if (/ER_RW/)
{
$founddata = 1;
}
if (/Addr : 0x\w+/)
{
$_=~tr/0-9//dc;
if ($founddata == 1)
{
$founddata = 0;
$olddata = hex($_);
}
if ($foundcode == 1)
{
$foundcode = 0;
$oldtext = hex($_);
}
}
}
close CHILD;
$skip = 1 if ((!$textlen || ($text == $oldtext)) && (!$datalen || ($data == $olddata)));
}
}
else {
if ((-e $file) && (-e $symfile) &&
open (CHILD, "objdump --headers $symfile |"))
{
my $oldtext;
my $olddata;
my $oldbss;
while (<CHILD>)
{
if (/^\s+\d+\s+(\.\w+)\s+[0-9a-fA-F]+\s+([0-9a-fA-F]+)\s/)
{
if ($1 eq '.text')
{
$oldtext = hex($2);
}
elsif ($1 eq '.data')
{
$olddata = hex($2);
}
elsif ($1 eq '.bss')
{
$oldbss = hex($2);
}
}
}
close CHILD;
$skip = 1 if ((!$textlen || ($text == $oldtext)) &&
(!$datalen || ($data == $olddata)) &&
(!$bsslen || ($bss == $oldbss)));
print " - current" if ($skip && $debug);
}
}
if (!$skip)
{
chdir $workdir
or die "Can't cd to build directory \"$workdir\"\n";
# save executable in case relink fails
rename $file, "$file.bak"
or die "Can't rename \"$file\": $ERRNO\n"
if -e $file;
$makepath = &fixMakefile($makepath);
my $command;
if ($elffile){
if($makepath =~ /\.gcce/i){
$command =
sprintf ("make -r -s -f \"$makepath\" $debrel " .
"USERLDFLAGS=\"-Ttext 0x%lx -Tdata 0x%lx\"", $text, $data);
}
else {
$command =
sprintf ("make -r -s -f \"$makepath\" $debrel " .
"USERLDFLAGS=\"--ro-base 0x%lx --rw-base 0x%lx\"", $text, $data);
}
}
else {
$command =
sprintf ("make -r -s -f \"$makepath\" $debrel " .
"USERLDFLAGS=\"--image-base 0 -Ttext 0x%lx " .
"-Tdata 0x%lx -Tbss 0x%lx\"",
$text, $data, $bss);
}
print "\n\"$command\"" if ($debug);
open (CHILD, "$command |")
or die "\nERROR: Can't run \"$command\": $ERRNO\n";
close CHILD;
unlink $makepath;
if (-e $file)
{
unlink "$file.bak";
}
else # relink failed for some reason - restore saved
{
rename "$file.bak", $file;
}
}
print "\n";
}
else
{
print " - can't fixup\n";
}
}
}
close ROM;
}
#
# args - get command line args
#
sub args
{
my $arg;
my @args;
my $flag;
&help if (!@ARGV);
while (@ARGV)
{
$arg = shift @ARGV;
if ($arg=~/^[\-](\S*)$/)
{
$flag=$1;
if ($flag=~/^[\?h]$/i)
{
&help;
}
else
{
print "\nERROR: Unknown flag \"-$flag\"\n";
&usage;
exit 1;
}
}
else
{
push @args,$arg;
}
}
$rombuild = shift @args;
if (@args)
{
foreach $file (@args)
{
push @executables, quotemeta($file);
}
}
}
# recursive directory search
sub dirsearch
{
my ($input_path, $dir) = @_;
my $searchpath = "$input_path$dir\\";
my $workdir;
return unless (opendir DIRHANDLE, $searchpath);
my @allfiles = grep !/^\.\.?$/, readdir DIRHANDLE;
closedir DIRHANDLE;
# Breadth first search: scan files and collect list of subdirectories
my @dirlist;
foreach $entry (@allfiles)
{
my $entrypath = "$searchpath$entry";
if (-d $entrypath)
{
# don't look in udeb & urel directories which contain objects and binaries
push @dirlist, $entry unless ($entry =~ /(deb|rel)$/i);
}
elsif ($entry =~ /$dir$/i)
{
# ARM4/xxx.ARM4 => generated makefile
my $liney;
open (FILE, "<$entrypath");
while ($liney=<FILE>)
{
if ($liney =~ /^\# CWD\s(.+)\\/)
{
$workdir = lc $1;
}
if ($liney =~ /^\# Target\s(.*)$/)
{
my $target = lc $1;
# add to the hash table
my $build = lc $dir;
$map{"$build $target"} = [lc "$entrypath", $workdir];
$workdir = undef;
last;
}
}
close FILE;
}
}
undef @allfiles;
# Now process the subdirectories...
foreach $entry (@dirlist)
{
&dirsearch ($searchpath,$entry);
}
undef @dirlist;
}
sub help ()
{
my $build;
print "\nfixupsym - " .
"Fix up executables with locations taken from a ROM image V${MajorVersion}.${MinorVersion}.${PatchVersion}\n";
&usage;
exit 0;
}
sub usage ()
{
print <<EOF
Usage:
fixupsym <logfile> [<executables>]
Where:
<logfile> Log file from rombuild tool.
<executables> Names of additional executables to fix up.
ASSP-specific executables and EUSER are always included.
Example:
fixupsym rombuild.log efile efsrv .fsy
EOF
;
exit 0;
}
sub fixMakefile()
{
my $makefile = shift @_;
my $tmpMakfile = $makefile.".TMP";
open (FILEIN, $makefile) or die "Can't open file \"$makefile\" \n";
open (FILEOUT, ">".$tmpMakfile) or die "Can't create file \"$tmpMakfile\" \n";
while(<FILEIN>) {
if ($_ =~ /^\s*elf2e32/){
print FILEOUT "#".$_;
}
else {
print FILEOUT $_;
}
}
close FILEIN;
close FILEOUT;
$tmpMakfile;
}