Commit | Line | Data |
a687059c |
1 | package DB; |
2 | |
03a14243 |
3 | $header = '$Header: perldb.pl,v 3.0.1.1 89/10/26 23:14:02 lwall Locked $'; |
a687059c |
4 | # |
5 | # This file is automatically included if you do perl -d. |
6 | # It's probably not useful to include this yourself. |
7 | # |
8 | # Perl supplies the values for @line and %sub. It effectively inserts |
9 | # a do DB'DB(<linenum>); in front of every place that can |
10 | # have a breakpoint. It also inserts a do 'perldb.pl' before the first line. |
11 | # |
12 | # $Log: perldb.pl,v $ |
03a14243 |
13 | # Revision 3.0.1.1 89/10/26 23:14:02 lwall |
14 | # patch1: RCS expanded an unintended $Header in lib/perldb.pl |
15 | # |
a687059c |
16 | # Revision 3.0 89/10/18 15:19:46 lwall |
17 | # 3.0 baseline |
18 | # |
19 | # Revision 2.0 88/06/05 00:09:45 root |
20 | # Baseline version 2.0. |
21 | # |
22 | # |
23 | |
24 | open(IN,"/dev/tty"); # so we don't dingle stdin |
25 | open(OUT,">/dev/tty"); # so we don't dongle stdout |
26 | select(OUT); |
27 | $| = 1; # for DB'OUT |
28 | select(STDOUT); |
29 | $| = 1; # for real STDOUT |
30 | |
03a14243 |
31 | $header =~ s/.Header: ([^,]+),v(\s+\S+\s+\S+).*$/$1$2/; |
a687059c |
32 | print OUT "\nLoading DB from $header\n\n"; |
33 | |
34 | sub DB { |
35 | local($. ,$@, $!, $[, $,, $/, $\); |
36 | $[ = 0; $, = ""; $/ = "\n"; $\ = ""; |
37 | ($line) = @_; |
38 | if ($stop[$line]) { |
39 | if ($stop eq '1') { |
40 | $signal |= 1; |
41 | } |
42 | else { |
43 | package main; |
44 | $DB'signal |= eval $DB'stop[$DB'line]; print DB'OUT $@; |
45 | $DB'stop[$DB'line] =~ s/;9$//; |
46 | } |
47 | } |
48 | if ($single || $trace || $signal) { |
49 | print OUT "$sub($line):\t",$line[$line]; |
50 | for ($i = $line + 1; $i <= $max && $line[$i] == 0; ++$i) { |
51 | last if $line[$i] =~ /^\s*(}|#|\n)/; |
52 | print OUT "$sub($i):\t",$line[$i]; |
53 | } |
54 | } |
55 | if ($action[$line]) { |
56 | package main; |
57 | eval $DB'action[$DB'line]; print DB'OUT $@; |
58 | } |
59 | if ($single || $signal) { |
60 | if ($pre) { |
61 | package main; |
62 | eval $DB'pre; print DB'OUT $@; |
63 | } |
64 | print OUT $#stack . " levels deep in subroutine calls!\n" |
65 | if $single & 4; |
66 | $start = $line; |
67 | while ((print OUT " DB<", $#hist+1, "> "), $cmd=<IN>) { |
68 | $single = 0; |
69 | $signal = 0; |
70 | $cmd eq '' && exit 0; |
71 | chop($cmd); |
72 | $cmd =~ /^q$/ && exit 0; |
73 | $cmd =~ /^$/ && ($cmd = $laststep); |
74 | push(@hist,$cmd) if length($cmd) > 1; |
75 | ($i) = split(/\s+/,$cmd); |
76 | eval "\$cmd =~ $alias{$i}", print OUT $@ if $alias{$i}; |
77 | $cmd =~ /^h$/ && do { |
78 | print OUT " |
79 | T Stack trace. |
80 | s Single step. |
81 | n Next, steps over subroutine calls. |
82 | f Finish current subroutine. |
83 | c [line] Continue; optionally inserts a one-time-only breakpoint |
84 | at the specified line. |
85 | <CR> Repeat last n or s. |
86 | l min+incr List incr+1 lines starting at min. |
87 | l min-max List lines. |
88 | l line List line; |
89 | l List next window. |
90 | - List previous window. |
91 | w line List window around line. |
92 | l subname List subroutine. |
93 | /pattern/ Search forwards for pattern; final / is optional. |
94 | ?pattern? Search backwards for pattern. |
95 | L List breakpoints and actions. |
96 | S List subroutine names. |
97 | t Toggle trace mode. |
98 | b [line] [condition] |
99 | Set breakpoint; line defaults to the current execution line; |
100 | condition breaks if it evaluates to true, defaults to \'1\'. |
101 | b subname [condition] |
102 | Set breakpoint at first line of subroutine. |
103 | d [line] Delete breakpoint. |
104 | D Delete all breakpoints. |
105 | a [line] command |
106 | Set an action to be done before the line is executed. |
107 | Sequence is: check for breakpoint, print line if necessary, |
108 | do action, prompt user if breakpoint or step, evaluate line. |
109 | A Delete all actions. |
110 | V package List all variables and values in package (default main). |
111 | < command Define command before prompt. |
112 | > command Define command after prompt. |
113 | ! number Redo command (default previous command). |
114 | ! -number Redo number\'th to last command. |
115 | H -number Display last number commands (default all). |
116 | q or ^D Quit. |
117 | p expr Same as \"package main; print DB'OUT expr\". |
118 | command Execute as a perl statement. |
119 | |
120 | "; |
121 | next; }; |
122 | $cmd =~ /^t$/ && do { |
123 | $trace = !$trace; |
124 | print OUT "Trace = ".($trace?"on":"off")."\n"; |
125 | next; }; |
126 | $cmd =~ /^S$/ && do { |
127 | foreach $subname (sort(keys %sub)) { |
128 | if ($subname =~ /^main'(.*)/) { |
129 | print OUT $1,"\n"; |
130 | } |
131 | else { |
132 | print OUT $subname,"\n"; |
133 | } |
134 | } |
135 | next; }; |
136 | $cmd =~ /^V$/ && do { |
137 | $cmd = 'V main'; }; |
138 | $cmd =~ /^V\s*(['A-Za-z_]['\w]*)$/ && do { |
139 | $packname = $1; |
140 | do 'dumpvar.pl' unless defined &main'dumpvar; |
141 | if (defined &main'dumpvar) { |
142 | &main'dumpvar($packname); |
143 | } |
144 | else { |
145 | print DB'OUT "dumpvar.pl not available.\n"; |
146 | } |
147 | next; }; |
148 | $cmd =~ /^l\s*(['A-Za-z_]['\w]*)/ && do { |
149 | $subname = $1; |
150 | $subname = "main'" . $subname unless $subname =~ /'/; |
151 | $subrange = $sub{$subname}; |
152 | if ($subrange) { |
153 | if (eval($subrange) < -$window) { |
154 | $subrange =~ s/-.*/+/; |
155 | } |
156 | $cmd = "l $subrange"; |
157 | } else { |
158 | print OUT "Subroutine $1 not found.\n"; |
159 | next; |
160 | } }; |
161 | $cmd =~ /^w\s*(\d*)$/ && do { |
162 | $incr = $window - 1; |
163 | $start = $1 if $1; |
164 | $start -= $preview; |
165 | $cmd = 'l ' . $start . '-' . ($start + $incr); }; |
166 | $cmd =~ /^-$/ && do { |
167 | $incr = $window - 1; |
168 | $cmd = 'l ' . ($start-$window*2) . '+'; }; |
169 | $cmd =~ /^l$/ && do { |
170 | $incr = $window - 1; |
171 | $cmd = 'l ' . $start . '-' . ($start + $incr); }; |
172 | $cmd =~ /^l\s*(\d*)\+(\d*)$/ && do { |
173 | $start = $1 if $1; |
174 | $incr = $2; |
175 | $incr = $window - 1 unless $incr; |
176 | $cmd = 'l ' . $start . '-' . ($start + $incr); }; |
177 | $cmd =~ /^l\s*(([\d\$\.]+)([-,]([\d\$\.]+))?)?/ && do { |
178 | $end = (!$2) ? $max : ($4 ? $4 : $2); |
179 | $end = $max if $end > $max; |
180 | $i = $2; |
181 | $i = $line if $i eq '.'; |
182 | $i = 1 if $i < 1; |
183 | for (; $i <= $end; $i++) { |
184 | print OUT "$i:\t", $line[$i]; |
185 | last if $signal; |
186 | } |
187 | $start = $i; # remember in case they want more |
188 | $start = $max if $start > $max; |
189 | next; }; |
190 | $cmd =~ /^D$/ && do { |
191 | print OUT "Deleting all breakpoints...\n"; |
192 | for ($i = 1; $i <= $max ; $i++) { |
193 | $stop[$i] = 0; |
194 | } |
195 | next; }; |
196 | $cmd =~ /^L$/ && do { |
197 | for ($i = 1; $i <= $max; $i++) { |
198 | if ($stop[$i] || $action[$i]) { |
199 | print OUT "$i:\t", $line[$i]; |
200 | print OUT " break if (", $stop[$i], ")\n" |
201 | if $stop[$i]; |
202 | print OUT " action: ", $action[$i], "\n" |
203 | if $action[$i]; |
204 | last if $signal; |
205 | } |
206 | } |
207 | next; }; |
208 | $cmd =~ /^b\s*(['A-Za-z_]['\w]*)\s*(.*)/ && do { |
209 | $subname = $1; |
210 | $subname = "main'" . $subname unless $subname =~ /'/; |
211 | ($i) = split(/-/, $sub{$subname}); |
212 | if ($i) { |
213 | ++$i while $line[$i] == 0 && $i < $#line; |
214 | $stop[$i] = $2 ? $2 : 1; |
215 | } else { |
216 | print OUT "Subroutine $1 not found.\n"; |
217 | } |
218 | next; }; |
219 | $cmd =~ /^b\s*(\d*)\s*(.*)/ && do { |
220 | $i = ($1?$1:$line); |
221 | if ($line[$i] == 0) { |
222 | print OUT "Line $i not breakable.\n"; |
223 | } else { |
224 | $stop[$i] = $2 ? $2 : 1; |
225 | } |
226 | next; }; |
227 | $cmd =~ /^d\s*(\d+)?/ && do { |
228 | $i = ($1?$1:$line); |
229 | $stop[$i] = ''; |
230 | next; }; |
231 | $cmd =~ /^A$/ && do { |
232 | for ($i = 1; $i <= $max ; $i++) { |
233 | $action[$i] = ''; |
234 | } |
235 | next; }; |
236 | $cmd =~ /^<\s*(.*)/ && do { |
237 | $pre = do action($1); |
238 | next; }; |
239 | $cmd =~ /^>\s*(.*)/ && do { |
240 | $post = do action($1); |
241 | next; }; |
242 | $cmd =~ /^a\s*(\d+)(\s+(.*))?/ && do { |
243 | $i = $1; |
244 | if ($line[$i] == 0) { |
245 | print OUT "Line $i may not have an action.\n"; |
246 | } else { |
247 | $action[$i] = do action($3); |
248 | } |
249 | next; }; |
250 | $cmd =~ /^n$/ && do { |
251 | $single = 2; |
252 | $laststep = $cmd; |
253 | last; }; |
254 | $cmd =~ /^s$/ && do { |
255 | $single = 1; |
256 | $laststep = $cmd; |
257 | last; }; |
258 | $cmd =~ /^c\s*(\d*)\s*$/ && do { |
259 | $i = $1; |
260 | if ($i) { |
261 | if ($line[$i] == 0) { |
262 | print OUT "Line $i not breakable.\n"; |
263 | next; |
264 | } |
265 | $stop[$i] .= ";9"; # add one-time-only b.p. |
266 | } |
267 | for ($i=0; $i <= $#stack; ) { |
268 | $stack[$i++] &= ~1; |
269 | } |
270 | last; }; |
271 | $cmd =~ /^f$/ && do { |
272 | $stack[$#stack] |= 2; |
273 | last; }; |
274 | $cmd =~ /^T$/ && do { |
275 | for ($i=0; $i <= $#sub; ) { |
276 | print OUT $sub[$i++], "\n"; |
277 | last if $signal; |
278 | } |
279 | next; }; |
280 | $cmd =~ /^\/(.*)$/ && do { |
281 | $inpat = $1; |
282 | $inpat =~ s:([^\\])/$:$1:; |
283 | if ($inpat ne "") { |
284 | eval '$inpat =~ m'."\n$inpat\n"; |
285 | if ($@ ne "") { |
286 | print OUT "$@"; |
287 | next; |
288 | } |
289 | $pat = $inpat; |
290 | } |
291 | $end = $start; |
292 | eval ' |
293 | for (;;) { |
294 | ++$start; |
295 | $start = 1 if ($start > $max); |
296 | last if ($start == $end); |
297 | if ($line[$start] =~ m'."\n$pat\n".'i) { |
298 | print OUT "$start:\t", $line[$start], "\n"; |
299 | last; |
300 | } |
301 | } '; |
302 | print OUT "/$pat/: not found\n" if ($start == $end); |
303 | next; }; |
304 | $cmd =~ /^\?(.*)$/ && do { |
305 | $inpat = $1; |
306 | $inpat =~ s:([^\\])\?$:$1:; |
307 | if ($inpat ne "") { |
308 | eval '$inpat =~ m'."\n$inpat\n"; |
309 | if ($@ ne "") { |
310 | print OUT "$@"; |
311 | next; |
312 | } |
313 | $pat = $inpat; |
314 | } |
315 | $end = $start; |
316 | eval ' |
317 | for (;;) { |
318 | --$start; |
319 | $start = $max if ($start <= 0); |
320 | last if ($start == $end); |
321 | if ($line[$start] =~ m'."\n$pat\n".'i) { |
322 | print OUT "$start:\t", $line[$start], "\n"; |
323 | last; |
324 | } |
325 | } '; |
326 | print OUT "?$pat?: not found\n" if ($start == $end); |
327 | next; }; |
328 | $cmd =~ /^!+\s*(-)?(\d+)?$/ && do { |
329 | pop(@hist) if length($cmd) > 1; |
330 | $i = ($1?($#hist-($2?$2:1)):($2?$2:$#hist)); |
331 | $cmd = $hist[$i] . "\n"; |
332 | print OUT $cmd; |
333 | redo; }; |
334 | $cmd =~ /^!(.+)$/ && do { |
335 | $pat = "^$1"; |
336 | pop(@hist) if length($cmd) > 1; |
337 | for ($i = $#hist; $i; --$i) { |
338 | last if $hist[$i] =~ $pat; |
339 | } |
340 | if (!$i) { |
341 | print OUT "No such command!\n\n"; |
342 | next; |
343 | } |
344 | $cmd = $hist[$i] . "\n"; |
345 | print OUT $cmd; |
346 | redo; }; |
347 | $cmd =~ /^H\s*(-(\d+))?/ && do { |
348 | $end = $2?($#hist-$2):0; |
349 | $hist = 0 if $hist < 0; |
350 | for ($i=$#hist; $i>$end; $i--) { |
351 | print OUT "$i: ",$hist[$i],"\n" |
352 | unless $hist[$i] =~ /^.?$/; |
353 | }; |
354 | next; }; |
355 | $cmd =~ s/^p( .*)?$/print DB'OUT$1/; |
356 | { |
357 | package main; |
358 | eval $DB'cmd; |
359 | } |
360 | print OUT $@,"\n"; |
361 | } |
362 | if ($post) { |
363 | package main; |
364 | eval $DB'post; print DB'OUT $@; |
365 | } |
366 | } |
367 | } |
368 | |
369 | sub action { |
370 | local($action) = @_; |
371 | while ($action =~ s/\\$//) { |
372 | print OUT "+ "; |
373 | $action .= <IN>; |
374 | } |
375 | $action; |
376 | } |
377 | |
378 | sub catch { |
379 | $signal = 1; |
380 | } |
381 | |
382 | sub sub { |
383 | push(@stack, $single); |
384 | $single &= 1; |
385 | $single |= 4 if $#stack == $deep; |
386 | local(@args) = @_; |
387 | for (@args) { |
388 | if (/^Stab/ && length($_) == length($_main{'_main'})) { |
389 | $_ = sprintf("%s",$_); |
390 | print "ARG: $_\n"; |
391 | } |
392 | else { |
393 | s/'/\\'/g; |
394 | s/(.*)/'$1'/ unless /^-?[\d.]+$/; |
395 | } |
396 | } |
397 | push(@sub, $sub . '(' . join(', ', @args) . ') from ' . $line); |
398 | if (wantarray) { |
399 | @i = &$sub; |
400 | } |
401 | else { |
402 | $i = &$sub; |
403 | @i = $i; |
404 | } |
405 | --$#sub; |
406 | $single |= pop(@stack); |
407 | @i; |
408 | } |
409 | |
410 | $single = 1; # so it stops on first executable statement |
411 | $max = $#line; |
412 | @hist = ('?'); |
413 | $SIG{'INT'} = "DB'catch"; |
414 | $deep = 100; # warning if stack gets this deep |
415 | $window = 10; |
416 | $preview = 3; |
417 | |
418 | @stack = (0); |
419 | @args = @ARGV; |
420 | for (@args) { |
421 | s/'/\\'/g; |
422 | s/(.*)/'$1'/ unless /^-?[\d.]+$/; |
423 | } |
424 | push(@sub, 'main(' . join(', ', @args) . ")" ); |
425 | $sub = 'main'; |
426 | |
427 | if (-f '.perldb') { |
428 | do './.perldb'; |
429 | } |
430 | elsif (-f "$ENV{'LOGDIR'}/.perldb") { |
431 | do "$ENV{'LOGDIR'}/.perldb"; |
432 | } |
433 | elsif (-f "$ENV{'HOME'}/.perldb") { |
434 | do "$ENV{'HOME'}/.perldb"; |
435 | } |
436 | |
437 | 1; |