ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/staticperl/perl/lib/DB.pm
Revision: 1.1
Committed: Thu Jun 30 14:27:08 2005 UTC (21 years, 3 months ago) by root
Branch: MAIN
CVS Tags: PERL-5-8-7, HEAD
Branch point for: PERL
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 #
2     # Documentation is at the __END__
3     #
4    
5     package DB;
6    
7     # "private" globals
8    
9     my ($running, $ready, $deep, $usrctxt, $evalarg,
10     @stack, @saved, @skippkg, @clients);
11     my $preeval = {};
12     my $posteval = {};
13     my $ineval = {};
14    
15     ####
16     #
17     # Globals - must be defined at startup so that clients can refer to
18     # them right after a C<require DB;>
19     #
20     ####
21    
22     BEGIN {
23    
24     # these are hardcoded in perl source (some are magical)
25    
26     $DB::sub = ''; # name of current subroutine
27     %DB::sub = (); # "filename:fromline-toline" for every known sub
28     $DB::single = 0; # single-step flag (set it to 1 to enable stops in BEGIN/use)
29     $DB::signal = 0; # signal flag (will cause a stop at the next line)
30     $DB::trace = 0; # are we tracing through subroutine calls?
31     @DB::args = (); # arguments of current subroutine or @ARGV array
32     @DB::dbline = (); # list of lines in currently loaded file
33     %DB::dbline = (); # actions in current file (keyed by line number)
34     @DB::ret = (); # return value of last sub executed in list context
35     $DB::ret = ''; # return value of last sub executed in scalar context
36    
37     # other "public" globals
38    
39     $DB::package = ''; # current package space
40     $DB::filename = ''; # current filename
41     $DB::subname = ''; # currently executing sub (fullly qualified name)
42     $DB::lineno = ''; # current line number
43    
44     $DB::VERSION = $DB::VERSION = '1.0';
45    
46     # initialize private globals to avoid warnings
47    
48     $running = 1; # are we running, or are we stopped?
49     @stack = (0);
50     @clients = ();
51     $deep = 100;
52     $ready = 0;
53     @saved = ();
54     @skippkg = ();
55     $usrctxt = '';
56     $evalarg = '';
57     }
58    
59     ####
60     # entry point for all subroutine calls
61     #
62     sub sub {
63     push(@stack, $DB::single);
64     $DB::single &= 1;
65     $DB::single |= 4 if $#stack == $deep;
66     # print $DB::sub, "\n";
67     if ($DB::sub =~ /(?:^|::)DESTROY$/ or not defined wantarray) {
68     &$DB::sub;
69     $DB::single |= pop(@stack);
70     $DB::ret = undef;
71     }
72     elsif (wantarray) {
73     @DB::ret = &$DB::sub;
74     $DB::single |= pop(@stack);
75     @DB::ret;
76     }
77     else {
78     $DB::ret = &$DB::sub;
79     $DB::single |= pop(@stack);
80     $DB::ret;
81     }
82     }
83    
84     ####
85     # this is called by perl for every statement
86     #
87     sub DB {
88     return unless $ready;
89     &save;
90     ($DB::package, $DB::filename, $DB::lineno) = caller;
91    
92     return if @skippkg and grep { $_ eq $DB::package } @skippkg;
93    
94     $usrctxt = "package $DB::package;"; # this won't let them modify, alas
95     local(*DB::dbline) = "::_<$DB::filename";
96    
97     # we need to check for pseudofiles on Mac OS (these are files
98     # not attached to a filename, but instead stored in Dev:Pseudo)
99     # since this is done late, $DB::filename will be "wrong" after
100     # skippkg
101     if ($^O eq 'MacOS' && $#DB::dbline < 0) {
102     $DB::filename = 'Dev:Pseudo';
103     *DB::dbline = "::_<$DB::filename";
104     }
105    
106     my ($stop, $action);
107     if (($stop,$action) = split(/\0/,$DB::dbline{$DB::lineno})) {
108     if ($stop eq '1') {
109     $DB::signal |= 1;
110     }
111     else {
112     $stop = 0 unless $stop; # avoid un_init warning
113     $evalarg = "\$DB::signal |= do { $stop; }"; &eval;
114     $DB::dbline{$DB::lineno} =~ s/;9($|\0)/$1/; # clear any temp breakpt
115     }
116     }
117     if ($DB::single || $DB::trace || $DB::signal) {
118     $DB::subname = ($DB::sub =~ /\'|::/) ? $DB::sub : "${DB::package}::$DB::sub"; #';
119     DB->loadfile($DB::filename, $DB::lineno);
120     }
121     $evalarg = $action, &eval if $action;
122     if ($DB::single || $DB::signal) {
123     _outputall($#stack . " levels deep in subroutine calls.\n") if $DB::single & 4;
124     $DB::single = 0;
125     $DB::signal = 0;
126     $running = 0;
127    
128     &eval if ($evalarg = DB->prestop);
129     my $c;
130     for $c (@clients) {
131     # perform any client-specific prestop actions
132     &eval if ($evalarg = $c->cprestop);
133    
134     # Now sit in an event loop until something sets $running
135     do {
136     $c->idle; # call client event loop; must not block
137     if ($running == 2) { # client wants something eval-ed
138     &eval if ($evalarg = $c->evalcode);
139     $running = 0;
140     }
141     } until $running;
142    
143     # perform any client-specific poststop actions
144     &eval if ($evalarg = $c->cpoststop);
145     }
146     &eval if ($evalarg = DB->poststop);
147     }
148     ($@, $!, $,, $/, $\, $^W) = @saved;
149     ();
150     }
151    
152     ####
153     # this takes its argument via $evalarg to preserve current @_
154     #
155     sub eval {
156     ($@, $!, $,, $/, $\, $^W) = @saved;
157     eval "$usrctxt $evalarg; &DB::save";
158     _outputall($@) if $@;
159     }
160    
161     ###############################################################################
162     # no compile-time subroutine call allowed before this point #
163     ###############################################################################
164    
165     use strict; # this can run only after DB() and sub() are defined
166    
167     sub save {
168     @saved = ($@, $!, $,, $/, $\, $^W);
169     $, = ""; $/ = "\n"; $\ = ""; $^W = 0;
170     }
171    
172     sub catch {
173     for (@clients) { $_->awaken; }
174     $DB::signal = 1;
175     $ready = 1;
176     }
177    
178     ####
179     #
180     # Client callable (read inheritable) methods defined after this point
181     #
182     ####
183    
184     sub register {
185     my $s = shift;
186     $s = _clientname($s) if ref($s);
187     push @clients, $s;
188     }
189    
190     sub done {
191     my $s = shift;
192     $s = _clientname($s) if ref($s);
193     @clients = grep {$_ ne $s} @clients;
194     $s->cleanup;
195     # $running = 3 unless @clients;
196     exit(0) unless @clients;
197     }
198    
199     sub _clientname {
200     my $name = shift;
201     "$name" =~ /^(.+)=[A-Z]+\(.+\)$/;
202     return $1;
203     }
204    
205     sub next {
206     my $s = shift;
207     $DB::single = 2;
208     $running = 1;
209     }
210    
211     sub step {
212     my $s = shift;
213     $DB::single = 1;
214     $running = 1;
215     }
216    
217     sub cont {
218     my $s = shift;
219     my $i = shift;
220     $s->set_tbreak($i) if $i;
221     for ($i = 0; $i <= $#stack;) {
222     $stack[$i++] &= ~1;
223     }
224     $DB::single = 0;
225     $running = 1;
226     }
227    
228     ####
229     # XXX caller must experimentally determine $i (since it depends
230     # on how many client call frames are between this call and the DB call).
231     # Such is life.
232     #
233     sub ret {
234     my $s = shift;
235     my $i = shift; # how many levels to get to DB sub
236     $i = 0 unless defined $i;
237     $stack[$#stack-$i] |= 1;
238     $DB::single = 0;
239     $running = 1;
240     }
241    
242     ####
243     # XXX caller must experimentally determine $start (since it depends
244     # on how many client call frames are between this call and the DB call).
245     # Such is life.
246     #
247     sub backtrace {
248     my $self = shift;
249     my $start = shift;
250     my($p,$f,$l,$s,$h,$w,$e,$r,$a, @a, @ret,$i);
251     $start = 1 unless $start;
252     for ($i = $start; ($p,$f,$l,$s,$h,$w,$e,$r) = caller($i); $i++) {
253     @a = @DB::args;
254     for (@a) {
255     s/'/\\'/g;
256     s/([^\0]*)/'$1'/ unless /^-?[\d.]+$/;
257     s/([\200-\377])/sprintf("M-%c",ord($1)&0177)/eg;
258     s/([\0-\37\177])/sprintf("^%c",ord($1)^64)/eg;
259     }
260     $w = $w ? '@ = ' : '$ = ';
261     $a = $h ? '(' . join(', ', @a) . ')' : '';
262     $e =~ s/\n\s*\;\s*\Z// if $e;
263     $e =~ s/[\\\']/\\$1/g if $e;
264     if ($r) {
265     $s = "require '$e'";
266     } elsif (defined $r) {
267     $s = "eval '$e'";
268     } elsif ($s eq '(eval)') {
269     $s = "eval {...}";
270     }
271     $f = "file `$f'" unless $f eq '-e';
272     push @ret, "$w&$s$a from $f line $l";
273     last if $DB::signal;
274     }
275     return @ret;
276     }
277    
278     sub _outputall {
279     my $c;
280     for $c (@clients) {
281     $c->output(@_);
282     }
283     }
284    
285     sub trace_toggle {
286     my $s = shift;
287     $DB::trace = !$DB::trace;
288     }
289    
290    
291     ####
292     # without args: returns all defined subroutine names
293     # with subname args: returns a listref [file, start, end]
294     #
295     sub subs {
296     my $s = shift;
297     if (@_) {
298     my(@ret) = ();
299     while (@_) {
300     my $name = shift;
301     push @ret, [$DB::sub{$name} =~ /^(.*)\:(\d+)-(\d+)$/]
302     if exists $DB::sub{$name};
303     }
304     return @ret;
305     }
306     return keys %DB::sub;
307     }
308    
309     ####
310     # first argument is a filename whose subs will be returned
311     # if a filename is not supplied, all subs in the current
312     # filename are returned.
313     #
314     sub filesubs {
315     my $s = shift;
316     my $fname = shift;
317     $fname = $DB::filename unless $fname;
318     return grep { $DB::sub{$_} =~ /^$fname/ } keys %DB::sub;
319     }
320    
321     ####
322     # returns a list of all filenames that DB knows about
323     #
324     sub files {
325     my $s = shift;
326     my(@f) = grep(m|^_<|, keys %main::);
327     return map { substr($_,2) } @f;
328     }
329    
330     ####
331     # returns reference to an array holding the lines in currently
332     # loaded file
333     #
334     sub lines {
335     my $s = shift;
336     return \@DB::dbline;
337     }
338    
339     ####
340     # loadfile($file, $line)
341     #
342     sub loadfile {
343     my $s = shift;
344     my($file, $line) = @_;
345     if (!defined $main::{'_<' . $file}) {
346     my $try;
347     if (($try) = grep(m|^_<.*$file|, keys %main::)) {
348     $file = substr($try,2);
349     }
350     }
351     if (defined($main::{'_<' . $file})) {
352     my $c;
353     # _outputall("Loading file $file..");
354     *DB::dbline = "::_<$file";
355     $DB::filename = $file;
356     for $c (@clients) {
357     # print "2 ", $file, '|', $line, "\n";
358     $c->showfile($file, $line);
359     }
360     return $file;
361     }
362     return undef;
363     }
364    
365     sub lineevents {
366     my $s = shift;
367     my $fname = shift;
368     my(%ret) = ();
369     my $i;
370     $fname = $DB::filename unless $fname;
371     local(*DB::dbline) = "::_<$fname";
372     for ($i = 1; $i <= $#DB::dbline; $i++) {
373     $ret{$i} = [$DB::dbline[$i], split(/\0/, $DB::dbline{$i})]
374     if defined $DB::dbline{$i};
375     }
376     return %ret;
377     }
378    
379     sub set_break {
380     my $s = shift;
381     my $i = shift;
382     my $cond = shift;
383     $i ||= $DB::lineno;
384     $cond ||= '1';
385     $i = _find_subline($i) if ($i =~ /\D/);
386     $s->output("Subroutine not found.\n") unless $i;
387     if ($i) {
388     if ($DB::dbline[$i] == 0) {
389     $s->output("Line $i not breakable.\n");
390     }
391     else {
392     $DB::dbline{$i} =~ s/^[^\0]*/$cond/;
393     }
394     }
395     }
396    
397     sub set_tbreak {
398     my $s = shift;
399     my $i = shift;
400     $i = _find_subline($i) if ($i =~ /\D/);
401     $s->output("Subroutine not found.\n") unless $i;
402     if ($i) {
403     if ($DB::dbline[$i] == 0) {
404     $s->output("Line $i not breakable.\n");
405     }
406     else {
407     $DB::dbline{$i} =~ s/($|\0)/;9$1/; # add one-time-only b.p.
408     }
409     }
410     }
411    
412     sub _find_subline {
413     my $name = shift;
414     $name =~ s/\'/::/;
415     $name = "${DB::package}\:\:" . $name if $name !~ /::/;
416     $name = "main" . $name if substr($name,0,2) eq "::";
417     my($fname, $from, $to) = ($DB::sub{$name} =~ /^(.*):(\d+)-(\d+)$/);
418     if ($from) {
419     local *DB::dbline = "::_<$fname";
420     ++$from while $DB::dbline[$from] == 0 && $from < $to;
421     return $from;
422     }
423     return undef;
424     }
425    
426     sub clr_breaks {
427     my $s = shift;
428     my $i;
429     if (@_) {
430     while (@_) {
431     $i = shift;
432     $i = _find_subline($i) if ($i =~ /\D/);
433     $s->output("Subroutine not found.\n") unless $i;
434     if (defined $DB::dbline{$i}) {
435     $DB::dbline{$i} =~ s/^[^\0]+//;
436     if ($DB::dbline{$i} =~ s/^\0?$//) {
437     delete $DB::dbline{$i};
438     }
439     }
440     }
441     }
442     else {
443     for ($i = 1; $i <= $#DB::dbline ; $i++) {
444     if (defined $DB::dbline{$i}) {
445     $DB::dbline{$i} =~ s/^[^\0]+//;
446     if ($DB::dbline{$i} =~ s/^\0?$//) {
447     delete $DB::dbline{$i};
448     }
449     }
450     }
451     }
452     }
453    
454     sub set_action {
455     my $s = shift;
456     my $i = shift;
457     my $act = shift;
458     $i = _find_subline($i) if ($i =~ /\D/);
459     $s->output("Subroutine not found.\n") unless $i;
460     if ($i) {
461     if ($DB::dbline[$i] == 0) {
462     $s->output("Line $i not actionable.\n");
463     }
464     else {
465     $DB::dbline{$i} =~ s/\0[^\0]*//;
466     $DB::dbline{$i} .= "\0" . $act;
467     }
468     }
469     }
470    
471     sub clr_actions {
472     my $s = shift;
473     my $i;
474     if (@_) {
475     while (@_) {
476     my $i = shift;
477     $i = _find_subline($i) if ($i =~ /\D/);
478     $s->output("Subroutine not found.\n") unless $i;
479     if ($i && $DB::dbline[$i] != 0) {
480     $DB::dbline{$i} =~ s/\0[^\0]*//;
481     delete $DB::dbline{$i} if $DB::dbline{$i} =~ s/^\0?$//;
482     }
483     }
484     }
485     else {
486     for ($i = 1; $i <= $#DB::dbline ; $i++) {
487     if (defined $DB::dbline{$i}) {
488     $DB::dbline{$i} =~ s/\0[^\0]*//;
489     delete $DB::dbline{$i} if $DB::dbline{$i} =~ s/^\0?$//;
490     }
491     }
492     }
493     }
494    
495     sub prestop {
496     my ($client, $val) = @_;
497     return defined($val) ? $preeval->{$client} = $val : $preeval->{$client};
498     }
499    
500     sub poststop {
501     my ($client, $val) = @_;
502     return defined($val) ? $posteval->{$client} = $val : $posteval->{$client};
503     }
504    
505     #
506     # "pure virtual" methods
507     #
508    
509     # client-specific pre/post-stop actions.
510     sub cprestop {}
511     sub cpoststop {}
512    
513     # client complete startup
514     sub awaken {}
515    
516     sub skippkg {
517     my $s = shift;
518     push @skippkg, @_ if @_;
519     }
520    
521     sub evalcode {
522     my ($client, $val) = @_;
523     if (defined $val) {
524     $running = 2; # hand over to DB() to evaluate in its context
525     $ineval->{$client} = $val;
526     }
527     return $ineval->{$client};
528     }
529    
530     sub ready {
531     my $s = shift;
532     return $ready = 1;
533     }
534    
535     # stubs
536    
537     sub init {}
538     sub stop {}
539     sub idle {}
540     sub cleanup {}
541     sub output {}
542    
543     #
544     # client init
545     #
546     for (@clients) { $_->init }
547    
548     $SIG{'INT'} = \&DB::catch;
549    
550     # disable this if stepping through END blocks is desired
551     # (looks scary and deconstructivist with Swat)
552     END { $ready = 0 }
553    
554     1;
555     __END__
556    
557     =head1 NAME
558    
559     DB - programmatic interface to the Perl debugging API (draft, subject to
560     change)
561    
562     =head1 SYNOPSIS
563    
564     package CLIENT;
565     use DB;
566     @ISA = qw(DB);
567    
568     # these (inherited) methods can be called by the client
569    
570     CLIENT->register() # register a client package name
571     CLIENT->done() # de-register from the debugging API
572     CLIENT->skippkg('hide::hide') # ask DB not to stop in this package
573     CLIENT->cont([WHERE]) # run some more (until BREAK or another breakpt)
574     CLIENT->step() # single step
575     CLIENT->next() # step over
576     CLIENT->ret() # return from current subroutine
577     CLIENT->backtrace() # return the call stack description
578     CLIENT->ready() # call when client setup is done
579     CLIENT->trace_toggle() # toggle subroutine call trace mode
580     CLIENT->subs([SUBS]) # return subroutine information
581     CLIENT->files() # return list of all files known to DB
582     CLIENT->lines() # return lines in currently loaded file
583     CLIENT->loadfile(FILE,LINE) # load a file and let other clients know
584     CLIENT->lineevents() # return info on lines with actions
585     CLIENT->set_break([WHERE],[COND])
586     CLIENT->set_tbreak([WHERE])
587     CLIENT->clr_breaks([LIST])
588     CLIENT->set_action(WHERE,ACTION)
589     CLIENT->clr_actions([LIST])
590     CLIENT->evalcode(STRING) # eval STRING in executing code's context
591     CLIENT->prestop([STRING]) # execute in code context before stopping
592     CLIENT->poststop([STRING])# execute in code context before resuming
593    
594     # These methods will be called at the appropriate times.
595     # Stub versions provided do nothing.
596     # None of these can block.
597    
598     CLIENT->init() # called when debug API inits itself
599     CLIENT->stop(FILE,LINE) # when execution stops
600     CLIENT->idle() # while stopped (can be a client event loop)
601     CLIENT->cleanup() # just before exit
602     CLIENT->output(LIST) # called to print any output that API must show
603    
604     =head1 DESCRIPTION
605    
606     Perl debug information is frequently required not just by debuggers,
607     but also by modules that need some "special" information to do their
608     job properly, like profilers.
609    
610     This module abstracts and provides all of the hooks into Perl internal
611     debugging functionality, so that various implementations of Perl debuggers
612     (or packages that want to simply get at the "privileged" debugging data)
613     can all benefit from the development of this common code. Currently used
614     by Swat, the perl/Tk GUI debugger.
615    
616     Note that multiple "front-ends" can latch into this debugging API
617     simultaneously. This is intended to facilitate things like
618     debugging with a command line and GUI at the same time, debugging
619     debuggers etc. [Sounds nice, but this needs some serious support -- GSAR]
620    
621     In particular, this API does B<not> provide the following functions:
622    
623     =over 4
624    
625     =item *
626    
627     data display
628    
629     =item *
630    
631     command processing
632    
633     =item *
634    
635     command alias management
636    
637     =item *
638    
639     user interface (tty or graphical)
640    
641     =back
642    
643     These are intended to be services performed by the clients of this API.
644    
645     This module attempts to be squeaky clean w.r.t C<use strict;> and when
646     warnings are enabled.
647    
648    
649     =head2 Global Variables
650    
651     The following "public" global names can be read by clients of this API.
652     Beware that these should be considered "readonly".
653    
654     =over 8
655    
656     =item $DB::sub
657    
658     Name of current executing subroutine.
659    
660     =item %DB::sub
661    
662     The keys of this hash are the names of all the known subroutines. Each value
663     is an encoded string that has the sprintf(3) format
664     C<("%s:%d-%d", filename, fromline, toline)>.
665    
666     =item $DB::single
667    
668     Single-step flag. Will be true if the API will stop at the next statement.
669    
670     =item $DB::signal
671    
672     Signal flag. Will be set to a true value if a signal was caught. Clients may
673     check for this flag to abort time-consuming operations.
674    
675     =item $DB::trace
676    
677     This flag is set to true if the API is tracing through subroutine calls.
678    
679     =item @DB::args
680    
681     Contains the arguments of current subroutine, or the C<@ARGV> array if in the
682     toplevel context.
683    
684     =item @DB::dbline
685    
686     List of lines in currently loaded file.
687    
688     =item %DB::dbline
689    
690     Actions in current file (keys are line numbers). The values are strings that
691     have the sprintf(3) format C<("%s\000%s", breakcondition, actioncode)>.
692    
693     =item $DB::package
694    
695     Package namespace of currently executing code.
696    
697     =item $DB::filename
698    
699     Currently loaded filename.
700    
701     =item $DB::subname
702    
703     Fully qualified name of currently executing subroutine.
704    
705     =item $DB::lineno
706    
707     Line number that will be executed next.
708    
709     =back
710    
711     =head2 API Methods
712    
713     The following are methods in the DB base class. A client must
714     access these methods by inheritance (*not* by calling them directly),
715     since the API keeps track of clients through the inheritance
716     mechanism.
717    
718     =over 8
719    
720     =item CLIENT->register()
721    
722     register a client object/package
723    
724     =item CLIENT->evalcode(STRING)
725    
726     eval STRING in executing code context
727    
728     =item CLIENT->skippkg('D::hide')
729    
730     ask DB not to stop in these packages
731    
732     =item CLIENT->run()
733    
734     run some more (until a breakpt is reached)
735    
736     =item CLIENT->step()
737    
738     single step
739    
740     =item CLIENT->next()
741    
742     step over
743    
744     =item CLIENT->done()
745    
746     de-register from the debugging API
747    
748     =back
749    
750     =head2 Client Callback Methods
751    
752     The following "virtual" methods can be defined by the client. They will
753     be called by the API at appropriate points. Note that unless specified
754     otherwise, the debug API only defines empty, non-functional default versions
755     of these methods.
756    
757     =over 8
758    
759     =item CLIENT->init()
760    
761     Called after debug API inits itself.
762    
763     =item CLIENT->prestop([STRING])
764    
765     Usually inherited from DB package. If no arguments are passed,
766     returns the prestop action string.
767    
768     =item CLIENT->stop()
769    
770     Called when execution stops (w/ args file, line).
771    
772     =item CLIENT->idle()
773    
774     Called while stopped (can be a client event loop).
775    
776     =item CLIENT->poststop([STRING])
777    
778     Usually inherited from DB package. If no arguments are passed,
779     returns the poststop action string.
780    
781     =item CLIENT->evalcode(STRING)
782    
783     Usually inherited from DB package. Ask for a STRING to be C<eval>-ed
784     in executing code context.
785    
786     =item CLIENT->cleanup()
787    
788     Called just before exit.
789    
790     =item CLIENT->output(LIST)
791    
792     Called when API must show a message (warnings, errors etc.).
793    
794    
795     =back
796    
797    
798     =head1 BUGS
799    
800     The interface defined by this module is missing some of the later additions
801     to perl's debugging functionality. As such, this interface should be considered
802     highly experimental and subject to change.
803    
804     =head1 AUTHOR
805    
806     Gurusamy Sarathy gsar@activestate.com
807    
808     This code heavily adapted from an early version of perl5db.pl attributable
809     to Larry Wall and the Perl Porters.
810    
811     =cut