# ROSE Compiler Framework/How to debug a translator

It is rare that your translator will just work after your finish up coding. Using gdb to debug your code is indispensable to make sure your code works as expected. This page shows examples of how to debug your translator.

## Preparations

First and foremost, make sure your ROSE installation and your translator was built with -g and without GCC optimizations turned on. This will ensure all debug information will be best preserved.
To configure ROSE installation with debugging options, you can add the following options to your normal configuration.
If you already built ROSE but forgot what options you used, you can go to your buildtree of ROSE to double check if debugging options are used:
Before you debug your own translators, you may want to doublecheck if ROSE's builtin translator (rose-compiler) can handle your input code properly. If not, you should report the bug to the ROSE team.
If rose-compiler can handle it but your customized translator cannot. The problem may be caused by the customizations you introduced in your translators.
Another thing is to reduce your input code to be as small as possible so it can just trigger the error you are interested in. This will simplify the bug hunting process dramatically. It is very difficult to debug a translator processing thousands of lines of code.

## Basics of GDB

gdb is a debugger. It provides a controlled execution environment for you to inspect if your program is running the way you expected.
Essentially, it allows you to:
* run your program within a controlled debugging environment: using gdb—args <program> <args...>
** or libtool—mode=execute gdb—args <progra> <args...> for libtool built executables.
* stop at desired execution points
** normal breakpoints (called breakpoints): using break <where>, <where> can be a function name, line_number, or file:line_number.
** when value changes for a given variable(called watchpoint): using watch <where>
** segmentation fault : this will happen automatically, so you can inspect how a seg fault happens
** assertion failure: this will happen automatically, so you can debug assertion failures.
* inspect and even change things like variables, types, etc. once your program stops at desired execution points
** inspect the call stack at the breakpoint: using backtrace or bt in short. frame <frame#> to go to the stack frame of your interests.
** look around relevant source code near the breakpoint: using list [+|-|filename:linenumber|filename:function]
** inspect the values of variables and expressions: using print <what>, <what> can be any variable, expression, or even function call.
** inspect the type of a variable: whatis variable_name
** change the content of a variable to a given value: set <var_name>=<value>
** call functions: using print function_name, this is helpful to call some dump functions for some class objects.
* control the execution further
** step one statement at a time, through the execution of your program: you can step through at the current frame (next), step down into a frame (step), or step out the current stack frame (finish),
** continue the execution until next breakpoint or watchpoint: using continue or c in short
** return from a function immediately, passing a given value: return <expression>
* and other things.
For a quick overview, you can look through a cheat sheet online:
* https://kapeli.com/cheat_sheets/GDB.docset/Contents/Resources/Documents/index
From Rob, There is a curses-based wrapper called "cgdb" .
* You get a split window: the bottom is the GDB console and the top is syntax-highlighted source code that automatically tracks your current location and supports PageUp/PageDn, which is a lot easier to use than GDB's "list" command.
* it requires ncurses-devl and readline-devel to install.

## A translator not built by ROSE's build system

This is also called out-of-sourcetree build for some people.
If the translator is built using a makefile without using libtool. The debugging steps of your translator are just classic steps to use gdb.
* Make sure your translator is compiled with the GNU debugging option -g so there is debugging information in your object codes
These are the steps of a typical debugging session:
1. Set a breakpoint
2. Examine the execution path to make sure the program goes through the path that you expected
3. Examine the local data to validate their values

### Example 1: debugging an AST traversal

We first prepare the example ROSE-based analyzer traversing AST to find loops. Rename it to be demo.C:
* wget https://raw.githubusercontent.com/rose-compiler/rose/develop/tutorial/visitorTraversal.C
* mv visitorTraversal.C demo.C
We can look into the example analyzer's source code: cat demo.C Essentially, we can see the following content:
A ROSE-based tool initializes ROSE first (at line 35). Then the frontend function is called to parse an iput code and generate an AST rooted at project of SgProject type (at line 40).
After that, a traversal object is declared at line 44. The object is used to traverse the input files of the project, using a preorder traversal.
The traversal object is based on a derived visitorTraversal class at line 6. This derived class has member functions to define what should happen during construction (line 14), visiting a node (line 18), and the end of the traversal (line 26).
Now get a sample makefile to build the source file into an executable file:
* wget https://raw.githubusercontent.com/rose-compiler/rose/develop/tutorial/SampleMakefile
The makefile should be self-explanatory. It uses rose-config in the installation path to set various environment variables for compilers, compilation and linking flags, library path, etc.
Get an example input code for the analyzer:
* wget https://raw.githubusercontent.com/rose-compiler/rose/develop/tutorial/inputCode_ExampleTraversals.C
The input code has two for-loops at line 20 and 41, as shown at link
Prepare the environment variable used to specify where ROSE is installed.
* export ROSE_HOME=/home/freecc/install/rose_install
Build the analyzer:
* make -f SampleMakefile
There should be an executable file named demo under the current directory:
Finally, run the demo analyzer to process the example input code:
* ./demo -c inputCode_ExampleTraversals.C
The analyzer should find two for loops and report the end of the traveral.

#### Debug The Translator

Now let's debug this simple translator.
First of all, use gdb -args to run the translator with options

#### Inspect post_construction_intialization

Breakpoints at the post_construction_initialization are useful to inspect when a node is created and/or if a node has required fields set after construction. For example, going through the callstack (using up and down command in gdb) leading to this function call can inspect if the node has parent or scope pointers set. If not, you can add such operations to fix bugs related NULL pointers.

#### Set a condition to Breakpoints

In real codes, there are hundreds of objects of same class type (e.g. SgForStatement). Many of them come from header files and will be present in AST. We should only stop when it mathes the one we want to inspect. Often, we can use the memory address of the object as a condition.

#### Use Watchpoints

You can use a watchpoint to stop execution whenever the value of an expression changes, without having to predict a particular place where this may happen. (This is sometimes called a data breakpoint.)
Watchpoints can be treated as special types of breakpoints. They will stop when the watched memory locations have value changes. This is especially useful when you want to know when some variable (or field of an object) is set to some value or cleared its value. For example, often a bug is related to some NULL value of some fields of a node. The fields may be set during construction of the node. But later mysteriously one field becomes NULL. It is extremely hard to find when this happens without using watchpoint.
For example, we want to watch the value changes to the parent field of the SgForStatement matching the memory address of the 2nd loop.
* We first stop at a breakpoint where we have access to the node's internal fields. This usually is done by stopping at SgForStatement::post_construction_initialization.
* Once the internal variables are visible in gdb at the proper breakpoint, we can grab the memory address of the internal variable. This requires your knowledge of how internal variables are named. You can either look at the class declaration of the object, or guess it by convention. For example, mostly something with an access function like get_something has a corresponding internal variable named p_something in ROSE AST node types.
* Finally, we have to watch the deferenced value of the memory address (watch *address). Watching the memory address (watch address) is to watch a constant value. It won't work.

## A translator shipped with ROSE

This is also called in-tree or in-sourcetree build. libtool is used to build the translators.
ROSE turns on -O2 and -g by default so the translators shipped with ROSE should already have some debugging information available. But some variables may be optimized away. To preserve the max debugging information, you may have to reconfigure/recompile rose to turn off optimizations.
ROSE uses libtool so the executables in the build tree are not real—they're simply wrappers around the actual executable files. You have two choices:
* Find the real executable in the .lib directory then debug the real executables there
* Use libtool command line as follows:
If you can set up alias command in your .bashrc, add the following:
then all your debugging sessions can be as simple as
The remaining steps are the same as a regular gdb session with the typical operations, such as breakpoints, printing data, etc.

### Example 2: Fixing a real bug in ROSE

1. Reproduce the reported bug:
Ah, so we've failed an assertion within the virtualCFG.h header file on line 111:
And the error was produced by running the lt-testVirtualCFG libtool executable translator, i.e. the actual translator name is testVirtualCFG (without the lt- prefix).
2. Run the same translator command line with Libtool to start a GDB debugging session:
The GDB session has started, and we're provided with a command line prompt to begin our debugging.
3. Let's run the program, which will hit the failed assertion:
Okay, we've reproduced the problem in our GDB session.
4. Let's check the backtrace to see how we wound up at this failed assertion:
5. Next, we'll move backwards (or upwards) in the program to get to the point of assertion:
Okay, so the assertion is inside of a constructor for CFGEdge:
Unfortunately, we can't tell at a glance which of the two conditions in the assertion is failing.
6. Figure out why the assertion is failing:
Let's examine the two conditions in the assertion:
So src.getNode is returning a non-null pointer to an SgNode. How bout tgt.getNode?
Ah, there's the culprit. So for some reason, tgt.getNode is returning a null SgNode pointer (0x0).
From here, we used the GDB up command to backtrace in the program to figure out where the node returned by tgt.getNode was assigned a NULL value.
We eventually found a call to SgReturnStmt::cfgOutEdges which returns a variable, called enclosingFunc. In the source code, there's currently no assertion to check the value of enclosingFunc, and that's why we received the assertion later on in the program. As a side note, it is good practice to add assertions as soon as possible in your source code so in times like this, we don't have to spend time unnecessarily back-tracing.
After adding the assertion for enclosingFunc, we run the program again to reach this new assertion point:
Okay, it's failing so we know that the assignment to enclosingFunc is NULL.
Okay, we're inside of an SgReturnStmt object. Let's set a break point where enclosingFunc is being assigned to:
So this is the line we're examining:
So the NULL value must be coming from SageInterface::getEnclosingProcedure(this);.
After code reviewing the function getEnclosingProcedure, we discovered a flaw in the algorithm.
The function tries to return a SgNode which is the enclosing procedure of the specified type, SgFunctionDefinition. However, upon checking the function's state at the point of return, we see that it incorrectly detected a SgBasicBlack as the enclosing procedure for the SgReturnStmt.
Specifically, the last piece: 0x7cd0e8 "SgBasicBlock".
But this is wrong because we're looking for SgFunctionDefinition, not SgBasicBlock.
Upon further examination, we figured out that the function simply returned the first enclosing node it found, and not the first enclosing node that matched the user's criteria.
We added the necessary logic to make the function complete, tested it to verify its correctness, and then resolved the bug.