
On Tue, Jun 2, 2009 at 4:47 PM, Christian Holmquist <c.holmquist@gmail.com>wrote:
- Loading debug info either for the currently running executable or from
an
offline executable
Care to elaborate a bit, I don't follow exactly. How is this useful compared to attaching a debugger?
It's not that uncommon that one would be running a debug build of something in an environment that doesn't have a debugger. Or perhaps a customer is using a release build and you don't want to give them private symbols, but you don't mind giving them public symbols. They can generate a useful stack trace this way for you. (How to output this without integrating logging facilities is, as you mention, something that would need to be worked out). The reason that I originally thought of this entire debugging library is actually because I thought it would be useful to add my own memory leak detection facilities a program I was writing, because I was tracing a difficult memory leak. (oh yea, might as well add memory corruption / leak detection to the list of cool things that would be possible with a library such as this). In Windows they have some CRT debugging functions that enable this sort of thing inside the CRT, but they do this by #define'ing new and delete to functions such as debug_new and debug_delete, this way with #defines they can use __FILE__, __LINE__, etc to track the location of allocations. It's preferable to overload operator new and delete instead, this way you solve a lot of problems with order of #includes, but if you overload operator new and delete you can't use the __FILE__ and __LINE__ macros or they will just refer to the source file / line number of the implementation of the overloaded operators. With a structured stack trace representation, you could simply move up 1 frame and get source / line information from inside the operators, ultimately allowing advanced memory leak / integrity checking via overloaded operators while still maintaining accurate source / line information. When the process exits, you could dump all detected memory leaks along with their entire stack traces, or if a double delete was detected you could dump an entire stack trace for where it was allocated. This was the original use case I had in mind, I thought of the first case (with private / public symbols) later. It also might be useful in a Q/A environment where if they detect a program crash they can give you a stack traec (although if the library is able to generate stack traces, even if only through the unhandled_exception handler, in release mode that might be sufficient to cover some of these other cases).
- Printing human readable stack traces from a running program
IMO getting a stack-trace really quick, and defer the print-out (using the dbghelp on windows for instance) until the user requests it would be more useful than printout only. Like:
FWIW DbgHelp library turned out to be grossly insufficient for what I needed, so my library is now using the DIA SDK. Which unfortunately relies on COM, but I don't think that should be too much of a problem.
- Assuming symbol information is loaded either for the running program or an offline program, format a block of memory in a human readable format to print the structure of the memory (for example, display member values of a class with field names, given a block of memory representing an instance of the class)
Care to provide an example here?
The easiest example to understand here is that you're actually using this library to _implement_ your own debugger. You have debug information for the debugee because it was generated by your compiler, your process is the debugger, you want to display the value of a symbol in the watch window. You know that the virtual address of the symbol is 0x12345678. You look it up in the symbol table and find that that the symbol at this location is of type: class foo { int a; double d; }; clearly sizeof(foo) == 12, so the above would be able to take the address 0x12345678, interpret the first 4 bytes as a signed integer, the last 8 bytes as a double precision floating point, and return those values to the caller to display in a watch window. The best way to get this information back to the caller is open for discussion. I was thinking it would just be a simple string pre-formatted according to some rules of the library, but it's not hard to imagine other possibilities. For example, a "symbol_field_iterator" that returned objects which you could call to_string() on, or value_as<T> so you could get the actual data in the correct type.
- launch process under a debugger and receive basic types of debugging notifications.
What kind of notifications are you referring to?
The types needed in order to implement a debugger. module was loaded into the process, thread was just created, exception just occurred, etc. I've no idea how debuggers are implemented under Linux, but in windows there's a debug api that provides these events very easily. I'm sure there's something similar under Linux, even if it's difficult, because GDB does some fairly advanced things.