|
1 # |
|
2 # Copyright (c) 2005-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 # Produces symbolic information given a ROFS log file and .map files for relevant binary files |
|
16 # |
|
17 |
|
18 require 5.003_07; |
|
19 no strict 'vars'; |
|
20 use English; |
|
21 use FindBin; # for FindBin::Bin |
|
22 |
|
23 my $PerlLibPath; # fully qualified pathname of the directory containing our Perl modules |
|
24 |
|
25 BEGIN { |
|
26 # check user has a version of perl that will cope require 5.005_03; |
|
27 # establish the path to the Perl libraries: currently the same directory as this script |
|
28 $PerlLibPath = $FindBin::Bin; # X:/epoc32/tools |
|
29 $PerlLibPath =~ s/\//\\/g; # X:\epoc32\tools |
|
30 $PerlLibPath .= "\\"; |
|
31 } |
|
32 |
|
33 use lib $PerlLibPath; |
|
34 use Modload; |
|
35 Load_SetModulePath($PerlLibPath); |
|
36 |
|
37 # Globals |
|
38 my $maksym = ""; |
|
39 my $rofsbuild; |
|
40 my $debug = 0; |
|
41 |
|
42 &args; |
|
43 &main; |
|
44 exit 0; |
|
45 |
|
46 sub CompareAddrs() |
|
47 { |
|
48 return -1 if ($a < $b); |
|
49 return 1 if ($a > $b); |
|
50 return 0; |
|
51 } |
|
52 |
|
53 # |
|
54 # main |
|
55 # |
|
56 sub main() |
|
57 { |
|
58 open (ROFS, "<$rofsbuild") or die "ERROR: Can't open rofsbuild log file \"$rofsbuild\"\n"; |
|
59 if ($maksym ne "") |
|
60 { |
|
61 open (SYM, ">$maksym") or die "ERROR: Can't open output file \"$maksym\"\n"; |
|
62 print "Creating $maksym...\n" |
|
63 } |
|
64 |
|
65 my $curretnLine; |
|
66 while ($currentLine = <ROFS>) |
|
67 { |
|
68 # Check that the given log file is from a rofs image and set up the name for the symbol file |
|
69 if ($currentLine =~ /^Creating Rofs image (\S*)/) |
|
70 { |
|
71 if ($maksym eq "") |
|
72 { |
|
73 # For backwards compatibility, replace trailing .img with .symbol |
|
74 # if no trailing .img, just append .symbol anyway |
|
75 $maksym = $1; |
|
76 $maksym =~ s/(\.img)?$/.symbol/i; |
|
77 close SYM; |
|
78 open (SYM, ">$maksym") or die "ERROR: Can't open output file \"$maksym\"\n"; |
|
79 print "\nCreating $maksym...\n" |
|
80 } |
|
81 next; |
|
82 } |
|
83 |
|
84 # found at end of file |
|
85 if ($currentLine =~ /^Writing Rom image/) |
|
86 { |
|
87 close SYM; |
|
88 $maksym = ""; |
|
89 next; |
|
90 } |
|
91 |
|
92 # Data file |
|
93 if ($currentLine =~ /^File \'(.*)\' size: \S+\s*$/) |
|
94 { |
|
95 my $file = $1; |
|
96 $file =~ /([^\\]+)$/; |
|
97 printf SYM "\nFrom $file\n\n00000000 0000 $1\n"; |
|
98 } |
|
99 |
|
100 # Executable file |
|
101 elsif ($currentLine =~ /^Compressed executable File \'(.*)\' size: \S+\s*, mode:\S+\s*$/) |
|
102 { |
|
103 ProcessCompressedLine($1); |
|
104 } |
|
105 } |
|
106 close SYM; |
|
107 close ROFS; |
|
108 } |
|
109 |
|
110 sub ProcessCompressedLine |
|
111 { |
|
112 my ($file) = @_; |
|
113 |
|
114 my $mapfile; |
|
115 my $mapfile2; |
|
116 print SYM "\nFrom $file\n\n"; |
|
117 |
|
118 # Look in map file for symbols in .text and relocate them |
|
119 $mapfile2 = $file.".map"; |
|
120 $mapfile = $file; |
|
121 $mapfile =~ s/\.\w+$/\.map/; |
|
122 if (!(open (MAP, "$mapfile2") || open (MAP, "$mapfile"))) |
|
123 { |
|
124 print "$file\nWarning: Can't open \"$mapfile2\" or \"$mapfile\"\n"; |
|
125 # couldn't find map file so output in format that is used for non-binary files |
|
126 my $BinSize = GetSizeFromBinFile($file); |
|
127 $file =~ /([^\\]+)$/; |
|
128 printf "00000000 %04x $1\n", $BinSize; |
|
129 printf SYM "00000000 %04x $1\n", $BinSize; |
|
130 } |
|
131 else |
|
132 { |
|
133 my @maplines; |
|
134 while ($_ = <MAP>) |
|
135 { |
|
136 push @maplines, $_; |
|
137 } |
|
138 close MAP; |
|
139 # See if we're dealing with the RVCT output |
|
140 if ($file =~m/ARMV5/i) |
|
141 { |
|
142 ProcessArmv5File($file, \@maplines); |
|
143 } |
|
144 elsif( ($file =~ /GCCE/i) || ($file =~ /ARM4/i) ) |
|
145 { |
|
146 ProcessGcceOrArm4File($file, \@maplines); |
|
147 } |
|
148 else |
|
149 { |
|
150 print "\nWarning: cannot determine linker type used to create $file\n"; |
|
151 $file =~ /([^\\]+)$/; |
|
152 printf SYM "00000000 0000 $1\n"; |
|
153 } |
|
154 } |
|
155 } |
|
156 |
|
157 sub ProcessArmv5File |
|
158 { |
|
159 my ($file, $mapLines) = @_; |
|
160 my @maplines = @$mapLines; |
|
161 if ($maplines[0] !~ /^ARM Linker/) |
|
162 { |
|
163 print "\nWarning: expecting $file to be generated by ARM linker\n"; |
|
164 # file not in format produced by ARMV5 linker so treat file as non-binary file |
|
165 $file =~ /([^\\]+)$/; |
|
166 printf SYM "00000000 0000 $1\n"; |
|
167 } |
|
168 else |
|
169 { |
|
170 # scroll down to the global symbols |
|
171 while ($_ = shift @maplines) |
|
172 { |
|
173 if ($_ =~ /Global Symbols/) |
|
174 { |
|
175 last; |
|
176 } |
|
177 } |
|
178 |
|
179 my %syms; |
|
180 my $baseOffset; # offset to subtract from each address so that the first entry has address 0x0 |
|
181 |
|
182 foreach (@maplines) |
|
183 { |
|
184 # name address ignore size section |
|
185 if (/^\s*(.+)\s*(0x\S+)\s+[^\d]*(\d+)\s+(.*)$/) |
|
186 { |
|
187 my $sym = $1; |
|
188 my $addr = hex($2); |
|
189 my $size = sprintf("%04x",$3); |
|
190 my $section = $4; |
|
191 $size = sprintf("%04x", 8) if ($section =~ /\(StubCode\)/); |
|
192 |
|
193 # it is possible that there will be more than one entry in a log file for a |
|
194 # particular address, this is because aliases are included. |
|
195 # The following code checks that the correct function (i.e. the one with |
|
196 # non-zero size) is being included in the symbol file. |
|
197 if(exists $syms{$addr}) |
|
198 { # an entry at this address exists, replace if it is an alias |
|
199 if( ($size != 0) && ($addr > 0) ) |
|
200 { |
|
201 if( ! defined $baseOffset ) |
|
202 { |
|
203 $baseOffset = $addr; |
|
204 } |
|
205 $syms{$addr - $baseOffset} = "$size $sym $section"; |
|
206 } |
|
207 } |
|
208 else |
|
209 { # no entry at this address so create one regardless of whether size is zero |
|
210 if( $addr > 0 ) |
|
211 { |
|
212 if( ! defined $baseOffset ) |
|
213 { |
|
214 $baseOffset = $addr; |
|
215 } |
|
216 $syms{$addr - $baseOffset} = "$size $sym $section"; |
|
217 } |
|
218 } |
|
219 |
|
220 } |
|
221 } |
|
222 |
|
223 # Write symbols in address order |
|
224 my @addrs = sort CompareAddrs keys %syms; |
|
225 for ($i = 0; $i < @addrs ; $i++) |
|
226 { |
|
227 my $thisaddr = $addrs[$i]; |
|
228 printf SYM "%08x %s\n", |
|
229 $thisaddr, $syms{$thisaddr}; |
|
230 } |
|
231 } |
|
232 } |
|
233 |
|
234 sub ProcessGcceOrArm4File |
|
235 { |
|
236 my ($file, $mapLines) = @_; |
|
237 my @maplines = @$mapLines; |
|
238 my %syms; |
|
239 my $stubhex=1; |
|
240 |
|
241 # Find text section |
|
242 while (($_ = shift @maplines) && !(/^\.text\s+/)) |
|
243 { |
|
244 } |
|
245 |
|
246 /^\.text\s+(\w+)\s+\w+/ or die "ERROR: Can't get .text section info for \"$file\"\n"; |
|
247 |
|
248 my $imgtext=hex($1); |
|
249 |
|
250 # Slurp symbols 'til the end of the text section |
|
251 foreach (@maplines) |
|
252 { |
|
253 |
|
254 # blank line marks the end of the text section |
|
255 last if (/^$/); |
|
256 |
|
257 # .text <addr> <len> <library(member)> |
|
258 # .text$something |
|
259 # <addr> <len> <library(member)> |
|
260 # <addr> <len> LONG 0x0 |
|
261 |
|
262 if (/^\s(\.text)?\s+(0x\w+)\s+(0x\w+)\s+(.*)$/io) |
|
263 { |
|
264 my $address = hex($2); |
|
265 my $length = hex($3); |
|
266 my $libraryfile = $4; |
|
267 next if ($libraryfile =~ /^LONG 0x/); |
|
268 |
|
269 $syms{$address+$length} = ' '; # impossible symbol as end marker |
|
270 |
|
271 #set $stubhex value as $address if there is a match |
|
272 if ($libraryfile =~ /.*lib\(.*d\d*s_?\d{5}.o\)$/io) |
|
273 { |
|
274 $stubhex=$address; |
|
275 } |
|
276 next; |
|
277 } |
|
278 |
|
279 # <addr> <symbol name possibly including spaces> |
|
280 if (/^\s+(\w+)\s\s+([a-zA-Z_].+)/o) |
|
281 { |
|
282 my $addr = hex($1); |
|
283 my $symbol = $2; |
|
284 $symbol = "stub $symbol" if ($addr == $stubhex); |
|
285 $syms{$addr} = $symbol; |
|
286 next; |
|
287 } |
|
288 } |
|
289 |
|
290 # Write symbols in address order |
|
291 @addrs = sort CompareAddrs keys %syms; |
|
292 for ($i = 0; $i < @addrs - 1; $i++) |
|
293 { |
|
294 my $symbol = $syms{$addrs[$i]}; |
|
295 next if ($symbol eq ' '); |
|
296 printf SYM "%08x %04x %s\n", |
|
297 $addrs[$i] - $imgtext, $addrs[$i+1]-$addrs[$i], $symbol; |
|
298 } |
|
299 # last address assumed to be imgtext+lentext |
|
300 |
|
301 close MAP; |
|
302 } |
|
303 |
|
304 # |
|
305 # args - get command line args |
|
306 # |
|
307 sub args |
|
308 { |
|
309 my $arg; |
|
310 my @args; |
|
311 my $flag; |
|
312 |
|
313 &help if (!@ARGV); |
|
314 |
|
315 while (@ARGV) |
|
316 { |
|
317 $arg = shift @ARGV; |
|
318 |
|
319 if ($arg=~/^[\-\/](\S*)$/) |
|
320 { |
|
321 $flag=$1; |
|
322 |
|
323 if ($flag=~/^[\?h]$/i) |
|
324 { |
|
325 &help; |
|
326 } |
|
327 elsif ($flag=~/^d$/i) |
|
328 { |
|
329 $debug = 1; |
|
330 } |
|
331 else |
|
332 { |
|
333 print "\nERROR: Unknown flag \"-$flag\"\n"; |
|
334 &usage; |
|
335 exit 1; |
|
336 } |
|
337 } |
|
338 else |
|
339 { |
|
340 push @args,$arg; |
|
341 } |
|
342 } |
|
343 |
|
344 if (@args) |
|
345 { |
|
346 $rofsbuild = shift @args; |
|
347 if (@args) |
|
348 { |
|
349 $maksym = shift @args; |
|
350 if (@args) |
|
351 { |
|
352 print "\nERROR: Incorrect argument(s) \"@args\"\n"; |
|
353 &usage; |
|
354 exit 1; |
|
355 } |
|
356 } |
|
357 } |
|
358 } |
|
359 |
|
360 sub help () |
|
361 { |
|
362 my $build; |
|
363 |
|
364 &Load_ModuleL('E32TPVER'); |
|
365 print "\nmaksymrofs - Produce symbolic information given a ROFS image (Build ", |
|
366 &E32tpver, ")\n"; |
|
367 &usage; |
|
368 exit 0; |
|
369 } |
|
370 |
|
371 sub usage () |
|
372 { |
|
373 print <<EOF |
|
374 |
|
375 Usage: |
|
376 maksymrofs <logfile> [<outfile>] |
|
377 |
|
378 Where: |
|
379 <logfile> Log file from rofsbuild tool. |
|
380 <outfile> Output file. Defaults to imagename.symbol. |
|
381 EOF |
|
382 ; |
|
383 exit 0; |
|
384 } |
|
385 |
|
386 sub GetSizeFromBinFile () |
|
387 { |
|
388 my ($file) = @_; |
|
389 my $tmpfile = "temp.info"; |
|
390 system("readimage $file -o $tmpfile"); |
|
391 return 0 if (!-e $tmpfile); |
|
392 |
|
393 open (TMP, "<$tmpfile"); |
|
394 my $line; |
|
395 my $size = 0; |
|
396 while ($line = <TMP>) |
|
397 { |
|
398 print $line; |
|
399 if ($line =~ /^Code size\W+(\w+)$/) |
|
400 { |
|
401 $size = hex($1); |
|
402 last; |
|
403 } |
|
404 } |
|
405 close TMP; |
|
406 unlink $tmpfile; |
|
407 return $size; |
|
408 } |
|
409 |