## Copyright (c) 2005-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: # Produces symbolic information given a ROFS log file and .map files for relevant binary files#require 5.003_07;no strict 'vars';use English;use FindBin; # for FindBin::Binmy $PerlLibPath; # fully qualified pathname of the directory containing our Perl modulesBEGIN { # check user has a version of perl that will cope require 5.005_03; # establish the path to the Perl libraries: currently the same directory as this script $PerlLibPath = $FindBin::Bin; # X:/epoc32/tools $PerlLibPath =~ s/\//\\/g; # X:\epoc32\tools $PerlLibPath .= "\\";}use lib $PerlLibPath;use Modload;Load_SetModulePath($PerlLibPath);# Globalsmy $maksym = "";my $rofsbuild;my $debug = 0;&args;&main;exit 0;sub CompareAddrs(){ return -1 if ($a < $b); return 1 if ($a > $b); return 0;}## main#sub main(){ open (ROFS, "<$rofsbuild") or die "ERROR: Can't open rofsbuild log file \"$rofsbuild\"\n"; if ($maksym ne "") { open (SYM, ">$maksym") or die "ERROR: Can't open output file \"$maksym\"\n"; print "Creating $maksym...\n" } my $curretnLine; while ($currentLine = <ROFS>) { # Check that the given log file is from a rofs image and set up the name for the symbol file if ($currentLine =~ /^Creating Rofs image (\S*)/) { if ($maksym eq "") { # For backwards compatibility, replace trailing .img with .symbol # if no trailing .img, just append .symbol anyway $maksym = $1; $maksym =~ s/(\.img)?$/.symbol/i; close SYM; open (SYM, ">$maksym") or die "ERROR: Can't open output file \"$maksym\"\n"; print "\nCreating $maksym...\n" } next; } # found at end of file if ($currentLine =~ /^Writing Rom image/) { close SYM; $maksym = ""; next; } # Data file if ($currentLine =~ /^File \'(.*)\' size: \S+\s*$/) { my $file = $1; $file =~ /([^\\]+)$/; printf SYM "\nFrom $file\n\n00000000 0000 $1\n"; } # Executable file elsif ($currentLine =~ /^Compressed executable File \'(.*)\' size: \S+\s*, mode:\S+\s*$/) { ProcessCompressedLine($1); } } close SYM; close ROFS;}sub ProcessCompressedLine{ my ($file) = @_; my $mapfile; my $mapfile2; print SYM "\nFrom $file\n\n"; # Look in map file for symbols in .text and relocate them $mapfile2 = $file.".map"; $mapfile = $file; $mapfile =~ s/\.\w+$/\.map/; if (!(open (MAP, "$mapfile2") || open (MAP, "$mapfile"))) { print "$file\nWarning: Can't open \"$mapfile2\" or \"$mapfile\"\n"; # couldn't find map file so output in format that is used for non-binary files my $BinSize = GetSizeFromBinFile($file); $file =~ /([^\\]+)$/; printf "00000000 %04x $1\n", $BinSize; printf SYM "00000000 %04x $1\n", $BinSize; } else { my @maplines; while ($_ = <MAP>) { push @maplines, $_; } close MAP; # See if we're dealing with the RVCT output if ($file =~m/ARMV5/i) { ProcessArmv5File($file, \@maplines); } elsif( ($file =~ /GCCE/i) || ($file =~ /ARM4/i) ) { ProcessGcceOrArm4File($file, \@maplines); } else { print "\nWarning: cannot determine linker type used to create $file\n"; $file =~ /([^\\]+)$/; printf SYM "00000000 0000 $1\n"; } }}sub ProcessArmv5File{ my ($file, $mapLines) = @_; my @maplines = @$mapLines; if ($maplines[0] !~ /^ARM Linker/) { print "\nWarning: expecting $file to be generated by ARM linker\n"; # file not in format produced by ARMV5 linker so treat file as non-binary file $file =~ /([^\\]+)$/; printf SYM "00000000 0000 $1\n"; } else { # scroll down to the global symbols while ($_ = shift @maplines) { if ($_ =~ /Global Symbols/) { last; } } my %syms; my $baseOffset; # offset to subtract from each address so that the first entry has address 0x0 foreach (@maplines) { # name address ignore size section if (/^\s*(.+)\s*(0x\S+)\s+[^\d]*(\d+)\s+(.*)$/) { my $sym = $1; my $addr = hex($2); my $size = sprintf("%04x",$3); my $section = $4; $size = sprintf("%04x", 8) if ($section =~ /\(StubCode\)/); # it is possible that there will be more than one entry in a log file for a # particular address, this is because aliases are included. # The following code checks that the correct function (i.e. the one with # non-zero size) is being included in the symbol file. if(exists $syms{$addr}) { # an entry at this address exists, replace if it is an alias if( ($size != 0) && ($addr > 0) ) { if( ! defined $baseOffset ) { $baseOffset = $addr; } $syms{$addr - $baseOffset} = "$size $sym $section"; } } else { # no entry at this address so create one regardless of whether size is zero if( $addr > 0 ) { if( ! defined $baseOffset ) { $baseOffset = $addr; } $syms{$addr - $baseOffset} = "$size $sym $section"; } } } } # Write symbols in address order my @addrs = sort CompareAddrs keys %syms; for ($i = 0; $i < @addrs ; $i++) { my $thisaddr = $addrs[$i]; printf SYM "%08x %s\n", $thisaddr, $syms{$thisaddr}; } }}sub ProcessGcceOrArm4File{ my ($file, $mapLines) = @_; my @maplines = @$mapLines; my %syms; my $stubhex=1; # Find text section while (($_ = shift @maplines) && !(/^\.text\s+/)) { } /^\.text\s+(\w+)\s+\w+/ or die "ERROR: Can't get .text section info for \"$file\"\n"; my $imgtext=hex($1); # Slurp symbols 'til the end of the text section foreach (@maplines) { # blank line marks the end of the text section last if (/^$/); # .text <addr> <len> <library(member)> # .text$something # <addr> <len> <library(member)> # <addr> <len> LONG 0x0 if (/^\s(\.text)?\s+(0x\w+)\s+(0x\w+)\s+(.*)$/io) { my $address = hex($2); my $length = hex($3); my $libraryfile = $4; next if ($libraryfile =~ /^LONG 0x/); $syms{$address+$length} = ' '; # impossible symbol as end marker #set $stubhex value as $address if there is a match if ($libraryfile =~ /.*lib\(.*d\d*s_?\d{5}.o\)$/io) { $stubhex=$address; } next; } # <addr> <symbol name possibly including spaces> if (/^\s+(\w+)\s\s+([a-zA-Z_].+)/o) { my $addr = hex($1); my $symbol = $2; $symbol = "stub $symbol" if ($addr == $stubhex); $syms{$addr} = $symbol; next; } } # Write symbols in address order @addrs = sort CompareAddrs keys %syms; for ($i = 0; $i < @addrs - 1; $i++) { my $symbol = $syms{$addrs[$i]}; next if ($symbol eq ' '); printf SYM "%08x %04x %s\n", $addrs[$i] - $imgtext, $addrs[$i+1]-$addrs[$i], $symbol; } # last address assumed to be imgtext+lentext close MAP;}## 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; } elsif ($flag=~/^d$/i) { $debug = 1; } else { print "\nERROR: Unknown flag \"-$flag\"\n"; &usage; exit 1; } } else { push @args,$arg; } } if (@args) { $rofsbuild = shift @args; if (@args) { $maksym = shift @args; if (@args) { print "\nERROR: Incorrect argument(s) \"@args\"\n"; &usage; exit 1; } } }}sub help (){ my $build; &Load_ModuleL('E32TPVER'); print "\nmaksymrofs - Produce symbolic information given a ROFS image (Build ", &E32tpver, ")\n"; &usage; exit 0;}sub usage (){ print <<EOFUsage: maksymrofs <logfile> [<outfile>]Where: <logfile> Log file from rofsbuild tool. <outfile> Output file. Defaults to imagename.symbol.EOF ; exit 0;}sub GetSizeFromBinFile (){ my ($file) = @_; my $tmpfile = "temp.info"; system("readimage $file -o $tmpfile"); return 0 if (!-e $tmpfile); open (TMP, "<$tmpfile"); my $line; my $size = 0; while ($line = <TMP>) { print $line; if ($line =~ /^Code size\W+(\w+)$/) { $size = hex($1); last; } } close TMP; unlink $tmpfile; return $size;}