| 1 |
#!/usr/bin/perl -w |
| 2 |
############################################################################# |
| 3 |
## |
| 4 |
## Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). |
| 5 |
## All rights reserved. |
| 6 |
## Contact: Nokia Corporation (qt-info@nokia.com) |
| 7 |
## |
| 8 |
## This file is part of the utilities of the Qt Toolkit. |
| 9 |
## |
| 10 |
## $QT_BEGIN_LICENSE:LGPL$ |
| 11 |
## GNU Lesser General Public License Usage |
| 12 |
## This file may be used under the terms of the GNU Lesser General Public |
| 13 |
## License version 2.1 as published by the Free Software Foundation and |
| 14 |
## appearing in the file LICENSE.LGPL included in the packaging of this |
| 15 |
## file. Please review the following information to ensure the GNU Lesser |
| 16 |
## General Public License version 2.1 requirements will be met: |
| 17 |
## http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
| 18 |
## |
| 19 |
## In addition, as a special exception, Nokia gives you certain additional |
| 20 |
## rights. These rights are described in the Nokia Qt LGPL Exception |
| 21 |
## version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
| 22 |
## |
| 23 |
## GNU General Public License Usage |
| 24 |
## Alternatively, this file may be used under the terms of the GNU General |
| 25 |
## Public License version 3.0 as published by the Free Software Foundation |
| 26 |
## and appearing in the file LICENSE.GPL included in the packaging of this |
| 27 |
## file. Please review the following information to ensure the GNU General |
| 28 |
## Public License version 3.0 requirements will be met: |
| 29 |
## http://www.gnu.org/copyleft/gpl.html. |
| 30 |
## |
| 31 |
## Other Usage |
| 32 |
## Alternatively, this file may be used in accordance with the terms and |
| 33 |
## conditions contained in a signed written agreement between you and Nokia. |
| 34 |
## |
| 35 |
## |
| 36 |
## |
| 37 |
## |
| 38 |
## |
| 39 |
## $QT_END_LICENSE$ |
| 40 |
## |
| 41 |
############################################################################# |
| 42 |
|
| 43 |
# A script to get around some shortcomings in elf2e32, namely: |
| 44 |
# - Returning 0 even when there are errors. |
| 45 |
# - Excluding symbols from the dso file even when they are present in the ELF file. |
| 46 |
# - Including symbols in the the dso file even when they are not present in the ELF file. |
| 47 |
# - Overwriting the old dso file even when there are no changes (increases build time). |
| 48 |
|
| 49 |
use File::Copy; |
| 50 |
|
| 51 |
my @args = (); |
| 52 |
my @definput; |
| 53 |
my @defoutput; |
| 54 |
my @dso; |
| 55 |
my @tmpdso; |
| 56 |
foreach (@ARGV) { |
| 57 |
if (/^--definput/o) { |
| 58 |
@definput = split('=', $_); |
| 59 |
} elsif (/^--defoutput/o) { |
| 60 |
@defoutput = split('=', $_); |
| 61 |
} elsif (/^--dso/o) { |
| 62 |
@dso = split('=', $_); |
| 63 |
} elsif (/^--tmpdso/o) { |
| 64 |
@tmpdso = split('=', $_); |
| 65 |
$tmpdso[0] = "--dso"; |
| 66 |
} else { |
| 67 |
push(@args, $_); |
| 68 |
} |
| 69 |
} |
| 70 |
|
| 71 |
@definput = () if (!@definput || ! -e $definput[1]); |
| 72 |
|
| 73 |
if (@dso && !@tmpdso || !@dso && @tmpdso) { |
| 74 |
print("--dso and --tmpdso must be used together.\n"); |
| 75 |
exit 1; |
| 76 |
} |
| 77 |
|
| 78 |
my $buildingLibrary = (@defoutput && @dso) ? 1 : 0; |
| 79 |
|
| 80 |
my $fixupFile = ""; |
| 81 |
my $runCount = 0; |
| 82 |
my $returnCode = 0; |
| 83 |
|
| 84 |
# For debugging. Make it nonzero to give verbose output. |
| 85 |
my $debugScript = 1; |
| 86 |
my @usedDefFiles; |
| 87 |
sub recordDefFile { |
| 88 |
return if (!$debugScript); |
| 89 |
|
| 90 |
my ($msg, $file) = @_; |
| 91 |
my $content = "$msg, $file:\n"; |
| 92 |
my $defFileFd; |
| 93 |
if (!open($defFileFd, "< $file")) { |
| 94 |
print("Warning: Could not open $file (for debug analysis)\n"); |
| 95 |
return; |
| 96 |
} |
| 97 |
while (<$defFileFd>) { |
| 98 |
$content .= $_; |
| 99 |
} |
| 100 |
|
| 101 |
push(@usedDefFiles, $content); |
| 102 |
} |
| 103 |
sub printRecordedDefFiles { |
| 104 |
return if (!$debugScript); |
| 105 |
|
| 106 |
foreach (@usedDefFiles) { |
| 107 |
print ("$_\n"); |
| 108 |
} |
| 109 |
} |
| 110 |
|
| 111 |
sub missingSymbolMismatch |
| 112 |
{ |
| 113 |
my $missingSymbolSum = $_[0]; |
| 114 |
|
| 115 |
printRecordedDefFiles; |
| 116 |
|
| 117 |
print("Bug in the native elf2e32 tool: Number of missing symbols does not\n"); |
| 118 |
print("match number of removed symbols in the output DEF file.\n\n"); |
| 119 |
|
| 120 |
print("Original elf2e32 output:\n"); |
| 121 |
print(" $missingSymbolSum Frozen Export\(s\) missing from the ELF file\n\n"); |
| 122 |
|
| 123 |
print("However $defoutput[1] contains more missing entries than that.\n\n"); |
| 124 |
|
| 125 |
print("This needs to be fixed manually in the DEF file.\n"); |
| 126 |
exit(2); |
| 127 |
} |
| 128 |
|
| 129 |
if ($debugScript) { |
| 130 |
print("PATH: $ENV{PATH}\n"); |
| 131 |
print("EPOCROOT: $ENV{EPOCROOT}\n"); |
| 132 |
} |
| 133 |
|
| 134 |
while (1) { |
| 135 |
if (++$runCount > 2) { |
| 136 |
printRecordedDefFiles if ($debugScript); |
| 137 |
print("Internal error in $0, link succeeded, but exports may be wrong.\n"); |
| 138 |
last; |
| 139 |
} |
| 140 |
|
| 141 |
my $elf2e32Pipe; |
| 142 |
my $elf2e32Cmd = "elf2e32 @args" |
| 143 |
. " " . join("=", @definput) |
| 144 |
. " " . join("=", @defoutput) |
| 145 |
. " " . join("=", @tmpdso); |
| 146 |
open($elf2e32Pipe, "$elf2e32Cmd 2>&1 |") or die ("Could not run elf2e32"); |
| 147 |
|
| 148 |
my %fixupSymbols; |
| 149 |
my $foundBrokenSymbols = 0; |
| 150 |
my $missingSymbolSum = 0; |
| 151 |
my $missingSymbolCount = 0; |
| 152 |
my $errors = 0; |
| 153 |
while (<$elf2e32Pipe>) { |
| 154 |
print; |
| 155 |
if (/Error:/io) { |
| 156 |
$errors = 1; |
| 157 |
} elsif (/symbol ([a-z0-9_]+) absent in the DEF file, but present in the ELF file/io) { |
| 158 |
$fixupSymbols{$1} = 1; |
| 159 |
$foundBrokenSymbols = 1; |
| 160 |
} elsif (/([0-9]+) Frozen Export\(s\) missing from the ELF file/io) { |
| 161 |
$missingSymbolSum = $1; |
| 162 |
$foundBrokenSymbols = 1; |
| 163 |
} |
| 164 |
} |
| 165 |
close($elf2e32Pipe); |
| 166 |
|
| 167 |
if ($debugScript) { |
| 168 |
recordDefFile("Run no $runCount, elf2e32 DEF file input", "$definput[1]"); |
| 169 |
recordDefFile("Run no $runCount, elf2e32 DEF file output", "$defoutput[1]"); |
| 170 |
} |
| 171 |
|
| 172 |
if ($errors) { |
| 173 |
$returnCode = 1; |
| 174 |
last; |
| 175 |
} |
| 176 |
|
| 177 |
if ($buildingLibrary && $runCount == 1) { |
| 178 |
my $tmpDefFile; |
| 179 |
my $newDefFile; |
| 180 |
my $origDefFile; |
| 181 |
my $savedNewDefFileLine = ""; |
| 182 |
if ($definput[1]) { |
| 183 |
open($origDefFile, "< $definput[1]") or die("Could not open $definput[1]"); |
| 184 |
} |
| 185 |
open($newDefFile, "< $defoutput[1]") or die("Could not open $defoutput[1]"); |
| 186 |
open($tmpDefFile, "> $defoutput[1].tmp") or die("Could not open $defoutput[1].tmp"); |
| 187 |
print($tmpDefFile "EXPORTS\n") or die("Could not write to temporary DEF file: $!"); |
| 188 |
$fixupFile = "$defoutput[1].tmp"; |
| 189 |
while (1) { |
| 190 |
my $origDefLine; |
| 191 |
my $origSym; |
| 192 |
my $origOrdinal; |
| 193 |
my $origExtraData; |
| 194 |
my $newDefLine; |
| 195 |
my $newSym; |
| 196 |
my $newOrdinal; |
| 197 |
my $newExtraData; |
| 198 |
my $defLine; |
| 199 |
my $sym; |
| 200 |
my $ordinal; |
| 201 |
my $extraData; |
| 202 |
if ($definput[1]) { |
| 203 |
# Read from original def file, and skip non-symbol lines |
| 204 |
while (1) { |
| 205 |
$origDefLine = <$origDefFile>; |
| 206 |
if (defined($origDefLine)) { |
| 207 |
$origDefLine =~ s/[\n\r]//; |
| 208 |
if ($origDefLine =~ /([a-z0-9_]+) +\@ *([0-9]+) (.*)/i) { |
| 209 |
$origSym = $1; |
| 210 |
$origOrdinal = $2; |
| 211 |
$origExtraData = $3; |
| 212 |
last; |
| 213 |
} |
| 214 |
} else { |
| 215 |
last; |
| 216 |
} |
| 217 |
} |
| 218 |
} |
| 219 |
|
| 220 |
if ($savedNewDefFileLine) { |
| 221 |
# This happens if the new def file was missing an entry. |
| 222 |
$newDefLine = $savedNewDefFileLine; |
| 223 |
$newDefLine =~ /([a-z0-9_]+) +\@ *([0-9]+) (.*)/i or die("$0: Shouldn't happen"); |
| 224 |
$newSym = $1; |
| 225 |
$newOrdinal = $2; |
| 226 |
$newExtraData = $3; |
| 227 |
} else { |
| 228 |
# Read from new def file, and skip non-symbol lines |
| 229 |
while (1) { |
| 230 |
$newDefLine = <$newDefFile>; |
| 231 |
if (defined($newDefLine)) { |
| 232 |
$newDefLine =~ s/[\n\r]//; |
| 233 |
if ($newDefLine =~ /([a-z0-9_]+) +\@ *([0-9]+) (.*)/i) { |
| 234 |
$newSym = $1; |
| 235 |
$newOrdinal = $2; |
| 236 |
$newExtraData = $3; |
| 237 |
last; |
| 238 |
} |
| 239 |
} else { |
| 240 |
last; |
| 241 |
} |
| 242 |
} |
| 243 |
} |
| 244 |
$savedNewDefFileLine = ""; |
| 245 |
last if (!defined($origDefLine) && !defined($newDefLine)); |
| 246 |
|
| 247 |
if (defined($origOrdinal) && (!defined($newOrdinal) || $origOrdinal != $newOrdinal)) { |
| 248 |
# If the symbol is missing from the new def file, use the original symbol. |
| 249 |
$savedNewDefFileLine = $newDefLine; |
| 250 |
$defLine = $origDefLine; |
| 251 |
$sym = $origSym; |
| 252 |
$ordinal = $origOrdinal; |
| 253 |
$extraData = $origExtraData; |
| 254 |
} else { |
| 255 |
$defLine = $newDefLine; |
| 256 |
$sym = $newSym; |
| 257 |
$ordinal = $newOrdinal; |
| 258 |
if ($newExtraData =~ /ABSENT/) { |
| 259 |
# Special case to keep "DATA [0-9]+" data in absent entries. |
| 260 |
$extraData = $origExtraData; |
| 261 |
} else { |
| 262 |
$extraData = $newExtraData; |
| 263 |
} |
| 264 |
} |
| 265 |
if (exists($fixupSymbols{$sym})) { |
| 266 |
# Fix symbols that have returned after first being marked ABSENT. |
| 267 |
$extraData =~ s/ ABSENT//; |
| 268 |
} elsif ($defLine =~ s/; MISSING://) { |
| 269 |
# Auto-absent symbols. |
| 270 |
$extraData .= " ABSENT"; |
| 271 |
if (++$missingSymbolCount > $missingSymbolSum) { |
| 272 |
missingSymbolMismatch($missingSymbolSum); |
| 273 |
} |
| 274 |
} |
| 275 |
print($tmpDefFile "\t$sym \@ $ordinal $extraData\n") or die("Could not write to temporary DEF file: $!"); |
| 276 |
} |
| 277 |
print($tmpDefFile "\n") or die("Could not write to temporary DEF file: $!"); |
| 278 |
close($origDefFile) if ($definput[1]); |
| 279 |
close($newDefFile); |
| 280 |
close($tmpDefFile); |
| 281 |
|
| 282 |
$definput[1] = "$defoutput[1].tmp"; |
| 283 |
|
| 284 |
} |
| 285 |
if (!$foundBrokenSymbols || $errors) { |
| 286 |
last; |
| 287 |
} |
| 288 |
|
| 289 |
print("Rerunning elf2e32 due to DEF file / ELF file mismatch\n"); |
| 290 |
}; |
| 291 |
|
| 292 |
if ($fixupFile) { |
| 293 |
unlink($defoutput[1]); |
| 294 |
move($fixupFile, $defoutput[1]); |
| 295 |
} |
| 296 |
|
| 297 |
exit $returnCode if ($returnCode != 0); |
| 298 |
|
| 299 |
if ($buildingLibrary) { |
| 300 |
my $differenceFound = 0; |
| 301 |
|
| 302 |
if (-e $dso[1]) { |
| 303 |
my $dsoFile; |
| 304 |
my $tmpdsoFile; |
| 305 |
my $dsoBuf; |
| 306 |
my $tmpdsoBuf; |
| 307 |
open($dsoFile, "< $dso[1]") or die("Could not open $dso[1]"); |
| 308 |
open($tmpdsoFile, "< $tmpdso[1]") or die("Could not open $tmpdso[1]"); |
| 309 |
binmode($dsoFile); |
| 310 |
binmode($tmpdsoFile); |
| 311 |
while(read($dsoFile, $dsoBuf, 4096) && read($tmpdsoFile, $tmpdsoBuf, 4096)) { |
| 312 |
if ($dsoBuf ne $tmpdsoBuf) { |
| 313 |
$differenceFound = 1; |
| 314 |
} |
| 315 |
} |
| 316 |
close($tmpdsoFile); |
| 317 |
close($dsoFile); |
| 318 |
} else { |
| 319 |
$differenceFound = 1; |
| 320 |
} |
| 321 |
|
| 322 |
if ($differenceFound) { |
| 323 |
copy($tmpdso[1], $dso[1]) or die("Could not copy $tmpdso[1] to $dso[1]: $!"); |
| 324 |
} |
| 325 |
} |