Getting Started
Introduction
Sample Programs
IDEs
History
Advice
Mini-Tutorial
Tutorials
Code Snippets

Resources
Web Sites
More Tutorials
Forums
Vendors/Tools
Books
Magazines
Newsletters
NewsGroups
User Groups
Talk Shows
Blogs

Controls
Overview
Button
Check3State
Checkbox
ComboBox
Frame
Graphic
Image
ImageX
ImgButton
ImgButtonX
Label
Line
ListBox
ListView
Option
Progress Bar
Scrollbar
StatusBar
TAB
TextBox
Toolbar
TreeView

GBIC >> PowerBASIC >> Tutorials >> Debugging

PowerBASIC Information Center Tutorials
These tutorials were written to help you get a quick, but thorough, understanding of PowerBASIC - the scope of the language as well as it's specific capabilities.

Introduction       Projects       Language           Messages       Functions           Advanced
  • Overview
  • Examples
  • IDE
  • Compilation
  • Distribution
  • Project Files
  • DDT Windows
  • Controls
  • Menus
  • Dialogs  
  • Help Files
  • Resources  
  • Templates  
  • Project Shell  
  • Syntax
  • Operators
  • Data Types
  • Variables
  • Scope
  • Declarations  
  • Procedures
  • Flow Control
  • Windows
  • Messages
  • Callbacks
  • Mouse
  • Keyboard
  • Dialogs
  • Controls
  • Subclassing
  • Arithmetic
  • Trig  
  • Strings
  • Arrays
  • Date/Time
  • Printing
  • Files
  • Folders
  • Keyboard
  • Mouse
  • Sound
  • System
  • Error Traps
  • Debugging
  • Objects
  • Graphics
  • Databases
  • API
  • DLLs
  • ASM
  • Threads
  • Debugging
    PowerBASIC provides a complete set of tools with which to identify execution/logic errors within the source code. Programs can be walked through line by line and variables watched for value changes as the lines are executed. These tools greatly simplify the process of resolving problems within the program.

    In general, there are two sets of capabilities: one which is used as part of a normal compile and execute session, and one which requires using the integrated debugger that is built into the PowerBASIC editor.

    As a debugging strategy, using tools during compile and execute is preferred. Once put in place, the debugging statements can be used over and over to help locate program issues. When these fail to provide the information needed, the use of the integrated debugger is appropriate.

    See the error trapping tutorial for additional features PowerBASIC offers that can be helpful in debugging an application.

    Debugging: During Normal Compile and Execute
    There are 3 compiler directives which will provide the programmer with both on-screen displays and log file records of program error/execution details.

    The first two, #Debug Display and #Debug Error are perhaps the easiest of the debugging tools to use. Simply place the two compiler directives one time at the top of the program. and the debugging features will be inserted into the compiled program, ready to provide information to the programmer. The third, #Tools, is a switch that turns on 4 other debugging features. The four features take a little more time and effort to set up, but also return the greatest amount of information.

      DirectiveDescription
      #DEBUG DISPLAY ON   Displays a message when an untrapped run-time error occurs. As seen in this example, the error message appears in a popup dialog and allows you to stop or continue execution.

      This does not display errors captured using On Error and Try/Catch statements. These will be processing normally in the application.

      #DEBUG ERROR ON Detects array boundary and null-pointer errors. As seen in this example, the error message appears in a popup dialog and allows you to stop or continue execution.

      #TOOLS ON Enables CallStk, CallStk$, Profile, and Trace debugging tools. All of these require placement of one or more statements into the application.

      CallStk, Profile, and Trace statements store their output in files, while CallStk$ returns information to a program variable for use/display as the programmer chooses.

    All three compiler directives affect performance of the final application, so their use is normally limited to development only.

    The default for all 3 compiler directives is off. Other compiler directives useful for other aspects of debugging that are discussed further down this page.

    There are four debugging tools enabled by the #Tools On compiler directive. These are very powerful tools and provide the most details of any of the PowerBASIC debugging capabilities.

    • 1. Profile - time spent in each procedure
    • 2. Trace - lists procedures in the order they are called
    • 3. CallStk$ - returns procedure from specific level in call stack
    • 4. CallStk - returns complete call stack listing

    Here's additional information on each of these. A sample application is provided further down the page, showing how the examples in the next few paragraphs were generated.

    1. Profile
    Profile prepares a list of all procedures executed, the number of times the procedures are called, and the total time spent within the procedure. To enable profiling, insert these following statement at the last line of the PBMain() procedure.

        PROFILE "profile.txt"    'use your own file name
    

    When the application is terminated, a file is created which has the following information (the headers are not in the file, they're shown here for information purposes only).

        Procedure       Calls    Time (ms)
        ===========     =====    ========
        MySub_2,         1,         0
        MySub_1,         1,         0
        ButtonProc,      1,         0
        PBMain,          1,         0
    

    It's important to note that the time listed for a procedure includes the time spent in any procedure it calls!

    The value of profiling is not only in determining which subroutines take too much time, but also to see if subroutines are inadvertently being called too often - a common problem in event-driven programs.

    2. Trace
    There are five different statements which make up the PowerBASIC Trace capabilities. Collectively, the statements enable documenting the flow of an application. In particular, there are five types of information captured.

        1. passing through a label
        2. entry and exit from procedures
        3. procedure argument values (on entry only)
        4. run-time errors
        5. custom messages
    

    Here's an example of the output of a series of trace statements. In this example, a button press runs MySub_1 which then calls MySub_2. Each sub has a single Long argument. Both procedures includes a Trace PRINT statement containing "passing through ...", The full code for this example is provided further down this page.

        Trace Begins...
         ButtonProc()
          MySub_1(1508532)
          passing through MySub_1
           MySub_2(1508532)
           passing through MySub_2
           MySub_2 Exit
          MySub_1 Exit
         ButtonProc Exit
    

    In this example, you can see the entry into the button callback function, followed by the program flow through MySub_1 and MySub_2. Both entry and exit from the procedures are logged.

    And finally, here are the five Trace statements that may be used in a PowerBASIC application.

        Trace NEW "filename.txt"       - create output file
        Trace ON                       - start logging
        Trace PRINT "custom message"   - log a custom message
        Trace OFF                      - stop logging
        Trace CLOSE                    - close output file
    

    Trace NEW creates the output file, deleting any pre-existing file by that name. Trace ON and Trace OFF pairs can be used as often as necessary - one pair to capture the entire program, or multiple pairs to selective trace only portions of a program. A Trace PRINT, used to print a custom message by the programmer, can only be used between Trace ON and Trace OFF statements. To close the output file, use the Trace CLOSE

    The more obvious use of Trace is to see if an application performs as expected, or if it branches off in unexpected directions. Trace will also make it obvious when a procedure is executed more often than expected - a common problem in event-driven programs.

    3. CallStk
    PowerBASIC keeps track of all nested procedure calls, maintaining a list called the "stack frame". With the CallStk statement, a snapshot of the current stack frame can be written to a file. Here's the code.

        CallStk "stackfile.txt"    'use any file name
    

    And here's an example of the information found in the file.

        PBMain()
        ButtonProc()
        MySub_1(1508532)
        MySub_2(1508532)
    

    When #TOOLS OFF is used, all CallStk statements are ignored.

    4. CallStk$
    CallStk$ allows a program to capture an item from the call stack, placing it in a variable for use by the program. Here's the code:

        iResult$ = CallStk$(n)   'n is the stack level to return
                                 'n=1 is current level
                                 'n=2 is level that called this procedure
                                 'n=... and so on
    
        MySub_1(395454)          'example of string returned by CallStk$
    

    When #TOOLS OFF is used, all CallStk$ statements return "".

    Example Application
    The following example was used to create the stack, trace, and profile examples above.

        #Compile Exe
        #Dim All
        #Debug Error On     'catch array/pointer errors
        #Debug Display On   'display untrapped errors
        #Tools On           'enables Trace/Profile/CallStk/CallStk$
        Global a() As Single
        Function PBMain() As Long
            Trace New "tracetest.txt"
            Trace On
            Local hDlg As Dword
            Dialog New Pixels, 0, "Button Test",300,300,200,200, _
                                       %WS_OverlappedWindow To hDlg
            Control Add Button, hDlg, 100,"Push", 50,10,100,20 _
                                       Call ButtonProc
            Dialog Show Modal hDlg
            Profile "profiletest.txt"
            Trace Off
        End Function
    
        CallBack Function ButtonProc() As Long
            MySub_1 Cb.Hndl
        End Function
    
        Sub MySub_1(h As Long)
            Trace Print "passing through MySub_1"
            MySub_2(h)
        End Sub
    
        Sub MySub_2(h As Long)
            CallStk "stacktest.txt"
            Trace Print "passing through MySub_2"
        End Sub 
    

    Debugging: Using Integrated Debugger (Debug Mode)
    The entire (lengthy) discussion on this page so far covered only those debugging tools which can be used during a normal compile and run session.

    This next section covers the use of the integrated debugger, which is a part of the PowerBASIC editor. In a debugging session, code is added by the compiler which allows the integrated debugger to control, line by line, execution of the application. Additionally, at each line a programmer can view or change the current value of any in-scope variable(s).

    Debug mode can be entered in three ways - two menu options and one toolbar button.

    • Menu: Run / Compile and Debug
    • Menu: Debug / Run
    • Toolbar: "Compile and Debug Current File" button

    In all three cases, the program will be compiled and execution will begin. When a debug session is started, it stops on the first line within the PBMain() function. This gives the programmer an opportunity to set breakpoints and watch variables.

    Breakpoints can also be set at any time during a PowerBASIC editing session.

    Once debug mode is started, the PowerBASIC menu and toolbar are changed to reflect additional debug mode features, as discussed in the next two sections.

    Breakpoints
    In debug mode, execution of a program will at the first line of PBMain() and also at any line of code which has been designated as a breakpoint.

    To set a line of code as a breakpoint, use the F9 hot key or the Debug/Toggle Breakpoint menu sequence. Breakpoint lines are highlighted in red.

    The value of breakpoints is that they let the programmer evaluate the status of the program in several ways, including changing variable values as needed, before continuing execution of the program.

    The following actions can be taken once a breakpoint is reached and program execution has been stopped.

    • Display the value of a variable (Variable Evaluator window)
    • Monitor list of variable/values (Variable Watcher window)
    • Clear existing or set new breakpoints
    • Continue running the program one line at a time
    • Run the program to the next breakpoint, next error, or to completion

    Debug Mode Toolbar
    Once PowerBASIC enters debug mode the toolbar changes as shown in the following image, offering features available only in debug mode.

     

    The additional toolbar entries are a subset of the complete debug menu options as shown in the next paragraph.

    Debug Menu
    When in debug mode, the debug menu submenus become active, providing the following options. The options can be broken into the following categories.

      Run (6) - Run, Run to Caret, Animate, Stop, Restart, Exit Debugging
      Step (3) - Step Into, Step Over, Step out
      Breakpoints (2) - Toggle Breakpoint, Clear All Breakpoints
      Variables (3) Evaluate Variable, Variable Watch Window, Clear All Watches
      Register Watch (1) Watch CPU Registers

    And here is the full list of options.

    • Run F5
      Compile and debug the current source document/Primary Source File, stopping at the first line in PBMain()

    • Run to Caret CTRL+F8
      Run the program from the current bookmark until reaching the line where the caret has been placed, or until it reaches a bookmark.

    • Animate Ctrl F5
      Run one line at a time (Step-Into mode) until a breakpoint is reached, the Stop button is pressed, or the program completes. Step-to-step delay time can set in the IDE Options dialog.

    • Stop CTRL+BREAK
      Halt the debugger, return to normal edit mode.

    • Step Into F8
      Debugger follows all code lines, including into those which lead into procedures. It cannot step into an API call nor into an external module.

    • Step Over SHIFT+F8
      Debugger executes, but does not display procedure code.

    • Step Out CTRL+SHIFT+F8
      Debugger stops after executing the current procedure.

    • Evaluate Variable
      Opens a window in which the programmer can get or change the value of a variable. From here, variables can also be added/removed from the Variable Watcher window. Note: string variable lengths may not be changed.

    • Clear all Watches
      Remove all variables from the Variable Watch window.

    • Toggle Breakpoint F9
      Set/release breakpoint (current line).

    • Clear all Breakpoints
      Release all breakpoints.

    • Watch CPU Registers
      Show/hide Register Watcher window (displays CPU registers/flag values).

    • Variable watch window
      Show/hide Variable Watcher window (displays ERR and selected variable value).

    • Program Restart SHIFT+F5
      Stops the current debug session and starts a new one. All variables will be re-initialized. Debug session will begin, stopping at the first line of PBMain().

    • Exit Debugging
      Halts the current program and terminates the debugger, returning to normal editing mode.

      The variable list in the Variable Watch window is retained between debugging sessions, until the IDE is closed.

    Variable Watcher Window
    In debug mode PowerBASIC conveniently provides the ability to specify a list of variables whose values can be watched in a separate window - the Variable Watcher window.

    This window is only visible in debug mode when execution is stopped at a breakpoint. It is not visible when the program is running freely in debug mode.

    To specify which variables will be in the watch window, enter debug mode and select a variable by double clicking on it. Once selected, use the context menu "Watch" to add a variable to the watch list.

    If a variable has already been added to the watch list, the context menu will say "UnWatch" and allow removal of a variable from the watch list.

    Variables can also be add/removed from the Variable Watcher list from the Variable Evaluator windows, discussed in the next section.

    A sample Variable Watch Window is shown below. It contains the list of variables and their current values.

    Not that only variables in-scope will have values listed. When a variables goes out of scope the values will be listed as "<<Cannot Be Displayed>>".

    To modify one of the variables on the watch list, simply double click on the variable to open the Variable Evaluator window, which is used to view/change a variable's value.

    Variable Evaluator Window
    In addition to watching the values of a list of variables, PowerBASIC provides the Variable Evaluator window that allows programmers to select a single variable, then read or modify its value before continuing with execution of the program.

    The Variable Evaluator window can be opened using the "Debug/Evaluate Variable" menu sequence, the "Evaluate variable" toolbar button, or by highlighting a variable in the IDE, then using the "Evaluate" context menu selection.

    If a variable is a string type, it's length may not be changed in the Variable Evaluator window. If a new value of incorrect length is entered, the Variable Evaluator window will adjust the length as needed.

    The watch status of a variable can also be turned on/off in this window.

    Register Variables
    As a method of improving application performance, PowerBASIC offers a feature called Register Variables. This feature is discussed in more detail elsewhere in the tutorial. The register values can also be viewed while in debug mode by using the Debug/Watch CPU Registers menu sequence.

    Register variables can also be on the watch list, making them visible from both windows.

    Debug Compiler Directives
    One set of compiler directives were discussed at the top of this page, those directives which work during a normal compile and execute session.

    There are also two other compiler directives which work only during Debug mode.

      DirectiveDescription
      #DEBUG CODE OFF Suppresses generation of debugging code. As part of compiling for debugging, code is generated to create breakpoints and other debugging features. The extra code can slow down the code being debugged.

      With #Debug Code OFF, the extra debug code is suppressed until a #Debug Code ON is reached.

      Where #Debug Code OFF is used, breakpoints may not be assigned.

      These statements are ignored during normal compiling.

      #DEBUG PRINT "msg" Displays custom message in the IDE's Debug Window. This is simply a convenient way of displaying a series of messages while a program is running without having to create a listbox, or some other control, for that purpose.

      The Debug Window (lower part of the IDE client window) can be scrolled. Non-printable characters are converted to hex format.

      These statements are ignored during normal compiling.

    Here's an image of a simple application in the PowerBASIC IDE, showing two lines written in the Debug window using the #Debug Print compiler directive.

    Code Finder F2
    Finally, while not exclusively a debug mode option, PowerBASIC provides a quick way to see all procedures (Sub/Function/Method/Property) in a project. Code Finder, as it is called, can be accessed using the Find (binocular) icon on the toolbar, through the Edit/Code Finder menu sequence or using the F2 hot key.

    To display a procedure, just double click on the procedure name within the Code Finder window. This ability to quickly locate and move through code can be very valuable in locating and modifying source code issues.

    If you have any suggestions or corrections, please let me know.