2. Stack Manipulation Commands
8. Interrupting and Single Stepping
12. Copyright and Terms Of Use
For example, if you did not define a method for main, after starting Mindy you would see something like the following:
No applicable methods for main with arguments #[]The first line is the error message. The second line tells you about the thread that encountered the error. For more information about threads see Section Threads. The third line tells you about the current stack frame for the thread; in this example, the last function called, which is at the top of the stack, is the invoke-debugger function. It was called with one argument, a <simple-error>.
thread [0] D main
fp 0x10034090: invoke-debugger({<simple-error> 0x1023fa91})
mindy>
The following sections discuss the various commands provided by the debugger. As a general rule, you can invoke a command by typing at least a unique prefix of its name. There are three commonly used commands for which a single letter suffices, regardless of all other command names:
This documentation uses the term built-in for definitions created in C code, within Mindy\qs implementation. Opposed to built-in definitions are definitions written in Dylan code. Parts of Mindy are built-in and parts are defined in Dylan code. Of course, all user code is written in Dylan. Some debugger commands behave differently depending on whether the object being manipulated was defined in Dylan code or built-in.
mindy> downThe first line tells you about the new current frame, which is a call to the error function. For a function written in Dylan, as opposed to a built-in function, the debugger tries to show the line of source code associated with the current frame. If the debugger could not find the source file, it still prints the line number from the source file.
fp 0x10034078: error({<simple-error> 0x1023fa91}, #[], #())
/afs/cs.cmu.edu/project/gwydion/mindy/src/runtime/cond.dylan
132 signal(cond);
mindy>
While moving down the stack, you might have expected to see a call to the signal function before seeing a call to the error function. This does not happen because signal tail calls invoke-debugger. When a function tail calls another function, the callee reuses the current stack frame of the caller.
In addition to the up and down commands, you can move to a specified stack frame using the frame command. The debugger numbers stack frames starting at zero at the top of the stack. Currently, the debugger does not print frame numbers when it prints frame information, so moving with the frame command is only useful as a rough thumb bar. The following is an example of using this command to go to the top of the stack:
mindy> frame 0If you use the frame command without supplying a frame number, the command prints the current frame\qs information. This is useful if the description of the current frame has scrolled off the screen, and you want to see it again.
fp 0x10034090: invoke-debugger({<simple-error> 0x1023fa91})
mindy>
You can view the entire stack by using the backtrace command. The current frame stays the same, but the backtrace command always shows the entire stack from the top to the bottom. The following is example output from this command:
mindy> backtrace
fp 0x10034090: invoke-debugger({<simple-error> 0x1023fa91})
fp 0x10034078: error({<simple-error> 0x1023fa91}, #[], #()) \\
[/afs/cs.cmu.edu/project/gwydion/mindy/src/runtime/cond.dylan, line 132]
fp 0x10034058: main()
mindy>
mindy> localsYou can use the print command to print a specific local variable. The following is an example of printing the cond variable shown in the previous sample output:
noise: #[]
cond: {<simple-error> 0x1023fa91}
mindy>
mindy> print condThe print command can also print the value of global variables:
$0={<simple-error> 0x1023fa91}
mindy>
mindy> print sizeFor information on the labels the debugger assigns to values (that is, the $N identifications), see Section Debugger Variables.
$1={<generic-function> size}
mindy>
If the debugger does not find a local variable with the name you supplied, the debugger looks for a global variable by that name in the current library and module. For more information about libraries and modules, see Section Libraries and Modules.
You can refer to global variables in libraries and modules that are not the current library and module by prefixing variable names with module and/or library names. We support a colon notation that only works in the Mindy debugger and has nothing to do with legal Dylan syntax. For example, foo:bar:baz refers to the baz variable in the bar module of the foo library. There must not be any whitespace anywhere in the identifier. To refer to a variable in the current library but in a module that is not the current module, use the form quux:splat, which refers to the splat variable in the quux module.
For more information about the print command, see Section Evaluating Expressions.
mindy> libraryThe following is an example of using the module command after having just switched to the Dylan-user library:
Dylan-User
Dylan
Current library is Dylan
mindy> library dylan-user
mindy>
mindy> moduleThe i in the second column indicates that those modules are being imported into the Dylan-user library as opposed to being defined there. The module command also indicates which modules are exported from the current library. For example, if you were to switch to the Dylan library, the module command would produce the following output:
Dylan-User
i File-Descriptors
i Threads
i Extensions
i System
i Dylan
The current module is Dylan-User
mindy>
mindy> library dylanThe x in the first column indicates that those modules are exported. There were no xs in the listing of modules in the Dylan-user library because no modules are exported from the Dylan-user library. There were no is in the listing of modules for the Dylan library because the Dylan library does not import any modules.
mindy> module
Dylan-User
x File-Descriptors
x Threads
Builtin-Stuff
x Extensions
x System
x Dylan
The current module is Dylan-User
mindy>
Whenever you change libraries with the library command, the debugger resets the current module to the Dylan-user module. This is because the debugger needs to make a module current in the new library, and every library has a Dylan-user module.
mindy> print list(1, 2, 3)The print command evaluates the variable list and then invokes that function with the arguments 1, 2, and 3. The debugger labels values printed with a dollar sign and a number, and you can use these labels in later expressions. For more information on these, see Section Debugger Variables.
$2=#(1, 2, 3)
mindy> print vector(4, 5, 6)
$3=#[4, 5, 6]
mindy>
The expressions that the debugger accepts are limited. An expression can be one of the following:
mindy> print values(1, 2, 3)If an error occurs while the debugger is evaluating the expression, it prints the error message, aborts the print command, and returns to the debugger prompt. The following is an example of this situation:
$4=1, $5=2, $6=3
mindy> print error("oops")The call command is like the print command, but the call command does not handle errors by aborting. When you use the call command, and the expression causes an error, the debugger returns to its prompt, but any stack frames that were created due to the call command are now visible for inspection. The following is an example of using the call command:
invocation failed:
oops
mindy>
mindy> call error("oops")The print and call commands can also evaluate multiple, comma-separated expressions:
oops
thread [0] D main
fp 0x100341f4: invoke-debugger({<simple-error> 0x102456b1})
mindy>
mindy> print 1, 2, 3
$7=1
$8=2
$9=3
mindy>
mindy> p list(1, 2, 3)The notation $-N provides a dynamic alternative to identifying debugger variables. This notation refers to previously printed values by using N as a count from the most recently printed value to the least recently printed. The counting begins at one.
$4=#(1, 2, 3)
mindy> p second($4)
$5=2
mindy>
mindy> print a:, b:, c:, d:You can use $ as a shorthand for $-1, and $$ for $-2:
$12=a
$13=b
$14=c
$15=d
mindy> print $-1, $-2, $-3, $-4
$16=d
$17=c
$18=b
$19=a
mindy>
mindy> p 2Mindy keeps references to all debugger variables to prevent them from being garbage collected. If you no longer care about previously printed values, you might want to use the flush command to get rid of them:
$20=2
mindy> p list($, 4)
$21=#(2, 4)
mindy> p list($$, 6)
$22=#(2, 6)
mindy>
mindy> flushYou can use $aN notation to refer to the arguments passed to the function call associated with the current stack frame. N is the argument number, counting from zero. The following is an example:
Flushed all debugger variables.
mindy> p $0
invocation failed:
No debug variable $0
mindy> p list(a:, b:, c:)
$0=#(a, b, c)
mindy>
mindy> frameThe $aN notation does not identify a debugger variable, and the debugger does not have to create storage for these values because they are already stored on the call stack. The flush command has no effect on argument values.
fp 0x10034078: error({<simple-error> 0x1023fa91}, #[], #())
/afs/cs.cmu.edu/project/gwydion/mindy/src/runtime/cond.dylan
132 signal(cond);
mindy> p $a0
$1={<simple-error> 0x1023fa91}
mindy> p $a1
$2=#[]
mindy> p $a2
$3=#()
mindy>
The debugger has commands that allow you to try to continue executing your program. The most common way to continue execution is to invoke a Dylan restart. To either list the available restarts or invoke a restart, you use the restart command:
mindy> call cerror("go on", "oops")In this example, the restart command lists two restarts. The cerror function establishes the "go on" restart (numbered 0). The call command establishes the "Blow off call" restart (numberd 1). The restart 0 command caused cerror to return #f, which the call command printed.
oops
thread [0] D main
fp 0x1003428c: invoke-debugger({<simple-error> 0x10245361})
mindy> restart
0 [{class <simple-restart>}]: go on
1 [{class <abort>}]: Blow off call
mindy> restart 0
$0=#f
fp 0x10034090: invoke-debugger({<simple-error> 0x1023fa91})
mindy>
The abort command invokes the first restart that handles <abort> restarts. The following is an example of this command:
mindy> call error("oops")If Mindy entered the debugger due to a condition that allows returning as part of its recovery protocol, then you can use the return command. For example, consider an <ignorable-error> condition that is a subclass of <error> and that allows returning as part of its recovery protocol. The following example shows returning from the signalling of this condition:
oops
thread [0] D main
fp 0x100341fc: invoke-debugger({<simple-error> 0x10241d49})
mindy> abort
fp 0x10034090: invoke-debugger({<simple-error> 0x1023fa91})
mindy>
mindy> call signal(make(<ignorable-error>))
{<ignorable-error> 0x10247759}
thread [0] D main
fp 0x100341d4: invoke-debugger({<ignorable-error> 0x10247759})
mindy> restart
0 [{class <abort>}]: Blow off call
Returning is allowed:
ignore it.
mindy> return
$0=#f
fp 0x10034090: invoke-debugger({<simple-error> 0x10244831})
mindy>
module: Dylan-UserIf you were to run this program and then interrupt it, you would see output similar to the following:
define method main (#rest noise)
foo(#t);
end;
define method foo (x)
if (x)
foo(#f);
else
foo(#t);
end;
end;
^CAfter interrupting the program you have the full debugger at your disposal, as if an error had occurred. Additionally, you can use the continue command to resume execution:
Interrupted
thread [0] R main
fp 0x10034060: foo(#f, #())
foo.dylan
8 if (x)
mindy>
mindy> continueYou can also use the step command to advance line by line through your program. When stepping, if the debugger encounters a function call, it descends into that function and steps line by line. The following is an example:
^C
Interrupted
thread [0] R main
fp 0x10034060: foo(#f, #())
foo.dylan
8 if (x)
mindy> step
foo.dylan
11 foo(#t)
mindy> step
foo.dylan
8 if (x)
mindy> step
foo.dylan
9 foo(#f)
mindy> step
foo.dylan
8 if (x)
mindy>
module: dylan-userIf you were to put a breakpoint at line 6 (the second puts), Mindy would produce output similar to the following:
define constant foo =
method ()
puts("this is a test\\n");
puts("of breakpoints.\\n");
#f;
end;
mindy> break foo, 6The continue and step commands can be used to continue execution (see Section Interrupting and Single Stepping):
breakpoint 1 installed in {anonymous <byte-method> 0x10243d31\\
#()} at line 6 (pc 47)
mindy> call foo()
this is a test
Breakpoint
thread [0] R main
fp 0x100341dc: {anonymous <byte-method> 0x10243d31 #()}(#())
foo.dylan
6 puts("of breakpoints.\\n");
mindy>
mindy> stepThe breakpoint command evaluates its first argument, so you can use an arbitrary expression for the function. For example, you could use find-method to extract a specific method from a generic function and insert a breakpoint in that method:
of breakpoints.
foo.dylan
7 #f;
mindy> c
$0=#f
fp 0x10034090: invoke-debugger({<simple-error> 0x10243e49})
mindy>
mindy> br find-method(size, list(<table>)), 886The breakpoint command with no arguments lists the currently installed breakpoints:
breakpoint 1 installed in {<byte-method> size #({class <table>})}\\
at line 886 (pc 35)
mindy>
mindy> breakpointThe delete N command removes a breakpoint, where N is the breakpoint ID reported in the breakpoint listing.
id where
1 pc 47 in {<component> 0x10204ea9}
mindy>
Sometimes the Mindy compiler has to split a single top level form into multiple methods. When this happens, the debugger cannot always figure out where to insert your breakpoint. Consider the following program:
module: dylan-userWhen this program is compiled, the compiler has to put the contents of the block in a seperate method. Because of this, if you were to try to insert a breakpoint at line 7 it would not work:
define constant foo =
method ()
block (exit)
puts("this is a test\\n");
puts("of breakpoints.\\n");
#f;
end;
end;
mindy> break foo, 7To insert a breakpoint into this method, you need to use the disassemble command. It disassembles a method and all Mindy-generated methods that might be associated with that method. For example:
{anonymous <byte-method> 0x10243f59 #()} does not span line n\\
umber 7
mindy>
mindy> disassemble fooAs you can see, the function foo has been split into three methods. The first one corresponds to the part of foo that is outside the block. The second method corresponds to the code inside the block. And the third one corresponds to the exit function established by the block. Look for the second method which spans line 7. The following shows how to install the breakpoint:
anonymous component, from "foo.dylan"
5 block (exit)
47: b0 push function catch
48: 21 push const(1) {<method-info> 0x10205149}
49: b2 push function list
50: a3 push value <object>
51: 91 call nargs = 1, for single
52: 0e push #()
53: 10 push #t
54: 06 make-method
55: 71 call nargs = 1, tail
{<method-info> 0x10205149}, anonymous component, from "foo.dylan"
5 block (exit)
51: 31 push arg(1)
52: 20 push const(0) {<method-info> 0x102050b1}
53: b1 push function list
54: 90 call nargs = 0, for single
55: 0e push #()
56: 10 push #t
57: 06 make-method
58: 60 pop local(0)
6 puts("this is a test\\n");
59: b2 push function puts
60: 23 push const(3) "this is a test\\n"
61: 81 00 call nargs = 1, for 0
7 puts("of breakpoints.\\n");
63: b2 push function puts
64: 24 push const(4) "of breakpoints.\\n"
65: 81 00 call nargs = 1, for 0
8 #f;
67: 11 push #f
68: 02 return single
{<method-info> 0x102050b1}, exit component, from "foo.dylan"
5 block (exit)
39: b0 push function apply
40: a1 push value throw
41: 30 push arg(0)
42: 32 push arg(2)
43: 73 call nargs = 3, tail
mindy>
mindy> br 0x10205149, 7
breakpoint 1 installed in {<method-info> 0x10205149} at line 7 (pc 63)
mindy> call foo()
this is a test
Breakpoint
thread [0] R main
fp 0x100341f8: {anonymous <byte-method> 0x10245f41 #({class <object>})}\\
({<catch> 0x10245f81}, #())
foo.dylan
7 puts("of breakpoints.\\n");
mindy> c
of breakpoints.
$0=#f
fp 0x10034090: invoke-debugger({<simple-error> 0x10244071})
mindy>
mindy> p spawn-thread(foo:, curry(break, "Thread foo"))In this example, the thread command lists three threads: the main (or original) thread and the two threads you just created. The c in the first column indicates which thread the debugger is currently examining. The [N] indicates the thread ID for each thread. The D and R designations indicate the status of each thread. The main, foo, and bar labels are the debug-names passed as the first argument to spawn-thread.
$0={<thread> 0x10243f49}
mindy> p spawn-thread(bar:, curry(break, "Thread bar"))
$1={<thread> 0x10246f19}
mindy> thread
c [0] D main
[1] R foo
[2] R bar
mindy>
The different thread status codes are as follows:
STATUS MEANINGGiving the thread command an argument causes the debugger to examine another thread. You can designate threads with either its numeric ID or the debug-name passed to spawn-thread:
D current thread the debugger is examining
R running/runable
S suspended
B blocked on a lock
W waiting for an event
mindy> thread fooSometimes it is useful to temporarily disable some threads while debugging other threads. The disable <thread-id-or-name> command disables (suspends) the indicated thread, and the enable command allows a thread to run again:
thread [1] R foo
fp 0x102550bc: {anonymous <byte-method> 0x102443d9 #({class <\\
object>})}({<catch> 0x10244421}, #(), {<value-cell> 0x1024436\\
9}, {<breakpoint> 0x102441e1})
/afs/cs.cmu.edu/project/gwydion/mindy/src/runtime/cond.dylan
212 init-arguments: list(format-string: "Continue from break"))
mindy> thread 0
thread [0] D main
fp 0x10034090: invoke-debugger({<simple-error> 0x1023fa91})
mindy>
mindy> disable fooIn this example, The status of the foo thread changes from R (runnable) to S (suspended) when it is disabled.
[1] S 1 foo
mindy> enable foo
[1] R foo
mindy>
If you repeatedly use the disable command on the same thread, then the enable command must be used the same number of times to before the thread\qs status changes to R. The 1 after the S above is the number of times the thread foo has been disabled.
When a thread is suspended, the continue and step commands do not advance the thread\qs execution. The disable and enable commands can help you find thread synchronization problems by allowing you to explicitly control when each thread runs.
Invoking the disable or enable command with no argument affects the current thread the debugger is examining.
The kill <thread-id-or-name> command kills the indicated thread.
The quit command causes Mindy to exit without executing any of the on-exit hooks. If you want the on-exit hooks to run, you should invoke the exit function with the print command:
mindy> print exit()The tron command turns on an internal trace facility that prints the arguments and results for every function call. The troff command turns this off.
The error command repeats the error message for the condition that caused this thread to drop into the debugger.
The gc command invokes the garbage collector.
The describe command takes an expression as an argument and evaluates it. If the result is an instance of a class defined in Dylan, as opposed to a built-in class, then the debugger identifies the class, prints the slot names, and prints the slot values. If the result of the expression is an instance of a built-in class, then the debugger prints the value and its class. The describe command does not create or assign to debugger variables, but you can use debugger variables in the expression given to the command. The following examples show the describe command:
mindy> describe make
{<generic-function> make} is an instance of {class <generic-function>}
mindy> describe "Testing"
"Testing" is an instance of {class <byte-string>}
mindy> describe make(<table>)
{<object-table> 0x10245d79} is an instance of {class <object-table>}
and has the following slots:
merged-hash-state-slot: {permanent hash state}
shrink-to-slot: 100
shrink-when-slot: 10
expand-to-slot: 300
expand-when-slot: 200
bucket-states-slot: #[{permanent hash state}, {permanent hash state}, \\
{permanent hash state}, {permanent hash state}, {permanent hash state}]
bucket-count-slot: 5
bucket-array-slot: #[#(), #(), #(), #(), #()]
item-count-slot: 0
Use and copying of this software and preparation of derivative works based on this software are permitted, including commercial use, provided that the following conditions are observed:
Bug reports, questions, comments, and suggestions should be sent by E-mail to the Internet address gwydionbugs@cs.cmu.edu.