Thursday, June 18, 2009

CDT-EDC Expression Parsing

I was fortunate to spend some time working at home recently with Max. He's a good coworker: sleeps much of the day and can be trusted with any confidential info that floats by. Sure, there were the occasional insistent interruptions, but no more than I get at the office.

Last sprint I started working on variable display in the EDC debugger and this quickly unraveled in a few interesting directions. One involves parsing and evaluating C/C++ expressions. The DSF framework considers all variables to be expressions, so if you want to display the value of variable "i" then you need to implement the same API used for more complex expressions like "i + 2" or "*((ShapePtr*)i).fore_color". I could probably work around this just to splash some simple variable values up but eventually we would need to parse and evaluate expressions anyway.

I approached this with some dread: the expression engine in our legacy debugger back-end was created in the mid 90's based on an early version of the CodeWarrior C++ compiler's front-end. As the C++ language evolved and the debugger was ported to support an endless series of now deceased architectures and platforms it's expression engine was extensively poked, prodded and patched. Eventually I would try to gather up all of the expression issues for a release and work on them all together. It usually took me a day of staring at the code to remember how it worked and some CVS sleuthing to discover why various "adjustments" were made. Then I would attempt to fix everything I could without breaking anything. Afterward I would go work on something else and forget the whole experience until the next release.

But when I first talked to Doug Schaefer about developing a new debugger in CDT he wondered if the CDT language parser could be used by the debugger for expression parsing. The debugger in the JDT does this, it uses the Java language parser to break an expression into actionable opcodes and then has an evaluation engine that executes those to get a value.

I set out to try this in the CDT and so far it is working great! After some startup pointers from Ed, and Mike, and Markus I've got the CDT language parser chewing on various expressions I give it and then producing a stack full of actions (add, subtract, dereference, look up value etc.) that get executed to produce a value. This can be used a lot of places in a debugger: in the Expressions View, when you hover in the editor, and in the Variable View's details pane. There is a lot more to flesh out but it's nice to be able to leverage so much existing work in CDT and build something that will be much easier to maintain in the future.

Monday, June 1, 2009

CDT-EDC Source Mapping

One of the basic things a debugger needs to do is show you where you are in your source code when you stop at a breakpoint or exception or after stepping. When this happens an EDC debugger's TCF debug agent sends it an event that includes a memory address for the location. If there is no other information available you'll end up in the Debug View with a stack frame location that looks like this:


The next step is to use the EDC-DSF Modules service to determine if this address is in some code the debugger knows about. The Modules service keeps track of all the bits of code loaded in the target process. If you can find a module for the address then you can show something more interesting like this:


Finally the EDC debugger checks to see if debug symbols are available for that module. Debug symbols include a mapping table of address ranges to line numbers in your source code. The EDC-DSF Symbols service checks to see if this information is available. If it can find a source location for the address then you can show a complete description like this:



So that's what I got working last sprint using the Windows debugger and an executable built with gcc/mingw and Dwarf2 for testing. After you have a source file to work with the existing source mapping facilities in CDT can handle finding missing source files and remapping files to new locations. Our legacy debugger back-end does it's own source mapping and it was a problem to keep it in sync with the mapping we are already doing in CDT. The whole process is simple faster, and less error prone in the EDC debugger.