sl@0
|
1 |
#! perl
|
sl@0
|
2 |
# Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
|
sl@0
|
3 |
# All rights reserved.
|
sl@0
|
4 |
# This component and the accompanying materials are made available
|
sl@0
|
5 |
# under the terms of the License "Eclipse Public License v1.0"
|
sl@0
|
6 |
# which accompanies this distribution, and is available
|
sl@0
|
7 |
# at the URL "http://www.eclipse.org/legal/epl-v10.html".
|
sl@0
|
8 |
#
|
sl@0
|
9 |
# Initial Contributors:
|
sl@0
|
10 |
# Nokia Corporation - initial contribution.
|
sl@0
|
11 |
#
|
sl@0
|
12 |
# Contributors:
|
sl@0
|
13 |
#
|
sl@0
|
14 |
# Description:
|
sl@0
|
15 |
#
|
sl@0
|
16 |
|
sl@0
|
17 |
if (@ARGV<1)
|
sl@0
|
18 |
{
|
sl@0
|
19 |
#........1.........2.........3.........4.........5.........6.........7.....
|
sl@0
|
20 |
print <<USAGE_EOF;
|
sl@0
|
21 |
|
sl@0
|
22 |
Usage:
|
sl@0
|
23 |
printstk.pl d_exc_nnn [romimage.symbol]
|
sl@0
|
24 |
|
sl@0
|
25 |
Given the output of D_EXC, a file d_exc_nnn.txt and d_exc_nnn.stk, it
|
sl@0
|
26 |
uses the other information to try to put symbolic information against
|
sl@0
|
27 |
the stack image.
|
sl@0
|
28 |
|
sl@0
|
29 |
USAGE_EOF
|
sl@0
|
30 |
exit 1;
|
sl@0
|
31 |
}
|
sl@0
|
32 |
|
sl@0
|
33 |
sub add_object
|
sl@0
|
34 |
{
|
sl@0
|
35 |
my ($base, $max, $name) = @_;
|
sl@0
|
36 |
$address{$base} = [ $base, $max, $name ];
|
sl@0
|
37 |
my $key=$base>>20;
|
sl@0
|
38 |
my $maxkey=$max>>20;
|
sl@0
|
39 |
while ($key <= $maxkey) # allowing for objects that span the boundary
|
sl@0
|
40 |
{
|
sl@0
|
41 |
push @{$addresslist{$key}}, $base;
|
sl@0
|
42 |
$key+=1;
|
sl@0
|
43 |
}
|
sl@0
|
44 |
}
|
sl@0
|
45 |
|
sl@0
|
46 |
my $RomBase = 0xF8000000;
|
sl@0
|
47 |
my $RomLimit = 0xFFF00000;
|
sl@0
|
48 |
add_object($RomBase,$RomLimit, "ROM");
|
sl@0
|
49 |
|
sl@0
|
50 |
# Handle a MAKSYM.LOG file for a ROM
|
sl@0
|
51 |
#
|
sl@0
|
52 |
sub read_rom_symbols
|
sl@0
|
53 |
{
|
sl@0
|
54 |
my ($romimage)=@_;
|
sl@0
|
55 |
open ROMSYMBOLS, $romimage or print "Can't open $romimage\n" and return;
|
sl@0
|
56 |
|
sl@0
|
57 |
my $a;
|
sl@0
|
58 |
my $b;
|
sl@0
|
59 |
while (my $line = <ROMSYMBOLS>)
|
sl@0
|
60 |
{
|
sl@0
|
61 |
if(!($line =~ /^[0-9A-Fa-f]{8}/))
|
sl@0
|
62 |
{
|
sl@0
|
63 |
next;
|
sl@0
|
64 |
}
|
sl@0
|
65 |
# 8 bytes for the address
|
sl@0
|
66 |
|
sl@0
|
67 |
$a = substr $line,0,8;
|
sl@0
|
68 |
if(!($a =~ /[0-9A-Fa-f]{8}/))
|
sl@0
|
69 |
{
|
sl@0
|
70 |
next;
|
sl@0
|
71 |
}
|
sl@0
|
72 |
# 4 bytes for the length
|
sl@0
|
73 |
$b = substr $line,12,4;
|
sl@0
|
74 |
if(!($b =~ /[0-9A-Fa-f]{4}/))
|
sl@0
|
75 |
{
|
sl@0
|
76 |
next;
|
sl@0
|
77 |
}
|
sl@0
|
78 |
# rest of line is symbol
|
sl@0
|
79 |
my $symbol = substr $line,20;
|
sl@0
|
80 |
chomp $symbol;
|
sl@0
|
81 |
|
sl@0
|
82 |
my $base=hex($a);
|
sl@0
|
83 |
my $length=hex($b);
|
sl@0
|
84 |
if ($base < 0x50000000)
|
sl@0
|
85 |
{
|
sl@0
|
86 |
next; # skip this line
|
sl@0
|
87 |
}
|
sl@0
|
88 |
if ($length==0xffffffff)
|
sl@0
|
89 |
{
|
sl@0
|
90 |
$length=100; # MAKSYM bug? choose a rational length
|
sl@0
|
91 |
}
|
sl@0
|
92 |
add_object($base, $base+$length-1, $symbol);
|
sl@0
|
93 |
}
|
sl@0
|
94 |
print "ROM Symbols from $romimage\n";
|
sl@0
|
95 |
}
|
sl@0
|
96 |
|
sl@0
|
97 |
# Handle MAP file for a non execute-in-place binary
|
sl@0
|
98 |
#
|
sl@0
|
99 |
sub read_map_symbols
|
sl@0
|
100 |
{
|
sl@0
|
101 |
my ($binary, $binbase)=@_;
|
sl@0
|
102 |
$binary =~ /([^\\]+)$/;
|
sl@0
|
103 |
my $basename=$1;
|
sl@0
|
104 |
if (not open MAPFILE, "$basename.map")
|
sl@0
|
105 |
{
|
sl@0
|
106 |
print "Can't open map file for \n$binary.map)\n";
|
sl@0
|
107 |
return;
|
sl@0
|
108 |
}
|
sl@0
|
109 |
|
sl@0
|
110 |
|
sl@0
|
111 |
my @maplines;
|
sl@0
|
112 |
while (<MAPFILE>)
|
sl@0
|
113 |
{
|
sl@0
|
114 |
push @maplines, $_;
|
sl@0
|
115 |
}
|
sl@0
|
116 |
close MAPFILE;
|
sl@0
|
117 |
# See if we're dealing with the RVCT output
|
sl@0
|
118 |
if ($maplines[0] =~ /^ARM Linker/)
|
sl@0
|
119 |
{
|
sl@0
|
120 |
# scroll down to the global symbols
|
sl@0
|
121 |
while ($_ = shift @maplines)
|
sl@0
|
122 |
{
|
sl@0
|
123 |
if (/Global Symbols/)
|
sl@0
|
124 |
{
|
sl@0
|
125 |
last;
|
sl@0
|
126 |
}
|
sl@0
|
127 |
}
|
sl@0
|
128 |
# .text gets linked at 0x00008000
|
sl@0
|
129 |
$imgtext=hex(8000);#start of the text section during linking
|
sl@0
|
130 |
|
sl@0
|
131 |
foreach (@maplines)
|
sl@0
|
132 |
{
|
sl@0
|
133 |
# name address ignore size section
|
sl@0
|
134 |
if (/^\s*(.+)\s*(0x\S+)\s+[^\d]*(\d+)\s+(.*)$/)
|
sl@0
|
135 |
{
|
sl@0
|
136 |
my $symbol = $1;
|
sl@0
|
137 |
my $addr = hex($2);
|
sl@0
|
138 |
my $size = $3;
|
sl@0
|
139 |
if ($size > 0)#symbols of the 0 size contain some auxillary information, ignore them
|
sl@0
|
140 |
{
|
sl@0
|
141 |
add_object($addr-$imgtext+$binbase,#relocated address of the current symbol
|
sl@0
|
142 |
$addr-$imgtext+$binbase+$size,#relocated address of the current symbol + size of the current symbol
|
sl@0
|
143 |
"$binary $symbol");
|
sl@0
|
144 |
}
|
sl@0
|
145 |
}
|
sl@0
|
146 |
}
|
sl@0
|
147 |
}
|
sl@0
|
148 |
else
|
sl@0
|
149 |
#we are dealing with GCC output
|
sl@0
|
150 |
{
|
sl@0
|
151 |
my $imgtext;
|
sl@0
|
152 |
|
sl@0
|
153 |
# Find text section
|
sl@0
|
154 |
while (($_ = shift @maplines) && !(/^\.text\s+/))
|
sl@0
|
155 |
{
|
sl@0
|
156 |
}
|
sl@0
|
157 |
|
sl@0
|
158 |
/^\.text\s+(\w+)\s+(\w+)/
|
sl@0
|
159 |
or die "ERROR: Can't get .text section info for \"$file\"\n";
|
sl@0
|
160 |
$imgtext=hex($1);#start of the text section during linking
|
sl@0
|
161 |
$binbase-=$imgtext;
|
sl@0
|
162 |
|
sl@0
|
163 |
foreach (@maplines)
|
sl@0
|
164 |
{
|
sl@0
|
165 |
if (/___CTOR_LIST__/)
|
sl@0
|
166 |
{
|
sl@0
|
167 |
last; # end of text section
|
sl@0
|
168 |
}
|
sl@0
|
169 |
|
sl@0
|
170 |
if (/^\s(\.text)?\s+(0x\w+)\s+(0x\w+)\s+(.*)$/io)
|
sl@0
|
171 |
{
|
sl@0
|
172 |
$textlimit = hex($2)+$binbase+hex($3)-1;
|
sl@0
|
173 |
next;
|
sl@0
|
174 |
}
|
sl@0
|
175 |
|
sl@0
|
176 |
if (/^\s+(\w+)\s\s+([a-zA-Z_].+)/o)
|
sl@0
|
177 |
{
|
sl@0
|
178 |
my $addr = hex($1);
|
sl@0
|
179 |
my $symbol = $2;
|
sl@0
|
180 |
add_object($addr+$binbase,#relocated address of the current symbol
|
sl@0
|
181 |
$textlimit,#limit of the current object section
|
sl@0
|
182 |
"$binary $symbol");
|
sl@0
|
183 |
next;
|
sl@0
|
184 |
}
|
sl@0
|
185 |
}
|
sl@0
|
186 |
}
|
sl@0
|
187 |
#end of GCC output parsing
|
sl@0
|
188 |
}
|
sl@0
|
189 |
|
sl@0
|
190 |
# Handle a matched pair of D_EXC output files (.txt and .stk)
|
sl@0
|
191 |
#
|
sl@0
|
192 |
sub read_d_exc
|
sl@0
|
193 |
{
|
sl@0
|
194 |
my ($name)=@_;
|
sl@0
|
195 |
|
sl@0
|
196 |
$stackbase = 0;
|
sl@0
|
197 |
open D_EXC, "$name.txt" or die "Can't open $name.txt\n";
|
sl@0
|
198 |
|
sl@0
|
199 |
binmode D_EXC;
|
sl@0
|
200 |
read D_EXC, $data, 16;
|
sl@0
|
201 |
close D_EXC;
|
sl@0
|
202 |
|
sl@0
|
203 |
if ($data =~ /^(..)*.\0.\0/)
|
sl@0
|
204 |
{
|
sl@0
|
205 |
# Assuming Unicode
|
sl@0
|
206 |
close D_EXC;
|
sl@0
|
207 |
|
sl@0
|
208 |
# Charconv won't convert STDIN or write to STDOUT
|
sl@0
|
209 |
# so we generate an intermediate UTF8 file
|
sl@0
|
210 |
system "charconv -little -input=unicode $name.txt -output=utf8 $name.utf8.txt";
|
sl@0
|
211 |
|
sl@0
|
212 |
open D_EXC, "$name.utf8.txt" or die "Can't open $name.utf8.txt\n";
|
sl@0
|
213 |
}
|
sl@0
|
214 |
else
|
sl@0
|
215 |
{
|
sl@0
|
216 |
# Assuming ASCII
|
sl@0
|
217 |
open D_EXC, "$name.txt" or die "Can't open $name.txt\n";
|
sl@0
|
218 |
}
|
sl@0
|
219 |
|
sl@0
|
220 |
my $is_eka2_log = 0;
|
sl@0
|
221 |
|
sl@0
|
222 |
while (my $line = <D_EXC>)
|
sl@0
|
223 |
{
|
sl@0
|
224 |
|
sl@0
|
225 |
if ($line =~ /^EKA2 USER CRASH LOG$/)
|
sl@0
|
226 |
{
|
sl@0
|
227 |
$is_eka2_log = 1;
|
sl@0
|
228 |
next;
|
sl@0
|
229 |
}
|
sl@0
|
230 |
|
sl@0
|
231 |
# code=1 PC=500f7ff8 FAR=00000042 FSR=e8820013
|
sl@0
|
232 |
|
sl@0
|
233 |
if ($line =~ /^code=\d PC=(.{8})/)
|
sl@0
|
234 |
{
|
sl@0
|
235 |
$is_exc = 1;
|
sl@0
|
236 |
$fault_pc = hex($1);
|
sl@0
|
237 |
next;
|
sl@0
|
238 |
};
|
sl@0
|
239 |
|
sl@0
|
240 |
# R13svc=81719fc0 R14svc=50031da0 SPSRsvc=60000010
|
sl@0
|
241 |
|
sl@0
|
242 |
if ($line =~ /^R13svc=(.{8}) R14svc=(.{8}) SPSRsvc=(.{8})/)
|
sl@0
|
243 |
{
|
sl@0
|
244 |
$fault_lr = hex($2);
|
sl@0
|
245 |
next;
|
sl@0
|
246 |
}
|
sl@0
|
247 |
|
sl@0
|
248 |
# r00=fffffff8 00000000 80000718 80000003
|
sl@0
|
249 |
|
sl@0
|
250 |
if ($line =~ /^r(\d\d)=(.{8}) (.{8}) (.{8}) (.{8})/)
|
sl@0
|
251 |
{
|
sl@0
|
252 |
$registers{$1} = $line;
|
sl@0
|
253 |
if ($1 == 12)
|
sl@0
|
254 |
{
|
sl@0
|
255 |
$activesp = hex($3);
|
sl@0
|
256 |
$user_pc = hex($5);
|
sl@0
|
257 |
$user_lr = hex($4);
|
sl@0
|
258 |
}
|
sl@0
|
259 |
next;
|
sl@0
|
260 |
}
|
sl@0
|
261 |
|
sl@0
|
262 |
# User Stack 03900000-03905ffb
|
sl@0
|
263 |
# EKA1 format deliberately broken (was /^Stack.*/) to catch version problems
|
sl@0
|
264 |
|
sl@0
|
265 |
if ($line =~ /^User Stack (.{8})-(.{8})/)
|
sl@0
|
266 |
{
|
sl@0
|
267 |
$stackbase = hex($1);
|
sl@0
|
268 |
add_object($stackbase,hex($2), "Stack");
|
sl@0
|
269 |
next;
|
sl@0
|
270 |
}
|
sl@0
|
271 |
|
sl@0
|
272 |
# fff00000-fff00fff C:\foo\bar.dll
|
sl@0
|
273 |
|
sl@0
|
274 |
if ($line =~ /^(.{8})-(.{8}) (.+)/)
|
sl@0
|
275 |
{
|
sl@0
|
276 |
next if ($RomBase <= hex($1) && hex($1) < $RomLimit); # skip ROM XIP binaries
|
sl@0
|
277 |
add_object(hex($1), hex($2), $3);
|
sl@0
|
278 |
read_map_symbols($3, hex($1));
|
sl@0
|
279 |
}
|
sl@0
|
280 |
}
|
sl@0
|
281 |
close D_EXC;
|
sl@0
|
282 |
|
sl@0
|
283 |
die "$name.txt is not a valid EKA2 crash log" unless $is_eka2_log;
|
sl@0
|
284 |
|
sl@0
|
285 |
if ($stackbase == 0)
|
sl@0
|
286 |
{
|
sl@0
|
287 |
die "couldn't find stack information in $name.txt\n";
|
sl@0
|
288 |
}
|
sl@0
|
289 |
|
sl@0
|
290 |
die "couldn't find stack pointer in $name.txt\n" unless $activesp != 0;
|
sl@0
|
291 |
$activesp -= $stackbase;
|
sl@0
|
292 |
|
sl@0
|
293 |
# Read in the binary dump of the stack
|
sl@0
|
294 |
|
sl@0
|
295 |
open STACK, "$name.stk" or die "Can't open $name.stk\n";
|
sl@0
|
296 |
print "Stack Data from $name.stk\n";
|
sl@0
|
297 |
|
sl@0
|
298 |
binmode STACK;
|
sl@0
|
299 |
while (read STACK, $data, 4)
|
sl@0
|
300 |
{
|
sl@0
|
301 |
unshift @stack, (unpack "V", $data);
|
sl@0
|
302 |
}
|
sl@0
|
303 |
$stackptr = 0;
|
sl@0
|
304 |
}
|
sl@0
|
305 |
|
sl@0
|
306 |
# Handle the captured text output from the Kernel debugger
|
sl@0
|
307 |
#
|
sl@0
|
308 |
sub read_debugger
|
sl@0
|
309 |
{
|
sl@0
|
310 |
my ($name)=@_;
|
sl@0
|
311 |
|
sl@0
|
312 |
open DEBUGFILE, "$name" or die "Can't open $name\n";
|
sl@0
|
313 |
print "Kernel Debugger session from $name\n";
|
sl@0
|
314 |
|
sl@0
|
315 |
# stuff which should be inferred from "$name"
|
sl@0
|
316 |
|
sl@0
|
317 |
$stackbase = 0x81C00000;
|
sl@0
|
318 |
$stackmax = 0x81C01DC0;
|
sl@0
|
319 |
$activesp = 0x81c01bc4-$stackbase;
|
sl@0
|
320 |
add_object($stackbase,0x81C01FFF, "Stack");
|
sl@0
|
321 |
|
sl@0
|
322 |
while (my $line = <DEBUGFILE>)
|
sl@0
|
323 |
{
|
sl@0
|
324 |
if ($line =~ /^(\w{8}): ((\w\w ){16})/)
|
sl@0
|
325 |
{
|
sl@0
|
326 |
my $addr = hex($1);
|
sl@0
|
327 |
if ($addr < $stackbase || $addr > $stackmax)
|
sl@0
|
328 |
{
|
sl@0
|
329 |
next;
|
sl@0
|
330 |
}
|
sl@0
|
331 |
if (@stack == 0)
|
sl@0
|
332 |
{
|
sl@0
|
333 |
if ($addr != $stackbase)
|
sl@0
|
334 |
{
|
sl@0
|
335 |
printf "Missing stack data for %x-%x - fill with 0x29\n", $stackbase, $addr-1;
|
sl@0
|
336 |
@stack = (0x29292929) x (($addr-$stackbase)/4);
|
sl@0
|
337 |
}
|
sl@0
|
338 |
}
|
sl@0
|
339 |
unshift @stack, reverse (unpack "V4", (pack "H2"x16, (split / /,$2)));
|
sl@0
|
340 |
}
|
sl@0
|
341 |
}
|
sl@0
|
342 |
$stackptr = 0;
|
sl@0
|
343 |
}
|
sl@0
|
344 |
|
sl@0
|
345 |
read_d_exc(@ARGV[0]);
|
sl@0
|
346 |
if (@ARGV>1)
|
sl@0
|
347 |
{
|
sl@0
|
348 |
read_rom_symbols(@ARGV[1]);
|
sl@0
|
349 |
}
|
sl@0
|
350 |
|
sl@0
|
351 |
# We've accumulated the ranges of objects indexed by start address,
|
sl@0
|
352 |
# with a companion list of addresses subdivided by the leading byte
|
sl@0
|
353 |
# Now sort them numerically...
|
sl@0
|
354 |
|
sl@0
|
355 |
sub numerically { $a <=> $b }
|
sl@0
|
356 |
foreach my $key (keys %addresslist)
|
sl@0
|
357 |
{
|
sl@0
|
358 |
@{$addresslist{$key}} = sort numerically @{$addresslist{$key}};
|
sl@0
|
359 |
}
|
sl@0
|
360 |
|
sl@0
|
361 |
# Off we go, reading the stack!
|
sl@0
|
362 |
|
sl@0
|
363 |
sub skip_unused
|
sl@0
|
364 |
{
|
sl@0
|
365 |
my $skipped=0;
|
sl@0
|
366 |
while (@stack)
|
sl@0
|
367 |
{
|
sl@0
|
368 |
my $word=(pop @stack);
|
sl@0
|
369 |
if ($word!=0x29292929)
|
sl@0
|
370 |
{
|
sl@0
|
371 |
push @stack, $word;
|
sl@0
|
372 |
last;
|
sl@0
|
373 |
}
|
sl@0
|
374 |
$skipped += 4;
|
sl@0
|
375 |
}
|
sl@0
|
376 |
$stackptr += $skipped;
|
sl@0
|
377 |
return $skipped;
|
sl@0
|
378 |
}
|
sl@0
|
379 |
|
sl@0
|
380 |
sub lookup_addr
|
sl@0
|
381 |
{
|
sl@0
|
382 |
my ($word) = @_;
|
sl@0
|
383 |
|
sl@0
|
384 |
# Optimization - try looking up the address directly
|
sl@0
|
385 |
|
sl@0
|
386 |
my $base;
|
sl@0
|
387 |
my $max;
|
sl@0
|
388 |
my $name;
|
sl@0
|
389 |
if(defined $address{$word}) {
|
sl@0
|
390 |
($base, $max, $name) = @{$address{$word}};
|
sl@0
|
391 |
}
|
sl@0
|
392 |
if (!(defined $base))
|
sl@0
|
393 |
{
|
sl@0
|
394 |
my $key=$word>>20;
|
sl@0
|
395 |
my $regionbase;
|
sl@0
|
396 |
foreach $base (@{$addresslist{$key}})
|
sl@0
|
397 |
{
|
sl@0
|
398 |
if ($base <= $word)
|
sl@0
|
399 |
{
|
sl@0
|
400 |
$regionbase = $base;
|
sl@0
|
401 |
next;
|
sl@0
|
402 |
}
|
sl@0
|
403 |
if ($base > $word)
|
sl@0
|
404 |
{
|
sl@0
|
405 |
last;
|
sl@0
|
406 |
}
|
sl@0
|
407 |
}
|
sl@0
|
408 |
if(defined $regionbase)
|
sl@0
|
409 |
{
|
sl@0
|
410 |
($base, $max, $name) = @{$address{$regionbase}};
|
sl@0
|
411 |
}
|
sl@0
|
412 |
}
|
sl@0
|
413 |
if (defined $base && defined $max && $base <= $word && $max >= $word)
|
sl@0
|
414 |
{
|
sl@0
|
415 |
my $data = pack "V", $word;
|
sl@0
|
416 |
$data =~ tr [\040-\177]/./c;
|
sl@0
|
417 |
return sprintf "%08x %4s %s + 0x%x", $word, $data, $name, $word - $base;
|
sl@0
|
418 |
}
|
sl@0
|
419 |
return "";
|
sl@0
|
420 |
}
|
sl@0
|
421 |
|
sl@0
|
422 |
sub match_addr
|
sl@0
|
423 |
#
|
sl@0
|
424 |
# Try matching one of the named areas in the addresslist
|
sl@0
|
425 |
#
|
sl@0
|
426 |
{
|
sl@0
|
427 |
my $word = (pop @stack);
|
sl@0
|
428 |
|
sl@0
|
429 |
if ($word < 1024*1024)
|
sl@0
|
430 |
{
|
sl@0
|
431 |
push @stack, $word;
|
sl@0
|
432 |
return 0;
|
sl@0
|
433 |
}
|
sl@0
|
434 |
|
sl@0
|
435 |
my $result = lookup_addr($word);
|
sl@0
|
436 |
if ($result ne "")
|
sl@0
|
437 |
{
|
sl@0
|
438 |
print "$result\n";
|
sl@0
|
439 |
$stackptr+=4;
|
sl@0
|
440 |
return 1;
|
sl@0
|
441 |
}
|
sl@0
|
442 |
push @stack, $word;
|
sl@0
|
443 |
return 0;
|
sl@0
|
444 |
}
|
sl@0
|
445 |
|
sl@0
|
446 |
sub match_tbuf8
|
sl@0
|
447 |
#
|
sl@0
|
448 |
# Try matching a TBuf8
|
sl@0
|
449 |
# 0x3000LLLL 0x0000MMMM data
|
sl@0
|
450 |
#
|
sl@0
|
451 |
{
|
sl@0
|
452 |
if (scalar @stack <3)
|
sl@0
|
453 |
{
|
sl@0
|
454 |
return 0; # too short
|
sl@0
|
455 |
}
|
sl@0
|
456 |
my $word = (pop @stack);
|
sl@0
|
457 |
my $maxlen = (pop @stack);
|
sl@0
|
458 |
|
sl@0
|
459 |
my $len = $word & 0x0ffff;
|
sl@0
|
460 |
my $type = ($word >> 16) & 0x0ffff;
|
sl@0
|
461 |
if ( $type != 0x3000 || $maxlen <= $len || $maxlen > 4* scalar @stack
|
sl@0
|
462 |
|| ($stackptr < $activesp && $stackptr + $maxlen + 8 > $activesp))
|
sl@0
|
463 |
{
|
sl@0
|
464 |
push @stack, $maxlen;
|
sl@0
|
465 |
push @stack, $word;
|
sl@0
|
466 |
return 0; # wrong type, or invalid looking sizes, or out of date
|
sl@0
|
467 |
}
|
sl@0
|
468 |
|
sl@0
|
469 |
printf "TBuf8<%d>, length %d\n", $maxlen, $len;
|
sl@0
|
470 |
$stackptr += 8;
|
sl@0
|
471 |
|
sl@0
|
472 |
my $string="";
|
sl@0
|
473 |
while ($maxlen > 0)
|
sl@0
|
474 |
{
|
sl@0
|
475 |
$string .= pack "V", pop @stack;
|
sl@0
|
476 |
$maxlen -= 4;
|
sl@0
|
477 |
$stackptr += 4;
|
sl@0
|
478 |
}
|
sl@0
|
479 |
if ($len==0)
|
sl@0
|
480 |
{
|
sl@0
|
481 |
print "\n";
|
sl@0
|
482 |
return 1;
|
sl@0
|
483 |
}
|
sl@0
|
484 |
my $line = substr($string,0,$len);
|
sl@0
|
485 |
my @buf = unpack "C*", $line;
|
sl@0
|
486 |
$line =~ tr [\040-\177]/./c;
|
sl@0
|
487 |
printf "\n %s", $line;
|
sl@0
|
488 |
while ($len > 0)
|
sl@0
|
489 |
{
|
sl@0
|
490 |
my $datalen = 16;
|
sl@0
|
491 |
if ($datalen > $len)
|
sl@0
|
492 |
{
|
sl@0
|
493 |
$datalen = $len;
|
sl@0
|
494 |
}
|
sl@0
|
495 |
$len -= $datalen;
|
sl@0
|
496 |
printf "\n ";
|
sl@0
|
497 |
while ($datalen > 0)
|
sl@0
|
498 |
{
|
sl@0
|
499 |
my $char = shift @buf;
|
sl@0
|
500 |
printf "%02x ", $char;
|
sl@0
|
501 |
$datalen -= 1;
|
sl@0
|
502 |
}
|
sl@0
|
503 |
}
|
sl@0
|
504 |
printf "\n\n";
|
sl@0
|
505 |
return 1;
|
sl@0
|
506 |
}
|
sl@0
|
507 |
|
sl@0
|
508 |
# Skip the unused part of the stack
|
sl@0
|
509 |
|
sl@0
|
510 |
skip_unused;
|
sl@0
|
511 |
printf "High watermark = %04x\n", $stackptr;
|
sl@0
|
512 |
|
sl@0
|
513 |
# process the interesting bit!
|
sl@0
|
514 |
|
sl@0
|
515 |
my $printed_current_sp = 0;
|
sl@0
|
516 |
while (@stack)
|
sl@0
|
517 |
{
|
sl@0
|
518 |
if (!$printed_current_sp && $stackptr >= $activesp)
|
sl@0
|
519 |
{
|
sl@0
|
520 |
printf "\n >>>> current user stack pointer >>>>\n\n";
|
sl@0
|
521 |
|
sl@0
|
522 |
print $registers{"00"};
|
sl@0
|
523 |
print $registers{"04"};
|
sl@0
|
524 |
print $registers{"08"};
|
sl@0
|
525 |
print $registers{"12"};
|
sl@0
|
526 |
|
sl@0
|
527 |
if ($is_exc && $user_pc != $fault_pc)
|
sl@0
|
528 |
{
|
sl@0
|
529 |
print "\nWARNING: A kernel-side exception occured but this script\n";
|
sl@0
|
530 |
print "is currently limited to user stack analysis. Sorry.\n";
|
sl@0
|
531 |
my $result = lookup_addr($fault_pc);
|
sl@0
|
532 |
if ($result ne "")
|
sl@0
|
533 |
{
|
sl@0
|
534 |
print "Kernel PC = $result\n";
|
sl@0
|
535 |
}
|
sl@0
|
536 |
$result = lookup_addr($fault_lr);
|
sl@0
|
537 |
if ($result ne "")
|
sl@0
|
538 |
{
|
sl@0
|
539 |
print "Kernel LR = $result\n";
|
sl@0
|
540 |
}
|
sl@0
|
541 |
print "\n";
|
sl@0
|
542 |
}
|
sl@0
|
543 |
|
sl@0
|
544 |
my $result = lookup_addr($user_pc);
|
sl@0
|
545 |
if ($result ne "")
|
sl@0
|
546 |
{
|
sl@0
|
547 |
print "User PC = $result\n";
|
sl@0
|
548 |
}
|
sl@0
|
549 |
$result = lookup_addr($user_lr);
|
sl@0
|
550 |
if ($result ne "")
|
sl@0
|
551 |
{
|
sl@0
|
552 |
print "User LR = $result\n";
|
sl@0
|
553 |
}
|
sl@0
|
554 |
printf "\n >>>> current user stack pointer >>>>\n\n";
|
sl@0
|
555 |
$printed_current_sp = 1;
|
sl@0
|
556 |
}
|
sl@0
|
557 |
|
sl@0
|
558 |
printf "%04x ", $stackptr;
|
sl@0
|
559 |
|
sl@0
|
560 |
match_tbuf8() and next;
|
sl@0
|
561 |
match_addr() and next;
|
sl@0
|
562 |
|
sl@0
|
563 |
$word = pop @stack;
|
sl@0
|
564 |
$data = pack "V", $word;
|
sl@0
|
565 |
$data =~ tr [\040-\177]/./c;
|
sl@0
|
566 |
printf "%08x %4s ", $word, $data;
|
sl@0
|
567 |
$stackptr += 4;
|
sl@0
|
568 |
|
sl@0
|
569 |
if ($word == 0x29292929)
|
sl@0
|
570 |
{
|
sl@0
|
571 |
$skipped = skip_unused;
|
sl@0
|
572 |
if ($skipped != 0)
|
sl@0
|
573 |
{
|
sl@0
|
574 |
printf "\n....";
|
sl@0
|
575 |
}
|
sl@0
|
576 |
printf "\n";
|
sl@0
|
577 |
next;
|
sl@0
|
578 |
}
|
sl@0
|
579 |
|
sl@0
|
580 |
# Try matching $word against the known addresses of things
|
sl@0
|
581 |
printf "\n";
|
sl@0
|
582 |
}
|
sl@0
|
583 |
|
sl@0
|
584 |
|