|Home||Switchboard||Unix Administration||Red Hat||TCP/IP Networks||Neoliberalism||Toxic Managers|
|May the source be with you, but remember the KISS principle ;-)|
This work is licensed under the Creative Commons Attribution 2.0 License You are free to copy, distribute, and display the work, and to make derivative works (including translations). If you do, you must give the original author credit. The author specifically permits (and encourages) teachers to post, reproduce, and distribute some or all of this material for use in their classes or by their students.
If you want to use a debugger and have never used one before, then you have two tasks ahead of you. Your first task is to learn basic debugger concepts and vocabulary. The second is to learn how to use the particular debugger that is available to you. The documentation for your debugger will help you with the second task, but it may not help with the first. The purpose of this paper is to help you with the first task by providing an introduction to basic debugger concepts and terminology. Once you become familiar with these basics, then your debugger's documentation should make more sense to you.
It's worth noting that there is a generally accepted set of debugger terms and concepts. Most debuggers are evolutionary descendants of a Unix console debugger for C named dbx, so they share concepts and terminology derived from dbx. Many visual debuggers are simply graphic wrappers around a console debugger, so visual debuggers share the same heritage, and the same set of concepts and terms. (See Appendix C: A Short History of Debuggers, below)
Normally, there is no way to see the source code of a program while the program is running. This inability to "see under the covers" while the program is executing is a real handicap when you are debugging a program. The most primitive way of looking under the covers is to insert (depending on your programming language) print or display, or exhibit, or echo statements into your code, to display information about what is happening. But finding the location of a problem this way can be a slow, painful process. This is where a debugger comes in.
A debugger is a piece of software that enables you to run your program in debugging mode rather than in normal mode. Running a program in debugging mode allows you to look under the covers while your program is running. Specifically, a debugger enables you (1) to see the source code of each statement in your program as that statement executes, (2) to suspend or pause execution of the program at places of your chosing, (3) while the program is paused, to issue various commands in order to examine and change the internal state of the program, and (4) to resume (or continue) execution.
Debuggers come in two flavors (1) console-mode (or simply console) debuggers and (2) visual or graphical debuggers. Console debuggers are often a part of the language itself, or included in the language's standard libraries. The user interface to a console debugger is the keyboard and a console-mode window (Microsoft Windows users know this as a "DOS console"). When a program is executing under a console debugger, the lines of source code stream past the console window as they are executed. A typical debugger has many ways to specify the exact places in the program where you want execution to pause. When the debugger pauses, it displays a special debugger prompt that indicates that the debugger is waiting for keyboard input. The user types in commands that tell the debugger what to do next. Typical commands would be to display the value of certain program variables, or to continue execution of the program.
Visual debuggers are typically available as one component of a multi-featured IDE (interactive development environment). A powerful and easy-to-use visual debugger is an important selling-point for an IDE. The user interface of a visual debugger typically looks like the interface of a graphical text editor. The source code is displayed on the screen, in much the same way that it is displayed when you are editing it. The debugger has its own toolbar or menu with specialized debugger features. And it may have a special debugger margin an area to the left of the source code, used for displaying symbols for breakpoints, the current-line pointer, and so on. As the debugger runs, some kind of visual pointer (perhaps a yellow arrow) will move down this debugger margin, indicating which statement has just finished executing, or which statement is about to be executed. Features of the debugger can be invoked by mouse-clicks on areas of the source code, the debugger margin, or the debugger menus.
How you start the debugger (or put your program into debugging mode) depends on your programming language and on the kind of debugger that you are using. If you are using a console debugger, then depending on the facilities offered by your particular debugger you may have a choice of several different ways to start the debugger. One way may be to add an argument (e.g. -d) to the command line that starts the program running. If you do this, then the program will be in debugging mode from the moment it starts running. A second way may be to start the debugger, passing it the name of your program as an argument. For example, if your debugger's name is pdb and your program's name is myProgram, then you might start executing your program by entering pdb myProgram at the command prompt. A third way may be to insert statements into the source code of your program statements that put your program into debugging mode. If you do this, when you start your program running, it will execute normally until it reaches the debugging statements. When those statements execute, they put your program into debugging mode, and from that point on you will be in debugging mode. In this kind of situation, the command that puts your program into debugging mode usually involves some variant of the word trace, as in Rexx's trace(i) or Python's pdb.set_trace().
If you are working with an IDE that provides a visual debugger, then there is usually a "debug" button or menu item on your toolbar. Clicking it will start your program running in debug mode. As the debugger runs, some kind of visual pointer will move down the debugger margin, indicating what statement is executing.
To explore the features offered by debuggers, let's begin by imagining that you have a simple debugger to work with. This debugger is very primitive, with an extremely limited feature set. But as a purely hypothetical debugger, it has one major advantage over all real debuggers simply wishing for a new feature causes that feature magically to be added to the debugger's feature set!
At the outset, your debugger has very few capabilities. Once you start the debugger, it will show you the code for one statement in your program, execute the statement, and then pause. When the debugger is paused, you can tell it to do only two things: (1) the command print <aVariableName> will print the value of a variable, and (2) the command step will execute the next statement and then pause again. If the debugger is a console debugger, you must type these commands at the debugger prompt. If the debugger is a visual debugger, you can just click a Next button, or type a variable name into a special Show Variable window. And that is all the capabilities that the debugger has.
Although such a simple debugger is moderately useful, it is also very clumsy. Using it, you very quickly find yourself wishing for more control over where the the debugger pauses, and for a larger set of commands that you can execute when the debugger is paused.
What you desire most is for the debugger not to pause after every statement. Most programs do a lot of setup work before they get to the area where the real problems lie, and you are tired of having to step through each of those setup statements one statement at a time to get to the real trouble zone. In short, you wish you could set breakpoints. A breakpoint is an object that you can attach to a line of code. The debugger runs without pausing until it encouters a line with a breakpoint attached to it. The breakpoint tells the debugger to pause, so the debugger pauses.
With breakpoint functionality added to the debugger (wishing for it has made it appear!), you can now set a breakpoint at the beginning of the section of the code where the problem lies, then start up the debugger. It will run the program until it reaches the breakpoint. Then it will pause, and you can start examining the situation with your print command.
But when you're finished using the print command, you are back to where you were before single-stepping through the remainder of the program with the step command. You begin to wish for an alternative to the step command for a run to next breakpoint command. With such a command, you can set multiple breakpoints in the program. Then, when you are paused at a breakpoint, you have the option of single-stepping through the code with the step command, or running to the next breakpoint with the run to next breakpoint command.
With our hypothetical debugger, wishing makes it so! Now you have on-the-fly control over where the program will pause next. You're starting to get some real control over the debugging process!
The introduction of the run to next breakpoint command starts you thinking. What other useful alternatives to the step command can you think of?
Often you find yourself paused at a place in the code where you know that the next 15 statements contain no problems. Rather than stepping through them one-by-one, you wish you could to tell the debugger something like step 15 and it would execute the next 15 statements before pausing.
When you are working your way through a program, you often come to a statement that makes a call to a subroutine. In such cases, the step command is in effect a step into command. That is, it drops down into the subroutine, and allows you to trace the execution of the statements inside the subroutine, one by one.
However, in many cases you know that there is no problem in the subroutine. In such cases, you want to tell the debugger to step over the subroutine call that is, to run the subroutine without pausing at any of the statements inside the subroutine. The step over command is a sort of step (but don't show me any of the messy details) command. (In some debuggers, the step over command is called next.)
When you use step or step into to drop down into a subroutine, it sometimes happens that you get to a point where there is nothing more in the subroutine that is of interest. You wish to be able to tell the debugger to step out or run until subroutine end, which would cause it to run without pause until it encountered a return statement (or an implicit return of control to its caller) and then to pause.
And you realize that the step over and step into commands might be useful with loops as well as with subroutines. When you encounter a looping construct ( a for statement or a do while statement, for instance) it would be handy to be able to choose to step into or to step over the execution of the loop.
Almost always there comes a time when there is nothing more to be learned by stepping through the code. You wish for a command to tell the debugger to continue or simply run to the end of the program.
Even with all of these commands, if you are using a console debugger you find that you are still using the step command quite a bit, and you are getting tired of typing the word step. You wish that if you wanted to repeat a command, you could just hit the ENTER key at the debugger prompt, and the debugger would repeat the last command that you entered at the debugger prompt. Lo, wishing makes it so!
This is such a productivity feature, that you start thinking about other features that a console debugger might provide to improve its ease-of-use. You notice that you often need to print multiple variables, and you often want to print the same set of variables over and over again. You wish that you had some way to create a macro or alias for a set of commands. You might like, for example, to define a macro with an alias of foo the macro would consist of a set of debugger print statements. Once foo is defined, then entering foo at the debugger prompt runs the statements in the macro, just as if you had entered them at the debugger prompt.
Now that you have a debugger that gives you good control over where it pauses, the other thing that you start to wish for is to be able to do more kinds of things when the debugger is paused.
Ideally, when the debugger is paused you'd like to be able to do anything that you could do normally in the programming language. Display the values of variables, of course, but also change the values of variables. And you might even like to be able to do things that you couldn't normally do, such as back up to an earlier point in the program and re-run from that point.
When you are running a visual debugger, the debugger may will probably pop up with some special debugger windows with debugging information. A watchpoint window may show the values of your watch variables. A call stack window may show the call stack, and so on.
Eventually the end of the workday arrives. Your debugging work is not yet finished. You log off of your computer and go home for some well-earned rest. The next morning, you arrive at work bright-eyed and bushy-tailed and ready to continue debugging. You boot your computer, fire up the debugger, and find that all of the aliases, breakpoints, and watchpoints that you defined the previous day are gone! And now you have a really big wish for the debugger. You want it to have some persistence you want it to be able to remember this stuff, so you don't have to re-create it every time you start a new debugger session.
You can define aliases at the debugger prompt, which is great for aliases that you need to invent for special occasions. But often, there is a set of aliases that you need in every debugging session. That is, you'd like to be able to save alias definitions, and automatically re-create the aliases when you start any debugging session.
Most debuggers allow you to create a file that contains alias definitions. That file is given a special name (e.g. .perldb for Perl). When the debugger starts, it looks for the file with that special name, and automatically loads those alias defintions.
When you are stepping through a program, one of the questions that you may have is "How did I get to this point in the code?" The answer to this question lies in the call stack (also known as the execution stack) of the current statement. The call stack is a list of the functions that were entered to get you to your current statement. For example, if the main program module is MAIN, and MAIN calls function A, and function A calls function B, and function B calls function C, and function C contains statement S, then the execution stack to statement S is:
MAIN A B C statement S
If many interpreted languages, if your program crashes, the interpreter will print the call stack for you as a stack trace.
Some debuggers allow you to attach a set of conditions to breakpoints. You may be able to specify that the debugger should pause at the breakpoint only if a certain condition is met (for example VariableX > 100) or if the value of a certain variable has changed since the last time the breakpoint was encountered. You may be able, for example, to set the breakpoint to break when a certain counter reaches a value of (say) 100. This would allow a loop to run 100 times before breaking.
A breakpoint that has conditions attached to it is called a conditional breakpoint. A breakpoint that has no conditions attached to it is called an unconditional or simple breakpoint. In some debuggers, all breakpoints have conditions attached to them, and "unconditional" breakpoints are simply breakpoints with a condition of true.
Some debuggers support a kind of breakpoint called a watch or a watchpoint. A watchpoint is a conditional breakpoint that is not associated with any particular line, but with a variable. A watchpoint is useful when you would like to pause whenever a certain variable's value changes. Searching through your code, looking for every line that changes the variable's value, and setting breakpoints on those lines, would be both laborious and error-prone. watchpoints allow you to avoid all of that by associating a breakpoint with a variable rather than a point in the source code. Once a watchpoint has been defined, then it "watches" its variable. Whenever the value of the variable changes, the code pauses and you will probably get a message telling you why execution has paused. then you can look at where you are in the code and what the value of the variable is.
How you create (or "set" or "insert") a breakpoint will depend on your particular debugger, and especially on whether it is a visual debugger or a console-mode debugger. In this section we discuss how you typically set breakpoints in a visual debugger, and in the next section we will discuss how it is done in a console-mode debugger.
Visual debuggers typically let you scroll through the code until you find a point where you want to set a breakpoint. You place the cursor on the line of where you want to insert the breakpoint and then press a special hotkey or click a menu item or icon on the debugger toolbar. If an icon is available, it may be something that suggests the act of watching for instance it may look like a pair of glasses or binoculars. At that point, a special dialog may pop up allowing you to specify whether the breakpoint is conditional or unconditional, and (if it is conditional) allowing you to specify the conditions associated with the breakpoint.
Once the breakpoint has been placed, many visual debuggers place a red dot or a red octagon (similar to a American traffic "STOP" sign) in the margin to indicate there is a breakpoint at that point in the code.
These command names and functions are meant to illustrate a variety of generic functions supported by a typical console-mode debugger. The actual command names and arguments for any particular debugger will almost certainly be different than those in these examples.
|step or step into||Execute the next statement, and then pause. If the next statement calls a function, go into the function and pause before executing the first statement in the function.|
|next or step over||Execute only the next statement, and then pause again. If it is a function call, run the whole function and pause after returning from it. Will not step into functions the way step or step into does|
|step out||Execute the rest of the current function and pause in the function that called this one.|
|single step by machine instruction rather than by line of code.|
|Run to Cursor||Start running and continue running until reaching the line where the cursor is positioned. This kind of feature is available only in visual debuggers, not in console-mode debuggers.|
|continue executing your program until it completes or the next breakpoint or watchpoint is encountered|
|restart||Start again from the beginning.|
|break aFunctionName||Create a breakpoint and attach it to a
Will cause a break whenever the function with the name aFunctionName is entered.
|break aLineNumber||Create a breakpoint and attach it to a line
Will cause a break whenever the line with line number aLineNumber is executed.
|break aCondition||Create a breakpoint and attach it to a
Will cause a break whenever the condition aCondition is true. For example
break if inputFilename == ""
will trigger a pause if inputFilename is an empty string.
|watch aVariableName||sets a watchpoint.
The watchpoint will cause the program to pause whenever the value of variable aVariableName is changed. Some debuggers may support other commands such as rwatch and awatch
|rwatch aVariableName||causes the program to pause whenever the value of variable aVariableName is read|
|awatch aVariableName||causes the program to pause whenever the value of variable aVariableName is read or changed.|
|L||display all breakpoints and their conditions.|
|delete a breakpoint or watchpoint.
Without an argument, delete removes all breakpoints.
|delete or remove breakpoints that meet
To remove one, use that breakpoint's number as the argument to delete.
|delete or remove the breakpoint with the given breakpointNumber|
|info watch||Show information about all watchpoints/breakpoints|
|Typically, a debugger will offer some form of online help. A visual debugger will typically offer help from a menu item on the toolbar. A console-mode debugger will typically offer a h or help command.|
|display||It may get tedious to continually call print to see a value that changes frequently. Instead, using the display causes the displayed values to print at every line of execution.|
|list||prints lines of code in the program. The default is to print several lines of code before and after the current line of execution this is useful for seeing exactly where you are in the code.|
|call||call a function or procedure|
|bt||see the call stack|
The primordial Unix debugger seems to have been adb, the "absolute debugger". (See adb and adb) Adb was a source level debugger for C and assembly language programs, often used as an assembler debugger. Adb is now generally considered obsolete, although many other debuggers still have "adb compatibility" options.
dbx and dbx was written in 1981 by Mark Linton as his master's thesis at UC Berkeley. It was a huge improvement over adb. Originally designed as a debugger for interpreted Berkeley Pascal, it has been extended for use with programs written in compiled C, C++, FORTRAN, Pascal, and Modula-2.
dbx is completely command line driven. To use dbx, you compile your program with a special -g command line option. This causes the compiler to generate additional debugging information that describes the data type and scope of variables, function names, and parameters, and the correspondence between source line numbers and addresses in the executable code.
For many years, dbx was the standard Unix debugger. Other symbolic debuggers were written to be command-line compatible with dbx. In particular, gdb (the GNU debugger, see below) was written to be command-line compatible with gdb.
gdb is a debugger which is part of the Free Software Foundation's GNU operating system.The original version was written in (1987-1989?) by Richard M. Stallman. gdb is used to debug C programs, or programs in languages whose interpreters are written in C (such as Python and Perl). gdb will run on almost every flavor of Unix. As with dbx (see above) to use gdb, you compile your program with a special -g command line option.
With the growth in popularity of GNU, gdb pretty much replaced dbx as the Unix standard debugger. As a consequence of the influence of dbx and gdb, the user interfaces of many command-line debuggers are all very similar, and learning to use gdb will give you a leg up on learning to use many other debuggers.
DDD, the Data Display Debugger (which uses the Motif widget set) is a popular graphical front-end for command-line debuggers, include gdb and the Python, Java and Perl debuggers. Note that its name is spelled with all capital "D's" "DDD".
FAIR USE NOTICE This site contains copyrighted material the use of which has not always been specifically authorized by the copyright owner. We are making such material available in our efforts to advance understanding of environmental, political, human rights, economic, democracy, scientific, and social justice issues, etc. We believe this constitutes a 'fair use' of any such copyrighted material as provided for in section 107 of the US Copyright Law. In accordance with Title 17 U.S.C. Section 107, the material on this site is distributed without profit exclusivly for research and educational purposes. If you wish to use copyrighted material from this site for purposes of your own that go beyond 'fair use', you must obtain permission from the copyright owner.
ABUSE: IPs or network segments from which we detect a stream of probes might be blocked for no less then 90 days. Multiple types of probes increase this period.
Groupthink : Two Party System as Polyarchy : Corruption of Regulators : Bureaucracies : Understanding Micromanagers and Control Freaks : Toxic Managers : Harvard Mafia : Diplomatic Communication : Surviving a Bad Performance Review : Insufficient Retirement Funds as Immanent Problem of Neoliberal Regime : PseudoScience : Who Rules America : Neoliberalism : The Iron Law of Oligarchy : Libertarian Philosophy
War and Peace : Skeptical Finance : John Kenneth Galbraith :Talleyrand : Oscar Wilde : Otto Von Bismarck : Keynes : George Carlin : Skeptics : Propaganda : SE quotes : Language Design and Programming Quotes : Random IT-related quotes : Somerset Maugham : Marcus Aurelius : Kurt Vonnegut : Eric Hoffer : Winston Churchill : Napoleon Bonaparte : Ambrose Bierce : Bernard Shaw : Mark Twain Quotes
Vol 25, No.12 (December, 2013) Rational Fools vs. Efficient Crooks The efficient markets hypothesis : Political Skeptic Bulletin, 2013 : Unemployment Bulletin, 2010 : Vol 23, No.10 (October, 2011) An observation about corporate security departments : Slightly Skeptical Euromaydan Chronicles, June 2014 : Greenspan legacy bulletin, 2008 : Vol 25, No.10 (October, 2013) Cryptolocker Trojan (Win32/Crilock.A) : Vol 25, No.08 (August, 2013) Cloud providers as intelligence collection hubs : Financial Humor Bulletin, 2010 : Inequality Bulletin, 2009 : Financial Humor Bulletin, 2008 : Copyleft Problems Bulletin, 2004 : Financial Humor Bulletin, 2011 : Energy Bulletin, 2010 : Malware Protection Bulletin, 2010 : Vol 26, No.1 (January, 2013) Object-Oriented Cult : Political Skeptic Bulletin, 2011 : Vol 23, No.11 (November, 2011) Softpanorama classification of sysadmin horror stories : Vol 25, No.05 (May, 2013) Corporate bullshit as a communication method : Vol 25, No.06 (June, 2013) A Note on the Relationship of Brooks Law and Conway Law
Fifty glorious years (1950-2000): the triumph of the US computer engineering : Donald Knuth : TAoCP and its Influence of Computer Science : Richard Stallman : Linus Torvalds : Larry Wall : John K. Ousterhout : CTSS : Multix OS Unix History : Unix shell history : VI editor : History of pipes concept : Solaris : MS DOS : Programming Languages History : PL/1 : Simula 67 : C : History of GCC development : Scripting Languages : Perl history : OS History : Mail : DNS : SSH : CPU Instruction Sets : SPARC systems 1987-2006 : Norton Commander : Norton Utilities : Norton Ghost : Frontpage history : Malware Defense History : GNU Screen : OSS early history
The Peter Principle : Parkinson Law : 1984 : The Mythical Man-Month : How to Solve It by George Polya : The Art of Computer Programming : The Elements of Programming Style : The Unix Hater’s Handbook : The Jargon file : The True Believer : Programming Pearls : The Good Soldier Svejk : The Power Elite
Most popular humor pages:
Manifest of the Softpanorama IT Slacker Society : Ten Commandments of the IT Slackers Society : Computer Humor Collection : BSD Logo Story : The Cuckoo's Egg : IT Slang : C++ Humor : ARE YOU A BBS ADDICT? : The Perl Purity Test : Object oriented programmers of all nations : Financial Humor : Financial Humor Bulletin, 2008 : Financial Humor Bulletin, 2010 : The Most Comprehensive Collection of Editor-related Humor : Programming Language Humor : Goldman Sachs related humor : Greenspan humor : C Humor : Scripting Humor : Real Programmers Humor : Web Humor : GPL-related Humor : OFM Humor : Politically Incorrect Humor : IDS Humor : "Linux Sucks" Humor : Russian Musical Humor : Best Russian Programmer Humor : Microsoft plans to buy Catholic Church : Richard Stallman Related Humor : Admin Humor : Perl-related Humor : Linus Torvalds Related humor : PseudoScience Related Humor : Networking Humor : Shell Humor : Financial Humor Bulletin, 2011 : Financial Humor Bulletin, 2012 : Financial Humor Bulletin, 2013 : Java Humor : Software Engineering Humor : Sun Solaris Related Humor : Education Humor : IBM Humor : Assembler-related Humor : VIM Humor : Computer Viruses Humor : Bright tomorrow is rescheduled to a day after tomorrow : Classic Computer Humor
The Last but not Least
Copyright © 1996-2016 by Dr. Nikolai Bezroukov. www.softpanorama.org was created as a service to the UN Sustainable Development Networking Programme (SDNP) in the author free time. This document is an industrial compilation designed and created exclusively for educational use and is distributed under the Softpanorama Content License.
Original materials copyright belong to respective owners. Quotes are made for educational purposes only in compliance with the fair use doctrine.
FAIR USE NOTICE This site contains copyrighted material the use of which has not always been specifically authorized by the copyright owner. We are making such material available to advance understanding of computer science, IT technology, economic, scientific, and social issues. We believe this constitutes a 'fair use' of any such copyrighted material as provided by section 107 of the US Copyright Law according to which such material can be distributed without profit exclusively for research and educational purposes.
This is a Spartan WHYFF (We Help You For Free) site written by people for whom English is not a native language. Grammar and spelling errors should be expected. The site contain some broken links as it develops like a living tree...
|You can use PayPal to make a contribution, supporting development of this site and speed up access. In case softpanorama.org is down you can use the at softpanorama.info|
The statements, views and opinions presented on this web page are those of the author (or referenced source) and are not endorsed by, nor do they necessarily reflect, the opinions of the author present and former employers, SDNP or any other organization the author may be associated with. We do not warrant the correctness of the information provided or its fitness for any purpose.
Last modified: September, 12, 2017