imgtools/romtools/maksym/maksym.pl
author timothy.murphy@nokia.com
Sun, 28 Feb 2010 21:18:07 +0200
branchfix
changeset 279 733464eaac50
parent 0 044383f39525
child 590 360bd6b35136
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) 1996-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 ROM image
#

require 5.003_07;
no strict 'vars';
use English;
use FindBin;		# for FindBin::Bin

my $PerlLibPath;    # fully qualified pathname of the directory containing our Perl modules

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

# Globals
my $maksym = "";
my $rombuild;
my $debug = 0;

&args;
&main;

exit 0;

sub CompareAddrs()
{
    return -1 if ($a < $b);
    return 1 if ($a > $b);
    return 0;
}

#
# main
#
sub main()
{
  my $file;
  my $mapfile;
  my $mapfile2;
  my $text;
  my $data;
  my $bss;
  my $textsize;
  my $datasize;
  my $bsssize;
  my $totaldatasize;
  my $totalsize;

  open (ROM, "<$rombuild")
    or die "ERROR: Can't open rombuild log file \"$rombuild\"\n";
  if ($maksym ne "") {
    open (SYM, ">$maksym")
      or die "ERROR: Can't open output file \"$maksym\"\n";
    print "Creating $maksym...\n";
  }

  while (<ROM>) {
    # Start of ROM
    if (/^Creating Rom 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;
    }
    # end of ROM
    if (/^Writing Rom image/) {
      close SYM;
      $maksym = "";
      next;
    }
    # Data file
    if (/^Reading resource (.*) to rom linear address (.*)/) {
      $file = $1;
      my $data = hex($2);
      $file =~ /([^\\]+)$/;
      printf SYM "\nFrom    $file\n\n%08x    0000    $1\n", $data;
    }
    # Executable file
    elsif (/^Processing file (.*)/) {
      $file = $1;
      $text = 0;
      $data = 0;
      $bss = 0;
      $textsize = 0;
      $datasize = 0;
      $bsssize = 0;
      $totaldatasize = 0;

      # Work out final addresses of sections
      while (defined($_=<ROM>) && !/^$/) {
	if (/^Size:\s+(\w+)/) {
	  $totalsize = hex($1);
	} elsif (/^Code start addr:\s+(\w+)/) {
	  $text = hex($1);
	} elsif (/^Data start addr:\s+(\w+)/) {
	  $data = hex($1);
	} elsif (/^DataBssLinearBase:\s+(\w+)/) {
	  $bss = hex($1);
	} elsif (/^Text size:\s+(\w+)/) {
	  $textsize = hex($1);
	} elsif (/^Data size:\s+(\w+)/) {
	  $datasize = hex($1);
	} elsif (/^Bsssize:\s+(\w+)/) {
	  $bsssize = hex($1);
	} elsif (/^Total data size:\s+(\w+)/) {
	  $totaldatasize = hex($1);
	}
      }

      # Sanity check - text section can't be zero
      die "ERROR: Can't find rombuild info for \"$file\"\n"
	if (!$text);

      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";
	$file =~ /([^\\]+)$/;
	printf SYM "%08x    %04x    $1\n", $text, $totalsize;
      } else {
	local $/ = undef;
	my (@maplines) = split(/\n/, <MAP>);
	close MAP;
	# See if we're dealing with the RVCT output
	if ($maplines[0] =~ /^ARM Linker/) {
	  print "$file\n";
	 
		my %syms;
		my @hasharray;
		# Starts from begining of map file.		
		while (@maplines) {
		  $_ = shift @maplines;
		  if (/Global Symbols/) {
		    last;
		  } elsif (!/(ARM Code|Thumb Code)/) {
		    next;
		  }
		# name address type size section
		if (/^\s*(.+)\s*(0x\S+)\s+(ARM Code|Thumb Code)\s+[^\d]*(\d+)\s+(.*)$/) {
			# Check for static methods in local symbols section.
			my $sym = $1;
			my $addr = hex($2);
			my $size = sprintf("%04x",$4);
			my $section = $5;
			$size = sprintf("%04x", 8) if ($section =~ /\(StubCode\)/);
			if(exists($syms{$addr})) {
				push @{ $syms{$addr} }, "$size    $sym $section";	   
			}
			elsif ($addr > 0){
				@hasharray = "$size    $sym $section";
				$syms{$addr} = [@hasharray];
			}
		}
		}	
	
	  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\)/);
		  if(exists($syms{$addr})) {
			push @{ $syms{$addr} }, "$size    $sym $section";	   
		  }
	      elsif ($addr > 0) {
			@hasharray = "$size    $sym $section"; 
			$syms{$addr} = [@hasharray];
		  }
	    }
	  } # end of foreach

	  # .text gets linked at 0x00008000
	  # .data gets linked at 0x00400000
	  my $srctext = hex(8000);
	  my $srcdata = hex(400000);
	  my $j; 
	  # Write symbols in address order
	  my @addrs = sort CompareAddrs keys %syms;
	  for ($i = 0; $i < @addrs ; $i++) {
	    my $thisaddr = $addrs[$i];
	    my $romaddr = 0;
	    # see if its in the text segment
		if ($thisaddr >= $srctext && $thisaddr <= ($srctext+$textsize)) {
	      $romaddr = $thisaddr-$srctext+$text;
	    } elsif ( $data && ( $thisaddr >= $srcdata && $thisaddr <= ($srcdata+$datasize))) {
	      # its in the data segment
	      # is it from .data or .bss

  			# confusingly (?) $bss is the right value to use here
			# since we're interested in where the data gets copied to
			# in RAM rather than where it sits in ROM
		$romaddr = $thisaddr-$srcdata+$bss;
	      } elsif ( $bss && ( $thisaddr >= $srcdata && $thisaddr <= ($srcdata+$totaldatasize))) {
				# its BSS
		$romaddr = $thisaddr-$srcdata+$bss;
	      } else {
		my $errsym = $syms{$thisaddr}[0];
		my $erraddr = sprintf("%08x", $thisaddr);
		print "WARNING: Symbol $errsym @ $erraddr not in text or data segments\n";
		print "WARNING: The map file for binary $file is out-of-sync with the binary itself\n\n";
		next;
	      }

	    printf SYM "%08x    %s\n", $romaddr, $_ for @{$syms{$addrs[$i]}};
	  } # end of for.
        # See if we're dealing with the GCC output
	} elsif ($maplines[0] =~ /^Archive member included/) {
	  
	  my $imgtext;
	  my $textlen;
	  my %syms;
	  my $stubhex=1;

	  # Find text section
	  while (@maplines) {
	      $_ = shift @maplines;
	      last if /^\.text\s+/;
	  }

	  /^\.text\s+(\w+)\s+(\w+)/
			or die "ERROR: Can't get .text section info for \"$file\"\n";

		    $imgtext=hex($1);
		    $textlen=hex($2);

		    print "$file\n";

		# 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

				# EUSER.LIB(ds01423.o)
				# EUSER.LIB(C:/TEMP/d1000s_01423.o)
				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+$text, $addrs[$i+1]-$addrs[$i], $symbol;
		}
		# last address assumed to be imgtext+lentext

		close MAP;
	}
	# Must be x86 output
	else {
		while (@maplines) {
	      $_ = shift @maplines;
	      last if /^  Address/;
		}
	    shift @maplines;
	    
	    my ($lastname, $lastaddr);
		while (@maplines) {
	      $_ = shift @maplines;
	      last unless /^ 0001:(\w+)\s+(\S+)/;
		  my ($addr, $name) = (hex $1, $2);
		  if ($lastname) {
			  my $size = $addr - $lastaddr;
			  printf SYM "%08x    %04x    %s\n", $lastaddr + $text, $size, $lastname;
		  }
		  ($lastname, $lastaddr) = ($name, $addr);
	    }	    
	    printf SYM "%08x    %04x    %s\n", $lastaddr + $text, 0, $lastname if $lastname;
	}
	
	    }
	  }
	}
    close SYM;
    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;
	    } elsif ($flag=~/^d$/i) {
		$debug = 1;
	    } else {
		print "\nERROR: Unknown flag \"-$flag\"\n";
		&usage;
		exit 1;
	    }
	} else {
	    push @args,$arg;
	}
    }

    if (@args) {
	$rombuild = 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 "\nmaksym - Produce symbolic information given a ROM image (Build ",
	&E32tpver, ")\n";
    &usage;
    exit 0;
}

sub usage ()
{
    print <<EOF

Usage:
  maksym <logfile> [<outfile>]

Where:
  <logfile>   Log file from rombuild tool.
  <outfile>   Output file. Defaults to imagename.symbol.
EOF
    ;
    exit 0;
}