|
1 # |
|
2 # Copyright (c) 1996-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 ROM image |
|
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 $rombuild; |
|
40 my $debug = 0; |
|
41 |
|
42 &args; |
|
43 &main; |
|
44 |
|
45 exit 0; |
|
46 |
|
47 sub CompareAddrs() |
|
48 { |
|
49 return -1 if ($a < $b); |
|
50 return 1 if ($a > $b); |
|
51 return 0; |
|
52 } |
|
53 |
|
54 # |
|
55 # main |
|
56 # |
|
57 sub main() |
|
58 { |
|
59 my $file; |
|
60 my $mapfile; |
|
61 my $mapfile2; |
|
62 my $text; |
|
63 my $data; |
|
64 my $bss; |
|
65 my $textsize; |
|
66 my $datasize; |
|
67 my $bsssize; |
|
68 my $totaldatasize; |
|
69 my $totalsize; |
|
70 |
|
71 open (ROM, "<$rombuild") |
|
72 or die "ERROR: Can't open rombuild log file \"$rombuild\"\n"; |
|
73 if ($maksym ne "") { |
|
74 open (SYM, ">$maksym") |
|
75 or die "ERROR: Can't open output file \"$maksym\"\n"; |
|
76 print "Creating $maksym...\n"; |
|
77 } |
|
78 |
|
79 while (<ROM>) { |
|
80 # Start of ROM |
|
81 if (/^Creating Rom image (\S*)/) { |
|
82 if ($maksym eq "") { |
|
83 # For backwards compatibility, replace trailing .img with .symbol |
|
84 # if no trailing .img, just append .symbol anyway |
|
85 $maksym = $1; |
|
86 $maksym =~ s/(\.img)?$/.symbol/i; |
|
87 close SYM; |
|
88 open (SYM, ">$maksym") |
|
89 or die "ERROR: Can't open output file \"$maksym\"\n"; |
|
90 print "\nCreating $maksym...\n"; |
|
91 } |
|
92 next; |
|
93 } |
|
94 # end of ROM |
|
95 if (/^Writing Rom image/) { |
|
96 close SYM; |
|
97 $maksym = ""; |
|
98 next; |
|
99 } |
|
100 # Data file |
|
101 if (/^Reading resource (.*) to rom linear address (.*)/) { |
|
102 $file = $1; |
|
103 my $data = hex($2); |
|
104 $file =~ /([^\\]+)$/; |
|
105 printf SYM "\nFrom $file\n\n%08x 0000 $1\n", $data; |
|
106 } |
|
107 # Executable file |
|
108 elsif (/^Processing file (.*)/) { |
|
109 $file = $1; |
|
110 $text = 0; |
|
111 $data = 0; |
|
112 $bss = 0; |
|
113 $textsize = 0; |
|
114 $datasize = 0; |
|
115 $bsssize = 0; |
|
116 $totaldatasize = 0; |
|
117 |
|
118 # Work out final addresses of sections |
|
119 while (defined($_=<ROM>) && !/^$/) { |
|
120 if (/^Size:\s+(\w+)/) { |
|
121 $totalsize = hex($1); |
|
122 } elsif (/^Code start addr:\s+(\w+)/) { |
|
123 $text = hex($1); |
|
124 } elsif (/^Data start addr:\s+(\w+)/) { |
|
125 $data = hex($1); |
|
126 } elsif (/^DataBssLinearBase:\s+(\w+)/) { |
|
127 $bss = hex($1); |
|
128 } elsif (/^Text size:\s+(\w+)/) { |
|
129 $textsize = hex($1); |
|
130 } elsif (/^Data size:\s+(\w+)/) { |
|
131 $datasize = hex($1); |
|
132 } elsif (/^Bsssize:\s+(\w+)/) { |
|
133 $bsssize = hex($1); |
|
134 } elsif (/^Total data size:\s+(\w+)/) { |
|
135 $totaldatasize = hex($1); |
|
136 } |
|
137 } |
|
138 |
|
139 # Sanity check - text section can't be zero |
|
140 die "ERROR: Can't find rombuild info for \"$file\"\n" |
|
141 if (!$text); |
|
142 |
|
143 print SYM "\nFrom $file\n\n"; |
|
144 |
|
145 # Look in map file for symbols in .text and relocate them |
|
146 $mapfile2 = $file.".map"; |
|
147 $mapfile = $file; |
|
148 $mapfile =~ s/\.\w+$/\.map/; |
|
149 if (!(open (MAP, "$mapfile2") || open (MAP, "$mapfile"))) { |
|
150 print "$file\nWarning: Can't open \"$mapfile2\" or \"$mapfile\"\n"; |
|
151 $file =~ /([^\\]+)$/; |
|
152 printf SYM "%08x %04x $1\n", $text, $totalsize; |
|
153 } else { |
|
154 local $/ = undef; |
|
155 my (@maplines) = split(/\n/, <MAP>); |
|
156 close MAP; |
|
157 # See if we're dealing with the RVCT output |
|
158 if ($maplines[0] =~ /^ARM Linker/) { |
|
159 print "$file\n"; |
|
160 |
|
161 my %syms; |
|
162 my @hasharray; |
|
163 # Starts from begining of map file. |
|
164 while (@maplines) { |
|
165 $_ = shift @maplines; |
|
166 if (/Global Symbols/) { |
|
167 last; |
|
168 } elsif (!/(ARM Code|Thumb Code)/) { |
|
169 next; |
|
170 } |
|
171 # name address type size section |
|
172 if (/^\s*(.+)\s*(0x\S+)\s+(ARM Code|Thumb Code)\s+[^\d]*(\d+)\s+(.*)$/) { |
|
173 # Check for static methods in local symbols section. |
|
174 my $sym = $1; |
|
175 my $addr = hex($2); |
|
176 my $size = sprintf("%04x",$4); |
|
177 my $section = $5; |
|
178 $size = sprintf("%04x", 8) if ($section =~ /\(StubCode\)/); |
|
179 if(exists($syms{$addr})) { |
|
180 push @{ $syms{$addr} }, "$size $sym $section"; |
|
181 } |
|
182 elsif ($addr > 0){ |
|
183 @hasharray = "$size $sym $section"; |
|
184 $syms{$addr} = [@hasharray]; |
|
185 } |
|
186 } |
|
187 } |
|
188 |
|
189 foreach (@maplines) { |
|
190 # name address ignore size section |
|
191 if (/^\s*(.+)\s*(0x\S+)\s+[^\d]*(\d+)\s+(.*)$/) { |
|
192 my $sym = $1; |
|
193 my $addr = hex($2); |
|
194 my $size = sprintf("%04x",$3); |
|
195 my $section = $4; |
|
196 $size = sprintf("%04x", 8) if ($section =~ /\(StubCode\)/); |
|
197 if(exists($syms{$addr})) { |
|
198 push @{ $syms{$addr} }, "$size $sym $section"; |
|
199 } |
|
200 elsif ($addr > 0) { |
|
201 @hasharray = "$size $sym $section"; |
|
202 $syms{$addr} = [@hasharray]; |
|
203 } |
|
204 } |
|
205 } # end of foreach |
|
206 |
|
207 # .text gets linked at 0x00008000 |
|
208 # .data gets linked at 0x00400000 |
|
209 my $srctext = hex(8000); |
|
210 my $srcdata = hex(400000); |
|
211 my $j; |
|
212 # Write symbols in address order |
|
213 my @addrs = sort CompareAddrs keys %syms; |
|
214 for ($i = 0; $i < @addrs ; $i++) { |
|
215 my $thisaddr = $addrs[$i]; |
|
216 my $romaddr = 0; |
|
217 # see if its in the text segment |
|
218 if ($thisaddr >= $srctext && $thisaddr <= ($srctext+$textsize)) { |
|
219 $romaddr = $thisaddr-$srctext+$text; |
|
220 } elsif ( $data && ( $thisaddr >= $srcdata && $thisaddr <= ($srcdata+$datasize))) { |
|
221 # its in the data segment |
|
222 # is it from .data or .bss |
|
223 |
|
224 # confusingly (?) $bss is the right value to use here |
|
225 # since we're interested in where the data gets copied to |
|
226 # in RAM rather than where it sits in ROM |
|
227 $romaddr = $thisaddr-$srcdata+$bss; |
|
228 } elsif ( $bss && ( $thisaddr >= $srcdata && $thisaddr <= ($srcdata+$totaldatasize))) { |
|
229 # its BSS |
|
230 $romaddr = $thisaddr-$srcdata+$bss; |
|
231 } else { |
|
232 my $errsym = $syms{$thisaddr}[0]; |
|
233 my $erraddr = sprintf("%08x", $thisaddr); |
|
234 print "WARNING: Symbol $errsym @ $erraddr not in text or data segments\n"; |
|
235 print "WARNING: The map file for binary $file is out-of-sync with the binary itself\n\n"; |
|
236 next; |
|
237 } |
|
238 |
|
239 printf SYM "%08x %s\n", $romaddr, $_ for @{$syms{$addrs[$i]}}; |
|
240 } # end of for. |
|
241 # See if we're dealing with the GCC output |
|
242 } elsif ($maplines[0] =~ /^Archive member included/) { |
|
243 |
|
244 my $imgtext; |
|
245 my $textlen; |
|
246 my %syms; |
|
247 my $stubhex=1; |
|
248 |
|
249 # Find text section |
|
250 while (@maplines) { |
|
251 $_ = shift @maplines; |
|
252 last if /^\.text\s+/; |
|
253 } |
|
254 |
|
255 /^\.text\s+(\w+)\s+(\w+)/ |
|
256 or die "ERROR: Can't get .text section info for \"$file\"\n"; |
|
257 |
|
258 $imgtext=hex($1); |
|
259 $textlen=hex($2); |
|
260 |
|
261 print "$file\n"; |
|
262 |
|
263 # Slurp symbols 'til the end of the text section |
|
264 foreach (@maplines) { |
|
265 |
|
266 # blank line marks the end of the text section |
|
267 last if (/^$/); |
|
268 |
|
269 # .text <addr> <len> <library(member)> |
|
270 # .text$something |
|
271 # <addr> <len> <library(member)> |
|
272 # <addr> <len> LONG 0x0 |
|
273 |
|
274 if (/^\s(\.text)?\s+(0x\w+)\s+(0x\w+)\s+(.*)$/io) { |
|
275 my $address = hex($2); |
|
276 my $length = hex($3); |
|
277 my $libraryfile = $4; |
|
278 next if ($libraryfile =~ /^LONG 0x/); |
|
279 $syms{$address+$length} = ' '; # impossible symbol as end marker |
|
280 |
|
281 # EUSER.LIB(ds01423.o) |
|
282 # EUSER.LIB(C:/TEMP/d1000s_01423.o) |
|
283 if ($libraryfile =~ /.*lib\(.*d\d*s_?\d{5}.o\)$/io) { |
|
284 $stubhex=$address; |
|
285 } |
|
286 next; |
|
287 } |
|
288 |
|
289 # <addr> <symbol name possibly including spaces> |
|
290 if (/^\s+(\w+)\s\s+([a-zA-Z_].+)/o) { |
|
291 my $addr = hex($1); |
|
292 my $symbol = $2; |
|
293 $symbol = "stub $symbol" if ($addr == $stubhex); |
|
294 $syms{$addr} = $symbol; |
|
295 next; |
|
296 } |
|
297 } |
|
298 |
|
299 # Write symbols in address order |
|
300 @addrs = sort CompareAddrs keys %syms; |
|
301 for ($i = 0; $i < @addrs - 1; $i++) { |
|
302 my $symbol = $syms{$addrs[$i]}; |
|
303 next if ($symbol eq ' '); |
|
304 printf SYM "%08x %04x %s\n", |
|
305 $addrs[$i]-$imgtext+$text, $addrs[$i+1]-$addrs[$i], $symbol; |
|
306 } |
|
307 # last address assumed to be imgtext+lentext |
|
308 |
|
309 close MAP; |
|
310 } |
|
311 # Must be x86 output |
|
312 else { |
|
313 while (@maplines) { |
|
314 $_ = shift @maplines; |
|
315 last if /^ Address/; |
|
316 } |
|
317 shift @maplines; |
|
318 |
|
319 my ($lastname, $lastaddr); |
|
320 while (@maplines) { |
|
321 $_ = shift @maplines; |
|
322 last unless /^ 0001:(\w+)\s+(\S+)/; |
|
323 my ($addr, $name) = (hex $1, $2); |
|
324 if ($lastname) { |
|
325 my $size = $addr - $lastaddr; |
|
326 printf SYM "%08x %04x %s\n", $lastaddr + $text, $size, $lastname; |
|
327 } |
|
328 ($lastname, $lastaddr) = ($name, $addr); |
|
329 } |
|
330 printf SYM "%08x %04x %s\n", $lastaddr + $text, 0, $lastname if $lastname; |
|
331 } |
|
332 |
|
333 } |
|
334 } |
|
335 } |
|
336 close SYM; |
|
337 close ROM; |
|
338 } |
|
339 |
|
340 # |
|
341 # args - get command line args |
|
342 # |
|
343 sub args |
|
344 { |
|
345 my $arg; |
|
346 my @args; |
|
347 my $flag; |
|
348 |
|
349 &help if (!@ARGV); |
|
350 |
|
351 while (@ARGV) { |
|
352 $arg = shift @ARGV; |
|
353 |
|
354 if ($arg=~/^[\-\/](\S*)$/) { |
|
355 $flag=$1; |
|
356 |
|
357 if ($flag=~/^[\?h]$/i) { |
|
358 &help; |
|
359 } elsif ($flag=~/^d$/i) { |
|
360 $debug = 1; |
|
361 } else { |
|
362 print "\nERROR: Unknown flag \"-$flag\"\n"; |
|
363 &usage; |
|
364 exit 1; |
|
365 } |
|
366 } else { |
|
367 push @args,$arg; |
|
368 } |
|
369 } |
|
370 |
|
371 if (@args) { |
|
372 $rombuild = shift @args; |
|
373 if (@args) { |
|
374 $maksym = shift @args; |
|
375 if (@args) { |
|
376 print "\nERROR: Incorrect argument(s) \"@args\"\n"; |
|
377 &usage; |
|
378 exit 1; |
|
379 } |
|
380 } |
|
381 } |
|
382 } |
|
383 |
|
384 sub help () |
|
385 { |
|
386 my $build; |
|
387 |
|
388 &Load_ModuleL('E32TPVER'); |
|
389 print "\nmaksym - Produce symbolic information given a ROM image (Build ", |
|
390 &E32tpver, ")\n"; |
|
391 &usage; |
|
392 exit 0; |
|
393 } |
|
394 |
|
395 sub usage () |
|
396 { |
|
397 print <<EOF |
|
398 |
|
399 Usage: |
|
400 maksym <logfile> [<outfile>] |
|
401 |
|
402 Where: |
|
403 <logfile> Log file from rombuild tool. |
|
404 <outfile> Output file. Defaults to imagename.symbol. |
|
405 EOF |
|
406 ; |
|
407 exit 0; |
|
408 } |