File Coverage

lib/Devel/Trepan/DB/Sub.pm
Criterion Covered Total %
statement 76 243 31.2
branch 0 92 0.0
condition 0 36 0.0
subroutine 24 30 80.0
pod 1 6 16.6
total 101 407 24.8


line stmt bran cond sub pod time code
1             # Derived from perl5db.pl
2             # Tracks calls and returns and stores some stack frame
3             # information.
4             package DB;
5 12     12   83 use warnings; no warnings 'redefine'; use utf8;
  12     12   140  
  12     12   380  
  12         63  
  12         28  
  12         325  
  12         712  
  12         40  
  12         118  
6 12     12   310 no warnings 'once';
  12         27  
  12         368  
7 12     12   629 use English qw( -no_match_vars );
  12         3062  
  12         97  
8 12     12   4284 use version;
  12         1507  
  12         189  
9 12     12   848 use B;
  12         32  
  12         587  
10              
11 12     12   78 use constant SINGLE_STEPPING_EVENT => 1;
  12         26  
  12         752  
12 12     12   77 use constant NEXT_STEPPING_EVENT => 2;
  12         31  
  12         563  
13 12     12   78 use constant DEEP_RECURSION_EVENT => 4;
  12         35  
  12         698  
14 12     12   75 use constant RETURN_EVENT => 32;
  12         34  
  12         714  
15 12     12   70 use constant CALL_EVENT => 64;
  12         27  
  12         540  
16              
17 12     12   71 use vars qw($return_value @return_value @ret $ret @stack %fn_brkpt $deep);
  12         30  
  12         1448  
18              
19             BEGIN {
20 12     12   55 @DB::ret = (); # return value of last sub executed in list context
21 12         34 $DB::ret = ''; # return value of last sub executed in scalar context
22 12         28 $DB::return_type = 'undef';
23 12         77 %DB::fn_brkpt = ();
24              
25             # $deep: Maximium stack depth before we complain.
26             # See RT #117407
27             # https://rt.perl.org/rt3//Public/Bug/Display.html?id=117407
28             # for justification for why this should be 1000 rather than something
29             # smaller.
30 12         29 $DB::deep = 500;
31              
32             # $stack_depth is to track the current stack depth using the
33             # auto-stacked-variable trick. It is 'local'ized repeatedly as
34             # a simple way to keep track of #stack.
35 12         39 $DB::stack_depth = 0;
36 12         1552 @DB::stack = (0); # Per-frame debugger flags
37             }
38              
39             sub subcall_debugger {
40 0 0 0 0 0   if ($DB::single || $DB::signal) {
41 0 0         _warnall($#DB::stack . " levels deep in subroutine calls.\n") if $DB::single & 4;
42 0           local $DB::event = 'call';
43 0           $DB::single = 0;
44 0           $DB::signal = 0;
45 0           $DB::running = 0;
46              
47             # lock the debugger and get the thread id for the prompt
48 0 0         if ($ENV{PERL5DB_THREADED}) {
49 0           require threads;
50 0           require threads::shared;
51 0           import threads::shared qw(share);
52 12     12   87 no strict; no warnings;
  12     12   24  
  12         310  
  12         69  
  12         28  
  12         11002  
53 0           lock($DBGR);
54 0           $tid = eval { "[".threads->tid."]" };
  0            
55             }
56              
57 0           local $OP_addr = Devel::Callsite::callsite(1);
58              
59 0           $DB::subroutine = $sub;
60 0           my $entry = $DB::sub{$sub};
61 0 0         if ($entry =~ /^(.*)\:(\d+)-(\d+)$/) {
62 0           $DB::filename = $1;
63 0           $DB::lineno = $2;
64 0           $DB::caller = [
65             $DB::filename, $DB::lineno, $DB::subroutine,
66             0 != scalar(@_), $DB::wantarray
67             ];
68             }
69 0           for my $c (@clients) {
70             # Now sit in an event loop until something sets $running
71 0           my $after_eval = 0;
72 0           do {
73             # Show display expresions
74 0           my $display_aref = $c->display_lists;
75 0           for my $disp (@$display_aref) {
76 0 0 0       next unless $disp && $disp->enabled;
77 0           my $opts = {return_type => $disp->return_type,
78             namespace_package => $namespace_package,
79             fix_file_and_line => 1,
80             hide_position => 0};
81             # FIXME: allow more than just scalar contexts.
82 0           &DB::save_vars();
83 0           my $eval_result =
84             &DB::eval_with_return($disp->arg, $opts, @DB::saved);
85 0           my $mess;
86 0 0         if (defined($eval_result)) {
87 0           $mess = sprintf("%d: $eval_result", $disp->number);
88             } else {
89 0           $mess = sprintf("%d: undef", $disp->number);
90             }
91 0           $c->output($mess);
92             }
93              
94 0 0         if (1 == $after_eval ) {
    0          
95 0           $event = 'after_eval';
96             } elsif (2 == $after_eval) {
97 0           $event = 'after_nest'
98             }
99              
100             # call client event loop; must not block
101 0           $c->idle($event, $watch_triggered);
102 0           $after_eval = 0;
103 0 0 0       if ($running == 2 && defined($eval_str)) {
104             # client wants something eval-ed
105             # FIXME: turn into subroutine.
106              
107 0           local $nest = $eval_opts->{nest};
108 0           my $return_type = $eval_opts->{return_type};
109 0 0         $return_type = '' unless defined $return_type;
110 0           my $opts = $eval_opts;
111 0           $opts->{namespace_package} = $namespace_package;
112              
113 0           &DB::save_vars();
114 0 0         if ('@' eq $return_type) {
    0          
115 0           &DB::eval_with_return($eval_str, $opts, @DB::saved);
116             } elsif ('%' eq $return_type) {
117 0           &DB::eval_with_return($eval_str, $opts, @DB::saved);
118             } else {
119 0           $eval_result =
120             &DB::eval_with_return($eval_str, $opts, @DB::saved);
121             }
122              
123 0 0         if ($nest) {
124 0           $DB::in_debugger = 1;
125 0           $after_eval = 2;
126             } else {
127 0           $after_eval = 1;
128             }
129 0           $running = 0;
130             }
131             } until $running;
132             }
133             }
134             }
135              
136             sub check_for_stop()
137             {
138 0     0 0   my $brkpts = $DB::fn_brkpt{$sub};
139 0 0         if ($brkpts) {
140 0           my @action = ();
141 0           for (my $i=0; $i < @$brkpts; $i++) {
142 0           my $brkpt = $brkpts->[$i];
143 0 0         next unless defined $brkpt;
144 0 0         if ($brkpt->type eq 'action') {
145 0           push @action, $brkpt;
146 0           next ;
147             }
148 0           $stop = 0;
149 0 0         if ($brkpt->condition eq '1') {
150             # A cheap and simple test for unconditional.
151 0           $stop = 1;
152             } else {
153 0           my $eval_str = sprintf("\$DB::stop = do { %s; }",
154             $brkpt->condition);
155 0           my $opts = {return_type => ';', # ignore return
156             namespace_package => $namespace_package,
157             fix_file_and_line => 1,
158             hide_position => 0};
159 0           &DB::save_vars();
160 0           &DB::eval_with_return($eval_str, $opts, @DB::saved);
161             }
162 0 0 0       if ($stop && $brkpt->enabled && !($DB::single & RETURN_EVENT)) {
      0        
163 0           $DB::brkpt = $brkpt;
164 0           $event = $brkpt->type;
165 0 0         if ($event eq 'tbrkpt') {
166             # breakpoint is temporary and remove it.
167 0           undef $brkpts->[$i];
168             } else {
169 0           my $hits = $brkpt->hits + 1;
170 0           $brkpt->hits($hits);
171             }
172 0           $DB::single = 1;
173 0           $DB::wantarray = wantarray;
174 0           local $OP_addr = Devel::Callsite::callsite(1);
175 0           &subcall_debugger() ;
176 0           last;
177             }
178             }
179             }
180             }
181              
182             # Push the $DB:single onto @DB::stack and set $DB_single.
183             sub push_DB_single_and_set()
184             {
185             # Expand @stack.
186 0     0 0   $#DB::stack = $DB::stack_depth;
187              
188             # Save current single-step setting.
189 0           $DB::stack[-1] = $DB::single;
190              
191             # printf "++ \$DB::single for $sub: 0%x\n", $DB::single if $DB::single;
192             # Turn off all flags except single-stepping or return event.
193 0           $DB::single &= SINGLE_STEPPING_EVENT;
194              
195             # If we've gotten really deeply recursed, turn on the flag that will
196             # make us stop with the 'deep recursion' message.
197 0 0         $DB::single |= DEEP_RECURSION_EVENT if $#stack == $deep;
198             }
199              
200              
201             ####
202             # When debugging is enabled, this routine gets called instead of
203             # the orignal subroutine. $DB::sub contains the intended subroutine
204             # to be called. Thus, this routine must run &$DB::sub
205             # in order to get the original routine called. The fact that
206             # this routine is called instead allows us to wrap or put code
207             # around subroutine calls
208             #
209             sub DB::sub {
210             # Do not use a regex in this subroutine -> results in corrupted
211             # memory See: [perl #66110]
212              
213             # lock ourselves under threads
214 0 0   0 1   lock($DBGR) if $ENV{PERL5DB_THREADED};
215              
216             # Whether or not the autoloader was running, a scalar to put the
217             # sub's return value in (if needed), and an array to put the sub's
218             # return value in (if needed).
219 0           my ( $al, $ret, @ret ) = "";
220 0 0 0       if ($DB::sub eq 'threads::new' && $ENV{PERL5DB_THREADED}) {
221 0           print "creating new thread\n";
222             }
223              
224             # If the last ten characters are '::AUTOLOAD', note we've traced
225             # into AUTOLOAD for $DB::sub.
226 0 0 0       if ( length($DB::sub) > 10 && substr( $DB::sub, -10, 10 ) eq '::AUTOLOAD' ) {
227 12     12   99 no strict 'refs';
  12         27  
  12         2014  
228 0 0         $al = " for $$DB::sub" if defined $$DB::sub;
229             }
230              
231             # We stack the stack pointer and then increment it to protect us
232             # from a situation that might unwind a whole bunch of call frames
233             # at once. Localizing the stack pointer means that it will automatically
234             # unwind the same amount when multiple stack frames are unwound.
235 0           local $stack_depth = $stack_depth + 1; # Protect from non-local exits
236 0           push_DB_single_and_set();
237              
238 0 0 0       if (defined($DB::running) && $DB::running == 1) {
239 0           local @DB::_ = @_;
240 0           local(*DB::dbline) = "::_<$DB::filename";
241              
242             # FIXME: this isn't quite right;
243 0           $DB::addr = +B::svref_2object(\$DB::subroutine);
244              
245 0           check_for_stop();
246             }
247              
248             # FIXME: this isn't quite right. For mysterious reasons $DB::wantarray
249             # is tracking the wrong frame and is always @
250             # $DB::wantarray = $DB::wantarray ? '@' : ( defined $wantarray ? '$' : '.' );
251 0           $DB::wantarray = '?';
252              
253 0 0 0       if ($DB::sub eq 'DESTROY' or
    0 0        
254             substr($DB::sub, -9) eq '::DESTROY' or not defined wantarray) {
255 0           &$DB::sub;
256 12     12   83 no warnings 'uninitialized';
  12         31  
  12         672  
257 0           $DB::single |= pop(@stack);
258 0           $DB::ret = undef;
259             }
260             elsif (wantarray) {
261             # Called in array context. call sub and capture output.
262             # DB::DB will recursively get control again if appropriate;
263             # we'll come back here when the sub is finished.
264              
265             {
266 12     12   69 no strict 'refs';
  12         27  
  12         1264  
  0            
267             # call the original subroutine and save the array value.
268 0           @ret = &$DB::sub;
269             }
270              
271             # Pop the single-step value back off the stack.
272 0 0         if ($stack[$stack_depth]) {
273 0           $DB::single |= $stack[ $stack_depth-- ];
274 0 0         if ($single & RETURN_EVENT) {
275 0           $DB::return_type = 'array';
276 0           @DB::return_value = @ret;
277 0           DB::DB($DB::sub) ;
278 0           return @DB::return_value;
279             }
280             }
281 0           @ret;
282             } else {
283             # Called in array context. call sub and capture output.
284             # DB::DB will recursively get control again if appropriate;
285             # we'll come back here when the sub is finished.
286              
287 0 0         if ( defined wantarray ) {
288 12     12   118 no strict 'refs';
  12         30  
  12         472  
289             # call the original subroutine and save the array value.
290 0           $ret = &$DB::sub;
291             } else {
292 12     12   82 no strict 'refs';
  12         30  
  12         3443  
293             # Call the original lvalue sub and explicitly void the return
294             # value.
295 0           &$DB::sub;
296 0           undef $ret;
297             }
298              
299             # Pop the single-step value back off the stack.
300 0 0         $DB::single |= $stack[ $stack_depth-- ] if $stack[$stack_depth];
301 0 0         if ($single & RETURN_EVENT) {
302 0 0         $DB::return_type = defined $ret ? 'scalar' : 'undef';
303 0           $DB::return_value = $ret;
304 0           DB::DB($DB::sub) ;
305 0           return $DB::return_value;
306             }
307              
308             # Return the appropriate scalar value.
309 0           return $ret;
310             }
311             }
312              
313             ####
314             # When debugging is enabled, this routine gets called instead of the
315             # orignal subroutine in a left-hand (assignment) context. $DB::sub
316             # contains the intended subroutine to be called. Thus, this routine
317             # must run &$DB::sub in order to get the original routine called. The
318             # fact that this routine is called instead allows us to wrap or
319             # instrument code around subroutine calls.
320             #
321             sub DB::lsub : lvalue {
322             # Possibly [perl #66110] also applies here as in sub.
323              
324             # lock ourselves under threads
325 0 0   0 0   lock($DBGR) if $ENV{PERL5DB_THREADED};
326              
327             # Whether or not the autoloader was running, a scalar to put the
328             # sub's return value in (if needed), and an array to put the sub's
329             # return value in (if needed).
330 0           my ( $al, $ret, @ret ) = "";
331 0 0 0       if ($DB::sub =~ /^threads::new$/ && $ENV{PERL5DB_THREADED}) {
332 0           print "creating new thread\n";
333             }
334              
335             # If the last ten characters are '::AUTOLOAD', note we've traced
336             # into AUTOLOAD for $DB::sub.
337 0 0 0       if ( length($DB::sub) > 10 && substr( $DB::sub, -10, 10 ) eq '::AUTOLOAD' ) {
338 0 0         $al = " for $$DB::sub" if defined $$DB::sub;;
339             }
340              
341             # We stack the stack pointer and then increment it to protect us
342             # from a situation that might unwind a whole bunch of call frames
343             # at once. Localizing the stack pointer means that it will automatically
344             # unwind the same amount when multiple stack frames are unwound.
345 0           local $stack_depth = $stack_depth + 1; # Protect from non-local exits
346 0           push_DB_single_and_set();
347              
348 0           local(*DB::dbline) = "::_<$DB::filename";
349              
350             # FIXME: this isn't quite right;
351 0           $DB::addr = +B::svref_2object(\$DB::subroutine);
352              
353 0           check_for_stop();
354              
355 0 0         if (wantarray) {
356             # Called in array context. call sub and capture output.
357             # DB::DB will recursively get control again if appropriate; we'll come
358             # back here when the sub is finished.
359             {
360 12     12   85 no strict 'refs';
  12         30  
  12         1000  
  0            
361 0           @ret = &$DB::sub;
362             }
363              
364             # Pop the single-step value back off the stack.
365 0           $DB::single |= $stack[ $stack_depth-- ];
366 0 0         if ($DB::single & RETURN_EVENT) {
367 0           $DB::return_type = 'array';
368 0           @DB::return_value = @ret;
369 0           DB::DB($DB::sub) ;
370 0           return @DB::return_value;
371             }
372 0           @ret;
373             } else {
374             # Called in array context. call sub and capture output.
375             # DB::DB will recursively get control again if appropriate;
376             # we'll come back here when the sub is finished.
377              
378 0 0         if ( defined wantarray ) {
379 12     12   69 no strict 'refs';
  12         29  
  12         402  
380             # Save the value if it's wanted at all.
381 0           $ret = &$DB::sub;
382             } else {
383 12     12   69 no strict 'refs';
  12         28  
  12         2906  
384             # Void return, explicitly.
385 0           &$DB::sub;
386 0           undef $ret;
387             }
388              
389             # Pop the single-step value back off the stack.
390 0 0         $DB::single |= $stack[ $stack_depth-- ] if $stack[$stack_depth];
391 0 0         if ($DB::single & RETURN_EVENT) {
392 0 0         $DB::return_type = defined $ret ? 'scalar' : 'undef';
393 0           $DB::return_value = $ret;
394 0           DB::DB($DB::sub) ;
395 0           return $DB::return_value;
396             }
397              
398             # Return the appropriate scalar value.
399 0           return $ret;
400             }
401             }
402              
403             ####
404             # without args: returns all defined subroutine names
405             # with subname args: returns a listref [file, start, end]
406             #
407             sub subs {
408 0     0 0   my $s = shift;
409 0 0         if (@_) {
410 0           my(@ret) = ();
411 0           while (@_) {
412 0           my $name = shift;
413 0 0         next unless $name;
414             push @ret, [$DB::sub{$name} =~ /^(.*)\:(\d+)-(\d+)$/]
415 0 0         if exists $DB::sub{$name};
416             }
417 0           return @ret;
418             }
419 0           return keys %DB::sub;
420             }
421              
422             1;