Section 8. Debugging

Section 8.1. Debugging Utilities
When a bug is found using Covered, it is often useful for a developer to understand what utilities are available for debugging the problem at hand. Besides using some standard debugger, Covered comes with several built-in debugging facilities useful for narrowing in on the code that is causing the problem. They are the following:
  1. Global Covered option -D
  2. Internal code assertions
  3. Command-Line Interface (CLI) interactive layer
  4. Internal source code profiler
The following subsections will describe what these facilities are and how they can be used or added to.
Section 8.1. Built-in Command Debugging Utility (-D option)
Covered comes with a global command option (a global command is a command that can be used with any command) called '-D'. When this option is specified for any command, interal information is output to standard output during the command run. The information output is meant to help find the area of code which is causing the problem (in the case of a segfault or some other error which causes Covered to exit immediately) and to help understand the values that are being provided to the functions that are output the debug functionality.
The merge and report commands currently do not emit much debugging information; however, the score command contains a great deal of debugging information. Most of the debugging information comes from the database manager functions. Each function in the db.c source file contains a single debug output statement, specifying the name of the function being executed as the values of the parameters passed to that function. If any new functions are added to db.c, it is recommended that these functions output debug information. Additionally, the expression_operate function in expr.c contains a debug output statement that is useful for tracking what Covered is doing during the simulation phase of the score command. If key information is missing in any other functions, it is recommended that that information be displayed in debug output.
To display debug information, the file that you are working with should contain the following code.
 #include <stdio.h>
 #include "util.h"
 extern char user_msg[USER_MSG_LENGTH];
Once this code has been added to source file, add the debugging information using the snprintf function along with the print_output function specified in util.c. The following example specifies how to output some debug information:
 void foobar( char* name ) {
   snprintf( user_msg, USER_MSG_LENGTH, "In function foobar, name: %s", name );
   print_output( user_msg, DEBUG );
   // ...
Note that it is not necessary (or recommended) to specify a newline character after the user_msg string as the print_output function will take care of adding this character.
Section 8.2. Internal Assertions
The second debugging facility that is used by Covered are C assertions provided by the assert.h library. Assertions are placed in the code to make sure that Covered never attempts to access memory that it should not be accessing (to avoid segmentation fault messages whenever possible) and to verify that things are in the proper state when performing some type of function. The benefit of creating an assertion is that a problem can be detected at the source (speeding up debugging time) and a core dumpfile can be created when Covered is about to do something bad. The core file can be used by a debugger to see where in the code was executing when the problem occurred.
To use an internal assertion, make sure that the file you want to add the assertion to contains the following include.
 #include <assert.h>
Once this header file has been included, simply use its assert function to verify a condition that evaluates to TRUE or FALSE. The overhead for assertions is minimal so please don't be shy about putting them in wherever and whenver appropriate.

Section 8.3. Command-Line Interface
Covered comes equipped with its own command-line interface which allows the user to interactively run Covered's simulator and view internal signal, expression, thread and queue information. This CLI is called in the simulator (sim.c) each time a thread is executed. This allows the user to 'step' one thread simulation at a time, go to the 'next' timestep, or simply 'run' the simulation without user interaction. The CLI provides a prompt for the user to enter a command to execute.
For more information on how to use the CLI for debugging purposes, see the User Guide or simply type 'help' at the CLI command-line. Note that this capability only exists when Covered is built with the --enable-debug option to the configuration script.

Section 8.4. Internal Source Code Profiler
Though gcc and gprof work well as a generic source code profiling toolset, it was determined that it would be useful for Covered to have its own built-in profiler for the purposes of getting more Covered-specific information that developers might find interesting and/or useful.
The usage of a built-in profiler does, however, require the developers of Covered to add special calls within the source code to allow the timers to accurately record time spent in each function. Some of this work is done manually and some of it is done through the use of a Perl script which is located in the /b src directory called /b The following paragraphs describe how to properly add this information so that the profiler can generate profiling statistics about this function.
When a new function is added that the user wants to make profiling information available for, a macro called "PROFILE" should be called with the name of the function (capitalized) specified as the argument for the macro. Likewise, if the function is meant to be timed, the PROFILE_END macro should be specified as the last line prior the function returning. Please note that only one PROFILE_END can be specified per function, so these types of functions can only have one return() call at the very end of the function. The following example shows how this is accomplished:
 bool foobar() { PROFILE(FOOBAR);
   bool retval = TRUE;
   // Do some stuff.
   return (retval);
Once these profiling commands have been added to all needed functions, the code developer must run the script in the src directory to add these new functions to a mapping structure that is used by the profiling source code. If this script is not run, the new functions will not compile. There are no arguments to this script. It will parse all .c files looking for all PROFILE(...) calls, take the string specified within the call and append this information to a globally accessible structure located in the gen_prof.h and gen_prof.c files. Note that these two files are completely generated so any hand-modifications to these files will be lost when the script is run again. Please make any necessary modifications to this script instead.
Since the script only parses .c files, any profiling macros specified in a .y or .l file will not be parsed until the code is first generated into .c files.
Also note that certain functions should not be profiled! All profiling code should not be profiled. Also the timer functions in the util.c file should not be profiled (this would cause Covered to go into an infinite loop if this were to occur).

Go To Section...
Generated on Sun Nov 21 00:55:42 2010 for Covered by  doxygen 1.6.3