Selecting a tool for debugging

The IDE works with several third-party tools and contains its own features that help you debug improper program results,
process hanging, or process crashing.

These debugging use cases are defined as follows:

Improper program results

No fatal error occurs but the application doesn't do what's expected.

Process hanging

The application becomes unresponsive but continues running.

Process crashing

The application exits abruptly, without properly terminating its operations.

Guidelines on selecting a tool for each use case are given below.
The debugging capabilities of these tools are listed in Integrated tools.

Improper program results

There are many IDE tools that can help you find logic errors in program code or memory corruption issues.
Generally, you should first launch the application with the debugger attached
and try to reproduce the bad behavior. If you can't reproduce it, you can wait until you next see the improper results,
then attach the debugger to determine what state the program is in and how it
got there. For multiprocess programs, you can debug a child process.

If you step through the program's code and examine its memory and variable contents but can't figure out why the
application is misbehaving, you can investigate the issue using other tools:

If you think that data is being corrupted, run a memory-checking tool—Memory Analysis, Valgrind Helgrind, or
Valgrind Memcheck. These tools identify runtime errors that are often related to memory corruption, such as
reads of uninitialized or invalid memory.

If you suspect there's a bad value coming from another process or there's an odd interaction between processes,
use the System Profiler to see the system-level activity (e.g., kernel calls, interprocess messaging) on the
target. To do so, you must first run a kernel event trace
to capture this activity. The System Profiler then lets you
view the trace data.

If both these options fail to identify the cause, you must continue using the debugger.
You can set more breakpoints to see which code paths are followed when the bad behavior happens.

Process hanging

When you observe an unresponsive application, the IDE can help you inspect the application's current state. This way,
you can learn which processes are hanging without having to rerun the application and attempt to reproduce the problem.

The quickest way to start investigating a hanging process is to view the current target machine state through the
QNX System Information perspective. Here, the System Resources view lists CPU usage
by process, so you can see right away which processes are consuming excessive resources or no resources.
You can see thread-level details in the Process Information view, including thread states.

If the System Information doesn't give you a good idea of why a process is hanging, you can use other tools
to figure out what the application is doing:

You can run a kernel event trace to capture the system-level
activity on the target and then view the trace data with the System Profiler.
These data can tell you if a process is spinning (i.e., actively executing but not making progress) and if another
process is involved. An example would be livelock, when the interaction between processes is causing them to cycle
endlessly between the same states. The trace data can also reveal deadlock. For instance, if a process is waiting
on both a mutex and a semaphore, it's likely a case of priority inversion.

To see exactly where the application is stuck, you can attach the debugger to the hanging process. As soon as it attaches to a process, the GDB tool
stops execution and shows the current line of code (assuming there are matching binaries on the host).
This is particularly helpful for deadlock within a process. Suppose one thread is at the start of a critical
section. This likely means it can't acquire a necessary resource and is the cause of the deadlock.

Sometimes, attaching the debugger to find the current execution position and stepping through
the code doesn't tell you why the program is stuck.
In this case, you can use the Application Profiler to enable sampling-based profiling. This profiling method makes the application report its current line
at regular intervals, which tells you if a function is consuming a lot of execution time.

Note:
The Application Profiler won't help with deadlock because the application must be executing code for the tool
to receive samples.

Process crashing

When a process crashes on a machine running dumper, a core file is generated and the IDE gives you the
option of debugging that core file. If you choose to do so, the IDE downloads it from the target to the host's workspace
and launches the debugger. The core file contains the final state of the program, allowing you to see what happened.

When the program crashes, GDB stops execution and displays the stack trace, the current line of code, and the last
signal received by the program. There are a few options to continue investigating:

If you suspect that memory corruption is behind the crash, run a memory-checking tool—Memory Analysis, Valgrind Helgrind, or
Valgrind Memcheck. These tools pinpoint problematic lines of code such as illegal memory accesses or
double-freeing attempts.

If you suspect that a bad value coming from another process or even from a thread within the same process
is causing the crash, run a kernel event trace.
The System Profiler then displays data that lets you see any odd interactions between threads or processes.

If both these options fail to identify the cause, you must continue using the debugger.
You can set more breakpoints to see which code paths are followed before the crash occurs.