blob: f4103a4942778ca8fcb7d729216dc8726d76d420 [file] [log] [blame]
:
eval 'exec perl -wS $0 ${1+"$@"}'
if 0;
#**************************************************************
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
#**************************************************************
#
# rebase.pl - rebase windows dlls
#
# This perl script is to rebase all windows dlls. In principle this could
# be done with one simple command line like f.e.
# rebase -b 0x68000000 -d -R foo_dir -N bar.txt $(SOLARBINDIR)$/*.dll
# That would work fine for creating complete office install sets, but it
# could fail as soon as we are going to ship single dlls for a product
# patch. Therefore, this wrapper perl script is used. It reads a given base
# address file and rebases all files mentioned to the same address as
# previously. New dlls get appended to the list.
use strict;
#### globals #####
my $myname = '';
my $options_string = ''; # order of options is important
my %options_hash;
my $rebase_files;
my $misc_dir = $ENV{TEMP};
my $lastaddress;
my @old_files;
my @new_files;
#### main #####
$myname = script_id();
parse_options();
my %lastrun = read_coffbase( \$lastaddress );
# Get files specified on command line. Differ between those already
# listed in coffbase (%options_hash{'C'}) and additional ones.
get_files( \@old_files, \@new_files );
# Rebase libraries already listed in coffbase to the addresses given there.
rebase_again( \@old_files, \@new_files ) if ( @old_files );
# Rebase additional files.
rebase_initially( \@new_files, $lastaddress ) if ( @new_files );
exit 0;
#### subroutines ####
sub script_id
{
( my $script_name = $0 ) =~ s/^.*[\\\/]([\w\.]+)$/$1/;
my $script_rev;
my $id_str = ' $Revision$ ';
$id_str =~ /Revision:\s+(\S+)\s+\$/
? ($script_rev = $1) : ($script_rev = "-");
# print "\n$script_name -- version: $script_rev\n";
return $script_name;
}
sub parse_options
{
use Getopt::Std;
if ( !getopts('C:b:de:l:m:R:N:v', \%options_hash) || ($#ARGV < 0) ) {
print STDERR "Error: invalid command line.\n\n";
usage ();
exit 1;
}
# create options string (we cannot rely on a hash because for some options the
# order is important. -R option has to be specified before -N!)
foreach my $var ( 'C', 'b', 'e', 'l', 'R', 'N' ) {
if ($options_hash{$var} ) {
$options_string .= "-$var $options_hash{$var} ";
}
}
$options_string .= "-d " if $options_hash{"d"};
$options_string .= "-v " if $options_hash{"v"};
# some basic tests
if ( ! $options_hash{'C'}) {
print STDERR "Error: no coffbase specified\n\n";
usage ();
exit 2;
}
if ( ! $options_hash{'b'}) {
print STDERR "Error: no initial base address specified\n\n";
usage ();
exit 2;
}
if ($options_hash{"m"}) {
$misc_dir = $options_hash{"m"};
}
if ( ! -d $misc_dir ) {
print STDERR "Error: no directory to write work files. Please specify with -m\n";
usage ();
exit 3;
}
if ( $misc_dir !~ /[\/\\]$/ ) {
# append finishing path separator:
if ( $misc_dir =~ /([\/\\])/ ) {
$misc_dir .= $1;
}
}
$rebase_files = join " ", @ARGV;
# Cygwin's perl in a W32-4nt configuration wants / instead of \ .
$rebase_files =~ s/\\/\//g;
return;
}
sub read_coffbase
{
my ($addref) = shift;
my %baseaddresses;
my @entry;
if ( $options_hash{'C'} ) {
my $filename = $options_hash{'C'};
if ( -e $filename ) {
print "Repeated run, $filename present\n";
open( COFFBASE, $filename) or die "Error: cannot open $filename";
while ( my $line = <COFFBASE> ) {
# each row consists of three entries, separated by white space:
# dll-name base-address size
@entry = split /\s+/ , $line ;
if ( $entry[3] || ( ! $entry[2] ) ) {
print STDERR "Warning: coffbase file structure invalid?\n";
}
$baseaddresses{$entry[0]} = $entry[1];
if ( $entry[3] ) {
print STDERR "Warning: coffbase file structure invalid?\n";
}
}
close( COFFBASE );
$$addref = $entry[1];
} else {
print "Initial run, $filename not yet present\n";
}
} else {
die "Error: no coffbase specified.";
}
return %baseaddresses;
}
sub get_files
{
use File::Basename;
my ( $oldfiles_ref, $newfiles_ref ) = @_;
my @target = split / /, $rebase_files;
foreach my $pattern ( @target ) {
foreach my $i ( glob( $pattern ) ) {
my $lib = File::Basename::basename $i;
$lib =~ s/\+/\\\+/g;
if ( grep /^$lib$/i, (keys %lastrun) ) {
push @$oldfiles_ref, $i;
} else {
push @$newfiles_ref, $i;
}
}
}
return;
}
sub rebase_again
# rebase using given coffbase file
{
my $oldfiles_ref = shift;
my $newfiles_ref = shift;
my @grownfiles;
my $solarbin ="$ENV{SOLARVERSION}/$ENV{INPATH}/bin$ENV{UPDMINOREXT}";
my $command = "rebase " . $options_string;
if ( $ENV{WRAPCMD} ) {
$command = $ENV{WRAPCMD} . " " . $command;
}
$command =~ s/-C /-i /;
$command =~ s/-d//;
$command =~ s/-b $options_hash{'b'}//;
my $fname = $misc_dir . "rebase_again.txt";
open ( FILES, "> $fname") or die "Error: cannot open file $fname";
my $filesstring = join " ", @$oldfiles_ref;
print FILES "$filesstring\n";
close FILES;
$command .= "\@$fname";
# Cygwin's perl needs escaped \ in system() and open( COMMAND ... )
if ( "$^O" eq "cygwin" ) { $command =~ s/\\/\\\\/g; }
print "\n$command\n";
open( COMMAND, "$command 2>&1 |") or die "Error: Can't execute $command\n";
if ( $? ) {
die "Error: rebase failed: $?!\n";
}
while( <COMMAND> ) {
print;
# evaluate error messages
if ( /REBASE: ([^\s]+).*Grew too large/ ) {
my $toobig_name = $1;
if ( -e "$solarbin/so/$toobig_name" ) {
push @grownfiles, "$solarbin/so/$toobig_name";
print "name was : $toobig_name\n";
print "push $solarbin/so/$toobig_name\n";
} else {
push @grownfiles, "$solarbin/$toobig_name";
}
}
}
close( COMMAND );
if ( @grownfiles ) {
# Some files are larger than expected and therefore could not be rebased.
# Remove respective entries from coffbase and schedule rebase in 'rebase_initially'.
push @$newfiles_ref, @grownfiles;
my $coffbase = $options_hash{'C'};
my $coffbase_new = $options_hash{'C'} . ".new";
open( COFFBASENEW, "> $coffbase_new") or die "Error: cannot open $coffbase_new";
open( COFFBASE, $coffbase) or die "Error: cannot open $coffbase";
my @entry;
while ( my $line = <COFFBASE> ) {
@entry = split /\s+/ , $line ;
if ( $entry[3] ) {
print STDERR "Warning: coffbase file structure invalid?\n";
}
grep /^$entry[0]$/, @grownfiles or print COFFBASENEW $line;
}
close( COFFBASE );
close( COFFBASENEW );
rename $coffbase, $coffbase . ".old" or warn "Error: cannot rename $coffbase";
rename $coffbase_new, $coffbase or warn "Error: cannot rename $coffbase_new";
}
}
sub rebase_initially
{
my ($files_ref, $start_address) = @_;
my $command = "rebase ";
if ( $ENV{WRAPCMD} ) {
$command = $ENV{WRAPCMD} . " " . $command;
}
$command .= $options_string;
if ( $start_address ) {
$command =~ s/-b $options_hash{'b'}/ -b $start_address/;
}
my $fname = $misc_dir . "rebase_new.txt";
open ( FILES, "> $fname") or die "Error: cannot open file $fname";
my $filesstring = join " ", @$files_ref;
print FILES "$filesstring\n";
close FILES;
$command .= "\@$fname";
# Cygwin's perl needs escaped \ in system() and open( COMMAND ... )
if ( "$^O" eq "cygwin" ) { $command =~ s/\\/\\\\/g; }
print "\n$command\n";
my $error = system("$command");
if ($error) {
$error /= 256;
die "Error: rebase failed with exit code $error!\n";
}
}
sub usage
{
print "Usage:\t $myname <-C filename> <-b address> [-d] [-e <Size>] [-l <filename>] [-v] [-m dir] [-R <roordir>] [-N <filename>] <file[list]> \n";
# Options similar to rebase binary. Additional options: -m misc-directory
print "Options:\n";
print "\t -C coffbase_filename Write the list of base adresses to file coffbase_filename. ";
print "Mandatory.\n";
print "\t -b address Initial base address. Mandatory.\n";
print "\t -e SizeAdjustment Extra size to allow for image growth.\n";
print "\t -d Top down rebase.\n";
print "\t -l filename Write logfile filename.\n";
print "\t -m directory Directory to write work files.\n";
print "\t -R directory Root directory.\n";
print "\t -N filename Specify list of files not to be rebased.\n";
print "\t -v Verbose.\n";
return;
}