Debug Execution

Parent Previous Next

Debug Execution.

Before you can debug the execution of the bytecode, you must perform these 3 simple steps:


Once these 3 simple tasks are completed, you can debug the code with breakpoints, step in, step over, step out, run to cursor and much more, while simultaneously monitoring the call stack and value assignments.


How does it work?

The chapter Debug and Trace Analysis contains a detailed description, but the short version is:



Before Debugging.

Please carry out the following 3 simple steps to prepare the debugging session.


Step 1. Switch On Trace Information.

Open the project properties form:

» Select the project node in Project Explorer.

» Right-click the project node and choose the menu function Properties.



Modify the fields:

» Enable the check marks for the fields Trace Code and Trace Assignments  A .

» Add the path for CUF  B .

» Press the OK button and save the file.


Now the compiler will include extra instructions in the bytecode for the debugger, and the compiled bytecode will be saved to the CUF on the next compilation.


Step 2. Add TraceWrite Function.

» Copy and paste the line(s) marked below to your source.

» Edit the path in the library function  @TraceWriteFile(..)  to match your requirements. Please notice you can't use a placeholder like $(ProjectDir) here.

» Save the source file to disk.


Class Main

{

 Public Function Main(Integer x, y, z) : Integer

 {

   //Create our text variable.

   String text := "X=" + x.ToString() + " and Y=" + y.ToString();


   //Convert text to UTF8 bytes, rotated z bits left.

   Blob crypto := Encrypt(text, z);


   //Write to the public VM cells, which are readable to the host.

   //Each cell is assigned as @CellSetType(rowIdx, columnIdx, value).

   @CellSetString(1, 1, text);

   @CellSetBytes(1, 2, crypto);


   //VM writes all trace events to a file for the debugger.        

   @TraceWriteFile("c:\Data\QuickStart\QuickStart.evnt", False);    


   Return crypto.Length();

 }


 Private Function Encrypt(String text; Integer rotateBitsLeft) : Blob

 {

   //This is a very simple encryption which turns the text

   //into UTF8 bytes, and then rotates the bits to the left

   //(or alternatively to the right if rotateBitsLeft < 0).


   Integer cpUTF8 := 65001; //the utf8 codepage;

   Blob tmp := @EncodeStringToBytes(text, cpUTF8);

   Return tmp.Rotate(0, rotateBitsLeft);

 }

}


Now the trace events (created by the extra bytecode instructions of Step 1) are saved to a file just before we return from Main and finish execution.


Step 3. Compile and Execute.

Compile the modified source code and build the bytecode.

» Press Ctrl+F11 or click the menu item Compile > Compile + Build.


Now the rebuilt bytecode is stored both in memory but also in the Compilation Unit File (CUF) specified in Step 1.

» Verify the CUF was created/overwritten in the directory you specified.


To execute the bytecode and create the trace file:

» Press the function key F5 or click the menu item Compile > Test Execution.

» View the Setup tab-page.



» Load or specify the Compilation Unit File (CUF) you just created. We want to use the bytecode of this CUF1.

» Return to the Execute tab-page and execute the bytecode again as you did here.

» Please verify that the library function  @TraceWriteFile(..)  has created the trace file.


Note 1: Later you will learn how important it is, that the bytecode in the CUF is the same as the bytecode generating the trace events. This is why we take extra care and load the bytecode from the CUF, even though the same bytecode currently is also stored in memory.



Start Debugging.

Now you are ready to open the debugger, load the CUF + trace file, and start debugging the execution.

» Press the function key F7 or click the menu item Compile > Debug and Trace Analysis.

» View the Setup tab-page.

» Load the Compilation Unit File (CUF) and the trace events file using the dedicated drop-down buttons. Alternatively you can click the menu items Session > Load Compilation Unit File  and  Session > Load Trace Events.



» View the Trace Events tab-page.


Now the events should be presented like this colorized with values in red and statements in black.


TIP: If a lot of the black colored fields are missing, then you have a problem with the timestamps of the CUF (or the CUF is simply not loaded). To solve this please verify Step 1 and 2 are completed correctly, and finally execute Step 3 again to overwrite the CUF and the trace file.


» Start debugging by pressing the function key F7 or click the menu item Debug > Step In.

» Do it again to single-step to the next statement.

» Do it again.


Now you are here inside the called Encrypt function, ready to execute the statement in yellow.



Please notice the Call Stack entry (with the arrow) which identify the event that calls the Encrypt function from within the Main function. If you double-click the entry the cursor will jump to the call location.


» View the Trace Events tab-page.


Event 5 is the next statement the debugger will execute.


» View the Debug Execution tab-page.

» Single-step (F7) again. This will execute event 5.

» View the Trace Values tab-page.



Here you can follow all the explicit value assignments. Executing event 5 produced the value in event 6. If you double-click an entry in this list, you will jump to the event in question on the Trace Events tab-page.


» Please continue to single-step (F7) all the statements and repeat investigating the tab-pages.

» Please notice that event 13 is the last recorded event. The actual exit from the Main function with  Return crypto.Length();  is not recorded.


Try This.

Once you have completed the execution, feel free to:



Auto-Load Files.

If you repeatedly use the tools for testing (F5 Compile > Test Execution) or (F7 Compile > Debug and Trace Analysis), you can save a lot of time by having the IDE load all the required files automatically when the form is opened. This auto-load feature is described here and here.