2. Debugging Your GemStone Smalltalk Code

Previous chapter

Next chapter

Topaz can maintain up to eight simultaneous GemStone Smalltalk call stacks that provide information about the GemStone state of execution. Each call stack consists of a linked list of method or block contexts. Topaz provides debugging commands that enable you to:

This chapter introduces you to the Topaz debugging commands and provides some examples. For a detailed description of each of these commands, see Chapter 3.

2.1  Step Points and Breakpoints

For the purpose of determining exactly where a step will go during debugging, a GemStone Smalltalk method can be decomposed into step points. The locations of step points also determine where breakpoints can be set.

Generally, step points correspond to the message selector and, within the method, message-sends, assignments, and returns of nonatomic objects. (However, compiler optimizations may occasionally result in a different, nonintuitive step point, particularly in a loop.) The Topaz list steps method: command lists the source code of a given instance method and displays all step points (allowable breakpoints) in that source code.

For example:

topaz 1> set class String
topaz 1> list steps method: includesValue:
   includesValue: aCharacter
*  ^1                                                *******
 
   "Returns true if the receiver contains aCharacter, false
    otherwise. The search is case-sensitive."
 
   <primitive: 94>
 
   aCharacter _validateClass: AbstractCharacter .
*            ^2                                     *******
   ^ self includesValue: aCharacter asCharacter .
*  ^5     ^4                        ^3               *******
 

As shown here, the position of each method step point is marked with a caret (^) and a number.

If you use the Topaz step command (described below) to step through this method, the first step halts execution at the beginning of the method. The second step takes you to the point where _validateClass: is about to be sent to aCharacter. Stepping again would execute that message-send and halt execution at the point where asCharacter is about to be sent. Another step would cause that message to be sent and then halt execution just before the message includesValue: is sent to self.

The call stack becomes active, and the debugging commands become accessible, when you execute GemStone Smalltalk code containing a breakpoint (as well as when you encounter an error). As explained earlier, you can set a breakpoint at any step point. You can use the break command (described below) to set method breakpoints that halt execution at a particular step point within a method. In general, you can choose to set a method break before a message-send, an assignment, or a method return.

You can set a breakpoint on any method. Some methods, such as Boolean>>ifTrue: never hit the break points unless you invoke them with perform: or one of the GciPerform... functions, because sends of special selectors are optimized by the compiler.

2.2  Setting, Clearing, and Examining Breakpoints

You can use the break method and break classmethod commands to establish method breakpoints within your GemStone Smalltalk code:

break method aClassName aSelector [@ stepNumber]
break classmethod aClassName aSelector [@ stepNumber]

For example:

topaz 1> break classmethod GsFile openRead: @ 2

Establishes a breakpoint at step point 2 of the class method openRead: for GsFile.

topaz 1> set class String
topaz 1> break method ^ < @ 2

Establishes a breakpoint at step point 2 of the instance method “<” for the current
class (String).

The Topaz list breaks command allows you to display all method breakpoints currently set in the active method context. By supplying a selector as an argument to the list breaks command, you can display all breakpoints set in a given instance or class method for the current class, as shown in the following example.

topaz 1> list breaks method: <
	< aCharCollection
 
"Returns true if the receiver collates before the
argument. Returns false otherwise.
The comparison is case-insensitive unless the receiver
and argument are equal ignoring case, in which case
upper case letters collate before lower case letters.
The default behavior for SortedCollections and for
the sortAscending method in UnorderedCollection is
consistent with this method, and collates as follows:  
 
#( 'c' 'MM' 'Mm' 'mb' 'mM' 'mm' 'x' ) asSortedCollection 
 
yields the following sort order:
 
'c' 'mb' 'MM' 'Mm' 'mM' 'mm' 'x'
"
 
<primitive: 28>
   (aCharCollection _stringCharSize bitAnd: 16r7) ~~ 0 ifTrue:[
     ^ (DoubleByteString withAll: self) < aCharCollection .
   ]. 
aCharCollection _validateClass: CharacterCollection .
*                 ^2                                *******
^ aCharCollection > self

Alternatively, you can use the break list command to list all currently set method or message breakpoints:

topaz 1> break list
1: GsFile >> nextLine @ 1
2: GsFile class >> openRead: @ 2
3: String >> < @ 2

In the break list, each breakpoint is identified by a break index. To disable a breakpoint, supply that break index as the single argument to the break disable command:

topaz 1> break disable 2

A similar command line reenables the break point:

topaz 1> break enable 2

To delete a single breakpoint, supply that break index as the argument to the break delete command:

topaz 1> break delete 2

To delete all currently set breakpoints, type the following command:

topaz 1> break delete all

2.3  Examining the GemStone Smalltalk Call Stack

When you execute the code on which you have enabled a breakpoint, execution pauses. For example, if we put a breakpoint on the setter method for Animal’s instance variable #name:

topaz 1 > break method Animal name: @1

Then run this code:

topaz 1 > run
Animal new name: 'Dog'
%
a Breakpoint occurred (error 6005), Method breakpoint encountered.
1 1 Animal >> name:                               @1 line 1

You can display all of the contexts in the active call stack by issuing the where, stk or stack commands with no arguments. The where and stk command display a summary call stack, with one line for each context. Use the stack command to display method arguments and temporaries. When using the stack command, the volume of output displayed is controlled by the current level setting.

This is an example of the where summary:

topaz 1> where
==> 1 Animal >> name:                               @1 line 1
2 Executed Code                                 @3 line 1
3 UndefinedObject (GsNMethod class) >> _gsReturnToC @1 line 1
 

With display oops active, the where command provides more detail for each frame:

topaz 1> display oops
topaz 1> where
==> 1 Animal >> name:                               @1 line 1 [methId 25534209]
2 Executed Code                                 @3 line 1   [methId 25504513]
3 UndefinedObject (GsNMethod class) >> _gsReturnToC @1 line 1 [methId 4912641]
  [GsProcess 27551489]
 

Using the stack command provides additional information about the instance and temporary variable names and values for each context. With level 0 (the default), only the variable values themselves are displayed. This example is with display oops.

topaz 1> stack
==> 1 Animal >> name:                               @1 line 1 [methId 25534209]
    receiver [25517313 sz:3 cls: 27556097 Animal] a Animal
      name                [20 sz:0 cls: 76289 UndefinedObject] nil
      favoriteFood        [20 sz:0 cls: 76289 UndefinedObject] nil
      habitat             [20 sz:0 cls: 76289 UndefinedObject] nil
    newValue [25481729 sz:3 cls: 74753 String] Dog
2 Executed Code                                 @3 line 1   [methId 25504513]
    receiver [20 sz:0 cls: 76289 UndefinedObject] nil
3 UndefinedObject (GsNMethod class) >> _gsReturnToC @1 line 1 [methId 4912641]
    receiver [20 sz:0 cls: 76289 UndefinedObject] nil
 

With level 1, or higher levels, the variables for each instance variable is included in the display for stack. For example, with omit oops:

topaz 1> omit oops
topaz 1> level 1
topaz 1> stack
==> 1 Animal >> name:                               @1 line 1
    receiver a Animal
      name                nil
      favoriteFood        nil
      habitat             nil
    newValue Dog
2 Executed Code                                 @3 line 1
    receiver nil
3 UndefinedObject (GsNMethod class) >> _gsReturnToC @1 line 1
    receiver nil

The display of each context includes:

The display is governed by the setting of other Topaz commands such as limit, level, and display or omit.

Proceeding After a Breakpoint

When GemStone Smalltalk encounters a breakpoint during normal execution, Topaz halts and waits for your reply. Topaz provides commands for continuing execution, and for stepping into and over message-sends.

continue
Tells GemStone Smalltalk to continue execution from the context at the top of the stack, if possible. If execution halts because of an authorization error, for example, then the virtual machine can’t continue. As an option, the continue command can replace the value on the top of the stack with another object before it attempts to continue execution.

c
Same as continue.

step over
Tells GemStone Smalltalk to advance execution to the next step point (message-send, assignment, etc.) in the active context or its caller, and halt. The active context is indicated by the ==> in the stack; it is the context specified by the last frame, up, down or another command. Initially it is the top of the stack (the first context in the list).

step into
Tells GemStone Smalltalk to advance execution to the next step point (message-send, assignment, etc.) and halt. If the current step point is a message-send, then execution will halt at the first step point within the method invoked by that message-send.

Notice how this differs from step over; if the next message in the context contains step points itself, execution halts at the first of those step points. That is, the virtual machine “steps into” the new method instead of silently executing that method’s instructions and halting after the method has completed. The next step over command will then take place within the context of the new method.

Examining and Modifying Temporaries and Arguments

The Topaz temporary command lets you examine or modify the values of temporaries in the active context. If, for example, the method under inspection had a temporary variable named count, that currently had a value of 5, you could obtain its value by typing temporary and the variable name:

topaz 1> temporary count5

Similarly, you can use the temporary command to assign a new value to a temporary variable:

topaz 1> temporary count 8

For example, the following code sets a breakpoint, executes code, views and updates the value of a temporary variable, then continues execution to return the results of the code; which has been changed during debugging.

topaz 1> break classmethod String withAll:
topaz 1> run
String withAll: 'abc'
%
a Breakpoint occurred (error 6005), Method breakpoint encountered.
1 String class >> withAll:        								@1 line 1
topaz 1> stack
==> 1 String class >> withAll:                      @1 line 1
    receiver String
    aString abc
2 Executed Code                                 @2 line 1
    receiver nil
3 UndefinedObject (GsNMethod class) >> _gsReturnToC @1 line 1
    receiver nil
topaz 1> temporary
    aString abc
topaz 1> temporary aString 'xyz'
topaz 1> stack
==> 1 String class >> withAll:                      @1 line 1
    receiver String
    aString xyz
2 Executed Code                                 @2 line 1
    receiver nil
3 UndefinedObject (GsNMethod class) >> _gsReturnToC @1 line 1
    receiver nil
topaz 1> continue
xyz

Select a Context for Examination and Debugging

The Topaz commands frame, up, and down, as well as stack up, stack down, and stack scope, let you redefine the active context (used by the temporary, stack, and list commands) within the current call stack. Consider the call stack we examined earlier, with level 0 and omit oops:

topaz 1> stack
==> 1 Animal >> name:                               @1 line 1
    receiver anAnimal
    newValue Dog
2 Executed Code                                 @3 line 1
    receiver nil
3 UndefinedObject (GsNMethod class) >> _gsReturnToC @1 line 1
    receiver nil

The active context is indicated by ==>. You can also show the active context by using the frame command with no arguments:

topaz 1> frame1 Animal >> name:                               @1 line 1
    receiver anAnimal
    newValue Dog

The following command selects the caller of this context as the new active context:

topaz 1> frame 22 Executed Code                                 @3 line 1
    receiver nil

Now confirm that Topaz redefined the active context:

topaz 1> where
1 Animal >> name:                               @1 line 1
==> 2 Executed Code                                 @3 line 1
3 UndefinedObject (GsNMethod class) >> _gsReturnToC @1 line 1

You can also use up and down commands to make a different frame the active context.

Multiple Call Stacks

By default, when you continue executing code and encounter another breakpoint, the original call stack is lost.

The Topaz command stack save lets you retain the previous stack. This needs to be invoked for each stack you want to save.

The Topaz command stack all lets you display your list of saved call stacks. This display includes the top context of every call stack:

topaz 1> stack all 0:  1 Animal >> habitat                   @1 line 1
 1:  1 AbstractException >> _signalWith:   @6 line 25
*2:  1 Executed Code                       @3 line 1

The asterisk (*) indicates the active call stack, if one exists. If there are no saved stacks, a message to that effect is displayed.

When you type the stack change command, Topaz sets the active call stack to the call stack indicated by the integer in the stack all command output, and displays the newly selected call stack:

topaz 1> stack change 1
Stack 1 , GsProcess 27447553
1 AbstractException >> _signalWith:        @6 line 25
 

 

Previous chapter

Next chapter