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