line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
12
|
|
|
12
|
|
80
|
use warnings; no warnings 'redefine'; |
|
12
|
|
|
12
|
|
33
|
|
|
12
|
|
|
|
|
383
|
|
|
12
|
|
|
|
|
66
|
|
|
12
|
|
|
|
|
32
|
|
|
12
|
|
|
|
|
374
|
|
2
|
12
|
|
|
12
|
|
69
|
use English qw( -no_match_vars ); |
|
12
|
|
|
|
|
30
|
|
|
12
|
|
|
|
|
76
|
|
3
|
12
|
|
|
12
|
|
2716
|
use B; |
|
12
|
|
|
|
|
30
|
|
|
12
|
|
|
|
|
1305
|
|
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
=pod |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
=head2 tbacktrace(skip[,count,scan_for_DB]) |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
Collect the traceback information available via C<caller()>. Some |
10
|
|
|
|
|
|
|
filtering and cleanup of the data is done. |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
C<skip> defines the number of stack frames to be skipped, working |
13
|
|
|
|
|
|
|
backwards from the most current frame before the call the debugger |
14
|
|
|
|
|
|
|
DB::DB call if scan_for_DB is set, or the most-current frame. |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
C<count> determines the total number of call frames to be returned; all of |
17
|
|
|
|
|
|
|
them (well, the first 10^9) are returned if C<count> is omitted. |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
This routine returns a list of hashes, from most-recent to least-recent |
20
|
|
|
|
|
|
|
stack frame. Each has the following keys and values: |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
=over 4 |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
=item * |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
C<wantarray> - C<.> (null), C<$> (scalar), or C<@> (array) |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
=item * |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
C<fn> - subroutine name, or C<eval> information |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
=item * |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
C<args> - undef, or a reference to an array of arguments |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
=item * |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
C<file> - the file in which this item was defined (if any) |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
=item * |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
C<line> - the line on which it was defined |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
=item * |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
C<evaltext> - eval text if we are in an eval. |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
=back |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
=cut |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
# NOTE: this routine needs to be in package DB for us to be able to pick up the |
53
|
|
|
|
|
|
|
# subroutine args. |
54
|
|
|
|
|
|
|
sub tbacktrace($;$$$) { |
55
|
0
|
|
|
0
|
0
|
|
my ($self, $skip, $count, $scan_for_DB_sub) = @_; |
56
|
0
|
0
|
|
|
|
|
$skip = 0 unless defined($skip); |
57
|
0
|
0
|
|
|
|
|
$count = 1e9 unless defined($count); |
58
|
|
|
|
|
|
|
|
59
|
0
|
|
0
|
|
|
|
$scan_for_DB_sub ||= 1; |
60
|
|
|
|
|
|
|
# print "scan: $scan_for_DB_sub\n"; |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
# These variables are used to capture output from caller(); |
63
|
0
|
|
|
|
|
|
my ( $pkg, $file, $line, $fn, $hasargs, $wantarray, $evaltext, $is_require ); |
64
|
|
|
|
|
|
|
|
65
|
0
|
|
|
|
|
|
my $i=0; |
66
|
0
|
0
|
|
|
|
|
if ($scan_for_DB_sub) { |
67
|
12
|
|
|
12
|
|
71
|
no warnings qw(once uninitialized); # For $DB::event |
|
12
|
|
|
|
|
34
|
|
|
12
|
|
|
|
|
10563
|
|
68
|
0
|
0
|
|
|
|
|
my $db_fn = ($DB::event eq 'post-mortem') ? 'catch' : 'DB'; |
69
|
|
|
|
|
|
|
# Warning: There is a bug caller that lists DB:DB as the function |
70
|
|
|
|
|
|
|
# name rather than the name the debugged program may have been in |
71
|
0
|
|
|
|
|
|
while (my ($pkg, $file, $line, $fn) = caller($i++)) { |
72
|
0
|
0
|
0
|
|
|
|
if ("DB::$db_fn" eq $fn or ('DB' eq $pkg && $db_fn eq $fn)) { |
|
|
|
0
|
|
|
|
|
73
|
0
|
|
|
|
|
|
$i--; |
74
|
0
|
|
|
|
|
|
last ; |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
} |
77
|
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
|
79
|
0
|
|
|
|
|
|
$scan_for_DB_sub = $i; |
80
|
0
|
|
|
|
|
|
$count += $i; |
81
|
|
|
|
|
|
|
# print "++count: $count, i $i $DB::event\n"; # XX debug |
82
|
0
|
0
|
|
|
|
|
$i -= 2 if $DB::event eq 'call'; |
83
|
|
|
|
|
|
|
|
84
|
0
|
|
|
|
|
|
my ( @a, $args_ary ); |
85
|
0
|
|
|
|
|
|
my @callstack = (); |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
# # XXX Okay... why'd we do that? |
88
|
0
|
|
|
|
|
|
my $nothard = not $DB::frame & 8; |
89
|
0
|
|
|
|
|
|
local $DB::frame = 0; |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
# Start out at the skip count, $i. |
92
|
|
|
|
|
|
|
# If we haven't reached the number of frames requested, and caller() is |
93
|
|
|
|
|
|
|
# still returning something, stay in the loop. (If we pass the requested |
94
|
|
|
|
|
|
|
# number of stack frames, or we run out - caller() returns nothing - we |
95
|
|
|
|
|
|
|
# quit. |
96
|
|
|
|
|
|
|
# Up the stack frame index to go back one more level each time. |
97
|
0
|
|
0
|
|
|
|
while ($i <= $count and |
98
|
|
|
|
|
|
|
($pkg, $file, $line, $fn, $hasargs, $wantarray, $evaltext, |
99
|
|
|
|
|
|
|
$is_require) = caller($i)) |
100
|
|
|
|
|
|
|
{ |
101
|
0
|
|
|
|
|
|
my $addr = Devel::Callsite::callsite($i); |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
## print "++file: $file, line $line $fn\n"; # XX if $DB::DEBUGME; |
104
|
0
|
|
|
|
|
|
$i++; |
105
|
0
|
0
|
0
|
|
|
|
next if $pkg eq 'DB' && ($fn eq 'sub' || $fn eq 'lsub' || |
|
|
|
0
|
|
|
|
|
106
|
|
|
|
|
|
|
$file =~ m{Devel/Trepan/DB/Sub\.pm$}); |
107
|
|
|
|
|
|
|
# Go through the arguments and save them for later. |
108
|
0
|
|
|
|
|
|
@a = (); |
109
|
0
|
|
|
|
|
|
for my $arg (@DB::args) { |
110
|
0
|
|
|
|
|
|
my $type; |
111
|
0
|
0
|
0
|
|
|
|
if ( not defined $arg ) { # undefined parameter |
|
|
0
|
0
|
|
|
|
|
|
|
0
|
|
|
|
|
|
112
|
0
|
|
|
|
|
|
push @a, "undef"; |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
elsif ( $nothard and tied $arg ) { # tied parameter |
116
|
0
|
|
|
|
|
|
push @a, "tied"; |
117
|
|
|
|
|
|
|
} |
118
|
|
|
|
|
|
|
elsif ( $nothard and $type = ref $arg ) { # reference |
119
|
0
|
|
|
|
|
|
push @a, "ref($type)"; |
120
|
|
|
|
|
|
|
} |
121
|
|
|
|
|
|
|
else { # can be stringified |
122
|
0
|
|
|
|
|
|
local $_ = |
123
|
|
|
|
|
|
|
"$arg"; # Safe to stringify now - should not call f(). |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
# Backslash any single-quotes or backslashes. |
126
|
0
|
|
|
|
|
|
s/([\'\\])/\\$1/g; |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
# Single-quote it unless it's a number or a colon-separated |
129
|
|
|
|
|
|
|
# name. |
130
|
0
|
0
|
|
|
|
|
s/(.*)/'$1'/s |
131
|
|
|
|
|
|
|
unless /^(?: -?[\d.]+ | \*[\w:]* )$/x; |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
# Turn high-bit characters into meta-whatever. |
134
|
0
|
|
|
|
|
|
s/([\200-\377])/sprintf("M-%c",ord($1)&0177)/eg; |
|
0
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
# Turn control characters into ^-whatever. |
137
|
0
|
|
|
|
|
|
s/([\0-\37\177])/sprintf("^%c",ord($1)^64)/eg; |
|
0
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
|
139
|
0
|
|
|
|
|
|
push( @a, $_ ); |
140
|
|
|
|
|
|
|
} ## end else [ if (not defined $arg) |
141
|
|
|
|
|
|
|
} ## end for $arg (@args) |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
# If $wantarray is true, this is array (@)context. |
144
|
|
|
|
|
|
|
# If $wantarray is false, this is scalar ($) context. |
145
|
|
|
|
|
|
|
# If neither, $wantarray isn't defined. (This is apparently a 'can't |
146
|
|
|
|
|
|
|
# happen' trap.) |
147
|
0
|
0
|
|
|
|
|
$wantarray = $wantarray ? '@' : ( defined $wantarray ? '$' : '.' ); |
|
|
0
|
|
|
|
|
|
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
# if the sub has args ($hasargs true), make an anonymous array of the |
150
|
|
|
|
|
|
|
# dumped args. |
151
|
0
|
0
|
|
|
|
|
$args_ary = $hasargs ? [@a] : undef; |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
# remove trailing newline-whitespace-semicolon-end of line sequence |
154
|
|
|
|
|
|
|
# from the eval text, if any. |
155
|
0
|
0
|
|
|
|
|
$evaltext =~ s/\n\s*\;\s*\Z// if $evaltext; |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
# Escape backslashed single-quotes again if necessary. |
158
|
0
|
0
|
|
|
|
|
$evaltext =~ s/([\\\'])/\\$1/g if $evaltext; |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
# if the require flag is true, the eval text is from a require. |
161
|
0
|
0
|
|
|
|
|
if ($is_require) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
162
|
0
|
|
|
|
|
|
$fn = "require '$evaltext'"; |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
# if it's false, the eval text is really from an eval. |
166
|
|
|
|
|
|
|
elsif ( defined $is_require ) { |
167
|
0
|
|
|
|
|
|
$fn = "eval '$evaltext'"; |
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
# If the sub is '(eval)', this is a block eval, meaning we don't |
171
|
|
|
|
|
|
|
# know what the eval'ed text actually was. |
172
|
|
|
|
|
|
|
elsif ( $fn eq '(eval)' ) { |
173
|
0
|
|
|
|
|
|
$fn = "eval {...}"; |
174
|
|
|
|
|
|
|
} |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
# Stick the collected information into @callstack a hash reference. |
177
|
0
|
|
|
|
|
|
push(@callstack, |
178
|
|
|
|
|
|
|
{ |
179
|
|
|
|
|
|
|
addr => $addr, |
180
|
|
|
|
|
|
|
args => $args_ary, |
181
|
|
|
|
|
|
|
evaltext => $evaltext, |
182
|
|
|
|
|
|
|
file => $file, |
183
|
|
|
|
|
|
|
fn => $fn, |
184
|
|
|
|
|
|
|
line => $line, |
185
|
|
|
|
|
|
|
pkg => $pkg, |
186
|
|
|
|
|
|
|
wantarray => $wantarray, |
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
); |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
# Stop processing frames if the user hit control-C. |
191
|
|
|
|
|
|
|
# last if $signal; |
192
|
|
|
|
|
|
|
} ## end for ($i = $skip ; $i < ... |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
## use Data::Printer; Data::Printer::p @callstack; # XXX |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
# The function and args for the stopped line is DB::DB, |
197
|
|
|
|
|
|
|
# but we want it to be the function and args of the last call. |
198
|
|
|
|
|
|
|
# Se we need to adjust those in @callstack. |
199
|
|
|
|
|
|
|
# And the function and args for the file and line that called us |
200
|
|
|
|
|
|
|
# should also be the prior function and args. |
201
|
0
|
0
|
|
|
|
|
if ($scan_for_DB_sub) { |
202
|
0
|
|
|
|
|
|
my $len = @callstack; |
203
|
0
|
0
|
|
|
|
|
if ($len) { |
204
|
0
|
|
|
|
|
|
for (my $i=1; $i < $len; $i++) { |
205
|
0
|
|
|
|
|
|
$callstack[$i-1]->{args} = $callstack[$i]->{args}; |
206
|
0
|
|
|
|
|
|
$callstack[$i-1]->{fn} = $callstack[$i]->{fn}; |
207
|
0
|
|
|
|
|
|
$callstack[$i-1]->{wantarray} = $callstack[$i]->{wantarray}; |
208
|
|
|
|
|
|
|
} |
209
|
|
|
|
|
|
|
# $callstack[$len]->{args} = undef; |
210
|
|
|
|
|
|
|
# $callstack[$len]->{fn} = undef; |
211
|
|
|
|
|
|
|
} |
212
|
|
|
|
|
|
|
} |
213
|
|
|
|
|
|
|
|
214
|
0
|
0
|
|
|
|
|
if ($DB::event eq 'call') { |
215
|
0
|
0
|
|
|
|
|
unshift @callstack, { |
216
|
|
|
|
|
|
|
addr => $DB::addr, |
217
|
|
|
|
|
|
|
file => $DB::filename, |
218
|
|
|
|
|
|
|
fn => $DB::subroutine, |
219
|
|
|
|
|
|
|
line => $DB::lineno, |
220
|
|
|
|
|
|
|
pkg => $DB::package, |
221
|
|
|
|
|
|
|
args => $DB::hasargs, |
222
|
|
|
|
|
|
|
wantarray => $DB::wantarray ? $DB::wantarray : '', |
223
|
|
|
|
|
|
|
}; |
224
|
|
|
|
|
|
|
} |
225
|
|
|
|
|
|
|
# use Data::Printer; Data::Printer::p @callstack; |
226
|
|
|
|
|
|
|
|
227
|
0
|
|
|
|
|
|
@callstack; |
228
|
|
|
|
|
|
|
} |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
unless (caller) { |
231
|
|
|
|
|
|
|
require Data::Dumper; |
232
|
|
|
|
|
|
|
import Data::Dumper; |
233
|
|
|
|
|
|
|
$DB::frame = 0; |
234
|
|
|
|
|
|
|
our @callstack = tbacktrace(undef,undef,undef,0); |
235
|
|
|
|
|
|
|
our $sep = '-' x 20 . "\n"; |
236
|
|
|
|
|
|
|
# print Dumper(@callstack), "\n"; |
237
|
|
|
|
|
|
|
# print $sep; |
238
|
|
|
|
|
|
|
sub five { |
239
|
0
|
|
|
0
|
0
|
|
@callstack = tbacktrace(undef,undef,undef,0); |
240
|
0
|
|
|
|
|
|
print Dumper(@callstack), "\n"; |
241
|
0
|
|
|
|
|
|
print $sep; |
242
|
0
|
|
|
|
|
|
@callstack = tbacktrace(undef,1,undef,0); |
243
|
0
|
|
|
|
|
|
print Dumper(@callstack), "\n"; |
244
|
0
|
|
|
|
|
|
print $sep; |
245
|
0
|
|
|
|
|
|
@callstack = tbacktrace(1,0,undef,0); |
246
|
0
|
|
|
|
|
|
print Dumper(@callstack), "\n"; |
247
|
0
|
|
|
|
|
|
print $sep; |
248
|
0
|
|
|
|
|
|
5; |
249
|
|
|
|
|
|
|
} |
250
|
|
|
|
|
|
|
my $five = five(); |
251
|
|
|
|
|
|
|
# $five = eval "@callstack = tbacktrace(undef, undef, undef, 0)"; |
252
|
|
|
|
|
|
|
# print Dumper(@callstack), "\n"; |
253
|
|
|
|
|
|
|
print $sep; |
254
|
|
|
|
|
|
|
$five = eval "five"; |
255
|
|
|
|
|
|
|
print Dumper(@callstack), "\n"; |
256
|
|
|
|
|
|
|
} |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
1; |