HELP DEBUGGER Simon Nichols, October 1993 lib debugger; A source-level debugger for Pop-11. CONTENTS - (Use 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 [] 13.8 delete 13.9 down 13.10 frame [] 13.11 help 13.12 ignore [only] [] 13.13 inspect 13.14 next 13.15 pop11 13.16 print 13.17 quit 13.18 return [] 13.19 skip 13.20 source 13.21 step 13.22 stop 13.23 stop at [ :]  13.24 stop in 13.25 stop here 13.26 trace 13.27 unignore [only] [] 13.28 untrace 13.29 up 13.30 userstack [] 13.31 : 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- 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 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 to debugger_debugging and recompile the program. If you need the debugger again, just reassign 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-. ----------------------------------------------------------------------- 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 ; or the Ved command ved_stopin, i.e. stopin For a definition of , 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 ). This has the general form: [ : ] [
] [ ] Here, 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, 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 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: [] (line ) 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 ) 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 [] : , 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 [] ------------------------- Without an argument _______default prints the current default command, which is the command executed when you just type . 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 -------------------------------- 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 [] ----------------------------- 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 Owner: procedure Lexical local variables: Dynamic local variables: where and have the form = For example Stackframe 1 Owner: procedure foo Lexical local variables: y = 0 x = 3 Dynamic local variables: popdprecision = If the optional 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 help debugger in Ved, i.e., shows you this file. 13.12 ignore [only] [] --------------------------------------- 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 ------------------------------ 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 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 ----------------------------- Print the values of the specified variables. If a variable does not exist a mishap message is printed. Each may be a section pathname: see ___REF¯*¯________SECTIONS. If there is more than one , 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 [] ---------------------------- 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 [ :]  -------------------------------- 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 ------------------------------- 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 ----------------------------- 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] [] ----------------------------------------- Undoes the effect of a corresponding ______ignore command (see above). Without any arguments, ________unignore lists all the procedures currently being ignored. 13.28 untrace ------------------------------- 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 [] -------------------------- 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 : --------------------------- Execute a line of Pop-11 code. Note that one line only may be entered, since it is terminated by (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 : , For example, '/csuna/home/simonn/pop/test.p' : foo, line 16 If you using the debugger inside Ved, is made the current Ved file and the cursor is positioned on . 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 ... 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 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.