Breakpoints and watches both pause execution of the program and return control to the debugger under certain conditions. A breakpoint triggers when execution reaches a particular statement in the program and a watch triggers whenever a specific variable is modified. Stepping is like a breakpoint on every statement, often with the option to step "into" or "over" a subroutine, i.e. continue stepping through the statements of the subroutine or just execute it without pausing and resume stepping when it returns.

Whenever control returns to the debugger it lets the programmer ask to see the values of variables, and possibly modify them, before resuming execution. Some debuggers can be set to automatically perform some action like display a variable value and resume.

A debugger can interact with the target program in different ways. Some debuggers require the program to be loaded into the debugger which may then modify or "instrument" the program for debugging. Others can "attach" to a program that is already running. Some are built into the normal program execution environment (e.g. an interpreter) and can be set to run under certain conditions, e.g. errors.

Early debuggers such as Unix's adb only knew about the compiled executable code so sometimes debugging had to be done at the level of machine code instructions and numerical memory locations. If you were lucky, the debugger could access the program's symbol table and display the original names of subroutines and variables. Sometimes this required the program to be "compiled for debugging". Since compiling every program for debugging would add significantly to the size of a distribution of a whole operating system, it is common for programs to be distributed without debugging support but for individual programs to be made available with it.