xref: /aoo4110/main/postprocess/rebase/rebase.pl (revision b1cdbd2c)
1*b1cdbd2cSJim Jagielski:
2*b1cdbd2cSJim Jagielskieval 'exec perl -wS $0 ${1+"$@"}'
3*b1cdbd2cSJim Jagielski    if 0;
4*b1cdbd2cSJim Jagielski#**************************************************************
5*b1cdbd2cSJim Jagielski#
6*b1cdbd2cSJim Jagielski#  Licensed to the Apache Software Foundation (ASF) under one
7*b1cdbd2cSJim Jagielski#  or more contributor license agreements.  See the NOTICE file
8*b1cdbd2cSJim Jagielski#  distributed with this work for additional information
9*b1cdbd2cSJim Jagielski#  regarding copyright ownership.  The ASF licenses this file
10*b1cdbd2cSJim Jagielski#  to you under the Apache License, Version 2.0 (the
11*b1cdbd2cSJim Jagielski#  "License"); you may not use this file except in compliance
12*b1cdbd2cSJim Jagielski#  with the License.  You may obtain a copy of the License at
13*b1cdbd2cSJim Jagielski#
14*b1cdbd2cSJim Jagielski#    http://www.apache.org/licenses/LICENSE-2.0
15*b1cdbd2cSJim Jagielski#
16*b1cdbd2cSJim Jagielski#  Unless required by applicable law or agreed to in writing,
17*b1cdbd2cSJim Jagielski#  software distributed under the License is distributed on an
18*b1cdbd2cSJim Jagielski#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
19*b1cdbd2cSJim Jagielski#  KIND, either express or implied.  See the License for the
20*b1cdbd2cSJim Jagielski#  specific language governing permissions and limitations
21*b1cdbd2cSJim Jagielski#  under the License.
22*b1cdbd2cSJim Jagielski#
23*b1cdbd2cSJim Jagielski#**************************************************************
24*b1cdbd2cSJim Jagielski
25*b1cdbd2cSJim Jagielski
26*b1cdbd2cSJim Jagielski
27*b1cdbd2cSJim Jagielski#
28*b1cdbd2cSJim Jagielski# rebase.pl - rebase windows dlls
29*b1cdbd2cSJim Jagielski#
30*b1cdbd2cSJim Jagielski# This perl script is to rebase all windows dlls. In principle this could
31*b1cdbd2cSJim Jagielski# be done with one simple command line like f.e.
32*b1cdbd2cSJim Jagielski# rebase -b 0x68000000 -d -R foo_dir -N bar.txt $(SOLARBINDIR)$/*.dll
33*b1cdbd2cSJim Jagielski# That would work fine for creating complete office install sets, but it
34*b1cdbd2cSJim Jagielski# could fail as soon as we are going to ship single dlls for a product
35*b1cdbd2cSJim Jagielski# patch. Therefore, this wrapper perl script is used. It reads a given base
36*b1cdbd2cSJim Jagielski# address file and rebases all files mentioned to the same address as
37*b1cdbd2cSJim Jagielski# previously. New dlls get appended to the list.
38*b1cdbd2cSJim Jagielski
39*b1cdbd2cSJim Jagielskiuse strict;
40*b1cdbd2cSJim Jagielski
41*b1cdbd2cSJim Jagielski#### globals #####
42*b1cdbd2cSJim Jagielski
43*b1cdbd2cSJim Jagielskimy $myname         = '';
44*b1cdbd2cSJim Jagielskimy $options_string = ''; # order of options is important
45*b1cdbd2cSJim Jagielskimy %options_hash;
46*b1cdbd2cSJim Jagielskimy $rebase_files;
47*b1cdbd2cSJim Jagielskimy $misc_dir = $ENV{TEMP};
48*b1cdbd2cSJim Jagielskimy $lastaddress;
49*b1cdbd2cSJim Jagielskimy @old_files;
50*b1cdbd2cSJim Jagielskimy @new_files;
51*b1cdbd2cSJim Jagielski
52*b1cdbd2cSJim Jagielski#### main #####
53*b1cdbd2cSJim Jagielski
54*b1cdbd2cSJim Jagielski$myname = script_id();
55*b1cdbd2cSJim Jagielskiparse_options();
56*b1cdbd2cSJim Jagielskimy %lastrun = read_coffbase( \$lastaddress );
57*b1cdbd2cSJim Jagielski# Get files specified on command line. Differ between those already
58*b1cdbd2cSJim Jagielski# listed in coffbase (%options_hash{'C'}) and additional ones.
59*b1cdbd2cSJim Jagielskiget_files( \@old_files, \@new_files );
60*b1cdbd2cSJim Jagielski# Rebase libraries already listed in coffbase to the addresses given there.
61*b1cdbd2cSJim Jagielskirebase_again( \@old_files, \@new_files ) if ( @old_files );
62*b1cdbd2cSJim Jagielski# Rebase additional files.
63*b1cdbd2cSJim Jagielskirebase_initially( \@new_files, $lastaddress ) if ( @new_files );
64*b1cdbd2cSJim Jagielski
65*b1cdbd2cSJim Jagielskiexit 0;
66*b1cdbd2cSJim Jagielski
67*b1cdbd2cSJim Jagielski
68*b1cdbd2cSJim Jagielski#### subroutines ####
69*b1cdbd2cSJim Jagielski
70*b1cdbd2cSJim Jagielskisub script_id
71*b1cdbd2cSJim Jagielski{
72*b1cdbd2cSJim Jagielski    ( my $script_name = $0 ) =~ s/^.*[\\\/]([\w\.]+)$/$1/;
73*b1cdbd2cSJim Jagielski
74*b1cdbd2cSJim Jagielski    my $script_rev;
75*b1cdbd2cSJim Jagielski    my $id_str = ' $Revision$ ';
76*b1cdbd2cSJim Jagielski    $id_str =~ /Revision:\s+(\S+)\s+\$/
77*b1cdbd2cSJim Jagielski      ? ($script_rev = $1) : ($script_rev = "-");
78*b1cdbd2cSJim Jagielski#    print "\n$script_name -- version: $script_rev\n";
79*b1cdbd2cSJim Jagielski    return $script_name;
80*b1cdbd2cSJim Jagielski}
81*b1cdbd2cSJim Jagielski
82*b1cdbd2cSJim Jagielski
83*b1cdbd2cSJim Jagielskisub parse_options
84*b1cdbd2cSJim Jagielski{
85*b1cdbd2cSJim Jagielski    use Getopt::Std;
86*b1cdbd2cSJim Jagielski    if ( !getopts('C:b:de:l:m:R:N:v', \%options_hash) || ($#ARGV < 0) ) {
87*b1cdbd2cSJim Jagielski        print STDERR "Error: invalid command line.\n\n";
88*b1cdbd2cSJim Jagielski        usage ();
89*b1cdbd2cSJim Jagielski        exit 1;
90*b1cdbd2cSJim Jagielski    }
91*b1cdbd2cSJim Jagielski    # create options string (we cannot rely on a hash because for some options the
92*b1cdbd2cSJim Jagielski    # order is important. -R option has to be specified before -N!)
93*b1cdbd2cSJim Jagielski    foreach my $var ( 'C', 'b', 'e', 'l', 'R', 'N' ) {
94*b1cdbd2cSJim Jagielski        if ($options_hash{$var} ) {
95*b1cdbd2cSJim Jagielski            $options_string .= "-$var $options_hash{$var} ";
96*b1cdbd2cSJim Jagielski        }
97*b1cdbd2cSJim Jagielski    }
98*b1cdbd2cSJim Jagielski    $options_string .= "-d " if $options_hash{"d"};
99*b1cdbd2cSJim Jagielski    $options_string .= "-v " if $options_hash{"v"};
100*b1cdbd2cSJim Jagielski    # some basic tests
101*b1cdbd2cSJim Jagielski    if ( ! $options_hash{'C'}) {
102*b1cdbd2cSJim Jagielski        print STDERR "Error: no coffbase specified\n\n";
103*b1cdbd2cSJim Jagielski        usage ();
104*b1cdbd2cSJim Jagielski        exit 2;
105*b1cdbd2cSJim Jagielski    }
106*b1cdbd2cSJim Jagielski    if ( ! $options_hash{'b'}) {
107*b1cdbd2cSJim Jagielski        print STDERR "Error: no initial base address specified\n\n";
108*b1cdbd2cSJim Jagielski        usage ();
109*b1cdbd2cSJim Jagielski        exit 2;
110*b1cdbd2cSJim Jagielski    }
111*b1cdbd2cSJim Jagielski    if ($options_hash{"m"}) {
112*b1cdbd2cSJim Jagielski        $misc_dir = $options_hash{"m"};
113*b1cdbd2cSJim Jagielski    }
114*b1cdbd2cSJim Jagielski    if ( ! -d $misc_dir ) {
115*b1cdbd2cSJim Jagielski        print STDERR "Error: no directory to write work files. Please specify with -m\n";
116*b1cdbd2cSJim Jagielski        usage ();
117*b1cdbd2cSJim Jagielski        exit 3;
118*b1cdbd2cSJim Jagielski    }
119*b1cdbd2cSJim Jagielski    if ( $misc_dir !~ /[\/\\]$/ ) {
120*b1cdbd2cSJim Jagielski        # append finishing path separator:
121*b1cdbd2cSJim Jagielski        if ( $misc_dir =~ /([\/\\])/ ) {
122*b1cdbd2cSJim Jagielski            $misc_dir .= $1;
123*b1cdbd2cSJim Jagielski        }
124*b1cdbd2cSJim Jagielski    }
125*b1cdbd2cSJim Jagielski    $rebase_files = join " ", @ARGV;
126*b1cdbd2cSJim Jagielski    # Cygwin's perl in a W32-4nt configuration wants / instead of \ .
127*b1cdbd2cSJim Jagielski    $rebase_files =~ s/\\/\//g;
128*b1cdbd2cSJim Jagielski    return;
129*b1cdbd2cSJim Jagielski}
130*b1cdbd2cSJim Jagielski
131*b1cdbd2cSJim Jagielski
132*b1cdbd2cSJim Jagielskisub read_coffbase
133*b1cdbd2cSJim Jagielski{
134*b1cdbd2cSJim Jagielski    my ($addref) = shift;
135*b1cdbd2cSJim Jagielski    my %baseaddresses;
136*b1cdbd2cSJim Jagielski    my @entry;
137*b1cdbd2cSJim Jagielski    if ( $options_hash{'C'} ) {
138*b1cdbd2cSJim Jagielski        my $filename = $options_hash{'C'};
139*b1cdbd2cSJim Jagielski        if ( -e $filename ) {
140*b1cdbd2cSJim Jagielski            print "Repeated run, $filename present\n";
141*b1cdbd2cSJim Jagielski            open( COFFBASE, $filename) or die "Error: cannot open $filename";
142*b1cdbd2cSJim Jagielski            while ( my $line = <COFFBASE> ) {
143*b1cdbd2cSJim Jagielski                # each row consists of three entries, separated by white space:
144*b1cdbd2cSJim Jagielski                # dll-name base-address size
145*b1cdbd2cSJim Jagielski                @entry = split /\s+/ , $line ;
146*b1cdbd2cSJim Jagielski                if ( $entry[3] || ( ! $entry[2] ) ) {
147*b1cdbd2cSJim Jagielski                    print STDERR "Warning: coffbase file structure invalid?\n";
148*b1cdbd2cSJim Jagielski                }
149*b1cdbd2cSJim Jagielski                $baseaddresses{$entry[0]} = $entry[1];
150*b1cdbd2cSJim Jagielski                if ( $entry[3] ) {
151*b1cdbd2cSJim Jagielski                    print STDERR "Warning: coffbase file structure invalid?\n";
152*b1cdbd2cSJim Jagielski                }
153*b1cdbd2cSJim Jagielski            }
154*b1cdbd2cSJim Jagielski            close( COFFBASE );
155*b1cdbd2cSJim Jagielski            $$addref = $entry[1];
156*b1cdbd2cSJim Jagielski        } else {
157*b1cdbd2cSJim Jagielski            print "Initial run, $filename not yet present\n";
158*b1cdbd2cSJim Jagielski        }
159*b1cdbd2cSJim Jagielski    } else {
160*b1cdbd2cSJim Jagielski        die "Error: no coffbase specified.";
161*b1cdbd2cSJim Jagielski    }
162*b1cdbd2cSJim Jagielski    return %baseaddresses;
163*b1cdbd2cSJim Jagielski}
164*b1cdbd2cSJim Jagielski
165*b1cdbd2cSJim Jagielski
166*b1cdbd2cSJim Jagielskisub get_files
167*b1cdbd2cSJim Jagielski{
168*b1cdbd2cSJim Jagielski    use File::Basename;
169*b1cdbd2cSJim Jagielski    my ( $oldfiles_ref, $newfiles_ref ) = @_;
170*b1cdbd2cSJim Jagielski    my @target = split / /,  $rebase_files;
171*b1cdbd2cSJim Jagielski    foreach my $pattern ( @target ) {
172*b1cdbd2cSJim Jagielski        foreach my $i ( glob( $pattern ) ) {
173*b1cdbd2cSJim Jagielski            my $lib = File::Basename::basename $i;
174*b1cdbd2cSJim Jagielski	    $lib =~ s/\+/\\\+/g;
175*b1cdbd2cSJim Jagielski            if ( grep /^$lib$/i, (keys %lastrun) ) {
176*b1cdbd2cSJim Jagielski                push @$oldfiles_ref, $i;
177*b1cdbd2cSJim Jagielski            } else {
178*b1cdbd2cSJim Jagielski                push @$newfiles_ref, $i;
179*b1cdbd2cSJim Jagielski            }
180*b1cdbd2cSJim Jagielski        }
181*b1cdbd2cSJim Jagielski    }
182*b1cdbd2cSJim Jagielski    return;
183*b1cdbd2cSJim Jagielski}
184*b1cdbd2cSJim Jagielski
185*b1cdbd2cSJim Jagielski
186*b1cdbd2cSJim Jagielskisub rebase_again
187*b1cdbd2cSJim Jagielski# rebase using given coffbase file
188*b1cdbd2cSJim Jagielski{
189*b1cdbd2cSJim Jagielski    my $oldfiles_ref = shift;
190*b1cdbd2cSJim Jagielski    my $newfiles_ref = shift;
191*b1cdbd2cSJim Jagielski    my @grownfiles;
192*b1cdbd2cSJim Jagielski    my $solarbin ="$ENV{SOLARVERSION}/$ENV{INPATH}/bin$ENV{UPDMINOREXT}";
193*b1cdbd2cSJim Jagielski    my $command = "rebase " . $options_string;
194*b1cdbd2cSJim Jagielski    if ( $ENV{WRAPCMD} ) {
195*b1cdbd2cSJim Jagielski        $command = $ENV{WRAPCMD} . " " . $command;
196*b1cdbd2cSJim Jagielski    }
197*b1cdbd2cSJim Jagielski    $command =~ s/-C /-i /;
198*b1cdbd2cSJim Jagielski    $command =~ s/-d//;
199*b1cdbd2cSJim Jagielski    $command =~ s/-b $options_hash{'b'}//;
200*b1cdbd2cSJim Jagielski    my $fname = $misc_dir . "rebase_again.txt";
201*b1cdbd2cSJim Jagielski    open ( FILES, "> $fname") or die "Error: cannot open file $fname";
202*b1cdbd2cSJim Jagielski    my $filesstring = join " ", @$oldfiles_ref;
203*b1cdbd2cSJim Jagielski    print FILES "$filesstring\n";
204*b1cdbd2cSJim Jagielski    close FILES;
205*b1cdbd2cSJim Jagielski    $command .= "\@$fname";
206*b1cdbd2cSJim Jagielski    # Cygwin's perl needs escaped \ in system() and open( COMMAND ... )
207*b1cdbd2cSJim Jagielski    if ( "$^O" eq "cygwin" ) { $command =~ s/\\/\\\\/g; }
208*b1cdbd2cSJim Jagielski    print "\n$command\n";
209*b1cdbd2cSJim Jagielski    open( COMMAND, "$command 2>&1 |") or die "Error: Can't execute $command\n";
210*b1cdbd2cSJim Jagielski    if ( $? ) {
211*b1cdbd2cSJim Jagielski        die "Error: rebase failed: $?!\n";
212*b1cdbd2cSJim Jagielski    }
213*b1cdbd2cSJim Jagielski    while( <COMMAND> ) {
214*b1cdbd2cSJim Jagielski        print;
215*b1cdbd2cSJim Jagielski        # evaluate error messages
216*b1cdbd2cSJim Jagielski        if ( /REBASE: ([^\s]+).*Grew too large/ ) {
217*b1cdbd2cSJim Jagielski            my $toobig_name = $1;
218*b1cdbd2cSJim Jagielski            if ( -e "$solarbin/so/$toobig_name" ) {
219*b1cdbd2cSJim Jagielski                push @grownfiles, "$solarbin/so/$toobig_name";
220*b1cdbd2cSJim Jagielski                print "name was : $toobig_name\n";
221*b1cdbd2cSJim Jagielski                print "push $solarbin/so/$toobig_name\n";
222*b1cdbd2cSJim Jagielski            } else {
223*b1cdbd2cSJim Jagielski                push @grownfiles, "$solarbin/$toobig_name";
224*b1cdbd2cSJim Jagielski            }
225*b1cdbd2cSJim Jagielski        }
226*b1cdbd2cSJim Jagielski    }
227*b1cdbd2cSJim Jagielski    close( COMMAND );
228*b1cdbd2cSJim Jagielski    if ( @grownfiles ) {
229*b1cdbd2cSJim Jagielski        # Some files are larger than expected and therefore could not be rebased.
230*b1cdbd2cSJim Jagielski        # Remove respective entries from coffbase and schedule rebase in 'rebase_initially'.
231*b1cdbd2cSJim Jagielski        push @$newfiles_ref, @grownfiles;
232*b1cdbd2cSJim Jagielski        my $coffbase = $options_hash{'C'};
233*b1cdbd2cSJim Jagielski        my $coffbase_new = $options_hash{'C'} . ".new";
234*b1cdbd2cSJim Jagielski        open( COFFBASENEW, "> $coffbase_new") or die "Error: cannot open $coffbase_new";
235*b1cdbd2cSJim Jagielski        open( COFFBASE, $coffbase) or die "Error: cannot open $coffbase";
236*b1cdbd2cSJim Jagielski        my @entry;
237*b1cdbd2cSJim Jagielski        while ( my $line = <COFFBASE> ) {
238*b1cdbd2cSJim Jagielski            @entry = split /\s+/ , $line ;
239*b1cdbd2cSJim Jagielski            if ( $entry[3] ) {
240*b1cdbd2cSJim Jagielski                print STDERR "Warning: coffbase file structure invalid?\n";
241*b1cdbd2cSJim Jagielski            }
242*b1cdbd2cSJim Jagielski            grep /^$entry[0]$/, @grownfiles or print COFFBASENEW $line;
243*b1cdbd2cSJim Jagielski        }
244*b1cdbd2cSJim Jagielski        close( COFFBASE );
245*b1cdbd2cSJim Jagielski        close( COFFBASENEW );
246*b1cdbd2cSJim Jagielski        rename $coffbase, $coffbase . ".old" or warn "Error: cannot rename $coffbase";
247*b1cdbd2cSJim Jagielski        rename $coffbase_new, $coffbase or warn "Error: cannot rename $coffbase_new";
248*b1cdbd2cSJim Jagielski    }
249*b1cdbd2cSJim Jagielski}
250*b1cdbd2cSJim Jagielski
251*b1cdbd2cSJim Jagielski
252*b1cdbd2cSJim Jagielskisub rebase_initially
253*b1cdbd2cSJim Jagielski{
254*b1cdbd2cSJim Jagielski    my ($files_ref, $start_address) = @_;
255*b1cdbd2cSJim Jagielski    my $command = "rebase ";
256*b1cdbd2cSJim Jagielski    if ( $ENV{WRAPCMD} ) {
257*b1cdbd2cSJim Jagielski        $command = $ENV{WRAPCMD} . " " . $command;
258*b1cdbd2cSJim Jagielski    }
259*b1cdbd2cSJim Jagielski    $command .= $options_string;
260*b1cdbd2cSJim Jagielski    if ( $start_address ) {
261*b1cdbd2cSJim Jagielski        $command =~ s/-b $options_hash{'b'}/ -b $start_address/;
262*b1cdbd2cSJim Jagielski    }
263*b1cdbd2cSJim Jagielski    my $fname = $misc_dir . "rebase_new.txt";
264*b1cdbd2cSJim Jagielski    open ( FILES, "> $fname") or die "Error: cannot open file $fname";
265*b1cdbd2cSJim Jagielski    my $filesstring = join " ", @$files_ref;
266*b1cdbd2cSJim Jagielski    print FILES "$filesstring\n";
267*b1cdbd2cSJim Jagielski    close FILES;
268*b1cdbd2cSJim Jagielski    $command .= "\@$fname";
269*b1cdbd2cSJim Jagielski    # Cygwin's perl needs escaped \ in system() and open( COMMAND ... )
270*b1cdbd2cSJim Jagielski    if ( "$^O" eq "cygwin" ) { $command =~ s/\\/\\\\/g; }
271*b1cdbd2cSJim Jagielski    print "\n$command\n";
272*b1cdbd2cSJim Jagielski    my $error = system("$command");
273*b1cdbd2cSJim Jagielski    if ($error) {
274*b1cdbd2cSJim Jagielski        $error /= 256;
275*b1cdbd2cSJim Jagielski        die "Error: rebase failed with exit code $error!\n";
276*b1cdbd2cSJim Jagielski    }
277*b1cdbd2cSJim Jagielski}
278*b1cdbd2cSJim Jagielski
279*b1cdbd2cSJim Jagielski
280*b1cdbd2cSJim Jagielskisub usage
281*b1cdbd2cSJim Jagielski{
282*b1cdbd2cSJim Jagielski    print "Usage:\t $myname <-C filename> <-b address> [-d] [-e <Size>] [-l <filename>] [-v] [-m dir] [-R <roordir>] [-N <filename>] <file[list]> \n";
283*b1cdbd2cSJim Jagielski    # Options similar to rebase binary. Additional options: -m misc-directory
284*b1cdbd2cSJim Jagielski    print "Options:\n";
285*b1cdbd2cSJim Jagielski    print "\t -C coffbase_filename    Write the list of base adresses to file coffbase_filename. ";
286*b1cdbd2cSJim Jagielski    print                            "Mandatory.\n";
287*b1cdbd2cSJim Jagielski    print "\t -b address              Initial base address. Mandatory.\n";
288*b1cdbd2cSJim Jagielski    print "\t -e SizeAdjustment       Extra size to allow for image growth.\n";
289*b1cdbd2cSJim Jagielski    print "\t -d                      Top down rebase.\n";
290*b1cdbd2cSJim Jagielski    print "\t -l filename             Write logfile filename.\n";
291*b1cdbd2cSJim Jagielski    print "\t -m directory            Directory to write work files.\n";
292*b1cdbd2cSJim Jagielski    print "\t -R directory            Root directory.\n";
293*b1cdbd2cSJim Jagielski    print "\t -N filename             Specify list of files not to be rebased.\n";
294*b1cdbd2cSJim Jagielski    print "\t -v                      Verbose.\n";
295*b1cdbd2cSJim Jagielski    return;
296*b1cdbd2cSJim Jagielski}
297*b1cdbd2cSJim Jagielski
298*b1cdbd2cSJim Jagielski
299