How Would You Improve Today's Debugging Tools?
redelvis asks: "I recently came across an article by MIT's Media Lab on 'The Debugging Scandal and What to Do About It'. It's a few years old now, but it really got me thinking about how little the debugging process has improved over the last 5,10 or even 30 years. I have developed applications using modern IDE debuggers such as Borland's JBuilder, Microsoft's Visual C++, as well as standard tools like gdb and jdb. Despite the slick graphical interfaces, nice thread stack traces and local variable browsers, I still make sure I have on hand plenty of notepads, graph paper, pens and pencils so I can try to build up a picture of what state the program is in and to help me play detective in pinpointing what is going wrong with my (or other peoples) programs. Do other developers have similar problems? Do they find modern IDEs and debuggers have shortcomings in helping track down bugs? What would make a better debugger? Why do you think so much effort been invested in areas such as advanced modelling tools but so little in improving debugging tools?"
Why do you think so much effort been invested in areas such as advanced modelling tools but so little in improving debugging tools?
Easy. As anyone who's ever tried to use software knows, nobody uses debugging tools anyway.
-JDF
Project Builder absolutely sucks for debugging on its own. But, I use it for break point management, but from there I use the GDB console it has. I know dick about getting gdb upto that point, but PB does it nicely. Then I can use p for a normal inspection, and po for an object inspection. I like it. If it weren't for the GDB console, PB would really suck debugging. But with it, it rocks!
What we see depends on mainly what we look for. -- John Lubbock Now search for that bug slave!
Dont debug.
Eventually someone else will find the bugs and fix them for you at their own expense.
This is how the Open Source programming model works.
I don't need no instructions to know how to rock!!!!
But I'd like to be able to create 'conditional' breakpoints (i.e.: stop at this line when i==47).
Other than that, I'd like generalized hot-swapping of code and 'step back' (which I don't know if it's always factible); or at least be able to view a variable's history.
Shame that my IDE of choice (Eclipse) doesn't (AFAIK) support those.
Project Builder is meant to integrate (as you said, through breakpoint control) with GDB. It is not meant to perform debugging on its own.
It's a wonderful development environment -- Project Builder for the code, Interface Builder for the GUI, and GDB for debugging.
Cretin - a powerful and flexible CD reencoder
Doesn't it make you feel good to know that our freedoms are protected by politicans, lawyers and journalists.
One of my biggest problems with people on my current project is the lack of knowledge of how to use even the most basic tools. We program in C++ on Unix and many developers find calling up dbx to be a chore and, even when they get dbx up, have trouble using it. We have many other tools, ddd, other graphical debuggers but people just don't use them, relying on printfs and couts...
main(i){(10-putchar(((25208>>3*(i+=3))&7)+(i ?i-4?100:65:10)))?main(i-4):i;}
I'm a total amateur, but I personally find that software tools can ultimately only go so far in debugging. The two most important debugging tools I'm aware of can't be solved with software: a short break from the project to clear your train of thought, and another set of eyes which might better see what you've overlooked.
----------
Something cleverDebugging is essentially problem solving and if you don't have well developed skills doing that, then it's not going to be very easy to do. However, every person thinks differently and hence approaches to problem solving varies. It seems to me that although computers can help narrow down the scope of this issue, in the end, it's the brain that is the most powerful tool.
Remember those high school days of comparing the green text on your TRS-80 monitor to the print in your Softside magazine. Now that was fun... har har.
As much as everybody here likes to make fun of Visual Basic, I encourage all to have a look at VB's debugger. While there are a few improvements here and there that could be made, in general it far, far surpasses anything else that I have seen out there. (I have yet to play with VB.net--I am referring here to VB6).
Strategically embedded print statements - the time-honored way to find bugs.
That plus printing out and actually READING the code. Amazing what you can find by walking out of range of the screen and keyboard and just reading through the stuff.
I don't know if it's my greatest failing or greatest success as a developer, but I tend to be a println debugger all the way.
Recently I remember seeing some justification/defenses of this technique, I think it's sometimes called "logging based debugging".
When something goes wrong I figure out the related assumptions I'm making, and then test 'em by output to STDOUT or STDERR or a file. It avoids some of the "Heizenbug" problems debuggers can bring on (so long as dumping output can be reasonably expected to be reliable w/o bringing on crossproblems) and by thinking of your assumptions, you're tying into principles similar to "write tests first", part of XP practices.
One set of things this doesn't handle well is memory leaks and bottlenecks and looking out for runaway object creation and the like, but garden variety debuggers usually don't cover that too well either, you need special profiling tools anyway.
SO YOU'RE GOING TO DIE: The Comic for Dealing with Death
Real debugging uses (1) printf calls to trace execution path, dump variables, and detect the crash point down to the nearest few lines (2) eyeballs and brain to spot the goof now its position is locked down. Debuggers are just for the wierdass bugs, and mostly they break differently in those cases anyway, because they're singlestepping not running full tilt.
A good debugger for those cases whern one's needed is DDD.
Make them work better at debugging. What a pointless story/question this is.
Is miles in advance of earlier versions of debuggers. Change code at runtime, you sexy beast.
dominionrd.blogspot.com - Restaurants on
a) it is hard to make money on debuggers
b) making a good debugger is definately not easy
c) many developers prefer puzzling out the code on pen and paper then walking it in a debugger. Quite a few I have talked to believe that they make better code if they can solve the problem without resorting to debuggers. This BTW is why Linus does not like kernel debuggers.
d) most of the debuggers are good enough and as we all know from open source, a good enough solution will live forever. The existence of a debugger that mostly works gives most people a reason to spend their time elsewhere.
In my experience I have truly benefited more from programs like Purify or Insure (and now the great valgrind) than I have from a debugger.
Visual Basic supports a "watch" that allows you to break on condition such as when a variable changes at all or if a variable is set to a certain value. This is beautiful when trying to figure out how the currency value you just had disappeared. Add the watch saying when the currency = 0 and run the app so it breaks at ANY MODULE at ANY TIME.
This saves me time by not having to go into each module and watch the code to see if the value changes.
As for wanted features ( so as to not be totally off topic ) I really can't think of any that I would need per se. Since my favorite language is VB ( watch the flames poor in on that statement ) I have many tools for debugging that are perfect.
From the immediate window so I can run small snippits of code in break mode to the stack and watch windows.
Every time I hear something from the MIT Media Lab, it's a searing indictment of something terribly wrong software engineering or computer science, and how they are here to fix it with avatars or wearable computers or something. And then you never hear about the idea again.
I think that very few people use them often enough to justify spending lots of R+D hours+$$$ on the debugging tools. How often do you see "-DDEBUG" in Makefiles? You'd think that if debuggers were so useful, you wouldn't need to switch in debugging code in the app. But many programmers feel more at home locating the bug using printfs or similar, then just reading through the code. Pencil and paper often helps too.
Something I learnt from my BASIC days, which I still use in *sh/Python code is the use of the interactive interpreter (a.k.a. "command line" :-). This is especially helpful when trying to debug someone else's code - you can enter it line-at-a-time and see what happens. Yeah, so gdb can do that. But you think more about the code if you're typing it in yourself than you do repeatedly pressing the "step" key.
I have used debuggers such as disassemblers and monitors as well as gdb, the Delphi debugger etc. While they have uses I just don't find they do anything sufficiently different from manual debugging to make them worthwhile.
There's my £1E-2 :-)
The best way to learn how to write bug-free code is to NOT use a debugger at all. Every programmer should begin writing code in Notepad or some other basic, no-frills text editor. Just like everyone should learn how to type on a typewriter and not a computer. It forces you to NOT make mistakes, instead of correcting them (you don't have to "debug" a program if you don't put the bugs in in the first place!) It forces you to slow down and think about what you're doing, instead of blasting through a procedure and then run the debugger on it. If everyone programmed for at least a year without ever using a debugger, the quality of their code will improve far greater than any fancy IDE debugger will improve it.
A man's reach must exceed his grasp, or what's an erection for?
Too many people were dependant on them when I took programming classes in college. They'd write code carelessly, and then run it through the debugger, and do exactly what it said, instead of learning to code properly.
It's been my experience that current tools like Visual Studio are just fine. Once in a while maybe a kernel level debugger. Most often bugs are the result of some logic error in some algorithm you just know should be working. And with a little tracing and memory dumps you can find the problem.
However, if the error is such that cannot be tracked down within a reasonable amount of time and isn't confined to a small section of code then I wouldn't consider it a bug but a flaw in the design. A good design would eliminate such difficult bugs and then the smaller ones only need the simpler tools we currently have to track them down.
In my opinion, the advances in modeling tools help reduce the number of potential problems so there isn't as much of a need for advanced debuggers.
I'm sure some will disagree but this has been my experience. I've redesigned sections of code to eliminate an elusive bug and it's made for a more solid application.
Ascalante: Your bride is over 3,000 years old.
Kull: She told me she was 19!
mahlen
The real problem is that the majority of software that is written is fairly lousy. People often code to moving requirements, push code in directions it was never intended to go in, and work with designs that are in desperate need of landing on the compost heap.
Honest debugging is most useful when something is being developed in the first place. Domain knowledge is what is most useful when ancient and decrepit software is being modified to do something it shouldn't.
Software applications should be thought of as prarie lands. From time to time, lightning strikes, and burns out a huge chunk, which is all replaced by newer and healthier stuff. You need talented people to make sure the new code will work well with what's already there - but the end result is that the application will be healthier if frequent refactoring is done intelligently.
Education is the silver bullet.
Debuggers aren't flashy or glamorous. I don't know anybody that thinks debuggers are cool. The tools and pieces of a development environment that are going to catch a programmers eye first are what's focused on most. You look at a nicely developed IDE that's polished and slick, and you'll be impressed. It's eye candy that sells products more than anything else.
Sadly, most -programmers- even look at a development environment's debugger as an afterthought. IMHO, it's one of the single most important tools (if not THE most important) and it's what I check out first.
Have you ever used the Gnu Visual Debugger at the GNAT Libre software developers' site? It's a multi-platform (Linux/Unix/Windows), open-source debugger with a "different view" of the world. Check it out, you may be pleasantly suprised.
1) The ability to set conditional breakpoints.
2) The ability to see not only a variable's current value, but a stack of all of its previous values.
3) The ability to select a variable's previous value and jump to the line of code that set it to that.
4) The ability to change the value of a variable at any point.
5) The ability to add/change code on the fly.
6) The ability to jump into the debugger at any point in the program, even when I hadn't planned to before running it.
7) Auto-logging of method calls and (optionally) variable values, to be started and stopped as I see fit either while stepping through code or running it.
That's all that comes to mind off the top of my head.
"You cannot simultaneously prevent and prepare for war." -- Albert Einstein
... about Debugging Tools. He felt that engineers should just learn to write software without bugs in it.
What's actually needed is more intelligent languages and automated code checking tools, as well as better code review and coding practices. Strict code review and coding practices help make programming more like a real engineering endeavor, instead of the fly-by-the-seat-of-your-pants garage hack-fest that seems prevalent in a lot of existing code. But, the real challenge is to develop languages with features like the ability to detect potential problems in code using partial evaluation, and alert the programmer at compilation time rather than run time.
Basically, we're still in the hunter-gatherer stage of software development, and the Bug Problem needs to be fixed by a fundamental shift in paradigm that can move us beyond the need to deal with "bugs" explicitly. Until then, a snappier debugger interface and new debugging features will only have marginal impact on the ability to develop fault-free software.
* mild mannered physics grad student by day *
* daring code hacker by night *
http://www.silent-tristero.com
System.out.println(). Works fine for me most of the time. If not, I can print a stack trace and see what's going on...assuming Java, of course.
The only place I've seen that a debugger comes in handy is stepping through poorly understood code. Really, the code should be documented well enough to explain what's going on, but that's rarely the case.
"In a 32-bit world, you're a 2-bit user. You've got your own newsgroup, alt.total.loser." -Weird Al
At some point debugging comes down to, the computer can only do what people tell it to do. A lot of advancement has been made in making it easier for programmers to communicate with computers. Advances are made in methods for reporting just what is being done or why something can't be done. But in the end, the bottleneck is the programmer who has sit down with his pencil and paper and slide rule and figure out, "is this really what I want to tell the computer to do?"
There's an article in the latest issue of Embedded Systems Programming about using visualization tools for debugging. Well worth reading.
-Mark
Debugging is difficult primarily because debuggers do not appear to use any kind of intuition.
Let's say I have a break point on an if statement. The debugger should automatically show me the values of any variables in the condition, as well as the truth values of the individual expressions in that condition.
A debugger should have an "intelligent" step button that steps into code that has debugging symbols, but steps over system calls. It should also automatically skip to the end of loops if desired.
Debuggers should have "sanity" checks for values. Any time a pointer is null, or an long integer is set to some really wild value (like -3492883773642) that is nowhere close to the values that it originally contained, or a string doesn't have a null terminator, the debugger should alert you with a little icon, even if you aren't actively watching that variable.
One thing that sucks about debugging is when programs behave differently in the debugging environment than they do once compiled. We had several problems related to event handling in Visual Basic only occured if the program had been compiled. In debug mode, it worked fine.
Debuggers should keep a "state" history, especially for loops or recursive functions, so you can see the entire progression of a set of variables until the point of failure. This eliminates having to write in a bunch of printf statements to get a snapshot of each loop iteration or function call.
The debugger should be integrated into the IDE so you don't have to switch back and forth. Also, it would be really nice if debuggers executed under some kind of virtual machine that allowed you to more easily freeze execution, rewind it, tinker with it as it's running, etc. Visual Basic allows you to do some of this, but certain code changes require you to restart the whole program. I'd like it if you never had to restart, and the line between "debug mode" and "design mode" were almost entirely blurred.
Just my $0.02.
bytesmythe
Hypocrisy is the resin that holds the plywood of society together.
-- Scott Meyer
Sure, we all like debuggers with conditional breakpoints and backward stepping, but the more you add to the debugger the less opportunity you will of finding the bug (unless its a 'smack in the face' bug).
The only way of truely solving bugs is to know exactly whats going on in the code (and, also as important, is knowing the language, operating system, and the things going on in the background. IE - in Java, although it appears as if you aren't dealing with pointers, you are, and you should treat all objects like a reference, cause that's what they are). If you can't study the code (cause it was written poorly), it is a terrible terrible thing, because most bugs are not just one line fixes (and even those that are require you to know exactly what all is going on around them).
"Cherry picking" (just tuning up one line and "guessing" that that's the problem) is what most 'amateurs that taught themselves coding' do, and on major/enourmously large projects, this will do nothing more than cause trouble.
The best way to beat a bug is knowledge.
Good quote, too many chars. Seriously, the slashdot 120 char limit sucks!
A debugger is going to help you find and fix the bugs that got through:
Studies have shown repeatedly that the cost of fixing each bug increases at each stage. So if you are going to invest $1000 in new development tools, is it more economical to buy tools to detect bugs when they're cheap, or when they're expensive?
The original poster's questions are all loaded with the presumption that something is wrong with using graph paper, pens and pencils.
Why on earth do so many people feel all development tools need to be built into a software debugger or they are inferior???
One great tool he did not mentiong is the napkin.
For embedded programming, logic analyzers will let you store X number of steps before your program crashes. Of course, they cost $80,000, but it's still an alternative for the top 10% of employees of the top 100 tech companies...
Exception stack traces are a godsend.
Jason.
Good example is a damaged database. If you say "You have a damaged record", the customer says, "Well, fix the record and get all my data back!". If you say, "All your data is lost, but I think I can get most of it back if I get rid of this one record.", the customer says "DELETE that record!".
Necessity is the plea for every infringement of human freedom. It is the argument of tyrants; it is the creed of slaves.
The more work goes in before you get to the debugging stage, the less buggy your product will be. A well-designed system does not need as much debugging later. I know I'm idealizing, but I've seen this bear out, especially when version N > 1 comes out and it's been hacked to smithereens because of poor design choices in the previous iteration.
Probably the most amazing bit of self-fulfilling prophecy you'll ever hear on a software project is a manager saying, "We'd better start coding now, because we're going to have a lot of debugging to do."
As for catching things ahead of time, I've always put breadcrumbs in my code to spew to stderr or a Java error console class or wherever. Very easy to #ifdef out later and trivial to turn back on later.
This is not my sandwich.
Comment removed based on user account deletion
One feature I really liked, that exists in a few places such as VC++ and edebug (for emacs), is the ability to jump around in the code and set values at runtime. You can do a lot with these two features, from running the same code over and over at runtime with different values, to skipping over a part of the code you consider problematic and seeing if it helps.
One of the best debuggers I ever used is what I'm currently coding in - CA Clipper. Does it all, and I use VB 6 as well, so I know this is true.
It's Christmas everyday with BitTorrent.
Been writing code since 1978, and the only debugging tool I've ever needed is:
printf();
Seriously, an over-reliance on debugging tools is something I've *definitely* seen come into this industry.
Bah. Chimps.
; -- the corruption of government starts with its secrets. a truly free people keep no secrets. --
You can implement reversibility on a per-thread basis (though that's harder than it sounds, in my experience). For multiple threads, it's basically impossible.
It's much easier to implement back-stepping in a processor simulator or virtual machine than it is in a native-code debugger. Unless you single-step through all the instructions, keeping snapshots of all the relevant state along the way, you can't go back.
And if you do single-step, the performance will likely be so poor that you might as well use a simulator.
-Mark
Debuggers have their place, but in some cases, to have to resort to a debugger can mean that the code is too complicated, or badly designed in the first place. Furthermore, having to use a debugger many times on the same bits of code is a clear sign that the stlye of the code is bug-prone and it should be rewritten.
-- MartinG To mail me: echo kewyjlcxyzvjfxbqwh | tr bcefhjklqvwxyz
Almost all comments ignore the main problem with debuggers: they let you verify that a program works correctly for a given input, but tell you nothing about what happens for other inputs you haven't tried. Did you miss something? Are there buffer overflows or security holes? Coverage tools can help, but then you've got to come up with directed tests to reach all of the code, or prove that it can't be reached.
Complete formal verification for large programs is a pipe dream, but there is a lot that can be discoverd through static analysis. Consider Dawson Engler's Meta-Level Compilation project, which automatically found hundreds of errors in the Linux kernel, for an example of what is possible.
Engler and gang have gotten quiet lately, I wonder if they are trying to start a company.
There are other approaches, used in hardware verification, that can mix directed testing with symbolic methods (from a state that is reached in a simulation, can I reach some "bad" state? If so, generate a test vector that takes me there).
While waiting for these tools to be developed, get a four-year old. Let him/her play with your GUI. If it's a Gnome or KDE app, it will probably crash in under ten minutes, because the kid will do things that would never occur to the developer or tester.
One of the reasons debuggers are so far behind, is that they attempt to make the vonNeuman paradigm real for debugging programs.
I write CPU simulators. In this kind of environment, there may be hundreds of threads each performing one little iota of work per (simulated CPU) cycle. When a bug is encountered, the code that encounters the bug is not in any way related to the code that created the bug. And the cod that created the bug may have made its mistake thousands of simulated CPU cycles (billions of actual CPU instructions) before the code that stumbles over the bug-incarnate.
Stack back traces, and other vonNeuman-like debuggers are totally useless in this kind of programming environment. I am simulating real parallel things (circuits) on a sequential turing machine. Its no wonder that a debugger is useless--it is based on the wrong mental model of what I am programming.
I have to build the degugger into the actual simulation code--which I proport--is the right way to debug programs anyway.
Clippy!
If you mod me down the terrorists will have won
I use debuggers every day, and find them indespensible for tracking down obscure bugs. (Like the one I just hit a few minutes ago - why does MSVC barf when calling vector::clear? The debugger stops app execution in _free_base() in free.c. This doesn't happen if I recompile using STLPort instead of the default stl library. ) That said, when I don't use a debugger I'm sure I find myself writing more robust code - I'm more inclined to spend more time on proper exception handling, thinking about my design instead of: write, compile, run, oh it failed on line 2493, fix that line, run again, now it fails at line 2547, fix that ....
which results in code that works under the exact set of circumstances that you test it, but has no guarantee as to what will happen if the parameters change any. (And those pesky users always find those annoying 'special cases').
subrountins are just hierarchical encapuslations of these with inputs and outputs.
a given subroutine does not "fire" (is called) until all of the input wires have delivered there data. Thus one does not (usually) explicity control the order in which subroutines execute. as long as they have no dependencies (i.e. output wires from one leading to input wires of the other) then they are free to execute whenever their inputs are filled.
to debug in this language one watched the diagram. Graphicaly a value passes down a "wire" like a pig in a python and stops when it reaches an input (or maybe it splits if the wire splits, and goes to more than one input icon). once the subroutine icon has all its inputs filled, it pops open and reveals all the witing in side. the data again passes from the input connectors to the internal wires and so on. once all the outputs are satisfied, the window closes and were back in the original diagram.
you can place text boxes or graphs or chart recorders, or image plots on any wire. these show you the contents or changing contents of the wire in the format if the viewer. e.g. a strip chart recorder plots single or array values on a strip char that scrolls with time so you can watch them change.
you can selectively debug any part of the wiring diagram and let the other perform normally.
The neat part of the language is there is NO SUCH THING as a syntax error, or wrong pointer, or memory location overlap. Indeed there are no variables at all. just wires and controls that inject values into wires or display values in the wires. this makes it very suitable for control systems where those sort of programming errors are undesirable. Better to have wrong functionality that weird unexpected memory errors
the other cool thing about the language is that because it is inherently concurrent and event driven rather than sequenctial, the data flow language is easy to parallelize. It's also relatively easy to use an FPGA to hard code the functions of the icons into hardware.
the problem with the language is it requires garbarge collection and is the memory management is not so good as implemented. It's not too speedy either. But as I said it may be that its parallel advantages and near bug free coding and easy debugging outweigh single cpu speen in applications.
Some drink at the fountain of knowledge. Others just gargle.
Is a stuffed frog I've got from my gf that sits on top of my monitor. When I need to ask something about a hard bug, I ask him first, and just by asking most of the time the problem gets solved.
It's interesting to note that a lot of those day-to-day bugs can be solved by simply straightening out your train of thought by posing a question in a manner that someone who doesn't know the system can understand.
Some sort of smart dump of every variable & call in your app at any point. (Offourse for a short period of time only to avoid overflowing your memory. For instance limited to the last 5 function calls)
This could allow you to replay a certain function with exact parameters as they were. I now often find myself repeating 5 minutes of clicking & typing to reproduce a certain function behavior of one line of code which *sometimes* crashes.
When will I end this grieving ? When will my future begin ?
In Java:
System.println("MyVar = "+MyVar);
In C:
printf("MyVar is %d\n", MyVar);
In C++:
cout
In PHP
echo "MyVar is $MyVar <br>";
In Perl
print "MyVar is $MyVar\n";
Works better than any debugger I've ever used
HallmarkOrnaments.Com
I find myself routinely investigating problems with applications where I don't have immediate access to the source code, or where it's difficult to replicate the problem and we find that we have to correct it (restart, etc.) without getting an adequate opportunity to investigate.
I would love to be able to grab a snapshot of a process and identify exactly what it was doing. In some respects, this can be satisfied by getting a process to core dump and analyzing the core, but to date this has always been an annoying and time-consuming process, requiring source code to see anything useful.
When the codebase reaches a certain size and complexity, you are going to be using a debugger, thats why this thread is taking place.
Often the data I'm working on is tough to just look at to see if it's right; being able to write something that would plug into the debugger to display some data would be cool.
For example, lets say I'm writing a scanner driver and I'm receiving buffers of data from the scanner. There's no way to know in the debugger if they look right or not - but if I could write a debugger plugin that could basically be given access to the entire address space the program is in with a target of "show me your data starting at this address if you can" it'd be awesome.
Same would be true for any data that isn't represented as a data structure or ASCII. I found often doing Win32 GDI work that I wanted to see what a particular HBITMAP looked like at a given point of the program's execution and the only way to do it was to blit it onto the desktop or something.
- Steve
The only way of truely solving bugs is to know exactly whats going on in the code
This is the key. Anything that makes it easier to know what's going on in the code is good.
Modern debuggers like the one in Delphi (probably similar to J Builder's) make this fairly easy. You need the GUI interface so you're looking at the source all the time, command line debuggers obscure it. It needs to be absolutely easy to find out the state of any relevant variables. You need to be able to drop down into an assembly view (or some equivalent if you're in an interpreter) to see what code got generated at a low level.
The more *well-designed* stuff you add to the debugger, the better the opportunity for understanding the state of the program. Delphi doesn't have backward stepping; it would be great if it did, because it's often easy to detect that something has gone wrong, but hard to detect exactly when it happened. Conditional breakpoints are essential. Hardware breakpoints (which let the program run at full speed, but break when a particular memory location changes) are great.
You also want to be working in an environment where it's easy to add custom views of data structures, so that you'll see when things have gone wrong. Delphi (and probably Visual Basic, though I've never used it) are very good at that. If you've got a lot of numerical data, it's basically a one line addition to generate a graph of it, and one keypress and a second or two to wait to compile a new executable containing that addition.
You want tools like the various heap diagnostic utilities to be built in to the debugger, and you want system libraries to be written cleanly. It's easy to detect that you've got a memory leak if on exit your heap is always supposed to be completely empty; it's much harder if the run-time library leaves variable amounts of junk there, or if it's hard to determine what's there at all.
Knowledge about your program is good. Adding features that make it easier to see how your program runs makes debugging much easier.
Despite the slick graphical interfaces, nice thread stack traces and local variable browsers, I still make sure I have on hand plenty of notepads, graph paper, pens and pencils so I can try to build up a picture of what state the program is in and to help me play detective in pinpointing what is going wrong with my (or other peoples) programs. Do other developers have similar problems?
Several people have mentioned feature enhancements, many I would also like to see. However, your statement about stuck me as being a little deeper. Yes, we have the same problems. However, it is not the debugger it is the interface in general. Your desires are for the "paperless office." For years we heard about it, but it never came to fruition. In fact, it may never come. The problem with a User Interface is it presumes users think, and behave in the a similar fashion doing the same job. Ask two secretaries how they file paperwork for themselves. Look at the notes written by two experienced developers during a debugging session. Similar results? Certainly. Similar approaches? Possibly. Identical methods for getting there? Doubtful.
You need hand plenty of notepads, graph paper, pens and pencils because the task at hand requires you to keep track of abstract data. Why not screen prints, cut/paste of images, text, etc? Because the #2 pencil in your hand forces your to iterate you understanding (I am writing down X=2, then 3, then 4, then -32767 -- whoa!). In addition, you remove the "clutter" while also reducing the effort. Consider that you could cut/paste any sub area of the screen. X=2, now becomes X=2, cut, paste. X=3, cut, paste. X=-32767, cut, paste. X=2, 3, 4, 5, 6, 7 , 9, 37, -32767 looks very obvious. 37 records you must now relate together do not.
I have also come to believe that the device interface is part of the issue. It is easier (for me) to mentally connect the window on a monitor with the printed surface than it is two windows. Perhaps the solution is a 36 inch monitor where I can have multiple windows open, so I can see everything at once. But it would still suffer from relating data, which also includes looking away from the code. Perhaps avoiding the "deer in the headlights" visual lock.
As a Web developer, time is on the line and almost everything I do is in a rapid development environment. That being said, debugging information is extremely important.
On the ASP.NET and Cold Fusion MX application servers, the debugging information provided by each is excellent and thorough. On CFMX, each error is specified by line on the template on which it occurs and provides a 'stack trace' (meaning a list of all the pages involved in generating that particular Web page), execution times for each template, and a complete list of all variables in all scopes. Complex variables, such as structures and arrays, are output along with all the rest in an easy-to-understand format.
The one thing that could be done better by every application system, IMHO, is a self-documetation feature. I would like to be able to look at the source code and see a breakdown of all variables on the page right away. This may sound a little simple and not really a debugging tool, but I look at it as preventive maintenence.
Peer review - without the peer:
http://www.sjbaker.org/humor/cardboard_dog.html
www.sjbaker.org
How many times I've had another developer come to me saying "Dammit! I've been through this a million times and I JUST CAN'T FIGURE OUT WHY IT'S NOT WORKING!!!"
I then take a quick scan through the code and see the problem in a minute or two.
The reverse situation has also happened.
If you don't want to repeat the past, stop living in it.
ddd is, by far, the best debugger I've ever used. I used to hate visual debuggers, but ddd turned me around.
That being said, however, there is one improvement I'd like to see in all debuggers. That's a way to do memory checking. In other words, integrate Purify or Insure++ functionality into the debugger and have it break anytime there is a memory stomp. Memory problems are the biggest issue facing programmers of large, complex systems.
For those of you who say to write small objects and give them unit tests, or to rely on things like printf(), I suggest that you get a job in the real world. Complex systems are written by large groups of people. When you hit a problem, it may or may not be in your own code. It may or may not be because you're using an object incorrectly. You need a debugger to figure out where things are blowing up and why. Using printf() will work, but it's slow and requires multiple compile/link/test cycles. Not the best use of your time.
I'd like to see a debugger that told me where memory had been allocated/deallocated.
Things like the last content of an object (if it has been deleted) and where that memory was allocated etc...
thank God the internet isn't a human right.
There's probably a technical term for the pair consisting of a position in the code and the path taken to get there. It's a bit like what a mathematician would call in a point in the universal cover.
Doesn't it make you feel good to know that our freedoms are protected by politicans, lawyers and journalists.
So debugging code is easier for simpler, cleaner code. So KISS (Keep it simple and stupid) will be the best debugging tool, we will ever have.
How about instead of not using any debugging tools, you debug at write time?
For a lot of code, the compilier should be able to work out the pre and post conditions of a function, and then just check that when you call that function you don't violate them.
Also I'd like to be able to hover my mouse over a variable and see what range of values it could have. From here you can check that you never go outside the bounds of a variable, and so on.
Obviously you can never get it to work on all cases due to the halting problem, but it will work with a lot of code - and on confusing code you can manually add the special comments for the post and pre conditions - a good idea anyway for complex code.
> You might take a look at GVD, the GNU Visual Debugger, which can generate graphs of datastructures.
It also has pluggable language support, so $SOMEONE can add support for your favorite language to it.
Sheesh, evil *and* a jerk. -- Jade
This is actually one of the reasons I like the pair-based programming style set out in XP. Admittedly it is not really supposed to be for this sort of thing, but it is a really nice benefit
I just need the "why" command..
=)
A good debugger/disassembler is invaluable in finding obscure bugs. No amount of knowledge of your code and its structure can help you if a system call mangled a stack in a subtle way, especially with cumulative effects of buggy functions that have very very subtle bugs. Unless you are writting embedded code or something that doesn't rely on other code (an os, libs, etc.) you will never have a total view of what is going on. Debugging tools can help pinpoint generally where trouble is, and then it is up to the programmer and his detailed knowledge of the code to figure out what exactly is being affected and by what.
There is no right/wrong answer because "debugging" is such a vague term as well. Use all the tools available to you, and arrogance is not one of those. Nobody has perfect understanding of the internal intricacies of software running on top of an operating system running on top of a cpu.
The best way to beat a bug is to be knowledgable enough to use the right tool, at the right time, to find the correct cause of trouble. That could be anything from a cable tester, to a disassembler, to a coffee break, to another human being.
The hardest thing I've ever had to chase down were race conditions.
Race conditions don't act the way you'd think they would. If two threads both try to read a variable, you wouldn't necessarily think there'd be a problem, much less a problem that causes your program to suddenly decide to corrupt your hard drive and crash your program. And there's no really effective way to find out where the crash happened, because it happens at random, when you don't expect it.
Even printf()'s fail you here.
The only way to find a race condition is to hand-inspect code, and make sure every shared variable is protected by mutual exclusion.
If I ever got back into grad school, I could probably dedicate an entire career to solving just this one problem.
I think the real problem, though, is not that there's a lack of good debugging tools, but rather that the really good debugging tools are rare, and the more common ones may have power but are difficult to use. And digging even deeper than that, the real problem is that people tend not to use languages that will enforce programmer discipline and help to prevent programmer errors from getting into the software in the first place.
'nuff said
Trolls lurk everywhere. Mod them down.
But I only use debuggers for two purposes.
Purpose 1. Segmentation Fault (core dumped). Uhm, now where did that happen? Whip out gdb, find the line that generated SIGSEGV, and it's usually obvious how it happened. If not, I have it print out a stack backtrace. If I really can't figure it out then, a 5 minute walk around the block and I'll have figured it out as soon as I sit back down.
When writing in high level languages, I'm finding that debuggers are wholly unnecessary. In fact, I can't remember the last time I spent more than 20 minutes trying to track down a bug. *shrug*
It'd be nice if debuggers solved my problems automatically, but I'm really finding that I don't need them. I might even go so far as saying use of debuggers encourages dependency on debuggers, which in turn discourages thinking about the program itself. Not saying that EVERYONE does this, just that some of the best work gets done remarkably well even without debuggers.
The Linux kernel, for example, was largely developed without the aid of a debugger, and the core developers seem to eschew them. Here's a good thread on why the developers don't want to include a debugger.
Purpose 2. On the other hand, debuggers are remarkably good at helping you break program code. With having almost no experience using gdb, I was able to break the license key check on Intel's C Compiler in about an hour. I was amazed at how easy it was to attach a debugger to the compiler and skip the subroutine that performed the license key check. With no debugging symbols to work with. Disassemblers rule. It took another 10 minutes to turn this into a script that could be distributed as a wrapper for icc (called xicc), so all you had to do was set CC=xicc in the Makefile.
Sure I could have used LD_PRELOAD so that time() always returned a date within the trial period, but breaking program code with a debugger is just so gosh darn fun.
(call stack, what have you). If a debugger won't give you a stack trace (optimized code excepted:), throw it out. I've found that fixing a null pointer error is often as simpile as running the program in gdb until it crashes and then reading the results of backtrace. function name, parameters, source file and line nummber: (almost) everything you need to find out how that null got passed to your function.
Bill - aka taniwha
--
Leave others their otherness. -- Aratak
I believe you are referring to the Omniscient Debugger: "A software tool written with Java[TM] technology allows developers to step backwards through the execution of a program to determine where and how programming errors occurred. By recording each state change in the target application, it allows the developer to navigate "backwards in time" to see what the values of variables and objects WERE, enormously simplifying the task of debugging programs. "
While knowledge of a debugger is useful, it is only a part of the debugging arsenal. You can't beat the wisdom gained by experience. Some people are better at finding bugs than others. Some people have a broader knowledge of the interactions of various layers of software than others. The more bugs one finds and fixes, the better one gets at finding and fixing them. But move from one environment to another, and only the thought process is portable--you need to re-learn the context (which gets easier the more contexts you've worked in). And sometimes that environment doesn't have the debugger you're most familiar with. So again, the tool itself is devalued, and the ability to "debug outside the box" is emphasised. Sometimes you can't put a debugger on a system (live telephone switch); sometimes you can use a debugger but can't put a debuggable image on (same example--how's your hex and 68x00 assembler?). In short, a better tool isn't going to make debugging easier. It may shorten the time to identify the problem area, but it doesn't make the process of removing the bug easier, especially in huge systems with many interacting layers and heterogeneous nodes. That being said, I use stack traces, breakpoints, variable/parameter dumps, and registers when I can get them--and that's about it. The other features don't provide value to me (my opinion, but I'll share without imposing it). Design for debuggability--somebody will feed your software something that's out of spec. Controllable tracing is useful here, but put the control flags in a piece of shared memory that a utility can toggle on and off, because you can't modify environment variables for a running process outside that process. And if your execution environment is guaranteed to have a debugging environment available, master the debugger if you can, but make sure it doesn't master you so you can't debug without it. The best debugging toolset is, in order of importance, your mind, the source code, the occasional invitation to others to look at the code with you, a whiteboard or notebook, and a room free of distractions. Surface for air and refreshment every 45 minutes or so, and food every few hours (there's a reason the Jargon File has an entry for "rotary debugger"). Debugging software will inform this process, but feature-rich debuggers will not speed it up much.
The Seventh Rule: Take others more seriously than yourself, particularly when you are leading them.
I've been developing software professionally for over 10 years and I can count the number of time I've used a debugger on my fingers.
I've programmed in c, Objective-C, Java, and a little in C++. I've worked in healthcare, oil and gas, high tech, and most recently the financial field. In all cases I have found that I can track down my bugs by using my brains and sometimes inline print statements (yes, I admit it). I spend approximately 1/10 of my total development time doing debugging work as opposed to design or coding.
Debuggers are too big a context switch. They don't act like part of the IDE. The best I have ever seen is the debugger in Visual Age (by IBM). It allows some pretty amazing things: you can roll back the stack and continue executing, and you can change any code dynamically while debuggin (the debugger figures out how much of the stack needs to be rolled back to allow for the changes). It also has all the usual stuff like value inspectors, conditional breakpoints, etc.
The one thing I would really like is to have a more sophisticated watch system that allows me to use the IDE (not the debugger) to insert development-time only code. This would allow me to put in such things as print statements that would not be part of the "real" source code, but rather just part of my project. It would also allow logging, performance measurment, etc. to be done at development time. Note: I don't want to context switch into a debugger to do this!!!!
Helping with organizational effectiveness is our job.
Even front end tools are little help. DDD is much better than the cli but it still suffers the same performance faults as GDB and introduces some fun issues of its own. Even a 'commercial' tool such as Project Builder on Mac OS X groans to a halt with GDB running underneath and has some very odd concepts concerning when breakpoints are hit or not.
All this would be understandable if Win32 were the same but it isn't. Debugging on Win32 is a snap - just in time debugging, compile in time debugging, a debugger that works, integration with the editor and more. It is sad to say that if asked and irrespective of open / closed source issues, which OS were the better for development I would say Windows. In fact, if I'm faced with a bug in Mozilla, I'd rather fire up Windows and replicate the problem there than wade through the shit that GDB throws in my face.
Die GDB! Linux really needs a decent debugger and all the mod cons that Windows developers have benefited from in the past decade.
Recently I was given some Java code and asked to port it to C++. At the time, my knowledge of Java was pretty much at the "Where is the bathroom, please?" level. In particular, I could see where the reflection package was being used, but not how the program went from one particular bit of client code to another. I loaded the code into the debugger, started the program, set a few breakpoints at the really puzzling parts, and ran through it a few times. At that point, the student achieved enlightenment.
... and become more likely to run the darned thing and see what it really does. Sometimes, in this job, inspection is theory, and debugging and testing are experimentation.
As I've gotten more skilled at software development, I've become better able to read a bunch of code and analyze it
An MIT animal physiologist is said to have told his students, "The animal is always right. When in doubt, ask the animal." Ask the code; the code is always right. (It may be right in knowing what the bug is, but sometimes that's what you need to ask.)
P.S.: I've learned more Java since then. Running some programs through its debugger was one good way to help learn it.
Stupid job ads, weird spam, occasional insight at
If you don't have another programmer handy, try the practice of Rubber Ducking.
This is where when you are completely stuck, you take a little break. Then you come back, pull a rubber duck out of your drawer, and put it on your desk. Then you turn to it and say, "Rubber duck, here's my problem," and explain your troubles to it, just as you would to a fellow programmer.
About two thirds of the time I try this, I stop half way through and say, "Aha! That's the problem!" And even if the solution doesn't occur to me, the process of explaining the problem makes me go over it in an orderly way, so that I always think of new places to look.
Most of this discussion seems to be about interactive debugging tools, but as an individual concerned with mission critical telecommunications software where an outage can take out customer private networks, I tend to find less need for interactive debugging, and greater need for post-mortem diagnostic analysis that results from the following:
- faults generated in house system / integration testing
- faults generated in house automated unit / component testing
- faults generated in house automated system / scalability / performance testing
I need to isolate sometimes highly obscure run-time failures and discover what went wrong, then resolve the issue, which I do with:
- high levels of run-time instrumentation using (a) method / object / runtime c++ trace style classes, (b) trace back mechanisms for exception handling and, (c) assertion handling and (d) run-time verification mechanisms; all of which generate output to debug logs (sometimes when returned to support, these logs are multi-gigabyte in size, fortunately our development workstations are very high spec)
- post-mortem analysis scripts to interpret the contents of debug logs and look for faults, inconsistencies and other issues
- application level mechanisms to allow testing, deployment and other experts to enable run-time debug instrumentation (if it were enabled all the time, it would constitute considerable performance loss) sometimes at the direction of developers or deployment / field support personnel, and sometimes these personnel don't have access to machines where the components are installed (because the components are distributed CORBA components, and these personnel have access to host / user interfaces, but not to components in a silo in another country)
The problem is that we've had to design all of this from scratch: (a) general purpose c++ based debugging / tracing modules with command line / run time configuration options, (b) tools to stimulate the debugging facilities to do things [set / change debug trace levels / activation tags / identifiers], (c) tools to capture / wrap up and return trace logs back to support, including capturing host information (processes, memory, installed modules, environment, configuration) and other debugging items (debug stack traces, core dumps) and version information (component version, etc), (d) tools to analyse / work with / process logs for developers, (e) work instructions / process / documentation to educate developers, deployment experts and others about the use of these facilities, (f) make sure that there's a balance between getting the right level of detail, yet avoiding gigabytes of detailed code / method level information
Typically, once I have a debug log returned to me (as I am developer), I need to look at what was going on, and try to reproduce the fault with a unit test case, then inspect the component for faults of a similar type, and correct those with appropriate unit tests as well, then verify regression test for the component, make changes to multiple development branches, and wait for the scheduling of scalability / system / automated testing to ensure no other significant side effects, then safely know that the next release will have corrections.
We shouldn't have had to develop all of this in house: there should be standards for this. Other companies that I have worked with have the same adhoc construction of debugging facilities - for these situations were you need to analysis a running system, or obtain post-mortem results.
Interative debugging dwindles in comparison: unless you are working with obscure hardware, or related sorts of embedded systems, I think that an excessive need to use interative debugging says more about the lack of design / defensive coding / other engineering approaches to reliability of the constructed software. Interative debugging consumes about 10% of my debugging efforts (not including time spend on unit / component / system test design).
It must be nice to be one of you folks who work on one of those projects where you can just use your brain to understand all the relationships among data structures and various pieces of code or where you can make sure that you only ever work on code where you can be sure that it's structured cleanly with nice small functions that can be tested individually.
Out here on the wild frontier we're stuck working on code that was written many many years ago by people who weren't quite so clever as the average slashdot poster. These people left behind badly structured code with inelegant data structures and comments that don't accurately describe how the code works. This code consists of several tens of thousands of lines in the component I'm directly involved with and several hundreds of thousands of lines in the larger project.
So while it sure would be swell if all the functions were small, the data structures elegant, the code tidy, and the comments accurate, that's just not the way it is for many of us.
And it pains me to say, but much of the debugging we do is done using printf() because most debuggers are such unredeemable sacks of $#!].
I do much of my debugging using msdev from VC++ v6, and I find it to be even less useful than the CodeView debugger that I used in 1987. There's a few things that are better but there are a lot of things that are worse. How can I get msdev v6 to show some of my variables in hex and some in decimal? Is this such an esoteric request that the developers at MS couldn't be expected to anticipate it?
The number of things that the MS debugger can't do that I could do in 1992 using IBM's VisualAge C++ debugger is even longer. Is this progress?
Log4J is my debugger. 'cuz my webserver has no stinking GUI!
there's no place like ~
If you've ever followed the popular system computer simulators known as emulators, you've likely seen savestates. It's effectively saving all the variables of a system en bulk, to be leaded back again later so another approach might be taken. They have been very useful to emulator developers who often need to return to an exact point where a virtual machine breaks down, without having to re-run to a certain point.
It would be nice if debuggers could automate the process of saving the state of functions (and everything they immediately touch), so you could go "back in time" rather than need to restart a program in order to return to a non-bugged state. On small programs, it would also be very convenient to be able to save the state of the entire program.
Possible extentions of this idea would be a breakpoint-like auto-savestate at a certain line, and a "step back" feature to be able to rollback one line.
Of course, there would be many possible complications involved in using savestates - but I believe the potential dangers are far outweighed by the opportunities for quicker and more comprehensive testing and code-observation.
Ryan Fenton
I used to work for a company called Saber, who later changed their name to Centerline. We produced a product called Saber-C (and later Saber-C++, and the products were renamed CodeCenter and ObjectCenter).
This product was a C/C++ superdebugger. It started out as a C interpreter developed at Harvard. Now, an interpretive environment allowed a lot of neat features: You could tell whether or not variables had been initialized at reference time, you had complete stack and context information, it was pretty easy to unload and reload code in source modules (dynamic reloading). You also got dynamic type checking, which caught errors in downcasting (for instance). And everyone's favorite, array bounds checking.
With this tool debugging C code often meant: Loading the code, running your test case, and seeing where the debugger complained. The first time you ran your code through it was a humbling experience ... almost all production code has serious (but normally benign) errors.
Unfortunately the tool didn't scale well because it took time to load the interpreted code into the debugger and the heap and runtime requirements of interpreters stressed machines of the time (this was when Sun3s were common, and 3/50s couldn't even have more than 4MB memory).
I think it was 1990 when we released version 3, whose big new feature was object code debugging (it's not really that easy to have object code debugging as well as interpretive code, although we could certainly have implemented it more easily than we did). We of course maintained the ability to dynamically reload code fragments, so you could do a "make", reload the affected modules, and be on your way in a few seconds. This sure beat the several minute wait you normally had with the linker and debugger restart. But what you lost was some of the runtime checks -- including most of what made the product interesting. Still, the ability to have superdebugger capabilities on some code and still scale to large programs was very valuable.
About a year, maybe two years later we got visited by the people who eventually started Purify. They had a neat approach where they'd get most of the benefit of our tool, but in object code, by disassembling the object code, adding extra code to perform checks, and putting it back together. This would give about 80% of the functionality of our debugger but with much lower runtime costs and work even if you didn't have source code.
We ended up re-implementing this functionality such that we had a Purify competitor (and getting sued, and losing, even though Sun later patented the same technique we used).[1] Integrating it into the debugger allowed you to fine-tune the debugging capability you wanted on a module-by-module basis. This was a superb tool.
Now, what are the raw capabilities that made this stuff really neat?
The tool also provided two additional interesting features. One was called "action points". Since we had a C interpreter in the product it was no big deal to allow you to type C code into it and run it at arbitrary times. We'd allow you to attach any code you wanted to any line in the program or to just type code at the debug prompt and it would run in the current scope. This was useful for things like adding print statements without recompiling, for instance, and for adding assertions, and many other things.
The other feature was a graphical heap inspector. All this did was display structures as tables of their internal values and allow traversal of references to other structures, which would be displayed (including links between the structures). This made the shape of data a LOT easier to determine.
Several people talked about adding reverse execution. That was actually done for Java by a tools company back in 1996 (maybe 1997). It didn't always work, but it was pretty neat. The problem is that the recording code was pretty expensive and there's a limit to people's patience and what they'll spend on hardware (although I grant that hardware is a lot less of an issue today than it was even in 1997, to say nothing of 1989). Anyway this feature is a lot less interesting if your debugger can find errors at the point they occur.
Anyway, back in 1995 when I started to work with Visual-C++ on a regular basis I was appalled by what Microsoft was calling a "state of the art" debugger. Feh! It was 1985 technology with a pretty face. It really has not improved much since then either, although they do at least have a pessimistic heap allocator now. With their ability to hook in with the compiler they could do a phenomenal job with heap allocation tracking and instrumentation of code with error checks but they don't bother (because, I suppose, they make their money even without it).
Now, using a language with runtime error checking built in - such as Java, C#, or Visual Basic, seriously undermines the amount of effort you have to put into the debugger. Still, I'd like to see a lot better heap debugging features built into compilers and runtime environments.
Hope this gives people some ideas, and that they lead to tools I can use.
[1] One thing that could be done to avoid the Purify patents would be to have the compiler emit the instrumentation. For the OSS world, where you always have the source code, that is eminently practical. Furthermore you can get all the benefits of an interpreter but at higher performance. A big problem with Purify's technology, and the technology we came up with, was that you're doing a lot of heuristics during code inspection. It's easy to miss code or misinterpret code, and of course the code inspector is VERY architecture and compiler dependent. What I would like to see is a gcc/glibc/gdb combination where the compiler, libraries, and debugger all worked together. That wasn't possible back when the vendor controlled the compiler and you didn't have access to library source. Today it is, at least for the OSS world.
jim frost
jimf@frostbytes.com
This is more of an IDE thing than a debugger thing, but I'd really like to have an automated way of finding all the call sites that access a particular class or struct member.
... };
e.g. if I have
struct foo { int count;
I want to see all lines of code that access the 'count' member of struct foo. (WITHOUT showing all other occurrences of the string 'count' like a simple grep would).
Bonus points if the feature can track pointer aliasing - e.g. in the example above, *((int*)&foo) should also count as a hit... Or if I have an array 'int arr[]' and I want to see all access to arr[3], including *(arr+3) and arr[i] where i could equal 3.
I mainly use PHP for my development, but when it comes to client side applications I use Delphi / Kylix. For your basic simple things, it works quite well and has some nice debugging and error reporting. However, when doing things like database working using the BDE, its a nightmare. Most of the time the errors don't point to anything to help debug it. The errors are sometimes so general, it could mean someone forgot to put the toliet seat down.
I have found that many developers (of the debuggers or IDEs) don't spend enough time creating error messages for all sorts of common problems.
They have gotten 10 times better in recent years. I personally *hate* most C / C++ IDEs becuase the application just segfaults, or what not instead of saying what the hell happened. I am a poor C / C++ programmer, so it doesn't help me move any futher into it.
until (succeed) try { again(); }
To a certain extent programs like purify and bounds checker do automatic program debugging. BC will check for all kinds of runtime errors. Coupled with tight coding standards enforced by a lint like tool of your choosing a _LOT_ of bugs will be easily isolated automatically. When you combine these tools with a code coverage utility, a decent set of unit tests, a test utilty that can fail system and library calls you will discover a the bug count in released code will go down to nearly 0. Finding these bugs in developement is a lot easier that trying to do it with a core dump from the customers site. Take it from me I've worked for companies that released software where bugs that cause crashes, lost data etc were simply not acceptable.
People complaining about the debuggers themselves missing functionality are complaining because their code is either to poor to isolate the bug when it happens (causing it to propigate into areas where the bugs arn't ovious), or they simply arn't using all the tools avialable to them. Don't underestimate how useful enforced coding guidelines can be for writing bugfree code. There are whole classes of bugs that can be caught by a lint, but will result in hours of debugging. Variables that never get initialized are the perfect example.
Hate to break it to you, but if y^1/2 is implemented as a true function with a single return value, it is not the reverse of x^2.
Say you have y = 9. Was the x that was squared to produce that 3, or was it -3?
Similarly with sin. You know that y received the value of 0 after assignment from sin(x). But was x 0, pi, 2*pi, 3*pi, etc.?
That's just the theoretical problem; there's a bigger practical one involving floating point values. When an operation or cast causes precision loss there's no way to get that precision back. Let's say y is a float and you shift it to the right by 3 bits. Those 3 LSbs are gone forever, and there's no operation that can reverse that unless you log the value of every variable that undergoes an irreversible change.
All's true that is mistrusted
That's a pretty untutored opinion. I've used debuggers on about ten different platforms and found the MS Visual C++ debugger to be the best designed one I've used. It's well integrated, easy to look at, it has machine code disassembly built in and displays it between the code lines (if you want), it has intuitive hot keys, et cetera. There are some really bad debuggers out there. dbx on AIX was absolutely retarded, and couldn't set watch points without crashing. Their GUI for it was harder to use than the command line. The MS debugger is a dream by comparison.
* mild mannered physics grad student by day *
* daring code hacker by night *
http://www.silent-tristero.com
I would kick someone in the knees for an x86/Win32 disassembler that's as intuitive and easy to use as PS2Dis is for Playstation 2 MIPS code.
I'd been using that one for awhile (finding hidden bits in games I like), and I decided to check out the same kind of software for x86 disassembly. I felt like I was back in 1992 using DOS tools. Essentially all of the interfaces seem to be text-only, and there's none of the "click on an address and modify the code" functionality of PS2Dis, or the ease of navigation.
Since I'm only doing this for fun, it's just an irritation, but I imagine it would be very frustrating for a full developer.
"...always new atoms but always doing the same dance, remembering what the dance was yesterday." -Richard Feynman
I think the biggest advance in debugging would be teaching people to use them.
I know a lot of programmers, but I think I'm the only one I know that actually uses a debugger to find problems. I haven't personally seen any University courses on debugging techniques or tools.
I think it's an essential skill (like typing) that makes programmers *so* much more productive.
-me
Love many, trust a few, do harm to none.
Come on. Move over to the dark side. Use Visual C++!
Most of the responses are missing the point, I think. Step outside the box for a moment...
When you write software, you have an intended interpretation, namely, what you intend the program to do based on what you meant to write. The compiler, on the other hand, has its own interpretation of your program, based on what you actually wrote. Debugging is the process of finding discrepancies between those two interpretations.
Understanding this reveals what directions debugging tools should go. Current tools put the programmer in the driving seat, trying to understand how the system has interpreted their program. The next generation will put the system in the driving seat, asking the programmer what they meant that operation should do. Like with a human teddy bear, the act of explaining it to the system might even clarify things enough in the programmer's mind that the problem may become obvious. Or, we may end up in a kind of "pair debugging" situation where the system becomes a code reviewer.
sub f{($f)=@_;print"$f(q{$f});";}f(q{sub f{($f)=@_;print"$f(q{$f});";}f});
It runs during installation. To activate it, click 'I do not agree' when some incomprehensible gobbledegook called a 'EULA' is shown. A EULA is a kind of bug. Unless you refuse to accept, it will bug you again and again. Don't confuse bugs with viruses, however: Microsoft's debugger can't handle viral licenses, which is why they don't like the GPL. Once activated, the powerful EULA non-acceptance debugging option leaves your system bug-free.
- undoware.ca
Yes, I could really use a debugger that runs backward for a problem I'm having recently. I wrote about it here last month:
I can confirm that this is a bad idea.
Forget the whales - save the babies.
But I doubt this is true anymore as the VB we know and love is pretty much dead, it's VB.NET now, which is little more then a node to BASIC syntax for a .NET CLR.
-Jon
this is my sig.
I've got 1 and 3 in one window. The latest technology I use, I re-build while the server is running. Sometimes it's a little slow.
But I'd like something more like the debugger in multiple windows.
1. Call Stack
2. Variables ( but this needs to be much better for objects.
3. Line of code that I'm actually on.
Or you could define a function, dbprint, for example, that all your flow notes call, make dbprint do nothing when you don't need it, and delete any dbprint calls when you're done debugging.
Of course, that would be much easier...
That what was all this school was for... to teach us how to solve our own problems. -- janeowit
To me, and I quite probably am very alone on this, it would be better to conceive of a DBMS (forgive the gravitation toward this one example) - to chart the program flow at a general level. Not: But instead of spending the time sitting down and creating a whole DBMS, why not understand how to do so. It is part of the writing process to understand the function of your application (hopefully), but what we need more than rote programming is imaginative conceptualizing.
And, if you choose, you can take your concept, and follow the iterations down and break modules into components, components into functions, functions into code.
Of course, none of this has much to do with debugging.
And poor spelling doesn't mean poor organization skills. Poor mental organizers tend to have sequencing problems more than specific spelling problems, and crap classes like Study Skills in high school teach all the wrong ways to remember things (you "web" a database, not a textbook. Textbooks are almost always sequential, not relational).
Some people were never properly taught to spell, and some people don't type well. This does not make them poor organizers.
"There is no worse lie than a truth misunderstood by those who hear it." - William James
That what was all this school was for... to teach us how to solve our own problems. -- janeowit
A big part of the reason is that the languages paradigms that are popular today are directly copied from what was popular 5, 10, or even 30 years ago, with a little bit of a half-baked object system thrown on top (think C++, Java, etc.). Statically compiled "structured" programs don't lend themselves well to debugging, period. First of all, the debugger has to do a lot of contortion to do relatively simple stuff like stack and variable inspection. Then comes the problem of the "structured" style itself, which depends heavily on variable assignment and is very un-modular.
OO-design does reduce the granularity of program modularization and lessens the dependence on global variables somewhat, but inside, the objects are still programmed in a "structured" way. Even worse, object-overuse leads to a rat's nest of an object graph (my big beef with single-inheritance only object systems is that they encourage this).
For debuggers, steppers and stack-tracing to be really effective, a program has to be modularized with as fine granularity as possible. This is why functional and pseudo-functional languages generally tend to have and develop the best debuggers. Even before implementing any features, an interactive top-level is probably the best debugging tool available. But implementing stuff like advanced condition handling/breakpoints, stack-tracing/variable inspection, and function-tracing/steppers fits naturally into the language environment with minimal detriments to code size (anyone up for a little Java catch?) and performance.
In the great CONS chain of life, you can either be the CAR or be in the CDR.
... Only people are not adopting the new ideas.
:-(
For example, I used to work with a tool called BugTrapper from MuTek Solutions (it's now called AppSuite, and the company is now called Identify Software). It can record an application's runtime trace, replay it, rewind it and provide many more helpful debugging tools. Unfortunately it never caught on (maybe because of its price), and nobody has copied the idea to open-source tools
The trouble, as I see it, is that practically there is a huge amount of inertia when it comes to programming languages and methods.
.bz2), but I didn't have a hope of getting the main tar changed, because ppl don't like change. Another was a cleanup of ifconfig - but the changes weren't commited, even tho there were just bug fixes etc, because it would require testing on so many different platforms and libraries, that it wasn't worth it.
People still don't use debuggers (not saying good or bad, just stating it factly), people still use C very heavily, few people use lisp (although I do find more ppl using than I expected), and so on.
Visual programming never seemed to take off that well (the whole 'a routine is a box, connect the boxes' type thing), etc.
Going offtopic even more, I'm currently trying to redo all of the main command-line gnu tools, but am suffering from the same sort of problems. The command line tools suffer from really horrible problems that shouldn't exist, and the code is horrible for most of them, but they will never be fixed. For example, I patched 'tar' to autodetect the filetype (.gz or
My solution is to try to fix it all, break compatibility, and hope I can get enough done before I release it to have enough momentum to get somewhere.
I suspect debuggers are somewhat like console debugging a mainframe. While there are times it is the only expedient mechanism, the less one has to do it the better. For almost everything, there is a better way to do it, usually by including enough consistency checks or such and output of enough state to conveniently tell what's going on.
Against debuggers is that they occupy address space and time space. The program being run under the debugger is not the same as the production program. Each will have a different set of bugs and anomalous behaviour. After being burned a few times by debugging the wrong system, (with debugger instead of production), I would imagine there are more than a few developers who have a strong dislike for debuggers.
One strong argument for Open Source is that, assuming they don't take up too much resources, there is a tendency to just leave the bug-catchers in the production systems.
One of my bugbears is that debuggers don't seem to have caught up with object oriented programming yet. For example, often when I want to set a breakpoint, it would be really useful to be able to specify which object I want to break on as well, as I can usually narrow the problem down to a particular bit of code with a narrow set of objects. Now if there are thousands of identical objects like the one I want to debug, I have a problem. At the moment I have to solve it by finding a unique objet that will be activated just before the one I'm really interested in, breaking on that, then setting the breakpoint I really want, then running to that. Each time I do this I have to unset the breakpoint again, run to the first one, set it again etc.
This one single feature would greatly improve my productivity.
Also, simply generating a list of objects of a certain type would also be useful, so I can see how many there are in the system etc. And I'm sure there could be lots more OO-specific features other than these too. Come on debugger designers - please!
Skiing? Check out The Independant Skiers Portal
http://plan9.bell-labs.com/sys/doc/acidpaper.html
Acid: A Debugger Built From A Language
Phil Winterbottom
philw [ a t ] plan9.bell-labs.com
ABSTRACT
NOTE: Originally appeared in Proc. of the Winter 1994 USENIX Conf., pp. 211-222, San Francisco, CA
Acid is an unusual source-level symbolic debugger for Plan 9. It is implemented as a language interpreter with specialized primitives that provide debugger support. Programs written in the language manipulate one or more target processes; variables in the language represent the symbols, state, and resources of those processes. This structure allows complex interaction between the debugger and the target program and provides a convenient method of parameterizing differences between machine architectures. Although some effort is required to learn the debugging language, the richness and flexibility of the debugging environment encourages new ways of reasoning about the way programs run and the conditions under which they fail.
There are places where the networks are not touching,and there are places where they are-Boeing's Lori Gunter
I've been writing vc++ for a few years now, but one feature I'd REALLY like to see would be to be able to easily set conditional breakpoints on a particular instance of an object. In fact, more object awareness across the board would be nice. I'd also like to be able to be somewhere in a windows message handler, and be able to see where the message had come from. I'd like to be able to call functions from the watch window like I could in DEC FORTRAN. I'd like to see the VC++ debugger be able to enumerate over collection objects using for_each, and examine COM properties as if they were variables. I want the VB watch and immediate windows for VC++.
You can't win Darth. If you mod me down, I shall become more powerful than you could possibly imagine
Building houses is one thing.
Writing code in a way that avoids unneeded tools is another thing altogether.
; -- the corruption of government starts with its secrets. a truly free people keep no secrets. --
The Teso people held a superb lecture on reverse engineering and systematically finding security problems in binary code at this years Chaos Congress in Berlin.
They demonstrated a way to automatically analyze and segment binary code into basic blocks. A basic block is a segment of binary code that is being executed from top to bottoms, that is, it does not contain any jumps out of the block and is not the target of a jump into the code.
Team Teso then performed graph algorithms and data flow analysis algorithms on the basic block graph their primary tool produced. This is where things get interesting for debugging.
For example, the teso people were able to trace which basic blocks are being touched during code execution. You can imagine this as a graph of the program where each basic block is a block (node) and each jump is a vertice between the blocks. Upon execution, each basic block is colored as the code is being executed.
They also were able to reconstruct C program structures from binary, and they were able to reconstruct where data comes from that ends up in a certain buffer in a structure. This allowed them to check for matching buffer sizes automatically (!) and to retrace how to inject data into a program that has mismatching buffer sizes somewhere on the inside. Makes for some very easy, instantaneous exploit generation.
For more information, have a look at their slides from the lecture.
Kristian
But the real fallacy with "write-time debugging", and in fact all of the code-bug-free methodologies, is that there is very significant amounts of code that you must use to write your program that was written by someone else who is almost certainly not using your methodology (or, often, any methodology). So, even if your methodology worked on your own code it wouldn't work on the application as a whole.
I note that some of the most insidious bugs I've ever had to track down were caused by operating system errors. My favorite bug ever was under AIX where a call to select() with a 30-second timeout was returning in about 900 nanoseconds saying it had timed out. This caused a chain of failures. And, of course, it would only happen in some pretty unpredictable situations. In this case you needed two programs running under ptrace at the same time on the system for the bug to show itself - and it would only occur about one in five thousand calls to select() even under the failure conditions.
No amount of programmer effort on our part would have prevented this bug from biting us. We could certainly have put in a postcondition tester to check to see if the system call operated correctly (in fact that's how we worked around this problem) but can you realistically do that for every system call you ever make? Every library call you ever make? It's not practical to do so.
I'm all for doing things to minimize code errors, although to be completely honest the best method (as opposed to methodology) I've found to do that is to use languages that include their own run-time error checking, which are strongly typed, have mandatory exception handling, and which use garbage collection for heap management (Java being the only one I've used). The combination of such features leads to about 90% fewer bugs out-the-door and boosts programmer productivity by 200-400% over the long term versus something like C++ (that's data from several large programming projects I've been on).
It's that good because the environment tends to report problems as early as possible in the development process, when they are easiest to fix, and because of mandatory exception handling code more often gets written with failure handling in mind.
Even so, and even with methodologies that reduce bug rates even more, tools are often invaluable to producing good code. I find that heap inspection and profiling tools are very valuable for Java, for instance, as are techniques such as log instrumentation and assertion. (Unfortunately Java provides no facilities for any of this in-the-box, sigh.)
Anyway, to maximize programmer productivity and minimize bugs it pays to use an array of techniques and tools. Those who believe debuggers don't have their place, that they can be rendered pointless by technique, are badly mistaken.
jim frost
jimf@frostbytes.com
I find modern tools to be pretty sufficient. Some of the following features are quite important:
.NET for now), JDK 1.4.1 does this.
- Edit/Continue debugging.... VB used to do this (not in
- Watchpoints (when is something edited?)
- Jumping back stack frames (though you'll have to be careful to manually reset your shared state)
Tracking down bugs requires a certain kind of expertise. Usually it's harder to debug than to write new code, so that could be one reason why debuggers don't proliferate as much as modelling tools.
One way of gaining this expertise is to have experience in teaching other programmers in a hands-on course. You learn to spot common bugs quickly, and diagnose more complex ones. It's in an environment where you have 15+ people that all need your help at once... kinda pushes you towards honing that debugging sense.
In my experience, most "tough" debugging problems would have been solved if the developer just set the breakpoint and analyzed the code instead of sitting on their thumbs and thinking about it for 15 minutes. This might be fine for Kernhigan, Ritchie, Pike, and all those who suggest that "thinking" is the best way, but these guys also have *decades* of experience to do this without assistance. A debugger is a catalyst to this thought process.
Also, logging techniques are crucial, they isolate the location of a potential problem. But they're very time consuming to figure out WHY something is going wrong (because you never quite know what variables to dump out to stdout).
A debugger to seek stack traces & peek inside variables, change variable values, and edit/continue with your changes adds significantly to agility. It's partially why VB was so successful, and Eclipse is so popular in the Java world (and why most Smalltalkers have migrated to Java/Eclipse).
-Stu
They might incorporate LINT and run the program with mprof and thru a replacement malloc() to check leaks. Other than these, stepping into procedures and watching variables, what else is there to do with debuggers?? Theres no understandable direction to go from the debuggers' current state; theyre doing well.
On the other hand people seem to use debuggers less to take out program bugs. They rely more on reliable library functions, and post their problems in newsgroups for the library maintainers to fix. I personally use printf excessively to output the programs variables and state at each moment, then remove them from the final program. Its a more straightforward path than compiling with -g, powering up gdb and watching the variables, but then again gdb has its place.
"Give orange me give eat orange me eat orange give me eat orange give me you." -Nim Chimpsky
Is that because of the high level language, or because high-level languages encourage better coding styles?
I'm thinking of programming by contract here. My C++ and C is fairly sprinkled with assert()s, and my Java will be be likewise, when I move to version 1.4. With assertions on preconditions and postconditions and some unit tests, you can locate a bug to one method almost immediately, and if your methods are small (the current bast practice), that means only a handful of lines for you to inspect.
One of your repliers says:
If you need a debugger to understand what some code does, I suggest it it is badly written.
Ne mæg werig mod wyrde wiðstondan, ne se hreo hyge helpe gefremman.
I wasn't lumping the cherry pickers with the debugger users.
In fact, I was trying to make the point that using a debugger is good (hell, I use one!), just that you need the basic functionality that bebuggers have today without any extra bells and whistles. The submitter asks "what ELSE do you want?" My response is "nothing, we're at a good equilibrim point of debugging features now. Adding more will take away from the fact of understanding the code, and will become more dependent on solely using the debugger."
Good quote, too many chars. Seriously, the slashdot 120 char limit sucks!
I envy you your success rate. :-)
Where I work, we are blessed with enlightened management and team leaders. Our tests are automated, and we have clean builds from the source control system and test runs overnight every night, with summaries generated and mailed to the team in time for the morning. To those who haven't adopted such an automated approach, I cannot advocate it enough. The difference between this and an environment where you're bogged down running numerous tests by hand according to different levels of test spec that took some poor soul weeks to write is staggering. This is from bitter, and then much happier, personal experience.
I'm not entirely convinced by the "test first" philosophy. That's always struck me as more of a political point than a practical one. Where we work, when we want to add a feature, someone first writes a proposal summarising the requirements. We then go through a very iterative development phase, effectively doing the design work by repeated prototyping, and then filling in the blanks.
The key thing we get right, I think, is that as we do this, and we're happy with the results, we actually generate the automated tests from what happens: our software can record the actions it's taken, and various checksum-type information about the results, and can later replay that recording and match (or not) against the previously saved checksums. Making a test is as simple as hitting the record button and then running through some actions that give the correct results, and running the test is as simple as playing back the test file that was previously generated.
It obviously requires a certain amount of effort to implement such a system: you effectively need some sort of "macro language" for the test files, and you need to have a checksumming facility to verify all the data in your system at a given moment and flag discrepancies. Furthermore, these do need to be updated when new features are added (extra macros) or new state is introduced into your model (extra info in the checksums). For the amount of time, and developer tedium, this saves, though, I'd guess it's an investment well worth making for many development shops. It's not even as much work as it first sounds, because many apps are essentially event-driven or based on some sort of command pattern architecture anyway, which means you've already got most of the framework in place.
Even with all of this in place, it's still quite possible to get bugs that are hard to find, though. Just because you know such a test failed, if that test was based on complicated processing, the fault could be anywhere within that process. Still, at least you can always look back at the overnight test records to pinpoint where something was checked in that caused the change.
If you disagree, post your argument. (-1, Overrated) isn't your personal censorship tool for views you don't like.