When the program crashes, the debugger shows the position in the original code if it is a source-level debugger or symbolic debugger, commonly seen in integrated development environments. If it is a low-level debugger or a machine-language debugger it shows the line in the disassembly. (A "crash" happens when the program can't continue because of a programming bug. For example, perhaps the program tried to use an instruction not available on the current version of the CPU.)
Typically, debuggers also offer more sophisticated functions such as running a program step by step (single-stepping), stopping (breaking) (pausing the program to examine the current state) at some kind of event, and tracking the values of some variables. Some debuggers have the ability to modify the state of the program while it is running, rather than merely to observe it.
Debuggers make the debugging process much easier and faster, to the point where the availability of a good one for a particular language and platform can sway the decision to use that language rather than another language that is superior in other respects but lacks such tools.
An important information is, that software running under a debugger might behave differently than software running normally, because a debugger changes the internal timing of a software program. That makes it often really difficult to track down runtime problems in complex multi-threaded or distributed systems.
Notable debuggers include: