|
1 :: Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 :: All rights reserved. |
|
3 :: This component and the accompanying materials are made available |
|
4 :: under the terms of "Eclipse Public License v1.0" |
|
5 :: which accompanies this distribution, and is available |
|
6 :: at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 :: |
|
8 :: Initial Contributors: |
|
9 :: Nokia Corporation - initial contribution. |
|
10 :: |
|
11 :: Contributors: |
|
12 :: |
|
13 :: Description: |
|
14 :: |
|
15 |
|
16 @rem = '--*-Perl-*-- |
|
17 @echo off |
|
18 if "%OS%" == "Windows_NT" goto WinNT |
|
19 perl -x -S "%0" %1 %2 %3 %4 %5 %6 %7 %8 %9 |
|
20 goto endofperl |
|
21 :WinNT |
|
22 perl -x -S "%0" %* |
|
23 if NOT "%COMSPEC%" == "%SystemRoot%\system32\cmd.exe" goto endofperl |
|
24 if %errorlevel% == 9009 echo You do not have Perl in your PATH. |
|
25 goto endofperl |
|
26 @rem '; |
|
27 #!perl |
|
28 #line 28 |
|
29 |
|
30 use strict; |
|
31 use Getopt::Long; |
|
32 |
|
33 my $toolVersion = "1.0"; |
|
34 |
|
35 my $update = 0; |
|
36 my $use_perforce = 0; |
|
37 my $verbose = 0; |
|
38 my $defFile; |
|
39 |
|
40 # 1. Check arguments, output help etc. |
|
41 |
|
42 GetOptions ( |
|
43 'update' => \$update, # modify the files |
|
44 'perforce' => \$use_perforce, # apply "p4 edit" to changed files |
|
45 'v+' => \$verbose, # print extra diagnostic info |
|
46 'match=s' => \$defFile # only process DEF files matching a pattern |
|
47 ); |
|
48 |
|
49 if (@ARGV == 0) |
|
50 { |
|
51 print STDERR "\nfix_eabi_thunk_offsets.bat - Version $toolVersion\n"; |
|
52 |
|
53 print STDERR << 'END_OF_HELP'; |
|
54 |
|
55 Usage: fix_eabi_think_offsets [-update] [-perforce] [-match exp] build_log ... |
|
56 |
|
57 Parse the output from one or more build logs, extracting MAKEDEF errors and |
|
58 warnings which relate to EABI virtual function override thunks. Using this |
|
59 information, prepare modified DEF files in which each "missing" export is |
|
60 replaced by a corresponding "unfrozen" export. |
|
61 |
|
62 -update Overwrite the existing .def files with the modified versions |
|
63 -perforce Apply "p4 edit" to each of the modified .def files |
|
64 -match exp Process only .def files with names that contain "\exp" |
|
65 |
|
66 NOTE: The tool assumes that the original build source layout is replicated on |
|
67 the drive where it is being executed. |
|
68 |
|
69 Build logs will sometimes contain corrupted warning messages, in which case |
|
70 the tool will probably report that there is nothing to replace some missing |
|
71 symbol. It may help to edit the log file and try again: it is always safe to |
|
72 run this tool more than once on the same log file. |
|
73 |
|
74 END_OF_HELP |
|
75 |
|
76 exit(1); |
|
77 } |
|
78 |
|
79 my $parseWarnings = 1; |
|
80 my $parseErrors = 1; |
|
81 |
|
82 |
|
83 # 2. Parse the build logs, extracting the Makedef warnings & errors |
|
84 |
|
85 my $line; |
|
86 my $header; |
|
87 my $parseWarning = 0; |
|
88 my $parseError = 0; |
|
89 my $variant; |
|
90 my $component; |
|
91 my $sourceDefFile; |
|
92 my @errorOutput; |
|
93 my @warningOutput; |
|
94 |
|
95 my %DefFiles; |
|
96 my %TempDefFiles; |
|
97 |
|
98 sub newDefFile($) |
|
99 { |
|
100 my ($defFile) = @_; |
|
101 if (!defined $DefFiles{$defFile}) |
|
102 { |
|
103 @{$DefFiles{$defFile}} = \(); |
|
104 } |
|
105 } |
|
106 |
|
107 while ($line = <>) |
|
108 { |
|
109 if ($line =~ /^Chdir /) |
|
110 { |
|
111 $component = $line; |
|
112 $component =~ s/^Chdir //; |
|
113 $component =~ s/\s//g; |
|
114 next; |
|
115 } |
|
116 |
|
117 if (($line =~ /^ make/) && ($line =~ / CFG\=/)) |
|
118 { |
|
119 $variant = $line; |
|
120 $variant =~ s/^.*CFG\=//; |
|
121 $variant =~ s/ .*$//; |
|
122 $variant =~ s/\s//g; |
|
123 next; |
|
124 } |
|
125 |
|
126 if ($parseWarnings && ($line =~ /MAKEDEF WARNING:/)) |
|
127 { |
|
128 $parseWarning = 1; |
|
129 $parseError = 0; |
|
130 $header = $line; |
|
131 next; |
|
132 } |
|
133 |
|
134 if ($parseErrors && ($line =~ /MAKEDEF ERROR:/)) |
|
135 { |
|
136 $parseWarning = 0; |
|
137 $parseError = 1; |
|
138 $header = $line; |
|
139 next; |
|
140 } |
|
141 |
|
142 if ($line !~ /^ /) |
|
143 { |
|
144 $parseWarning = 0; |
|
145 $parseError = 0; |
|
146 next; |
|
147 } |
|
148 |
|
149 if ($parseWarning) |
|
150 { |
|
151 if ($header) |
|
152 { |
|
153 if ($defFile && ($header !~ /\\$defFile/i)) |
|
154 { |
|
155 $parseWarning = 0; |
|
156 $parseError = 0; |
|
157 next; |
|
158 } |
|
159 |
|
160 $sourceDefFile = $header; |
|
161 $sourceDefFile =~ s/^.*not yet Frozen in//; |
|
162 $sourceDefFile =~ s/://; |
|
163 $sourceDefFile =~ s/\s//g; |
|
164 |
|
165 push @warningOutput, "--\n$sourceDefFile ($variant)\n$component\n$header"; |
|
166 newDefFile($sourceDefFile); |
|
167 $header = ""; |
|
168 } |
|
169 |
|
170 next if ($line =~ /\*\*\*/); |
|
171 if ($line =~ /^ (\S.*}\.def)(\(\d+\) : \S+.*)$/) |
|
172 { |
|
173 push @{$DefFiles{$sourceDefFile}}, "W$2"; |
|
174 $TempDefFiles{$1} = $sourceDefFile; |
|
175 } |
|
176 push @warningOutput, $line; |
|
177 |
|
178 next; |
|
179 } |
|
180 |
|
181 if ($parseError) |
|
182 { |
|
183 if ($defFile && ($line !~ /\\$defFile/i)) |
|
184 { |
|
185 $parseWarning = 0; |
|
186 $parseError = 0; |
|
187 next; |
|
188 } |
|
189 |
|
190 if ($header) |
|
191 { |
|
192 $sourceDefFile = $line; |
|
193 $sourceDefFile =~ s/\(.*$//; |
|
194 $sourceDefFile =~ s/\s//g; |
|
195 |
|
196 push @errorOutput, "--\n$sourceDefFile ($variant)\n$component\n$header"; |
|
197 newDefFile($sourceDefFile); |
|
198 $header = ""; |
|
199 } |
|
200 |
|
201 next if ($line =~ /\*\*\*/); |
|
202 if ($line =~ /(\(\d+\) : \S+.*)$/) |
|
203 { |
|
204 push @{$DefFiles{$sourceDefFile}}, "E$1"; |
|
205 } |
|
206 push @errorOutput, $line; |
|
207 |
|
208 next; |
|
209 } |
|
210 |
|
211 # Catch a orphaned warning line... |
|
212 |
|
213 if ($line =~ /^ (\S.*}\.def)(\(\d+\) : \S+.*)$/) |
|
214 { |
|
215 my $tempDefFile = $1; |
|
216 my $newline = $2; |
|
217 |
|
218 next if ($defFile && ($tempDefFile !~ /\\$defFile/i)); |
|
219 |
|
220 my $sourceDefFile = $TempDefFiles{$tempDefFile}; |
|
221 push @{$DefFiles{$sourceDefFile}}, "W$newline"; |
|
222 push @warningOutput, $line; |
|
223 } |
|
224 |
|
225 } |
|
226 |
|
227 close BUILD_LOG; |
|
228 |
|
229 # 3. Process the information for each DEF file |
|
230 |
|
231 my %Classes; |
|
232 my @DefFileList; |
|
233 |
|
234 foreach my $def (sort keys %DefFiles) |
|
235 { |
|
236 my @replacements; |
|
237 my @errors; |
|
238 my @warnings; |
|
239 my $problems = 0; |
|
240 |
|
241 print "\n----\n$def\n"; |
|
242 if ($verbose > 1) |
|
243 { |
|
244 print "Information extracted from Makedef warnings and errors:\n"; |
|
245 # printed inside the following loop... |
|
246 } |
|
247 |
|
248 # Process into lists of errors and warnings which can be sorted |
|
249 |
|
250 my $previousline = ""; |
|
251 foreach $line (sort @{$DefFiles{$def}}) |
|
252 { |
|
253 next if ($line eq $previousline); # skip duplicates |
|
254 $previousline = $line; |
|
255 print "\t$line\n" if ($verbose > 1); |
|
256 |
|
257 if ($line =~ /^(.)\((\d+)\) : (((_ZTh|_ZTv)([n0-9_]+)_(NK?(\d+)(\S+)))\s.*)$/) |
|
258 { |
|
259 my $msgtype = $1; |
|
260 my $lineno = $2; |
|
261 my $defline = $3; |
|
262 my $symbol = $4; |
|
263 my $thunkprefix = $5; |
|
264 my $thunkoffset = $6; |
|
265 my $unthunked = $7; |
|
266 my $topnamelen = $8; |
|
267 my $restofsymbol = $9; |
|
268 |
|
269 if ($msgtype eq "E") |
|
270 { |
|
271 push @errors, "$unthunked\@$thunkprefix $thunkoffset $lineno $symbol"; |
|
272 } |
|
273 else |
|
274 { |
|
275 push @warnings, "$unthunked\@$thunkprefix $thunkoffset $symbol"; |
|
276 } |
|
277 |
|
278 my $class = substr $restofsymbol, 0, $topnamelen; |
|
279 $Classes{$class} = 1; |
|
280 } |
|
281 else |
|
282 { |
|
283 print "WARNING: Ignored - not a thunk: $line\n"; |
|
284 } |
|
285 } |
|
286 |
|
287 # Match up the errors and warnings for related symbols |
|
288 |
|
289 @errors = sort @errors; |
|
290 @warnings = sort @warnings; |
|
291 my $error; |
|
292 my $warning; |
|
293 while (scalar @errors && scalar @warnings) |
|
294 { |
|
295 # Unpack the first entry in each of the lists |
|
296 |
|
297 $error = shift @errors; |
|
298 my ($ekey, $eoffset, $eline, $esymbol) = split / /, $error; |
|
299 $warning = shift @warnings; |
|
300 my ($wkey, $woffset, $wsymbol) = split / /, $warning; |
|
301 |
|
302 # Are they for the same thunk? |
|
303 |
|
304 if ($ekey lt $wkey) |
|
305 { |
|
306 # no - unmatched error, so put back the warning |
|
307 unshift @warnings, $warning; |
|
308 print "Nothing to replace missing symbol on $eline : $esymbol\n"; |
|
309 $problems += 1; |
|
310 next; |
|
311 } |
|
312 |
|
313 if ($ekey gt $wkey) |
|
314 { |
|
315 # no - unmatched warning, so put back the error |
|
316 unshift @errors, $error; |
|
317 print "Nothing missing for replacement symbol : $wsymbol\n"; |
|
318 $problems += 1; |
|
319 next; |
|
320 } |
|
321 |
|
322 # Yes - create replacement instruction |
|
323 |
|
324 push @replacements, "$eline $esymbol => $wsymbol"; |
|
325 } |
|
326 |
|
327 # drain remaining problems, if any |
|
328 |
|
329 foreach my $error (@errors) |
|
330 { |
|
331 my ($ekey, $eoffset, $eline, $esymbol) = split / /, $error; |
|
332 print "Nothing to replace missing symbol on $eline : $esymbol\n"; |
|
333 $problems += 1; |
|
334 } |
|
335 foreach my $warning (@warnings) |
|
336 { |
|
337 my ($wkey, $woffset, $wsymbol) = split / /, $warning; |
|
338 print "Nothing missing for replacement symbol : $wsymbol\n"; |
|
339 $problems += 1; |
|
340 } |
|
341 |
|
342 if ($verbose) |
|
343 { |
|
344 print "\nSubstitions identified:\n\t"; |
|
345 print join("\n\t", sort @replacements); |
|
346 print "\n"; |
|
347 } |
|
348 |
|
349 open DEFFILE, "<$def" or print "Can't open $def: $!\n" and next; |
|
350 my @deflines = <DEFFILE>; |
|
351 close DEFFILE; |
|
352 my $changedlines = 0; |
|
353 |
|
354 foreach my $fix (@replacements) |
|
355 { |
|
356 my ($lineno, $before, $to, $after) = split ' ', $fix; |
|
357 |
|
358 my $line = @deflines[$lineno-1]; |
|
359 if ($line =~ /\s($after)\s/) |
|
360 { |
|
361 print "$lineno - already fixed\n"; |
|
362 next; |
|
363 } |
|
364 if ($line =~ /\s($before)\s/) |
|
365 { |
|
366 $line =~ s/(\s)$before(\s)/$1$after$2/; |
|
367 @deflines[$lineno-1] = $line; |
|
368 print "Changed $lineno to $line" if ($verbose > 1); |
|
369 $changedlines += 1; |
|
370 next; |
|
371 } |
|
372 print "$lineno doesn't contain $before\n"; |
|
373 $problems += 1; |
|
374 } |
|
375 print "\n"; |
|
376 |
|
377 if ($problems != 0) |
|
378 { |
|
379 print "WARNING: $problems thunks could not be repaired\n"; |
|
380 } |
|
381 |
|
382 if ($changedlines == 0) |
|
383 { |
|
384 print "Nothing to change\n"; |
|
385 next; |
|
386 } |
|
387 print "Will change $changedlines lines\n\n"; |
|
388 |
|
389 # Now update the file (and edit in Perforce if required) |
|
390 |
|
391 if ($update) |
|
392 { |
|
393 chmod 0666, $def; # make it writeable |
|
394 |
|
395 open DEFFILE, ">$def" or print "Can't open $def for writing: $!\n" and next; |
|
396 print DEFFILE @deflines; |
|
397 close DEFFILE; |
|
398 |
|
399 print "Updated $def\n"; |
|
400 push @DefFileList, $def; |
|
401 |
|
402 if ($use_perforce) |
|
403 { |
|
404 print "* p4 edit $def\n"; |
|
405 system "p4 edit $def"; |
|
406 print "\n"; |
|
407 } |
|
408 } |
|
409 } |
|
410 |
|
411 # 5. More diagnostic information |
|
412 |
|
413 if (scalar @DefFileList) |
|
414 { |
|
415 print "\nList of updated def files\n"; |
|
416 print join("\n", @DefFileList); |
|
417 print "\n"; |
|
418 } |
|
419 |
|
420 if ($verbose && scalar keys %Classes != 0) |
|
421 { |
|
422 print "\nList of affected classes:\n"; |
|
423 print join("\n", sort keys %Classes), "\n"; |
|
424 } |
|
425 |
|
426 __END__ |
|
427 :endofperl |