Adding debug symbols and instrumentation code to binaries

The active build configuration determines which make commands are used to compile and link binaries in the current project. To debug and analyze your program with certain tools, you must define the right options in those commands.

When you use the IDE to create a project based on standard makefiles, the IDE generates a default makefile that defines the compiler and linker flags required to build different binary versions. These flags are stored in variables with descriptive names (e.g., CCFLAGS_debug, LDFLAGS_profile).

If you create a project outside of the IDE or inherit a project from a third party, your makefiles might not be set up in this way. In this case, we recommend reorganizing them to use such variables because it makes it easy to support various analysis activities. You should define variables for storing compiler options, linker options, and libraries to link, for each of four binary versions:
  • debug
  • release
  • coverage
  • profile

No tool-enabling options should be used with the release version because it's intended for use in post-deployment (i.e., customer) environments. Also, for some activities, such as profiling, you may have to change the flags and rebuild if you want to measure different metrics.

For QNX Legacy Recursive Make projects, which use managed recursive makefiles, you must adjust the project properties to build the binary for debugging or for generating analysis data. You can't edit the makefiles directly.

Enabling debug symbols

The QNX build tools (qcc and q++) use the same flag for adding debug symbols as the GDB tools (gcc and g++), namely, the -g option. For standard makefiles, you simply add this option to the debug compiler flags:
CCFLAGS_debug += -g -O0 -fno-builtin
For QNX Legacy Recursive Make projects, you must ensure that the debug binary versions are selected for building:
  1. Choose Project > Properties > QNX C/C++ Project.
  2. In the Build Variants tab, expand the listings for all architectural variants that you want to build.
  3. Check the debug boxes for all variants that you want to debug.
  4. Click OK to confirm the settings and exit the properties window.

    The IDE updates the makefile and rebuilds the project.

Enabling Code Coverage instrumentation

If your project uses standard makefiles, you must define -f options to add instrumentation code for measuring which lines of code are executed. You should verify that the following options (shown in bold) are defined in the coverage variables:
CCFLAGS_coverage += -g -O0 -ftest-coverage -fprofile-arcs -nopipe -Wc,-auxbase-strip,$@
LDFLAGS_coverage += -ftest-coverage -fprofile-arcs
The relevant options are:
  • -O0 (“big-oh zero”) — turns off compiler optimization; optimization eliminates some lines of code, making it impossible to maintain separate execution counts for each line
  • -fprofile-arcs — adds code to the object files to record program arcs (flow)
  • -ftest-coverage — generates notes files (.gcno), which are needed to report program coverage
For QNX Legacy Recursive Make projects, you must modify the QNX C/C++ Project properties as follows:
  1. Choose Project > Properties > QNX C/C++ Project.
  2. In the Options tab, under Build Options, check Build with Code Coverage.

    You must have only one architecture and variant selected in the Build Variants tab. Otherwise, the IDE displays an error and won't build the project until you fix the configuration.

  3. In the Compiler tab, under Code Generation Options, set Optimization Level to “No optimize”.

    Code optimization should be turned off because it can produce inaccurate coverage results. Also, in this release, you don't need to explicitly specify the -f options for the compiler flags (CCFLAGS) or linker flags (LDFLAGS).

  4. Click OK to confirm the settings and exit the properties window.

    The IDE updates the makefile and rebuilds the project.

Full details about all UI fields that control the building of these types of projects are given in the QNX C/C++ Project properties reference.

Enabling call count instrumentation

The qconn agent periodically samples the execution position of a running process, by recording the current address every millisecond. This means that you don't need to instrument the binary to see where in the code your application spends most of its time. However, runtimes estimates based on statistical sampling don't tell the full story because you still need to know how often a function gets called when determining what areas to optimize.

In standard makefiles, to insert code that counts function calls, you must add the -p option to the profile compiler and linker flags:
CCFLAGS_profile += -p -g -O0
LDFLAGS_profile += -p

For the compiler, the -p option makes it insert code at every function entry to gather call information. This information allows the IDE to display who called that function and its place in the program's call graph, through the right-click menu of the Execution Time view. For the linker, the option makes it link in the profiling version of libc.

When the Sampling and Call Count Instrumentation profiling method is selected in the Application Profiler UI fields, the IDE always shows runtime estimates in the results, even if -p isn't specified. But in this case, neither the call counts nor the call information previously mentioned are shown.

Note: If your application uses libraries that weren't compiled with -p, the profiling results don't include call counts for their functions. If a lot of execution time is spent inside these functions, this profiling method may not be of much value and you may instead want to use function instrumentation, which is explained in the next subsection. With this other method, the time spent in a non-instrumented library function is charged to the caller.
For QNX Legacy Recursive Make projects, you must adjust the QNX C/C++ Project properties as follows:
  1. Choose Project > Properties > QNX C/C++ Project.
  2. In the Options tab, under Build Options, check Build for Profiling (Call Count Instrumentation).
  3. Click OK to confirm the settings and exit the properties window.

    The IDE updates the makefile and rebuilds the project.

Enabling function instrumentation

In standard makefiles, you must define options to add instrumentation code for measuring precise function runtimes. You should verify that the following options (shown in bold) are defined in the profile variables:
CCFLAGS_profile += -g -O0 -finstrument-functions
LIBS_profile += -lprofilingS

For the compiler, the -finstrument-functions option makes it insert code at every function entry and exit. This code calls a profiling library function that records the current time. When displaying the results, the IDE can then calculate the total time spent inside a given function, based on its entry and exit timestamps. For the linker, the -lprofilingS option makes it link in the profiling library (libprofilingS.a), which implements the time-recording methods.

For QNX Legacy Recursive Make projects, you must adjust the QNX C/C++ Project properties as follows:
  1. Choose Project > Properties > QNX C/C++ Project.
  2. In the Options tab, under Build Options, check Build for Profiling (Function Instrumentation).
  3. Click OK to confirm the settings and exit the properties window.

    The IDE updates the makefile and rebuilds the project.