sbsv1/abld/e32util/makedef.pl
changeset 599 fa7a3cc6effd
child 606 30b30f9da0b7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sbsv1/abld/e32util/makedef.pl	Fri Jun 25 17:29:25 2010 +0800
@@ -0,0 +1,553 @@
+#!/usr/bin/perl
+# Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
+# All rights reserved.
+# This component and the accompanying materials are made available
+# under the terms of "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:
+# all variables called *Path* are set up to end with a backslash
+# all variables called *Path or *File are stored as absolute (file)paths
+# all variables called UpPath* are stored as relative paths
+# 
+#
+
+use strict   ;
+
+use FindBin;		# for FindBin::Bin
+use Getopt::Long;
+
+my $PerlBinPath;	# fully qualified pathname of the directory containing this script
+my $EntryPoint;         
+my $InternalEntryPoint;
+
+# establish the path to the Perl binaries
+BEGIN {
+	require 5.005_03;				# check user has a version of perl that will cope
+	$PerlBinPath = $FindBin::Bin;	# X:/epoc32/tools
+
+	if ($^O eq "MSWin32")
+		{	
+		$PerlBinPath =~ s/\//\\/g;		# X:\epoc32\tools
+		}
+}
+use lib $PerlBinPath;
+
+use Defutl;
+use File::Copy;
+
+# Version
+my $MajorVersion = 1;
+my $MinorVersion = 1;
+my $PatchVersion = 0;
+
+my %Options;	# command line option information
+
+my $NamedSymLkup = 0;			# This flag is used to enable named lookup on emulator
+my $IgnoreUnfrozenExports = 0;	# This flag is used to ignore the 'unfrozen exports' warnings. This is 
+								# required for STDEXEs which export symbols just to enable 'named lookup'
+								# from within the STDEXE (via 'dlsym') and are never exposed outside (via def files or
+								# import libraries.
+my $ExportEntrypointE32Dll = 0;	 # Workaround: To export entry point _E32DLL for target type STDDLL
+
+# THE MAIN PROGRAM SECTION
+##########################
+
+{
+
+	my $INFILE;
+	my $FRZFILE;
+	my $OUTFILE;
+	my @ObjFiles;
+
+	# process the command-line
+	unless (GetOptions(\%Options, '1=s', '2=s', 'deffile=s', 'frzfile=s', 'inffile=s', 'overwrite', 'absent=s', 'ignore_unfrozen_noncallable', 'SystemTargetType', 'sym_name_lkup', 'ignore_unfrozen_exports','export_entrypoint_E32Dll')) {
+		exit 1;
+	}
+	unless (@ARGV==1) {
+		&Usage;
+	}
+
+#	check the flags
+
+	if (($Options{deffile} and $Options{inffile}) or (not ($Options{deffile} or $Options{inffile}))) {
+		die "MAKEDEF ERROR: Must specify either -Deffile [file] or -Inf [file]\n";
+	}
+	if ($Options{2} && !$Options{1}) {
+		die "MAKEDEF ERROR: Can't specify second export name and not first export name\n";
+	}
+
+#	process the flags
+	if ($Options{deffile}) {
+		$INFILE=$Options{deffile};
+		unless (-e $INFILE) {
+			die "MAKEDEF ERROR: $INFILE: Deffile not found\n";
+		}
+	}
+	else {
+		$INFILE=$Options{inffile};
+		unless (-e $INFILE) {
+			die "MAKEDEF ERROR: $INFILE: Inffile not found\n";
+		}
+	}
+	if ($Options{frzfile}) {
+		$FRZFILE=$Options{frzfile};
+#		check the frozen .DEF file exists
+		unless (-e $FRZFILE) {
+			die "MAKEDEF ERROR: $FRZFILE: Frzfile not found\n";
+		}
+	}
+	$OUTFILE=pop @ARGV;
+
+
+	$NamedSymLkup = $Options{sym_name_lkup};
+	$IgnoreUnfrozenExports = $Options{ignore_unfrozen_exports};
+	$ExportEntrypointE32Dll = $Options{export_entrypoint_E32Dll};	# Workaround: To export entry point _E32DLL for target type STDDLL
+
+#	Read the Frozen .DEF file if specified
+	my @FrzDataStruct;
+	if ($FRZFILE) {
+		eval { &Def_ReadFileL(\@FrzDataStruct, $FRZFILE); };
+		die $@ if $@;
+		if ($Options{1}) {
+#			Check that frozen def file matches the -1 and -2 arguments given, if any
+			my $export1="";
+			my $export2="";
+			foreach my $FrzRef (@FrzDataStruct) {
+				next unless $$FrzRef{Name};		# ignore lines not containing an export
+				if ($$FrzRef{Ordinal} == 1) {
+					$export1 = $$FrzRef{Name};
+					next;
+				}
+				if ($$FrzRef{Ordinal} == 2) {
+					$export2 = $$FrzRef{Name};
+					next;
+				}
+				if ($Options{1} && ($Options{1} ne $export1)) {
+					die "MAKEDEF ERROR: $FRZFILE: Frzfile ordinal 1 does not match command line\n";
+				}
+				if ($Options{2} && ($Options{2} ne $export2)) {
+					die "MAKEDEF ERROR: $FRZFILE: Frzfile ordinal 2 does not match command line\n";
+				}
+			}
+		}
+	}
+	elsif ($Options{1}) {
+#		create an export structure for the names passed on the command line
+		push @FrzDataStruct, {
+			Name=>$Options{1},
+			ExportName=>$Options{1},
+			Ordinal=>1
+		};
+		if ($Options{2}) {
+			push @FrzDataStruct, {
+				Name=>$Options{2},
+				ExportName=>$Options{2},
+				Ordinal=>2
+			};
+		}
+	}
+
+#	Read the Input .DEF file
+	my @InDataStruct;
+	if ($Options{deffile}) {
+		eval { &Def_ReadFileL(\@InDataStruct, $INFILE); };
+	}
+	else {
+		eval { &ReadInfFileL(\@InDataStruct, $INFILE); };
+	}
+	die $@ if $@;
+
+#	Compare the frozen .DEF data with the input .DEF or export info file data
+	my (@NewDataStruct, @MissingDataStruct, @MatchedDataStruct);
+	eval { &CompareFrzInL (\@NewDataStruct, \@MissingDataStruct, \@MatchedDataStruct, \@FrzDataStruct, \@InDataStruct); };
+	die $@ if $@;
+
+	# MAKEDEF should generate a warning if the def file has no exports (old or new)
+	# and the associated MMP 'targettype' is not a System Target type.
+	print "MAKEDEF WARNING: $OUTFILE has no EXPORTS\n" unless (@MatchedDataStruct || @NewDataStruct || $Options{SystemTargetType});
+
+#	Create the output .DEF file
+	eval { &CreateDefFileL(\@NewDataStruct, \@MatchedDataStruct, $OUTFILE, $FRZFILE); };
+	die $@ if $@;
+
+#	report missing frozen export errors
+	if (@MissingDataStruct) {
+		my @Errors;
+		my $Num=@MissingDataStruct;
+		my $Ref;
+		if ($FRZFILE) {
+			push @Errors, "MAKEDEF ERROR: $Num Frozen Export(s) missing from object files (POSSIBLE COMPATIBILITY BREAK):\n";
+			foreach $Ref (@MissingDataStruct) {
+				push @Errors, "  $FRZFILE($$Ref{LineNum}) : $$Ref{Name} \@$$Ref{Ordinal}\n";
+			}
+		}
+		else {
+			push @Errors, "MAKEDEF ERROR: command-line: $Num Frozen Export(s) missing from object files (POSSIBLE COMPATIBILITY BREAK):\n";
+			foreach $Ref (@MissingDataStruct) {
+				push @Errors, "  $$Ref{Name} \@$$Ref{Ordinal}\n";
+			}
+		}
+		die "\n", @Errors;
+	}
+	elsif ($Options{overwrite} && -w $FRZFILE) #sag
+		{
+		print "Copying $OUTFILE to $FRZFILE\n";
+		rename $FRZFILE, "$FRZFILE.bak";
+		copy($OUTFILE, $FRZFILE);
+		}
+
+	exit 0;
+}
+
+#######################################################################
+# SUBROUTINES
+#######################################################################
+
+sub Usage () {
+
+	print(
+		"\n",
+		"MAKEDEF - .DEF file generator V$MajorVersion.$MinorVersion.$PatchVersion\n",
+		"\n",
+		"MAKEDEF {options} [Output .DEF file]\n",
+		"\n",
+		"options:   (case-insensitive)\n",
+		"  -Deffile [Input .DEF file]\n",
+		"  -Inffile [Input export information file]\n",
+		"  -Frzfile [Frozen .DEF file]\n",
+		"  -1 [first export name] {-2 [second export name]}\n",
+		"  -Overwrite\n",
+		"  -Absent [symbol to use for absent exports]\n",
+		"  -ignore_unfrozen_noncallable\n",
+		"  -SystemTargetType\n",
+		"  -sym_name_lkup [Enable symbol lookup by name]\n",
+		"  -ignore_unfrozen_exports \n",
+		"\n",
+		"Either specify -Deffile or -Inffile, and\n",
+		"either -Frzfile or -1 {-2} if required.\n"
+	);
+	exit 1;
+}
+
+sub ReadInfFileL ($$$) {
+	my ($DataStructRef, $FILE)=@_;
+
+#	open export information file for reading
+	open (FILE, "<$FILE") or die "could not open $FILE: $!";
+
+#	read the export info. file, and create dummy frozen .DEF file text
+	my $LineNum=0;
+	my $Ordinal=0;
+	my $Comment='';
+	my $Name='';
+	my $InfType=0;	# dumpbin output
+	my %exports;	# MWLD workaround - record mangled names in case we don't see the demangled ones
+	my $Line;
+	while ($Line=<FILE>) {
+	        my $Data=0;
+			my $SymbolSize=0;
+		$LineNum++;
+		if ($InfType == 0) {
+			if ($Line =~ /\*\*\* ARCHIVE SYMBOL TABLE.* \*\*\*/o) {
+				$InfType=1;	# mwld disassembly output
+				next;
+			}
+			if ($Line =~ /^\s+(\?\S+)(\s+\((.*)\))?$/o) {
+#                   ??0TAgnAlarmDefaults@@QAE@XZ (public: __thiscall TAgnAlarmDefaults::TAgnAlarmDefaults(void))
+				$Name=$1;
+				$Comment=$3;
+			} 
+			elsif ($Line =~ /^\s+_(\S+)(\s+\((.*)\))?$/o) {
+# frozen ordinals like "UserNoLongerSupported01" seem to inherit a leading underscore in the dumpbin output
+				$Name=$1;
+				$Comment=$3;
+			}
+			elsif ($Line =~ /^\s+_(\S+) DATA (\d+)(\s+\((.*)\))?$/o) {
+#				Mark the data symbols and retain their sizes
+				$Name=$1;
+				$Data=1;
+				$SymbolSize=$2;
+				$Comment=$4;
+			}
+			else {
+				next;
+			}
+		}
+		else {
+			# The Windows CW linker produces .inf files with a 'something' unmangled comment at the end, the Linux CW linker doesn't
+			if ($Line =~ /^\s*\d+\s+\(.+\)\s+__imp_((.)(\S+))(\s+'__declspec\(dllimport\)\s+(.*)')?$/o) {
+					if ($2 eq "_") {
+							$Name = $3;		# C symbol, so remove leading underscore
+							$Comment = $5 if ($4);	# name isn't mangled anyway
+					} else {
+							$Name = $1;		# C++ mangled name
+							$Comment = $5 if ($4);	# can't unmangle names...
+					}
+
+					# One side-effect of ignoring comments if they're not present is that Windows entry points need to be
+					# specifically ignored.  Previously they were ignored by virture of the fact they had no comment.
+					next if ($Name eq "_E32Dll" || $Name eq "_E32Startup");
+
+					$Comment = $4 ? $5 : $Name;
+					
+					# need to save both the line number and
+					# comment
+					my %entry;
+					$entry{'lineNum'} = $LineNum;
+					$entry{'comment'} = $Comment;
+					$exports{$Name}=\%entry;
+					next;
+			}
+			if ($Line =~ /\*\*\* Unmangled Symbols \*\*\*/o) {
+				# Currently for Linux "Unmangled Symbols" section is blank
+				<FILE>; 
+				$Line = <FILE>; 
+				$LineNum+=2;
+				if ($^O eq "MSWin32") {
+					if ($Line !~ /^\s*\d+:\s+(\S+)$/o) {
+						print STDERR "MAKEDEF WARNING: unknown inf file format\n";
+						next;
+					}
+				}
+				$Name = length $1 ? $1 : '';
+# Workaround: if MWLD can't demangle the name, we will see only the __imp_ version.
+				if ($Name =~ /^__imp_(\S+)$/o) {
+					$Name = $1;
+				}
+				$Line = <FILE>; 
+				$LineNum++;
+				next if ($Line !~ /^\s+(.+)$/o);
+				$Comment = $1;
+			}
+			elsif ($Line =~ /^0x\S{8}\s+__imp__(\S+)$/o) {
+				$Name = $1;	# leading underscore already removed
+				$Comment = '';	# a C symbol, and therefore not mangled
+			}
+			else {
+				next;
+			}
+		}
+# Check for WINS entrypoint symbols
+		if ($Name eq "_E32Dll" || $Name eq "_E32Startup") {
+			$EntryPoint = $Name;
+			# when mwld resolves an exported symbol S coming from
+			# the def file, it looks both for S() and _S() in
+			# every object file but only for _S() in static
+			# libraries.
+			#
+			# As a consequence, we need to distinguish the
+			# internal entry point name from the external one.
+			$InternalEntryPoint = "_$Name" if ($InfType != 0);
+			my $entry = $exports{$Name};
+			$entry->{'lineNum'} = 0; # indicates processed name
+			next;
+		}
+		$Ordinal++;
+		$Comment='' if (!defined $Comment);
+		push @$DataStructRef, {
+			Ordinal=>$Ordinal,
+			Name=>$Name,
+			Data=>$Data,
+			Size=>$SymbolSize,
+			ExportName=>$Name,
+			Comment=>$Comment,
+			LineNum=>$LineNum
+		};
+		my $entry = $exports{$Name};
+		$entry->{'lineNum'} = 0; # indicates processed name
+	}
+	foreach $Name (keys %exports) {
+	    	my $entry = $exports{$Name};
+		$LineNum = $entry->{'lineNum'};
+		if ($LineNum > 0) {
+			$Ordinal++;
+			push @$DataStructRef, {
+				Ordinal=>$Ordinal,
+				Name=>$Name,
+				ExportName=>$Name,
+				Comment=> $entry->{'comment'},
+				LineNum=>$LineNum
+			};
+		}
+	}
+}
+
+sub CompareFrzInL ($$$$$) {
+	my ($NewStructRef, $MissingStructRef, $MatchedStructRef, $FrzStructRef, $InStructRef)=@_;
+	my $AbsentSubst = $Options{absent};
+	my $IgnoreNoncallable = $Options{ignore_unfrozen_noncallable};
+	
+#	compare the input export data with the frozen data
+
+#	this function trashes the frozen .DEF data structure and the new .DEF data structure
+
+#	nullify non-export statements in the structures
+	foreach (@$FrzStructRef,@$InStructRef) {
+		next if $$_{Name};
+		undef $_;
+	}
+
+	my $LastOrdinal=0;
+
+	my $FrzRef;
+	my $InRef;
+	FRZLOOP: foreach $FrzRef (@$FrzStructRef) {
+		next unless $$FrzRef{Name};		# ignore lines in the .DEF file not containing an export
+		if ($LastOrdinal<$$FrzRef{Ordinal}) {
+			$LastOrdinal=$$FrzRef{Ordinal};
+		}
+		foreach $InRef (@$InStructRef) {
+			next unless defined $InRef; # ignore nullified entries in the temporary array
+#			does the function name match?
+			if ($$InRef{Name} eq $$FrzRef{Name}) {
+#				give the generated export the same number as the corresponding frozen one
+				$$InRef{Ordinal}=$$FrzRef{Ordinal};
+				$$InRef{Data}=$$FrzRef{Data};
+				$$InRef{Size}=$$FrzRef{Size};
+#				if the export is marked as absent, redirect it appropriately
+				if ($$FrzRef{Absent}) {
+					if ($AbsentSubst) {
+						$$InRef{Name} = $AbsentSubst;
+						$$InRef{ExportName} = sprintf("\"_._.absent_export_%d\"", $$InRef{Ordinal});
+					}
+				}
+				push @$MatchedStructRef, $InRef;
+				undef $InRef;
+				next FRZLOOP;
+			}
+		}
+#		these frozen exports haven't been found in the object files
+#		first check for ABSENT declarations
+		if ($AbsentSubst and $$FrzRef{Absent}) {
+			$$FrzRef{Name} = $AbsentSubst;
+			$$FrzRef{ExportName} = sprintf("\"_._.absent_export_%d\"", $$FrzRef{Ordinal});
+			push @$MatchedStructRef, $FrzRef;
+			next FRZLOOP;
+		}
+
+#		No - it's really missing
+		push @$MissingStructRef, $FrzRef;
+#		put a comment in the generated .DEF file to that effect
+		$$FrzRef{Missing}=1;
+		push @$MatchedStructRef, $FrzRef;
+	}
+
+#	all the exports left in the new .DEF file aren't frozen - give them the right ordinals
+	foreach $InRef (@$InStructRef) {
+		next unless defined $InRef; # ignore nullified entries
+		if ($$InRef{Name} =~ /^_ZTV|_ZTI/) {
+			# EABI non-callable exports
+			next if ($IgnoreNoncallable);	
+		}
+		$LastOrdinal++;
+		$$InRef{Ordinal}=$LastOrdinal;
+		push @$NewStructRef, $InRef;
+	}
+}
+
+sub CreateDefFileL ($$$$) {
+#	creates a new .DEF file
+	my ($NewStructRef, $MatchedStructRef, $FILE, $FRZFILE)=@_;
+
+	my @Text=("EXPORTS\n");
+	my $LineNum=1;
+
+
+	my $InRef;
+	foreach $InRef (@$MatchedStructRef) {
+		my $Comment='';
+		if ($$InRef{Comment}) {
+			$Comment=" ; $$InRef{Comment}";
+		}
+		if ($$InRef{Missing}) {
+			push @Text, '; MISSING:';
+		}
+		my $Data = "";
+		if( defined $$InRef{Data} && $$InRef{Data} == 1) {
+		$Data = " DATA $$InRef{Size}" ;
+		}
+		my $r3unused = $$InRef{R3Unused} ? " R3UNUSED" : "";
+
+#		A def file entry with the keyword 'NONAME' indicates the MW linker that a named-lookup is not enabled. 
+#		Note that although it may seem, but named lookup is either enabled or disabled on a per-binary basis and not
+#		per-symbol.
+		my $noname = $NamedSymLkup ? "": " NONAME";
+		if ($$InRef{ExportName} and ($$InRef{ExportName} ne $$InRef{Name})) {
+			push @Text, "\t$$InRef{ExportName}=$$InRef{Name} \@ $$InRef{Ordinal} $noname$Data$r3unused$Comment\n";
+		} else {
+			push @Text, "\t$$InRef{Name} \@ $$InRef{Ordinal} $noname$Data$r3unused$Comment\n";
+		}
+		$LineNum++;
+		next;
+	}
+	if (@$NewStructRef) {
+
+#		warn about unfrozen exports and add them to the end of the generated .DEF file
+		my $Num=@$NewStructRef;
+		my @Warnings;
+
+		if(!$IgnoreUnfrozenExports) {
+			my $warning = "MAKEDEF WARNING: $Num export(s) not yet Frozen";
+
+			if ($FRZFILE)
+				{
+				$warning .= " in $FRZFILE";
+				}
+
+			$warning .= ":\n";
+
+			push @Warnings, $warning;
+		}
+
+		push @Text, "; NEW:\n";
+		$LineNum++;
+		foreach $InRef (@$NewStructRef) {
+			my $Comment='';
+			if ($$InRef{Comment}) {
+				$Comment=" ; $$InRef{Comment}";
+			}
+			my $Data = "";
+			if(defined $$InRef{Data} && $$InRef{Data} == 1){
+			$Data = " DATA $$InRef{Size}";
+			}
+			my $r3unused = $$InRef{R3Unused} ? " R3UNUSED" : "";
+			my $noname = $NamedSymLkup ? "": " NONAME";
+			if ($$InRef{ExportName} and ($$InRef{ExportName} ne $$InRef{Name})) {
+				push @Text, "\t$$InRef{ExportName}=$$InRef{Name} \@ $$InRef{Ordinal} $noname$Data$r3unused$Comment\n";
+			} else {
+				push @Text, "\t$$InRef{Name} \@ $$InRef{Ordinal} $noname$Data$r3unused$Comment\n";
+			}
+			$LineNum++;
+			if(!$IgnoreUnfrozenExports) {
+				push @Warnings, "  $FILE($LineNum) : $$InRef{Name} \@$$InRef{Ordinal}\n";
+			}
+			next;
+		}
+		print @Warnings;
+	}
+	if ($EntryPoint) {
+		push @Text, "\t$EntryPoint";
+		push @Text, "=$InternalEntryPoint" if ($InternalEntryPoint);
+		push @Text, "\t; Entry point for emulation\n";
+	}
+	elsif ($ExportEntrypointE32Dll) {		# Workaround: To export entry point _E32DLL for target type STDDLL
+		push @Text, "\t_E32Dll";
+		push @Text, "=__E32Dll" ;
+		push @Text, "\t; Entry point for STDDLL emulation\n";
+	}
+
+#	add a terminating newline
+	push @Text, "\n";
+
+#	write the new .DEF file
+	eval { &Def_WriteFileL(\@Text, $FILE); };
+	die $@ if $@;
+}
+