How do you extract local variable information (address and type) from a Delphi program or the compiler-generated debug info?

DelphiStackLocal VariablesDebug Symbols

Delphi Problem Overview


My goal is:

  • Given a suspended thread in a Delphi-compiled 32 or 64-bit Windows program, to walk the stack (doable)
  • Given stack entries, to enumerate the local variables in each method and their values. That is, at the very least, find their address and type (integer32/64/signed/unsigned, string, float, record, class...) the combination of which can be used to find their value.

The first is fine and it's the second that this question is about. At a high level, how do you enumerate local variables given a stack entry in Delphi?


At a low level, this is what I've been investigating:

RTTI: does not list this kind of information about methods. This was not something I actually ever thought was a realistic option, but listing here anyway.

Debug information: Loading the debug info produced for a debug build.

  • Map files: even a detailed map file (a text-format file! Open one and have a look) does not contain local variable info. It's basically a list of addresses and source file line numbers. Great for address to file&line correlation, e.g. the blue dots in the gutter; not great for more detailed information
  • Remote debugging information (RSM file) - no known information on its contents or format.
  • TD32/TDS files: my current line of research. They contain global and local symbols among a lot of other information.

The problems I'm encountering here are:

  • There's no documentation of the TD32 file format (that I can find.)
  • Most of my knowledge of them comes from the Jedi JCL code using them (JclTD32.pas) and I'm not sure how to use that code, or whether the structures there are extensive enough to show local vars. I'm pretty certain it will handle global symbols, but I'm very uncertain about local. There are a wide variety of constants defined and without documentation for the format, to read what they mean, I'm left guessing. However, those constants and their names must come from somewhere.
  • Source I can find using TDS info does not load or handle local symbols.

If this is the right approach, then this question becomes 'Is there documentation for the TDS/TD32 file format, and are there any code samples that load local variables?'

A code sample isn't essential but could be very useful, even if it's very minimal.

Delphi Solutions


Solution 1 - Delphi

Check if any debugging symbols weren't in binary. Also possible is using GDB (on Windows a port of it). It would be great if you found a .dbg or .dSYM file. They contain source code, eg.

gdb> list foo
56 void foo()
57 {
58  bar();
59  sighandler_t fnc = signal(SIGHUP, SIG_IGN);
60  raise(SIGHUP);
61  signal(SIGHUP, fnc);
62  baz(fnc);
63 }

If you don't have any debugging files, you may try to get MinGW or Cygwin, and use nm(1) (man page). It will read symbol names from binary. They may contain some types, like C++ ones:

int abc::def::Ghi::jkl(const std::string, int, const void*)

Don't forget to add --demangle option then or you'll get something like:

__ZN11MRasterFont21getRasterForCharacterEh

instead of:

MRasterFont::getRasterForCharacter(unsigned char)

Solution 2 - Delphi

Take a look at the http://download.xskernel.org/docs/file%20formats/omf/borland.txt Open Architecture Handbook. It is old, but maybe you find some relevant information about the file format.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDavidView Question on Stackoverflow
Solution 1 - DelphiTop SekretView Answer on Stackoverflow
Solution 2 - DelphiMuetze1View Answer on Stackoverflow