Forgot your password?
typodupeerror
Programming IT Technology

New & Revolutionary Debugging Techniques? 351

Posted by CmdrTaco
from the something-to-think-about dept.
An anonymous reader writes "It seems that people are still using print statements to debug programs (Brian Kernighan does!). Besides the ol' traditional debugger, do you know any new debugger that has a revolutionary way to help us inspect the data? (don't answer it with ddd, or any other debugger that got fancy data display), what I mean is a new revolutionary way. I have only found one answer. It seems that Relative Debugging is quite neat and cool."
This discussion has been archived. No new comments can be posted.

New & Revolutionary Debugging Techniques?

Comments Filter:
  • AppSight Debugger (Score:2, Informative)

    by dominick (550229) on Sunday May 02, 2004 @10:33AM (#9033526)
    I am attending a college pursuing my Software Engineering degree and a company called Mutek showed us via weblink a new problem to track software issues. They called it AppSight. It could tell you exactly at which point your program failed. It even showed all the .DLLs your program called, COM objects that were created and even system calls made by the App. Mutek was bought out I believe and is now called Identify Software. You can see more about their technology at: http://www.identify.com/ - Dominick
  • by Halo1 (136547) <jonas.maebeNO@SPAMelis.ugent.be> on Sunday May 02, 2004 @10:33AM (#9033529) Homepage
    Debugging backwards in time. See the Omniscient Debugger [lambdacs.com] for an implementation in Java. Instead of re-executing the program a thousand times, each time setting breakpoints and watchpoints in different places to get nearer to the root cause of the problem, this debugger completely records all key events and lets you view the complete program state at any point in time.
  • by cpu_fusion (705735) on Sunday May 02, 2004 @10:36AM (#9033545)
    I've found that aspect-oriented programming [aosd.net] using tools like AspectJ [aspectj.org] (for Java) can be a big help. There are aspect-oriented programming tools for many other languages.

    Basically, you can define an aspect to capture points in your program that are of particular note, and then do debug handling at those points. Aspect oriented programming allows you to break out that debug-handling logic into seperate modules, keeping your main sourcecode nice and clean.

    Aspect-oriented programming (AOP) has a lot of other uses too. I think in 5 years or so talking about AOP will be as commonplace as talking about OOP. They are orthogonal concepts.

    Cheers, Me

  • living under a rock? (Score:3, Informative)

    by hak1du (761835) on Sunday May 02, 2004 @10:44AM (#9033581) Journal
    Java Exceptions *were* a revolution in debugging.

    Only if you have been living under a rock. Most languages and compilers other than C and C++ have been doing that forever. Even C and C++ allowed you to get a complete backtrace and inspect the complete program state from a core file (software bloat has made more and more people turn off that feature, however).

  • by Novus (182265) on Sunday May 02, 2004 @10:49AM (#9033596) Homepage
    On the subject of software debugging techniques, I'd like to point out visual testing [cs.hut.fi], which (basically) allows you to try out method calls and fiddle with variables and examine the results (including execution history) graphically. MVT [cs.hut.fi] is a prototype visual testing tool for Java.
  • nothing new (Score:4, Informative)

    by hak1du (761835) on Sunday May 02, 2004 @10:50AM (#9033603) Journal
    There has been almost nothing new in programming environments or debuggers over the last 10-20 years.

    Almost those features you see in Visual C++, Visual Studio.NET, Eclipse, NetBeans, etc. have been around in IDEs since the 1980's. Debuggers have allowed you to step forwards and backwards, see the source code, examine data structures graphically, and modify the running source code for about as long.

    If anything, current commercial IDEs and debuggers still haven't caught up to the state of the art.
  • Re:.NET (Score:2, Informative)

    by gatkinso (15975) on Sunday May 02, 2004 @10:58AM (#9033624)
    1) you are correct, VISUAL STUDIO has a great debugger for its products - but that isn't .NET per se. The VC++ debugger is hands down the best in the industry but...

    2) gdb will do everthing VCDB does, just not as easily (ok not even remotely as easily)

    3) there are guys/gals at my work who write very tight code under gcc - they rarely need a debugger anyway. Their debugging is almost all done at design time

    Posts like that are just going to rile up their audiance and deserve their low score. Grow up.

    Some flamebait of my own: I will try to not look down my nose at you for being a VB "programmer."

  • A better solution (Score:3, Informative)

    by Morgahastu (522162) <bshel@WEEZERroRA ... ve my fave bands> on Sunday May 02, 2004 @11:01AM (#9033635) Journal
    A better solution is to make your program generate a log of everything that happens, when an object is created, when an database connection is made etc.

    And when you launch the program in debug mode everything is printed to a log file and when it crashes or a bug occurs you can just halt everything (if it hasn't crashed) and look at the log to see what it was doing.

    Different levels of logging could be used. Say level 1 with the most basic logging (database connections, disk access, network access, etc), level 2 includes all level 1 plus network traffic, level 3 has all object creations, etc.

    ex: logEvent(3,"DBO_Connection create");
  • Re:Exceptions (Score:4, Informative)

    by Delirium Tremens (214596) on Sunday May 02, 2004 @11:04AM (#9033642) Journal
    Java invented the dynamic analysis and handling of stack traces [sun.com], not just exceptions.
    If you are into dynamic analysis and recovery of exceptions -- that is, self-healing software --, that is a very powerful tool.
  • Some ideas (Score:5, Informative)

    by AeiwiMaster (20560) on Sunday May 02, 2004 @11:05AM (#9033647)
    They might not be revolutionary, but the is a few ideas
    which can be just to reduce the number of bugs in a program.

    1) 100% unit test coverage of your programs. [all-technology.com]
    2) Statistical Debugging [berkeley.edu]

    3) Valgrind [kde.org]

    4) The D programing Language [digitalmars.com]
    with build in support for unit testing, contracts and class Invariants.
  • Re:Exceptions (Score:4, Informative)

    by bdash (598142) <slashdot.org@bdash[ ]t.nz ['.ne' in gap]> on Sunday May 02, 2004 @11:06AM (#9033652) Homepage

    Java invented the dynamic analysis and handling of stack traces, not just exceptions.

    Where is your evidence that Java "invented" this? I have seen several other languages that are at least as old as Java that contain this feature, so some facts wouldn't go astray...

  • Data logging (Score:4, Informative)

    by mrm677 (456727) on Sunday May 02, 2004 @11:06AM (#9033654)
    Don't trivialize the data logging approach to debugging.

    In complex, multi-threaded systems where you are debugging timing events more often than programmer logic, data logging (aka print statements) is probably the only technique that works.

    In fact, one of the first things we implement in embedded systems is a data logger that can spit out your print statements over RS232. Yes, we can single-step through code using in-circuit emulators and JTAG interfaces, however I found this rarely useful.
  • by Anonymovs Coward (724746) on Sunday May 02, 2004 @11:08AM (#9033660)
    in a lot of higher-level languages, eg functional languages like lisp, haskell and ocaml. But not only debugging: in these languages you tend to write code that doesn't have bugs in the first place. No need for mallocs, no buffer overflows, no memory leaks. And if you're careful to write in a functional style, no "side-effect" bugs (variables that change value when you weren't expecting them to). For a language that started out in the 1950s, it's amazing how far ahead it was and still is as a development environment. This paper [mit.edu] is a fascinating read, especially the section on Worse is better [mit.edu] that describes why Unix/C won. And there are other languages like the ML family and Haskell. OCaml [inria.fr] (Objective Caml, a descendant of ML) is as concise and elegant as python, but produces native-code binaries quite competitive in speed with C, and occasionally faster [bagley.org]. I'm wondering why anyone uses C-like languages anymore.
  • The best debugging (Score:3, Informative)

    by Decaff (42676) on Sunday May 02, 2004 @11:19AM (#9033707)
    The best debugging system I have ever used is in Smalltalk. Its possible to stop code at any time, and then data can be inspected and altered, new classes coded and methods re-compiled without interrupting execution. When changes have been made code can be re-started or resumed.

    Features like exception handling with full stack trace in Java are great, but nothing beats the Smalltalk system of suspending execution and keeping the application 'alive', so it can be modified, inspected and resumed, when an error occurs.
  • by bluefoxlucid (723572) on Sunday May 02, 2004 @11:21AM (#9033718) Journal
    Memory leaks and such are easily tracked with valgrind, although for basic logic errors you want to use the printf() and gdb methods.

    Valgrind is http://valgrind.kde.org and requires that you turn off all pax protections for the binary you wish to debug.
  • Re:Exceptions (Score:3, Informative)

    by smallpaul (65919) <paul@@@prescod...net> on Sunday May 02, 2004 @11:34AM (#9033790)

    Java invented the dynamic analysis and handling of stack traces, not just exceptions.

    Python has the same feature and Python is older than Java. It would take some effort to prove that Python had introspection of stack traces before Java did, but it seems quite likely to me. And it seems even more likely that some variant of Lisp had it long before Python.

  • by Anonymovs Coward (724746) on Sunday May 02, 2004 @11:44AM (#9033837)
    are you asserting that functional language programs always work perfectly the first time you run them?

    Most of the time, yes. The reasons are, first, the strict checks it does before even agreeing to run your program, which eliminates a huge class of errors (usually emanating from typos that C will ignore), and the generally clean structure of the language that makes it easier to code what you have in mind. Consequently any errors you see when running the program are likely to be bugs in your algorithm itself, not in the implementation.

  • by Alan Cox (27532) on Sunday May 02, 2004 @11:51AM (#9033883) Homepage
    Its all very well talking about elegance and planning in advance until you try and deal with hardware. No amount of zen contemplation of your code is going to tell you what a debugger does about how the hardware and its documentation relate.

    The neatest debugging tricks I've seen so far are those logging all inputs and returns from the OS level. Since you can replay them you can rerun the app to an earlier point and investigate - in effect you can run it backwards from a bug to see how it got there.

  • Re:Exceptions (Score:3, Informative)

    by smallpaul (65919) <paul@@@prescod...net> on Sunday May 02, 2004 @11:59AM (#9033930)
    I'm looking at the source code for Python 1.1. It has a function called "extract_tb" which generates a list that you can manipulate and handle from a traceback. According to the changelog, that feature was added in 1994, the year before Java was released. I would bet money that the feature is much, much older than Python.
  • by hachete (473378) on Sunday May 02, 2004 @12:03PM (#9033949) Homepage Journal
    I agree with your comments 100% but try Log4j/Log4perl/Log4c. It allows you to turn debug info on/off through the config file. Saves you that extra claim

    h

  • Re:Exceptions (Score:3, Informative)

    by bdash (598142) <slashdot.org@bdash[ ]t.nz ['.ne' in gap]> on Sunday May 02, 2004 @12:14PM (#9034011) Homepage
    Care to name one of them?
    See this post [slashdot.org] for a concrete example of such a language. It would be nice to see some evidence of a) when Java grew these features, and b) that it was the first language to have such features.

    this implies that the language must have native multithread capabilities
    Huh? What does threading have to do with exception handling? The two are almost completely unrelated, and the presence of one feature in a language in no way requires nor implies the presence of the other.
  • by slickwillie (34689) on Sunday May 02, 2004 @12:33PM (#9034096)
    Same problem for real-time embedded software. Print statements take a relative eternity, assuming you even have someplace to print to. "Printing" to a memory buffer can help if you bypass the formatting.
  • Re:Data logging (Score:5, Informative)

    by mrm677 (456727) on Sunday May 02, 2004 @01:00PM (#9034235)
    Of course, as many people who debug multi-threaded programs have found, using print routines to output logs can make the bug 'go away', because quite often CRT functions like printf() etc are mutex'd, which serialises code execution, and thus alters the timing, and voila, race condition begone!

    Of course. A good data-logger design does not call expensive output routines in the timing sensitive threads. The routines should be low-cost and append information to some kind of shared memory block such that low-priority threads occasionally format and spit them out to your output device.
  • Re:don't debug (Score:3, Informative)

    by S3D (745318) on Sunday May 02, 2004 @01:04PM (#9034257)
    It's not always possible not to debug. Ever tryied programming multiagents systems ? The behavior of the system unpredictable (heh emergence), and it's quite often just plain impossible to tell why the system behave this or that way without debugger. Which rule or combination of rules exactly causing that specific situation...Print not help much if you have 1000 agents, and each have a lot of data. Only good old breakpoints help :)
  • by CondeZer0 (158969) on Sunday May 02, 2004 @01:05PM (#9034264) Homepage
    25 years later I still agree with Kernighan:

    The most effective debugging tool is still careful thought, coupled with
    judiciously placed print statements.

    -- Brian W. Kernighan, in the paper Unix for Beginners (1979)

    But I think the key to debugging is not the technique used for debugging, but how one wrote the code in the first place, here again God Kernighan hits the nail in the head:

    Debugging is twice as hard as writing the code in the first place. Therefore,
    if you write the code as cleverly as possible, you are, by definition, not
    smart enough to debug it.

    -- Brian W. Kernighan

    Once again, at the time of debugging, simplicity shows it's superiority to the complexity that seems to be so much in fashion this days. That is why I still prefer C to C++; rc [bell-labs.com] to bash; AWK/sed to Perl; Plan 9 [bell-labs.com] to Linux; Limbo [vitanuova.com] to Java; 9p [bell-labs.com] to NFS,...

    This is the forgotten key to software design: ...there are two ways of constructing a software design: One way is to make it
    so simple that there are obviously no deficiencies and the other way is to make
    it so complicated that there are no obvious deficiencies.

    -- C.A.R. Hoare, The 1980 ACM Turing Award Lecture

    Or put in another way:

    The cheapest, fastest, and most reliable components are those that aren't there.

    -- Gordon Bell

    Back in the topic of debugging, aside from the sacred printf, the Plan 9 [bell-labs.com] debugger acid [bell-labs.com] is often helpful, and now you can even use it on Linux/BSD!

    Plan 9 on Unix [swtch.com]

    Also the chapter on debugging in The Practice of Programming [bell-labs.com] by Brian W. Kernighan and Rob Pike is very good.

    Always remember:
    • Simplicity
    • Clarity
    • Generality
  • Re:Exceptions (Score:3, Informative)

    by JohnFluxx (413620) on Sunday May 02, 2004 @01:12PM (#9034335)
    Say you have a button on a form that performs some function. you have something like:

    doSomeFunc()

    Now you know that doSomeFunc() should be correct, and shouldn't have any errors. But you might have missed something - perhaps a divide by zero, or something.
    So you do:

    try {
    doSomeFunc();
    } catch (Exception e) { //handle
    }

    where you try your best to handle the error gracefully (tell the user, disable the button, contact admin team, suggest a work around, etc)

  • Re:Exceptions (Score:3, Informative)

    by John Courtland (585609) on Sunday May 02, 2004 @01:19PM (#9034396)
    What does threading have to do with exception handling? The two are almost completely unrelated, and the presence of one feature in a language in no way requires nor implies the presence of the other.
    I'd like to reinforce this statement. The only reason you would need multithreading is if you set up a watchdog timer to anticipate an infinite/semi-infinite loop state. Exceptions are almost exaclty like interrupt vectors. You set up a handler, it gets stored in a table, and if needed, it's called. In fact, some exceptions, like GPFs or invalid opcodes throw a hardware interrupt.

    Also, if you're smart, you can take the stack traces and find exactly what functions/datum those were. Had to do that a bunch on the IBM S/390. It's not hard, and with debugging code enabled, any exception generated will be able to produce line numbers and function traces.
  • Re:Exceptions (Score:5, Informative)

    by Paul Fernhout (109597) on Sunday May 02, 2004 @01:45PM (#9034542) Homepage
    Lisp and Smalltalk possibly in the 70s & certainly in the 80s (when I used ZetaLisp on a Symbolics and Smalltalk on various hardware -- Mac, TI, etc.).

    How much has been forgotten. Time and time again I hear people claiming Java invented something when it was just the place they first saw it compared to programming in C or TurboPascal or whatever. Java does have some ideas it popularized -- but they are things like interfaces. Much of its class design like for Swing was taken from ParcPlace Smatallk's VisualWorks. Hotspot profiling came from Smalltalk. MVC came from Smalltalk. etc. etc. Between Forth, Smalltalk, and Lisp (and a few other languages and libraries) most of the innovations people see now were invented a long time ago. VMs came from Smalltalk and IBM mainframes (first) and Pascal and Forth. Another example -- XML is a stupid version of Lisp s-expressions. And so it goes...

  • Re:Valgrind (Score:4, Informative)

    by Daniel (1678) <dburrowsNO@SPAMdebian.org> on Sunday May 02, 2004 @02:00PM (#9034618)
    AOL.

    Valgrind is possibly the most useful debugging tool I've found lately. It's especially great for tracking down slippery memory bugs -- you know, the type that are virtually impossible to find using most debugging tools.

    For people who haven't used it, what it basically does is recompile your program to target a simulated x86 CPU. It can detect branches that depend on uninitialized values, writes through a freed pointer, and a whole slew of other nasties that are difficult or impossible to detect with other tools.

    Daniel
  • by elan (171883) * on Sunday May 02, 2004 @02:10PM (#9034674)
    The code that calculated all the spreadsheet dependencies and what cells needed to be recomputed, was pretty complicated, as you might imagine.

    So they had the super-optimized version running in parallel with the dumb, calulate-every-cell-every-time engine, and then they'd compare the results.

    In certain cases, like this one, the technique is useful, but it's neither revolutionary nor new.

    -elan
  • Re:Valgrind (Score:5, Informative)

    by Soul-Burn666 (574119) on Sunday May 02, 2004 @02:18PM (#9034722) Journal
    It wasn't infered from your post, but it is important to note that your do not need to recompile your code to get it to work. It wraps already compiled executables. Though it would be smart to compile with -g so that it tells your which lines the errors happend and such.
  • by oliverthered (187439) <oliverthered@hotm a i l . c om> on Sunday May 02, 2004 @03:31PM (#9035161) Journal
    Jbuilder tells me in real time every sytax error in my code, I guess that's debugging.

    It also has good refactoring support, so no need to debug my poor hand refactoring. I guess that's kinda debugging.

    And it's very good at displaying my code in a way that allows me to find any bugs before running it, getters, setters, things I may have wanted to overload, UML diagrams etc... So I guess that's debugging.

    Debugging without even having to run the application, and wizards to perform all the monkey work so you don't gte bugs in the first place and intergrated junit testing.

    I think Eclipse has simila support.

    I'm not a very experianced java programmer, but my productivity is more than 4 times that of a friend whos been programming in java for more than 6 years. I do very little runtime debugging because my code is by and large bug free thanks to the design time and code time debugging in the IDE.

    Go download jbuilder [borland.com] trial or Eclipse with some sister project [eclipse.org] plugins (eclipse is a bit of a pain to use because it's still quite a recient product)
  • I have found... (Score:4, Informative)

    by dutky (20510) on Sunday May 02, 2004 @03:36PM (#9035183) Homepage Journal
    it is easiest if you just leave the bugs out in the first place.

    Failing that, as most of us do, the next best practice is to program defensively: anticipate where problems might occur in your code and include assertion checking and logging (yes, print statements) to illuminate those problem spots. Generally, I include debugging flags on the command line that allow me to control the level of assertion checking and logging (0=no logging, except for errors (the default), 1=log all branches, 2=log branches and variable values, 4=log everything).

    This defensive debugging strategy works quite well. First, it forces the programmer to think harder about both the algorithms they are using, and their implementation. I catch about a quarter of my programming errors just in the process of adding assertions. Second, the program will tend to abort as soon as a problem is detected, rather than running on for a couple billion instructions, dumping crap into the output file or database and then either aborting mysteriously on some marginally related condition, or, worse, completing without any reported errors! Finally, when errors are detected, the debugging can usually be done simply by inspecting the soure and following actual execution from the log file.

    All debugging comes down to one, fairly simple, idea: show me the program status at crucial points in the flow of control (generally at every branch and return). A few other tools are of some use under special circumstances: Purify [ibm.com], Electric Fence [perens.com] or Valgrind [kde.org] for detecting problems with dynamically allocated memory, or something like ddd [gnu.org] for examining linked structures (though I prefer to just write a validation function for my data structures, see my AVL-tree [bellatlantic.net] code for an example). Defensive programming works because it answers the important question that usually forces you into using the debugger: what the hell just happened?!? Defensive programming gives you a way to examine program states without invoking an outside tool.

    The only class of bugs that doesn't succumb well to this approach is race conditions. Unfortunately, anything that changes the timing of the program (such as stepping instruction-by-instruction in a debugger, or writting log messages out to a disk file) will change the behavior of the race condition. I'd be really interested in tools or techniques that could address this class of bugs.

  • Welcome to the 70s! (Score:3, Informative)

    by voodoo1man (594237) on Sunday May 02, 2004 @05:01PM (#9035672)
    Lisp and Smalltalk certainly had these capabilities in the 70s. Some of the Smalltalk stuff is described in a book I highly recommend, G. Kranser's (ed.) Smalltalk-80: Bits of History, Words of Advice. Interlisp had advanced stack-handling facilities for it's spaghetti-stack VM, and hooks into all the error handling facilities, dating back to the late 60s, when it was known as BBN-Lisp. Of course, development was also entirely structure-oriented, so instead of line numbers with your stack trace, you'd get the source code, right then and there (Smalltalk is the same way, but you get the text - in Interlisp, all the code was actual data structures).

    One thing that shouldn't be missed is that object-oriented exception handling, as popularized by Java, was invented in MIT Lisp Machine Lisp. This simplified and regularized error handling tremendously, to the point where today hooks into the deepest aspects of a typical implementation of Common Lisps' debugger are reduced to about a page's worth of code to deal with stack handling. I did a little work on the CLISP [cons.org] backend for SLIME [common-lisp.net], and this really surprised me.

  • Self Certifying Code (Score:1, Informative)

    by Anonymous Coward on Sunday May 02, 2004 @06:55PM (#9036355)
    as described at http://www-2.cs.cmu.edu/~necula/papers.html holds a lot of promise, especially if the proof annotations were saved in the executable along with symbol table information.
  • Delta Debugging (Score:1, Informative)

    by Anonymous Coward on Sunday May 02, 2004 @07:33PM (#9036611)
    Delta Debugging (http://www.st.cs.uni-sb.de/dd/) - has been featured on Slashdot before.

    Basic idea: Run a program with input data until it crashes. Debugger will find the diff in the input data that triggered the crash and the location in the source code where the crash originated. Also works for same input and different program versions.

    It's free and they have an online demo where you can upload your program with test cases and they will show you where the bug lies. (http://www.st.cs.uni-sb.de/askigor/)

    Also works in Eclipse with automated testing using JUNIT.
  • by Tomster (5075) on Sunday May 02, 2004 @10:47PM (#9037571) Homepage Journal
    Those of you who have written distributed applications/code know what a bitch it can be to debug something when multiple processes are involved.

    Those of you who have written multi-threaded applications know what a bitch it can be to debug something when multiple threads are involved.

    Those of you who have written timing-sensitive code know what a bitch it can be to debug something that is timing-related.

    Now, put all three of those into a pot and stir it around. That's what I and a co-worker have been working on the past four days.

    We sent four or five debug versions of the code to the customer for them to run in their production test environment over the past several days with various information printed to the console. With the dials turned way up, the problem usually manifested after a few hours (as opposed to a day or more, when operating under normal conditions). Each time, we'd get back a multi-megabyte log file which we would pore over to see if we had found the root cause of the problem. (Yes, grep was our dear, dear companion -- we're taking it out for drinks as soon as we've verified the problem has been fixed.)

    The problem was caused by a specific set of conditions -- the right things happening at the right time, in the right sequence, with a particular timing. To "trap" those conditions would require running both the client and server under a tracing debugger that recorded the time and "event" (e.g. method call, assignment, exception) of everything the system did and then allowed complex queries on the data produced. E.g. "How times per minute was update() called prior to isDead() returning true, on this instance?"

    The data could perhaps be recorded using AOP. Next time we run into a scenario like this, it might be worthwhile to break out AspectJ or AspectWorkz. But analysing it will be tricky.
  • by acz (120227) <z@NOSPAm.hert.org> on Monday May 03, 2004 @01:58AM (#9038287) Homepage
    IDA Pro [hert.org], the Interactive disassembler from datarescue [datarescue.com] is not only
    the best disassembler but also a great debugger, it can
    graph function flows, display pentium microcode, supports
    nearly every processors on the market (including your car's
    CPU.) Works nice with linux ELF binaries, etc... It is used by most antivirus researchers, crackers (who remove software protections), reverse engineers, hackers (who write exploits), etc. It runs perfect under wine without tweaking. Grab the
    demo and give it a go.


    Also under windows, SoftICE [compuware.com], is also an excellent debugger which lets you assemble in place and do many other neat things.

    Under linux, people have been trying to make SoftICE look-a-like debugger, such as LinICE, etc. and gdb is quite a powerful tool and is scriptable.

I bet the human brain is a kludge. -- Marvin Minsky

Working...