More often than not, a program does not produce the expected result upon its first execution. A debugger is a tool used to trace the execution and examine the content of variables. This is sufficient to determine what is going on in the program. In some cases, the debugger may enable changing the content of variables, changing the execution flow and, in rare cases, changing the program, all this while it is executing. This is useful to see the effect of proposed changes or to better test specific parts of a program.
Since it is tedious to trace the program execution through millions of executed statements, until it reaches the program section of interest, it is possible to specify breakpoints, statements where the execution will be interrupted. The program is then started and, once the specified breakpoint is reached, its execution may be traced step by step. Similarly, it is possible to set a watchpoint on some variable such that the program is interrupted each time this variable is modified. This is useful for determining why some variable does not have the expected content.
To achieve this, the debugger must be able to control the execution of a program. Most operating systems offer such facilities. They allow the debugger to execute a program one instruction at a time or until some specified addresses and to read or write the program memory. On Posix systems, this is achieved through the ptrace system call. It is even possible to attach to an already running process and start debugging it.
Nonetheless, the debugger is responsible for interpreting the program memory content. Indeed, a program is simply memory containing machine code and binary data. The user, on the other hand, understands procedures, variables, types and source code line numbers. Debugging information is stored in the executable file by the compiler and linker. This information gives the name and address of each variable and procedure as well as the address of each module line number. It also describes the type and offset of each field, for each type.
This information is used by the debugger to interact with the user. The debugger may also offer language modes to better support the syntax and calling conventions of each supported language. Effectively, the built-in types, syntax and naming changes from one language to another (e.g. char * and my_functionin C versus TEXT and Module.MyFonction in Modula-3).
In some cases, the debugging information is not available or this level or detail is not needed. Instead, it may be sufficient to trace all the interactions between the program and the operating system. Indeed, all file accesses, for instance, are performed through system calls and may be used to determine what the program is doing. Many operating systems allow tracing system calls in a program, for example strace or trace on Unix systems.