Search                        Top                                  Index
HELP DEBUGGER                                Simon Nichols, October 1993

    lib debugger;

A source-level debugger for Pop-11.


         CONTENTS - (Use <ENTER> g to access required sections)

  1   Introduction

  2   Compiling in debugging mode

  3   Turning off debugging

  4   Autoloading

  5   Automatically entering the debugger after a mishap or interrupt

  6   Setting a breakpoint from outside the debugger

  7   The current file

  8   Procedure specifications

  9   Action at a breakpoint

 10   Interaction inside Ved

 11   Interaction outside Ved

 12   Printing

 13   Commands
      13.1  ?
      13.2  abort
      13.3  animate
      13.4  backtrace [all]
      13.5  breakpoints
      13.6  continue
      13.7  default [<command>]
      13.8  delete <breakpoint number>
      13.9  down
      13.10 frame [<frame number>]
      13.11 help
      13.12 ignore [only] [<procedure spec>]
      13.13 inspect <variable name>
      13.14 next
      13.15 pop11
      13.16 print <variable names>
      13.17 quit
      13.18 return [<expression>]
      13.19 skip
      13.20 source
      13.21 step
      13.22 stop
      13.23 stop at [<file> :] <line>
      13.24 stop in <procedure spec>
      13.25 stop here
      13.26 trace <procedure spec>
      13.27 unignore [only] [<procedure spec>]
      13.28 untrace <procedure spec>
      13.29 up
      13.30 userstack [<depth>]
      13.31 : <Pop-11 statement>
      13.32 where

 14   Command scripts

 15   Problems
      15.1  Reloading parts of files
      15.2  dlocal expressions
      15.3  Specifying with_props in the define header


-----------------------------------------------------------------------
1  Introduction
-----------------------------------------------------------------------

This library package defines a source-level debugger for Pop-11. The
debugger accepts commands in terms of the source files, line numbers and
variable names of your program. In particular, it enables you to:

    # set breakpoints on source line numbers and source procedures;

    # single-step execution;

    # examine and update all variables, including lexical ones;

    # change the current execution context by moving up and down the
      call stack;

    # execute Pop-11 code in the current execution context.


-----------------------------------------------------------------------
2  Compiling in debugging mode
-----------------------------------------------------------------------

To make use of the debugger, you need do nothing more than load the
debugger library:

    lib debugger;

or

    uses debugger;

and ensure that * POP_DEBUGGING has a non-<false> value. After this, all
compilation, whether performed inside or outside Ved, will result in
procedures which can be debugged.

The debugger works by redefining the VM code planting procedures (see
REF * VMCODE) to add extra code to each procedure in order to maintain
the values of run-time state information required by the debugger and
also to plant checkpoints in the code corresponding to the boundaries
between source lines. When the procedure is executed, the checkpoint
code may invoke the debugger, depending on whether you have a breakpoint
set on the corresponding line or are single-stepping.

As a result, code compiled in debugging mode is both bulkier and runs
slower than code which is compiled normally.

Note that only procedures which have been compiled in debugging mode can
be debugged, i.e., you can only set breakpoints on such procedures.


-----------------------------------------------------------------------
3  Turning off debugging
-----------------------------------------------------------------------

To turn off all debugging, assign <false> to the variable
debugger_debugging. This means both that code subsequently compiled will
not have the extra debugging code planted and also that any code already
compiled in debugging mode will execute without calling the debugger.

Once you have debugged your program, you can assign <false> to
debugger_debugging and recompile the program. If you need the debugger
again, just reassign <true> to debugger_debugging.

The two aspects of debugging (compilation and execution) can be
independently switched on or off by assigning one of the words "compile"
or "execute" to the variable debugger_debugging.

Assigning "compile" to debugger_debugging means that code will be
compiled in debugging mode, but when it (or any code already compiled in
debugging mode) is executed the debugger will not be invoked. (Note that
you can selectively turn off debugging for particular procedures by
means of the debugger ignore command: see below.)

Assigning "execute" to debugger_debugging means that when you execute
code already compiled in debugging mode it will invoke the debugger, but
any code subsequently compiled will not have the extra debugging code
planted.

Regardless of the value of debugger_debugging, no debugging takes place
unless the value of pop_debugging is non-<false>.


-----------------------------------------------------------------------
4  Autoloading
-----------------------------------------------------------------------

Libraries that are autoloaded are never compiled in debugging mode:
debugging is always disabled when autoloading is taking place. This is
to prevent common Pop-11 utility procedures and Ved commands from
invoking the debugger.


-----------------------------------------------------------------------
5  Automatically entering the debugger after a mishap or interrupt
-----------------------------------------------------------------------

The debugger defines a procedure debugger_interrupt which you may assign
to interrupt to cause interrupts and mishaps to invoke the debugger.
This is not done by default.

Note that if you use the load marked range facility in Ved (see
HELP * LMR) to load a line which only assigns to interrupt, this will
have no effect as ved_lmr locally redefines the interrupt procedure. You
should load a marked range which includes both an assignment to
interrupt and a call to the code you wish to debug. Alternatively.
either assign to interrupt outside of Ved, or in immediate mode (see
HELP * IM).


-----------------------------------------------------------------------
6  Setting a breakpoint from outside the debugger
-----------------------------------------------------------------------

To set a breakpoint on a procedure from outside the debugger, use either
the macro stopin, i.e.

    stopin <procedure spec>;

or the Ved command  ved_stopin, i.e.

    <ENTER> stopin <procedure spec>

For a definition of <procedure spec>, see the section below entitled
"Procedure specifications".

Setting a breakpoint on a procedure has the same effect as setting a
breakpoint on the line containing the first (executable) statement
within the procedure. However, breakpoints can only be set on line
numbers from within the debugger.


-----------------------------------------------------------------------
7  The current file
-----------------------------------------------------------------------

This help file will sometimes refer to the current file. If you are
debugging a program and are stopped at a breakpoint in some procedure P,
the file in which P is defined is the current file.


-----------------------------------------------------------------------
8  Procedure specifications
-----------------------------------------------------------------------

Many of the commands listed below, the Pop-11 macro stopin and the Ved
command ved_stopin take a procedure specification as argument (referred
to in this help file as <procedure spec>). This has the general form:

    [ <file> : ] [ <section prefix> ] [ <name prefix> ] <name>

Here, <name> is the name of the procedure and must be given, e.g.

    insert

If the procedure is defined locally to another, you must prefix its name
with the name of its parent. The two names are separated by a dot, e.g.

    sort.insert

if the definition of insert is nested inside the definition of sort. If
the parent is itself a local procedure, you must add another prefix for
its parent, and so on, e.g.

    create_set.sort.insert

If the procedure is defined in a section, you can prefix the name with
its section pathname (see REF * SECTIONS) to remove any potential
ambiguity, e.g.

    $-set_utils$-create_set.sort.insert

Finally, <file> is the name (as a string) of the file in which the
procedure is defined, e.g.

    'set_utils.p' : $-set_utils$-create_set.sort.insert

If a <file> is not given, the current file (see above) is used. If there
is no current file, the debugger searches all the files which have been
loaded in debugging mode for a procedure with the given name.


-----------------------------------------------------------------------
9  Action at a breakpoint
-----------------------------------------------------------------------

When a procedure has a breakpoint set on it or on one of its source
lines, invoking it by any means will cause execution to pause at the
breakpoint and a message to be printed showing the file name and line
number of the source line that is about to be executed. For example:

    [Breakpoint] '/csuna/home/simonn/pop/test.p' : foo, line 16

The debugger command loop is then entered, and the debugger will prompt
for input. The debugger prompt is:

    debug(N):

where N is an integer representing the current debugger level.

In the debugger command loop, any of the commands listed below may be
given. Commands which do not cause execution of your program to resume
will return to the debugger command loop when they have completed.


-----------------------------------------------------------------------
10  Interaction inside Ved
-----------------------------------------------------------------------

When using the debugger in Ved, all debugger interaction (requests for
commands and output from commands) takes place in the immediate mode Ved
buffer (see HELP * IM), since this is where Ved-based interaction with
Poplog languages usually takes place. Although this means that program
interaction and debugger interaction take place in the same Ved buffer,
this does save excessive switching between buffers (at least three if a
program performs any input or output).

Single-stepping causes the source file containing the relevant procedure
to be edited. The cursor is positioned on the line being executed and is
moved as execution proceeds.


-----------------------------------------------------------------------
11  Interaction outside Ved
-----------------------------------------------------------------------

Although the debugger is really designed for use in Ved, it is quite
usable outside (at the Pop-11 top level). The main difference (not
surprisingly) is that stopping at a breakpoint does not cause the file
containing the procedure with the breakpoint to be edited. Instead, each
source line is printed as it is executed. This can sometimes be
confusing: however, if you get lost as to exactly what's being executed,
use the backtrace or where commands, described below.


-----------------------------------------------------------------------
12  Printing
-----------------------------------------------------------------------

All printing by the debugger is done with pr locally assigned the value
of the procedure variable debugger_pr. By default, debugger_pr has the
value * SYSPR, so that any customized printing procedures you may have
defined as the * CLASS_PRINT of particular items' keys will be invoked.

You can change the value of debugger_pr; for example, if there is an
error in one of your customized printing routines and you would prefer
printing done using * SYS_SYSPR (Poplog's standard printing procedure),
just assign sys_syspr to debugger_pr

    sys_syspr -> debugger_pr;

To restore the default behaviour, do

    syspr -> debugger_pr;


-----------------------------------------------------------------------
13  Commands
-----------------------------------------------------------------------

The following sections outline the available commands. A particularly
useful command is ? which lists the available commands.

All command names may be abbreviated. If an abbreviation is ambiguous
(i.e. it could refer to more than one command), a mishap results.

Each command synopsis (specified in the subheading for the command)
specifies any required or optional command arguments. Optional arguments
are enclosed in bold square brackets, thus:

    backtrace [all]


13.1  ?
-------

Displays a list of the available commands.


13.2  abort
-----------

Aborts execution (i.e. does a * SETPOP).


13.3  animate
-------------

Sets animation mode, which enables you to watch your program execute in
slow motion. Use the continue command (see below) after the animate
command to start the animation.

Animation mode is especially useful when you have assigned
debugger_interrupt to interrupt: you can watch your program execute and
interrupt it (with the keyboard interrupt character, usually CTRL-C)
when you get to a point where you want to single-step, look at the
values of variables, etc.

The variable debugger_pause_interval controls how long the debugger
pauses at each source line (in seconds), with a default value of 1/2 a
second. To change the pause to, for example, 1/4 of a second, do

    0.25 -> debugger_pause_interval;


13.4  backtrace [all]
---------------------

Print a call stack backtrace, i.e. a list of all currently active
procedure invocations. Each procedure invocation corresponds to a call
stack frame, and is printed in the form:

    [<frame number>] <procedure name>  (line <line number>)

for example

    > [1] baz  (line 16)
      [2] foo  (line 23)
      [9] compile

The ">" indicates the currently selected frame. This starts off as the
frame relating to the active call, i.e., the current procedure
invocation, which is always frame number 1. This can be changed by using
the frame command with an argument (see below). This argument will be a
frame number, which is one of the numbers enclosed in square brackets.

In the above example, frames numbers from 3 to 8 are not listed. This is
because they correspond to certain system procedures or are anonymous
procedures. The missing system procedures are displayed if the optional
parameter "all" is supplied to the backtrace command. Anonymous
procedures (i.e. ones whose * PDPROPS are <false>) are usually never
shown, even though the numbering of stack frames respects their
presence. The one exception to this rule is when an anonymous procedure
is the currently active procedure.


13.5  breakpoints
-----------------

Lists all the breakpoints you have set, in the form

    [<breakpoint number>] <file name> : <procedure name>, <line number>

for example

    [1] '/csuna/home/simonn/pop/test1.p' : foo, line 16
    [2] '/csuna/home/simonn/pop/test2.p' : baz, line 23

Each breakpoint is assigned an integer breakpoint number, which is the
number displayed in square brackets. The breakpoint number is required
if you wish to delete the breakpoint (see the description of the delete
command, below).


13.6  continue
--------------

Continue execution, stopping at the next breakpoint (if there is one).


13.7  default [<command>]
-------------------------

Without an argument default prints the current default command, which is
the command executed when you just type <RETURN>. The default default
command is step.

With an argument, default sets the default command to the given command.
For example

    default next

sets the default command to next, which is often a useful thing to do.

If you do not want a default command, type

    default none

to the debugger prompt.

It is possible to change the default command from outside the debugger
by assigning to the variable debugger_default_command either a word
representing the name of a command or a list representing a complete
command (name and arguments). For example:

    "next" -> debugger_default_command;

    [print x] -> debugger_default_command;

debugger_default_command is actually an active variable: see
HELP * ACTIVE_VARIABLES.


13.8  delete <breakpoint number>
--------------------------------

Delete the specified breakpoint. The breakpoint is specified using an
integer breakpoint number, as displayed by the breakpoints command (see
above). For example, to delete the breakpoint on line 23 of procedure
baz as shown in the breakpoints example above, do

    delete 2

Instead of a breakpoint number, the word "all" may be used. The command

    delete all

deletes all the breakpoints currently set.


13.9  down
----------

Moves down the call stack by one frame, displaying information relating
to the frame called by the current one. This usually makes sense only if
you have previously moved up the call stack by means of the up or frame
commands (see below).

Down is equivalent to frame N, where N is the current frame number plus
one.


13.10  frame [<frame number>]
-----------------------------

Displays call stack frame information relating to the current frame
(procedure invocation). The name of the owner procedure, and the name
and value of both lexical and dynamic local variables are printed, in
the form

    Stackframe <frame number>
    Owner: procedure <procedure name>
    Lexical local variables:
     <lexical local bindings>
    Dynamic local variables:
     <dynamic local bindings>

where <lexical local bindings> and <dynamic local bindings> have the
form

    <variable name> = <variable value>

For example

    Stackframe 1
    Owner: procedure foo
    Lexical local variables:
     y = 0
     x = 3
    Dynamic local variables:
     popdprecision = <true>

If the optional <frame number> is given, it selects and displays
information for the specified frame. Further uses of the frame command
without an argument will reference the selected frame.

The frame number is one of the numbers displayed by the backtrace
command (see above).


13.11  help
-----------

Same as doing

    help debugger

to the Pop-11 top level, or

    <ENTER> help debugger

in Ved, i.e., shows you this file.


13.12  ignore [only] [<procedure spec>]
---------------------------------------

Causes execution of the specified procedure (and all procedures defined
locally to it) to proceed without entering the debugger, regardless of
any breakpoints set in the procedure. You will not be able to step into
the procedure either. Trace output is still produced, though (see the
description of the trace command, below).

This command is useful when you want to ignore frequently used utility
procedures when debugging, or for coping with troublesome dlocal
expressions (see the section "A problem with dlocal expressions",
below).

If you want to ignore a procedure but still want to debug its local
procedures, use the "only" argument in addition to the procedure
specification, e.g.

    ignore only foo

to ignore procedure foo but not its local procedures.

Without any arguments, ignore lists all the procedures currently being
ignored.


13.13  inspect <variable name>
------------------------------

Invokes the Pop-11 structure browser on the specified variable:
see HELP * INSPECT. If the variable does not exist, a mishap message is
printed.

The <variable name> may be a section pathname: see REF * SECTIONS.


13.14  next
-----------

Step on to the next source line. If the current source line is a
procedure call, step over the procedure, i.e. only stop in it if a break
point is set for that procedure.


13.15  pop11
------------

Enter a nested invocation of the Pop-11 compiler, such that compilation
respects the current lexical variable bindings. So, if you are stopped
inside a procedure foo with a local lexical variable x, any use of
the variable x will access the lexical local of foo.

When you exit the compiler you will return to the debugger.


13.16  print <variable names>
-----------------------------

Print the values of the specified variables. If a variable does not
exist a mishap message is printed.

Each <variable name> may be a section pathname: see REF * SECTIONS. If
there is more than one <variable name>, they are separated by spaces or
tabs.

Note that the ":" command, which is followed by a Pop-11 statement, is
more general since it allows arbitrary Pop-11 expressions to be printed
rather than just variables (see ":", below).


13.17  quit
-----------

Quits the current invocation of the debugger command loop. The effect is
similar to the continue command (see above) in that execution of any
running program will continue until the next (if any) breakpoint. If no
program is being debugged, the current invocation of the debugger is
terminated and you will return either to any previous invocation of the
debugger (if the current debugger level is greater than one) or else the
Pop-11 top level.


13.18  return [<expression>]
----------------------------

Return immediately from the current procedure invocation, without
executing the rest of the procedure (contrast skip, below). A return
value may optionally be specified.

Beware of specifying a value to be returned when the procedure being
returned from has already pushed a return value on the user stack. You
can use the userstack command (see below) to examine the user stack.


13.19  skip
-----------

Complete the current procedure invocation without single-stepping and
stop in the caller (contrast return, above).


13.20  source
-------------

Displays the source code for the procedure corresponding to the
currently selected frame. This is in contrast to where (see below),
which always shows the source for the currently executing procedure
(frame number 1). So, if you are stopped at a breakpoint and select a
frame with the frame command (see above), source will show you the
source code for that frame.

If you using the debugger inside Ved, the source file corresponding to
the selected frame is made the current Ved file and the cursor is
positioned on the line currently executing. Outside of Ved, only the
source line is shown.


13.21  step
-----------

Single-step, i.e. step on to the next source line. If the current source
line is a procedure call, step into the procedure whether there is break
point set for it or not.


13.22  stop
-----------

Without any arguments, stop behaves like breakpoints, i.e., it lists all
the breakpoints you have set (see breakpoints, above).


13.23  stop at [<file> :] <line>
--------------------------------

Stop at (i.e. set a breakpoint on) a given line number in the current
file. A different file name may be specified: the file name is enclosed
in string quotes and is separated from the line number by a colon.

The stop at command may also be given as stopat.


13.24  stop in <procedure spec>
-------------------------------

Stop in (i.e. set a breakpoint on) the given procedure.

Setting a breakpoint on a procedure has the same effect as setting a
breakpoint on the line containing the first executable statement within
the procedure. This sometimes has unexpected consequences. For example,
when the first executable statement in a procedure is the start of a
loop, a breakpoint will then be placed at the top of the loop, and
execution will pause each time round the loop.

The stop in command may also be given as stopin.


13.25  stop here
----------------

Stop at the current line number in the current file.


13.26  trace <procedure spec>
-----------------------------

An interface to the Pop-11 trace command (see HELP * TRACE). This causes
information to be printed whenever the specified procedure is invoked.
Its arguments (if any) are printed when the procedure is entered and its
results (if any) are printed when it exits. Abnormal exits and process
suspends/resumes are also displayed.

The debugger assigns 0 to popmaxtraceindent causing a procedure's
recursion depth always to be displayed in square brackets.

There is a similar restriction to the use of the trace command inside
the debugger as outside: generally, only top-level permanent procedures,
not lexical ones, may be traced (see HELP * LVARS for information about
lexically scoped variables). There is a slight relaxation of this
restriction in the debugger: procedures which are top-level lvars may be
traced.


13.27  unignore [only] [<procedure spec>]
-----------------------------------------

Undoes the effect of a corresponding ignore command (see above).

Without any arguments, unignore lists all the procedures currently being
ignored.


13.28  untrace <procedure spec>
-------------------------------

Turns off tracing for the specified procedure. See trace, above.


13.29  up
---------

Moves up the call stack by one frame, displaying information relating to
the frame which called the current one, i.e., the immediate caller of
the current procedure. You can move back down the call stack by means of
the down or frame commands (see above).

Up is equivalent to frame N, where N is the current frame number minus
one.


13.30  userstack [<depth>]
--------------------------

Prints the values currently on the user stack (see HELP * STACK)
without removing them. If the optional depth argument is given, only
that number of items are printed.


13.31  : <Pop-11 statement>
---------------------------

Execute a line of Pop-11 code. Note that one line only may be entered,
since it is terminated by <RETURN> (i.e., a newline character). The
evaluation of the Pop-11 statement respects the current lexical variable
bindings. So, if you are stopped inside a procedure with a local lexical
variable x, the following will print its value:

    : x =>

If x is a list, the following will print its head:

    : hd(x) =>

It is even possible to update x, for example:

    : tl(x) -> x;


13.32  where
------------

Tells you where you are, i.e., which procedure you are currently
executing, the file in which it is defined and the line about to be
executed, as follows

    <file name> : <procedure name>, <line number>

For example,

    '/csuna/home/simonn/pop/test.p' : foo, line 16

If you using the debugger inside Ved, <file name> is made the current
Ved file and the cursor is positioned on <line number>. This is useful
when you have edited source files or looked at help files (for example)
in the middle of a debugging session, and want to recover the debugging
context.

Outside of Ved, the current source line is displayed before the file
name and line number, for example:

        n + 1 -> n;
    '/csuna/home/simonn/pop/test.p' : foo, line 16


-----------------------------------------------------------------------
14  Command scripts
-----------------------------------------------------------------------

The debugger supports command scripts, which are sequences of debugger
commands, delimited by the syntax words debugger and enddebugger, i.e.

    debugger
        <command-1>
        ...
        <command-N>
    enddebugger;

The commands must be written one per line, since each command is
terminated by the end of line character. In addition, there should be
nothing either following the debugger opener or preceding the
enddebugger closer on the same source line. Thus, a one-line script:

    debugger <command> enddebugger;

is NOT allowed.

Not all commands make sense in a command script, particularly commands
concerning the state or execution of the currently active procedure,
i.e.

    animate
    continue
    frame
    next
    return
    skip
    step
    where

If a script contains such a command, the message

    No active procedures compiled in debugging mode

will be printed and the command ignored.

A command script is particularly useful for large applications, where
you might establish useful debugger settings -- such as breakpoints and
procedures to be ignored -- and save them for subsequent debugging
sessions.

Note that a command script must generally be located in a file distinct
from the source code you wish to refer to in the script. In addition, it
must be loaded after any source code to which the commands in the script
refer. A command script may also be entered at the Pop-11 top-level (or
immediate mode).


-----------------------------------------------------------------------
15  Problems
-----------------------------------------------------------------------

There are a number of potential problems which you may encounter when
using the debugger.


15.1  Reloading parts of files
------------------------------

If a part of a file which has been compiled in debugging mode is
reloaded (for example, using * LMR or * LCP in Ved) this can cause
problems if both the following conditions hold:

    a) lines have been inserted in the range being recompiled without an
       offsetting number of deletions (i.e., there has been a net
       increase in the number of lines in the file due to additions in
       the range to be reloaded);

    b) there are procedure definitions beyond the end of the range being
       recompiled.

The effect of these two circumstances is that the line numbers of
procedures beyond the end of the range that is reloaded will change.
When such procedures are debugged, single-stepping will show the wrong
source line (the setting of breakpoints will also be problematic).

A warning message is printed when this problem is likely to occur, for
example

    ;;; WARNING - LINE NUMBER INFORMATION MAY BE INACCURATE AFTER LINE 48
    ;;; FILE     :  /csuna/home/simonn/pop/test.p   LINE NUMBER:  49

Currently, it is essentially the second condition above which gives rise
to this message, i.e., a range has been recompiled and there are
procedure definitions beyond the end of the range. Thus, the presence of
the warning is not a guarantee of problems.

The solution is either to reload the complete file or to extend the
range to be loaded up to the end of the file.


15.2  dlocal expressions
------------------------

If a procedure has a * DLOCAL expression which calls a procedure which is
compiled in debugging mode, there is a potential problem when debugging
that procedure inside Ved. The problem arises because Ved immediate mode
is a Poplog * PROCESS; the program being debugged (as with any Poplog
program run from immediate mode) is another process; when swapping
between the two, dlocal entry/exit code is run. If this code invokes a
procedure which is being debugged it is possible to get into a state
where the procedure invoked from the dlocal entry/exit code seems to be
repeatedly invoked and no progress is apparently made.

Note that the dlocal expression code itself is never compiled in
debugging mode: the problem only arises when it calls a procedure
compiled in debugging mode.

The solution is to use the ignore command (see above) to ignore the
offending procedure.


15.3  Specifying with_props in the define header
------------------------------------------------

If you write procedure definitions of the form (see HELP * DEFINE):

    define foo() with_props baz;
        ...
    enddefine;

then you will not be able to reference the above procedure by the name
foo, only by the name baz. For example, you can say:

    stop in baz

but not

    stop in foo

This happens because the debugger works at the VM code level, and
receives information about a procedure definition via sysPROCEDURE. The
Pop-11 compiler calls sysPROCEDURE with a procedure's pdprops, which may
not be the same as the name appearing in the source code if with_props
is used.


--- C.all/help/debugger
--- Copyright University of Sussex 1993. All rights reserved.