|
1 # |
|
2 # Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 # All rights reserved. |
|
4 # This component and the accompanying materials are made available |
|
5 # under the terms of the License "Eclipse Public License v1.0" |
|
6 # which accompanies this distribution, and is available |
|
7 # at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 # |
|
9 # Initial Contributors: |
|
10 # Nokia Corporation - initial contribution. |
|
11 # |
|
12 # Contributors: |
|
13 # |
|
14 # Description: |
|
15 # Relinks the debug exe/dlls in a ROM if the make file is present |
|
16 # |
|
17 |
|
18 require 5.003_07; |
|
19 use strict; |
|
20 no strict 'vars'; |
|
21 use English; |
|
22 use Cwd; |
|
23 use FindBin; # for FindBin::Bin |
|
24 |
|
25 my $PerlLibPath; # fully qualified pathname of the directory containing our Perl modules |
|
26 |
|
27 BEGIN { |
|
28 # check user has a version of perl that will cope |
|
29 require 5.005_03; |
|
30 # establish the path to the Perl libraries: currently the same directory as this script |
|
31 $PerlLibPath = $FindBin::Bin; # X:/epoc32/tools |
|
32 $PerlLibPath =~ s/\//\\/g; # X:\epoc32\tools |
|
33 $PerlLibPath .= "\\"; |
|
34 } |
|
35 |
|
36 use lib $PerlLibPath; |
|
37 use Modload; |
|
38 Load_SetModulePath($PerlLibPath); |
|
39 |
|
40 # Globals |
|
41 my $debug = 0; |
|
42 my $rombuild; |
|
43 my @executables = ( 'euser' ); |
|
44 |
|
45 cwd =~ /^(.:)/o; |
|
46 my $drive = $1; |
|
47 |
|
48 # get EPOCROOT for searching directories |
|
49 my $epocroot = lc $ENV{EPOCROOT}; |
|
50 |
|
51 &args; |
|
52 &main; |
|
53 |
|
54 exit 0; |
|
55 |
|
56 |
|
57 # |
|
58 # main |
|
59 # |
|
60 sub main |
|
61 { |
|
62 my $file; |
|
63 my $text; |
|
64 my $data; |
|
65 my $bss; |
|
66 my $textlen; |
|
67 my $datalen; |
|
68 my $bsslen; |
|
69 |
|
70 open (ROM, "<$rombuild") |
|
71 or die "ERROR: Can't open rombuild log file \"$rombuild\"\n"; |
|
72 |
|
73 die "ERROR: \"$rombuild\" isn't a rombuild log file\n" |
|
74 unless ((<ROM> =~ /^ROMBUILD/) || (<ROM> =~ /^ROMBUILD/)); |
|
75 |
|
76 # build up a hash of all the make files indexed by build and exe name |
|
77 # |
|
78 # do this in a more directed way based on the map files for the |
|
79 # executables we are interested in. |
|
80 |
|
81 %map = (); |
|
82 &dirsearch($epocroot . "EPOC32\\", "BUILD"); |
|
83 |
|
84 while (<ROM>) |
|
85 { |
|
86 if (/^Writing Rom image/) |
|
87 { |
|
88 # stop at end of first ROM, ignoring any extension ROMs |
|
89 # This is necessary because the same file could appear |
|
90 # at different places in different extensions. |
|
91 # |
|
92 last; |
|
93 } |
|
94 if (/^Processing file (.*)/) |
|
95 { |
|
96 my $datalen; |
|
97 my $skip; |
|
98 |
|
99 $file = lc $1; |
|
100 $text = $bss = $data = $datalen = 0; |
|
101 |
|
102 # Work out final addresses of sections |
|
103 while (defined($_=<ROM>) && !/^$/) |
|
104 { |
|
105 if (/^Code start addr:\s+(\w+)/) |
|
106 { |
|
107 $text = hex($1); |
|
108 } |
|
109 elsif (/^DataBssLinearBase:\s+(\w+)/) |
|
110 { |
|
111 $data = hex($1); |
|
112 } |
|
113 elsif (/^Code size:\s+(\w+)/) |
|
114 { |
|
115 $textlen = hex($1); |
|
116 } |
|
117 elsif (/^Data size:\s+(\w+)/) |
|
118 { |
|
119 $datalen = hex($1); |
|
120 $bss = $data + $datalen; |
|
121 } |
|
122 elsif (/^BssSize:\s+(\w+)/) |
|
123 { |
|
124 $bsslen = hex($1); |
|
125 } |
|
126 } |
|
127 |
|
128 # Sanity check - text section can't be zero (other sections may be) |
|
129 die "ERROR: Can't find rombuild info for \"$file\"\n" |
|
130 if (!$text); |
|
131 |
|
132 # get the build and exe name |
|
133 # protect $epocroot with \Q and \E to stop it |
|
134 # using \ as a special character |
|
135 if ($file =~ /^\Q$epocroot\Eepoc32\\release\\(.*)\\(.*)\\(.*)$/o) |
|
136 { |
|
137 $build = lc $1; |
|
138 $debrel = uc $2; |
|
139 $executablefile = lc $3; |
|
140 } |
|
141 |
|
142 # Only relink this file if it's kernel-side or matches the regexp |
|
143 if ($build =~ /^(M|S)/i) |
|
144 { |
|
145 $skip = 0; |
|
146 } |
|
147 else |
|
148 { |
|
149 $skip = 1; |
|
150 foreach $re (@executables) |
|
151 { |
|
152 $skip = 0 if ($file =~ /$re/i); |
|
153 } |
|
154 } |
|
155 print "$file - skipped\n" if ($skip && $debug); |
|
156 next if ($skip); |
|
157 |
|
158 if (! defined $map{"$build $executablefile"}) |
|
159 { |
|
160 print "$file - no makefile\n"; |
|
161 next; |
|
162 } |
|
163 if ($debrel ne "UDEB") |
|
164 { |
|
165 print "$file - can't fixup $debrel\n"; |
|
166 next; |
|
167 } |
|
168 |
|
169 # relink this file |
|
170 print "$file"; |
|
171 |
|
172 # lookup the makefile name |
|
173 ($makepath, $workdir) = @{$map{"$build $executablefile"}}; |
|
174 |
|
175 # only relink if we have a makefile |
|
176 if ($makepath && $workdir) |
|
177 { |
|
178 # optimisation: don't relink if already at correct address |
|
179 $file =~ /(.+\.)[^\.]+/; |
|
180 my $symfile = $drive.$1."sym"; |
|
181 my $buf; |
|
182 my $elffile; |
|
183 open SYMFILE, $symfile or print"\nCannot open $symfile\n"; |
|
184 read SYMFILE, $buf, 4; |
|
185 if ($buf =~/^\x7F\x45\x4C\x46/){ |
|
186 $elffile = $buf; |
|
187 } |
|
188 close SYMFILE; |
|
189 if ($elffile){ |
|
190 if ((-e $file) && (-e $symfile) && |
|
191 open (CHILD, "fromelf -v $symfile |")) |
|
192 { |
|
193 my $oldtext; |
|
194 my $olddata; |
|
195 my $foundcode = 0; |
|
196 my $founddata = 0; |
|
197 while (<CHILD>) |
|
198 { |
|
199 if (/ER_RO/) |
|
200 { |
|
201 $foundcode = 1; |
|
202 } |
|
203 if (/ER_RW/) |
|
204 { |
|
205 $founddata = 1; |
|
206 } |
|
207 |
|
208 if (/Addr : 0x\w+/) |
|
209 { |
|
210 $_=~tr/0-9//dc; |
|
211 if ($founddata == 1) |
|
212 { |
|
213 $founddata = 0; |
|
214 $olddata = hex($_); |
|
215 } |
|
216 |
|
217 if ($foundcode == 1) |
|
218 { |
|
219 $foundcode = 0; |
|
220 $oldtext = hex($_); |
|
221 } |
|
222 } |
|
223 } |
|
224 close CHILD; |
|
225 $skip = 1 if ((!$textlen || ($text == $oldtext)) && (!$datalen || ($data == $olddata))); |
|
226 } |
|
227 } |
|
228 else { |
|
229 if ((-e $file) && (-e $symfile) && |
|
230 open (CHILD, "objdump --headers $symfile |")) |
|
231 { |
|
232 my $oldtext; |
|
233 my $olddata; |
|
234 my $oldbss; |
|
235 while (<CHILD>) |
|
236 { |
|
237 if (/^\s+\d+\s+(\.\w+)\s+[0-9a-fA-F]+\s+([0-9a-fA-F]+)\s/) |
|
238 { |
|
239 if ($1 eq '.text') |
|
240 { |
|
241 $oldtext = hex($2); |
|
242 } |
|
243 elsif ($1 eq '.data') |
|
244 { |
|
245 $olddata = hex($2); |
|
246 } |
|
247 elsif ($1 eq '.bss') |
|
248 { |
|
249 $oldbss = hex($2); |
|
250 } |
|
251 } |
|
252 } |
|
253 close CHILD; |
|
254 $skip = 1 if ((!$textlen || ($text == $oldtext)) && |
|
255 (!$datalen || ($data == $olddata)) && |
|
256 (!$bsslen || ($bss == $oldbss))); |
|
257 print " - current" if ($skip && $debug); |
|
258 } |
|
259 } |
|
260 |
|
261 if (!$skip) |
|
262 { |
|
263 chdir $workdir |
|
264 or die "Can't cd to build directory \"$workdir\"\n"; |
|
265 |
|
266 # save executable in case relink fails |
|
267 rename $file, "$file.bak" |
|
268 or die "Can't rename \"$file\": $ERRNO\n" |
|
269 if -e $file; |
|
270 |
|
271 $makepath = &fixMakefile($makepath); |
|
272 my $command; |
|
273 if ($elffile){ |
|
274 if($makepath =~ /\.gcce/i){ |
|
275 $command = |
|
276 sprintf ("make -r -s -f \"$makepath\" $debrel " . |
|
277 "USERLDFLAGS=\"-Ttext 0x%lx -Tdata 0x%lx\"", $text, $data); |
|
278 } |
|
279 else { |
|
280 $command = |
|
281 sprintf ("make -r -s -f \"$makepath\" $debrel " . |
|
282 "USERLDFLAGS=\"--ro-base 0x%lx --rw-base 0x%lx\"", $text, $data); |
|
283 } |
|
284 } |
|
285 else { |
|
286 $command = |
|
287 sprintf ("make -r -s -f \"$makepath\" $debrel " . |
|
288 "USERLDFLAGS=\"--image-base 0 -Ttext 0x%lx " . |
|
289 "-Tdata 0x%lx -Tbss 0x%lx\"", |
|
290 $text, $data, $bss); |
|
291 } |
|
292 print "\n\"$command\"" if ($debug); |
|
293 |
|
294 open (CHILD, "$command |") |
|
295 or die "\nERROR: Can't run \"$command\": $ERRNO\n"; |
|
296 close CHILD; |
|
297 |
|
298 unlink $makepath; |
|
299 if (-e $file) |
|
300 { |
|
301 unlink "$file.bak"; |
|
302 } |
|
303 else # relink failed for some reason - restore saved |
|
304 { |
|
305 rename "$file.bak", $file; |
|
306 } |
|
307 } |
|
308 |
|
309 print "\n"; |
|
310 } |
|
311 else |
|
312 { |
|
313 print " - can't fixup\n"; |
|
314 } |
|
315 } |
|
316 } |
|
317 close ROM; |
|
318 } |
|
319 |
|
320 # |
|
321 # args - get command line args |
|
322 # |
|
323 sub args |
|
324 { |
|
325 my $arg; |
|
326 my @args; |
|
327 my $flag; |
|
328 |
|
329 &help if (!@ARGV); |
|
330 |
|
331 while (@ARGV) |
|
332 { |
|
333 $arg = shift @ARGV; |
|
334 |
|
335 if ($arg=~/^[\-\/](\S*)$/) |
|
336 { |
|
337 $flag=$1; |
|
338 |
|
339 if ($flag=~/^[\?h]$/i) |
|
340 { |
|
341 &help; |
|
342 } |
|
343 else |
|
344 { |
|
345 print "\nERROR: Unknown flag \"-$flag\"\n"; |
|
346 &usage; |
|
347 exit 1; |
|
348 } |
|
349 } |
|
350 else |
|
351 { |
|
352 push @args,$arg; |
|
353 } |
|
354 } |
|
355 |
|
356 $rombuild = shift @args; |
|
357 |
|
358 if (@args) |
|
359 { |
|
360 foreach $file (@args) |
|
361 { |
|
362 push @executables, quotemeta($file); |
|
363 } |
|
364 } |
|
365 } |
|
366 |
|
367 |
|
368 # recursive directory search |
|
369 sub dirsearch |
|
370 { |
|
371 my ($input_path, $dir) = @_; |
|
372 my $searchpath = "$input_path$dir\\"; |
|
373 my $workdir; |
|
374 |
|
375 return unless (opendir DIRHANDLE, $searchpath); |
|
376 my @allfiles = grep !/^\.\.?$/, readdir DIRHANDLE; |
|
377 closedir DIRHANDLE; |
|
378 |
|
379 # Breadth first search: scan files and collect list of subdirectories |
|
380 my @dirlist; |
|
381 foreach $entry (@allfiles) |
|
382 { |
|
383 my $entrypath = "$searchpath$entry"; |
|
384 if (-d $entrypath) |
|
385 { |
|
386 # don't look in udeb & urel directories which contain objects and binaries |
|
387 push @dirlist, $entry unless ($entry =~ /(deb|rel)$/i); |
|
388 } |
|
389 elsif ($entry =~ /$dir$/i) |
|
390 { |
|
391 # ARM4/xxx.ARM4 => generated makefile |
|
392 my $liney; |
|
393 open (FILE, "<$entrypath"); |
|
394 while ($liney=<FILE>) |
|
395 { |
|
396 if ($liney =~ /^\# CWD\s(.+)\\/) |
|
397 { |
|
398 $workdir = lc $1; |
|
399 } |
|
400 if ($liney =~ /^\# Target\s(.*)$/) |
|
401 { |
|
402 my $target = lc $1; |
|
403 |
|
404 # add to the hash table |
|
405 my $build = lc $dir; |
|
406 $map{"$build $target"} = [lc "$entrypath", $workdir]; |
|
407 $workdir = undef; |
|
408 last; |
|
409 } |
|
410 } |
|
411 close FILE; |
|
412 } |
|
413 } |
|
414 undef @allfiles; |
|
415 # Now process the subdirectories... |
|
416 foreach $entry (@dirlist) |
|
417 { |
|
418 &dirsearch ($searchpath,$entry); |
|
419 } |
|
420 undef @dirlist; |
|
421 } |
|
422 |
|
423 sub help () |
|
424 { |
|
425 my $build; |
|
426 |
|
427 &Load_ModuleL('E32TPVER'); |
|
428 print "\nfixupsym - " . |
|
429 "Fix up executables with locations taken from a ROM image (Build ", |
|
430 &E32tpver, ")\n"; |
|
431 &usage; |
|
432 exit 0; |
|
433 } |
|
434 |
|
435 sub usage () |
|
436 { |
|
437 print <<EOF |
|
438 |
|
439 Usage: |
|
440 fixupsym <logfile> [<executables>] |
|
441 |
|
442 Where: |
|
443 <logfile> Log file from rombuild tool. |
|
444 <executables> Names of additional executables to fix up. |
|
445 ASSP-specific executables and EUSER are always included. |
|
446 |
|
447 Example: |
|
448 fixupsym rombuild.log efile efsrv .fsy |
|
449 EOF |
|
450 ; |
|
451 exit 0; |
|
452 } |
|
453 sub fixMakefile() |
|
454 { |
|
455 my $makefile = shift @_; |
|
456 my $tmpMakfile = $makefile.".TMP"; |
|
457 open (FILEIN, $makefile) or die "Can't open file \"$makefile\" \n"; |
|
458 open (FILEOUT, ">".$tmpMakfile) or die "Can't create file \"$tmpMakfile\" \n"; |
|
459 while(<FILEIN>) { |
|
460 if ($_ =~ /^\s*elf2e32/){ |
|
461 print FILEOUT "#".$_; |
|
462 } |
|
463 else { |
|
464 print FILEOUT $_; |
|
465 } |
|
466 } |
|
467 close FILEIN; |
|
468 close FILEOUT; |
|
469 $tmpMakfile; |
|
470 } |