Starting / finishing / restarting, Controlling the execution, Watching

V. Debuging

V.1 Starting, finishing and restarting of the debugger

V.1.1 Starting the debugger

    Before you start the debugger you must select the class which is going to be traced. You set this class the same way you set the class to run - choose the menu command System|Options and in the section Compiler fill in the field Main class. If you try to start without setting this class a message

    don't know which class to start

    window after you select the menu command Debug|Go.

    Before you start the debugger you must also make sure that you have compiled the main class and all classes which are used during the application runs (or more exactly all that ones which are going to be traced) are compiled with the option '-g'. If you are not sure about this choose the menu command System|Options and in the section Compiler check in the appropriate field.

    If you have compiled all which is which is necessary and selected the class to debug you can try to start the debugger. From the main menu select the command Debug|Go and wait for a moment.

    The first thing the debugger does is that it clears the Output window and prints the line with the following text into it

    debugger session is starting...

    Now the debugger initializes itself. It tries to set all breakpoints and so on. In some cases the initialization fails and the debugger hangs. In such a case look at chapter "The debugger limitations and known problems".

    If the initialization succeeds the line

    debugger session has started

    window and the debugger will start the class selected above (the debugger will call the method "main" of this class).

    Now the debugger behavior depends on the fact whether you have set some breakpoint or not. If you have set all breakpoints on lines from which no one is reached the debugger will run till the application finishes or till you choose from the main menu the command Debug|Finish debugging. If you have not set any breakpoint the default breakpoint at the beginning of the main method of the class selected above is set.

    The debugger stops if it reaches a line with a breakpoint. The debugger updates the contents of the Watches, Locals, Call Stack and Threads windows and it also tries to open the editor window with the source code for the class we stopped in. The line on which the debugger has stopped will be colored with different color. See an example

    The yellow line is the current line with the code which is going to be executed. The red line is the line of a source code on which a breakpoint is set.

    Now you can trace the source code and watch the application state. See chapters "Controlling the execution of the application" and "Watching the state of the application".

    Note: While the debugger is starting most commands in the Debug submenu of the main menu are disabled and only the commands Finish debugging, Restart debugging and some other are enabled. The rest of command will become enabled when a breakpoint is reached.

    Note: If some breakpoints cannot be set during the debugger initialization error messages are printed into the Output window. In such a case make sure that the breakpoint is set on a line with a source code (not on a commend or on the variable definition etc.) or try to recompile the class with the option '-g'.

V.1.2 Finishing the debugger

    After you find the problem with the application you usually want to finish the debugging. To achieve this select the command Debug|Finish debugging. Sometimes the debugger finishes itself without choosing this command. It happens in case that the application reaches the "System.exit(...)" calling, or when an unhandled exception occurs in your application etc.

    Note: The debugger automatically finishes also when the compilation starts and before exiting the Xelfi.

V.1.3 Restarting the debugger

    In some cases you need to stop the debugger and start it again. Than you can use the command Debug|Restart debugging which just stops the debugger and starts it again.

V.2 Controlling the execution of the application

    If the debugger has stopped at a breakpoint in a source code you can do several things. You can continue in the application execution, trace into or over the class method etc. But before doing this it would be useful to learn more about breakpoints.

V.2.1 Breakpoints

V.2.1.1 What a breakpoint is

    Every breakpoint stores information about the class name and the number of the line it is set on. Every breakpoint can be in one of three states: enabled, disable or invalid. You can change the breakpoint state from the disabled to enabled or from enabled to disabled. But you cannot change the state of a breakpoint from invalid to enabled or to disabled. After a breakpoint is created it is in the state enabled. The breakpoint state can be changed to invalid when the debugger starts and tries to set up all enabled breakpoints from the window Breakpoints. If the debugger cannot set up a breakpoint while it is starting an error message will appear in the Output window.

    Every breakpoint shown in the Breakpoints window has following format

    [breakpoint number] classname:linenumber : state

    [1] mypackage.ClassA:23 : enabled
    [2] mypackage.ClassB:15 : disabled

    When you will inserting a breakpoint you must make sure that every class on which you set a breakpoint is stored in the file with the same name. If you have for example such a (nonsense) code in your application like this

            ClassA.java:
    
            line 1:         class ClassA {
            line 2:                 int a;
            line 3:         }
            line 4: 
            line 5:         class ClassC {
            line 6:                 int x;
            line 7:         }
            line 8: 
            line 9:         ClassC() {
            line 10:                x = 5;
            line 11:        }
    
    

    the debugger will not be able to set up a breakpoint on the line with the number 10. Even if the line

    [1] ClassC:10 : enabled

    may exist for some time in the Breakpoints window the breakpoint state will be changed to invalid

    [1] ClassC:10 : invalid

    after the debugger starts or even earlier.

V.2.1.2 The "Breakpoints" window

    window use the command Window|Breakpoints.

    In this window you see information about all breakpoints in this Xelfi session. All breakpoints are loaded and stored in the .XelfiOptions file. For more details look at the chapter about the Xelfi Options.

    window contains the list of breakpoints You can choose any of them and can make some action with it. You can delete it, insert a new breakpoint in front of other one, enable or disable this breakpoint or you can get to the source code with the line on which the breakpoint is set.

2.1.3 Inserting a new breakpoint

    If you need to insert a new breakpoint on some position in a source code you have two possibilities. Firstly you can place the cursor in the editor window with the source code on the line you want the debugger stops at. Than you choose the command Debug|Toggle breakpoint from the menu. After this a new field will be added into the Breakpoints window.

    If the debugger has not been started while inserting a new breakpoint the line on which the breakpoint has been set will be colored with a breakpoint line color.

    The situation may be different if the debugger has been successfully started in time of inserting of a new breakpoint. In that case the debugger checks whether the breakpoint is valid and if it is not it will change the breakpoint state to invalid. For more details see the chapter "What the breakpoint is".

    The second way how to insert a breakpoint is to use the dialog in which you specify the class name and the number of the line on which the breakpoint has to be set. To invoke this dialog make the Breakpoints window active and press the combination of keys Ctrl+I. The dialog will appear and you have to fill in two fields. The first one must be a non-blank string. The second field has to be an integer number above zero.

    After you confirm the data in the dialog the breakpoint will be inserted and checked in similar way as described in case of inserting through an editor window.

V.2.1.4 Deleting a breakpoint

    You usually delete breakpoints if you do not need them more. You can delete the breakpoint in two ways. Firstly you can place the cursor on the line with the source code on which the breakpoint is set. Than you choose from the menu the command Debug|Toggle breakpoint and the breakpoint disappears from all editor windows and also from the Breakpoint window.

    The second way how to delete the breakpoint is to select the appropriate line in the Breakpoints window and press Delete key.

V.2.1.5 Disabling a breakpoint

    Disabling and deleting breakpoints are similar actions with the difference that disabled breakpoints stay in the Breakpoint window. To disable the breakpoint you have to select someone from the list in the Breakpoints window. The breakpoint specified cannot be in state invalid. Than press the combination of keys Ctrl+D. The text describing the breakpoint in the Breakpoints window will change and all lines in editor windows to which this breakpoint belonged will be shown in their normal line color.

V.2.1.6 Enabling a breakpoint

    Enabling and inserting a breakpoint are similar actions because they have the same effect to the running debugger. To enable the breakpoint you have to select someone from the list in the Breakpoints window. The breakpoint specified cannot be in state invalid. Than press the combination of keys Ctrl+E. The text describing the breakpoint in the Breakpoints window will change and all lines in editor windows to which this breakpoint belonged will be shown they will be colored by the breakpoint line color.

V.2.1.7 Getting to the source code with the specified breakpoint

    The easiest way to get to a line with the source on which a breakpoint is set is to select that breakpoint in the Breakpoints window and than press the Enter key or double click with the left mouse button on that breakpoint.

    The debugger will try to open the editor window for the class and to place the cursor on the line specified in that breakpoint. If it does not succeeds the Output window will appear with a message that the source code for this class cannot be found. For example

    source code for class 'mypackage.TestClass' not found

V.2.1.8 The breakpoints line numbers consistency

    If you insert some breakpoints and edit the source code the line numbers will soon become inconsistent. This means that line numbers in the Breakpoints window will be different from that ones appearing in the editor window status line. To eliminate this unpleasant effect you can press the combination of keys Ctrl+R in the active Breakpoints window. This will "refresh" the contents of this window and repair it into a consistent state.

    Note that if you jump to the source code in the way described in the chapter "Getting to the source code with the specified breakpoint" you will get to the correct line.

V.2.2 Continuing in the application execution

    If you want to continue in the application execution after the debugger has stopped at the breakpoint or after you have done a step you must select the command Debug|Go again. The debugger will continue in application tracing till it reaches some breakpoint or till the application finishes.

    (Sometimes it may happen (e.g. if the application does not call System.exit(...) method to exit) that the debugger does not finishes automatically. Than you must finish it by hand choosing the command Debug|Finish debugging from the menu.

V.2.3 Tracing over a method

    To do a step and trace over the instruction on the current line (the line which is colored with a different color - see the chapter "Setting up the debugger options") use the command Debug|Trace over from the main menu.

V.2.4 Tracing into a method

    To do a single step and get into the method called from the current line (the line which is colored with a different color - see the chapter "Setting up the debugger options") use the command Debug|Trace into from the main menu.

V.2.5 Tracing out of a method

    There is no way to say the debugger "go back to the method from which the current one has been called". To do this you must use the Call Stack window (for details see bellow). Double click on the line with method from which the current one was called. This will move the cursor into the editor window to the line from which the current method was called. Place the cursor on the position you want to get and use the command Debug|Go to cursor.

    Although this is not nice too much it has one advantage - you can "get out" from several method calls at once.

V.2.6 Getting to a cursor position

    If you want to get to some line in your traced application and you do not want to set a new breakpoint you can use the command Debug|Go to cursor.

    Place the cursor on the line you want the debugger stops at. Than select the command Debug|Go to cursor. If the debugger reaches the specified line it will stop otherwise you will have to use the command Debug|Finish debugging to stop the debugger.

V.3 Watching the state of the application

V.3.1 The "Watches" window

    Watches window use the command Window|Watches.

    In this window you usually look for values of selected variables in an exact moment of a current thread execution. This window is updated whenever the debugger stops (e.g. at a breakpoint). The variables are stored in a list which is loaded and saved in .XelfiOptions file - for more details look into the chapter about the Xelfi options. You can insert new variables (watches) into this list, delete them or edit names of watches (not variables) in the list.

    Values in the window are displayed in form

    [watch name]: [watch value]

    Here are some examples of watches

    a : 50
    flag: true
    point: {x: 34, y: 25, z: 93}
    c: {array: [3, 4, 5, 0], flag: false}

    is an instance of a class which has three fields: x, y, z of integer type and the variable c is an instance of a class which contains two data members. The first one is an integer array with four fields, the second one is a boolean variable flag.

    You often need to get a value of an exact field. If we return back to our example we could have these watches

    point.x: 34
    c.array[2]: 5
    k: 3
    c.array[k]: 0

    Note: If you want to use array indexes in watch names you can use only single integer variables.

    Note: If you will try to display the contents of multidimensional arrays in the Watches window you will get null reference for every field. We believe that this is a bug in JDK implementation (or maybe only in some implementations).

    Sometimes you find useful to show array indexes or decrease (or increase) the depth of recursive searching of complex structures. You can change these settings by the command System|Options. For more details see the chapter "Setting the debugger options".

    Various texts which can occur on the place of a watch value and their meanings:

    • is not defined - the debugger is not started, the current thread is not known, the variable does not exists or it is not visible from the current context
    • is not in scope - the specified variable has not been initialized yet
    • index missing - an array index is missing
    • field missing - a class field name is missing
    • out of bounds - the specified index is out of array bounds
    • invalid expression - a syntax error in a watch name
    • is not an array element - ClassCastException has occurred while obtaining an array field value
    • is not a class field - ClassCastException has occurred while obtaining a class field value
    • ? or null - a current value cannot be obtained from some reason

    Note: If you still obtain the text is not defined on a place of a watch value make sure that the class is compiled with the '-g' option - see the chapter "Starting the debugger".

V.3.1.1 Inserting a new watch

    If you want to add a new watch you have three possibilities. You can use the command Debug|Add watch. from the menu or you can press a combination of keys Ctrl+I in an active Watches window or you can double click with a left mouse button on the last item in this window. When a dialog window appears you insert a watch name and confirm it. After that a new watch is added into the Watches window and a current value is evaluated for this watch.

    Note: The Xelfi prevents to insert a watch twice.

V.3.1.2 Deleting a watch

    If you want to delete a watch use a left mouse button or arrow keys on the keyboard to specify the watch to delete and than press the Delete key.

V.3.1.3 Changing a watch name

    Sometimes you need to change a watch name. For example if you want to change an array index. You have two possibilities to do it. You can press the Enter key or double click with a left mouse button on some item in the Watches window. When a dialog window appears you insert a new watch name and confirm it. After that an old watch is deleted and a new one is added on the position.

    Note: The Xelfi prevents to insert a watch twice.

V.3.2 The "Locals" window

    window use the command Window|Locals.

    In this window you can see all local variables and the current method arguments with their values. Because this window is very similar to the Watches window we want described it more.

    The only difference to the Watches window is that you cannot insert or delete watches. On the other hand sometimes it may be pleasant to see all local variables together without adding them into the Watches window manually.

V.3.3 The "Call Stack" window

    window use the command Window|Call Stack.

    This window provides information about a stack of methods which have been called since the application started. Every method call is on a single line and the contents of the window may look like this

    [1] xelfi.debugger.TestClass.main(args: is not defined)
    [2] xelfi.debugger.TestClass.setA(a: 23)

    This means that in the class xelfi.debugger.TestClass the method setA was called from the method main with one argument a set to a value 23. If you look at the first line you see that the argument args of the method main "is not defined". This is because the value of this argument cannot be get on this context of an execution (see the chapter "The "Watches" window" for details).

    This window has one very useful feature. If you select a line and press the Enter key or double click with a left mouse button on it an editor window with a source code for the specified class will be open (or activated) and the cursor will be placed at a line on which the selected context was left (if it is not the last line in the window) or to the position of a current line (it the selected line in the window was the last one).

    Note: This feature was already described in the chapter "Tracing out of a method".

V.3.4 The "Threads" window

    window use the command Window|Threads.

    window you see information about all thread groups and threads existing in the debugged application. All thread groups are numbered. In an example above you can see a thread group xelfi.debugger.TestClass.main with a number 1.

    Every thread group contains one or more threads which may be running or suspended. If we use the previous example the thread group xelfi.debugger.TestClass.main contains one thread called main which is suspended (probably because it has stopped at a breakpoint).

    The contents of this window is updated whenever you do a step or when the debugger stops at a breakpoint. But sometimes it may happen that you must update the window by hand. For example when the debugged application runs for a long time without reaching any line with a breakpoint. To refresh the Threads window activate it and press a combinations of keys Ctrl+R.