如何从Delphi程序或编译器生成的调试信息中提取局部变量信息(地址和类型)?


105

我的目标是:

  • 给定Delphi编译的32或64位Windows程序中的挂起线程,可以遍历堆栈(可行)
  • 给定堆栈条目,以枚举每种方法中的局部变量及其值。也就是说,至少要找到它们的地址和类型(整数32/64 /有符号/无符号,字符串,浮点数,记录,类...),可以将它们的组合用于查找其值。

第一个很好,这是这个问题的第二个。从高层次上讲,如何在Delphi中给定堆栈条目的情况下枚举局部变量?


从低层次看,这就是我一直在研究的内容:

RTTI:未列出有关方法的此类信息。我实际上从未想到过这是一个现实的选择,但无论如何都要在此处列出。

调试信息:加载为调试版本生成的调试信息。

  • 地图文件:即使是详细的地图文件(一种文本格式的文件!打开其中的文件并查看)也不包含局部变量信息。它基本上是地址和源文件行号的列表。非常适合地址与文件和线的关联,例如装订线中的蓝点;不太适合获得更详细的信息
  • 远程调试信息(RSM文件)- 关于其内容或格式的未知信息
  • TD32 / TDS文件:我目前的研究方向。它们包含许多其他信息中的全局和局部符号。

我在这里遇到的问题是:

  • 没有TD32文件格式的文档(我可以找到。)
  • 我对它们的大部分了解都来自使用它们的Jedi JCL代码(JclTD32.pas),我不确定如何使用该代码,或者不确定其中的结构是否足够广泛以显示本地var。我很确定它将处理全局符号,但是我对局部符号不确定。我定义了各种各样的常量,并且没有格式的文档,要阅读它们的含义,我在猜测。但是,这些常量及其名称必须来自某个地方。
  • 我可以使用TDS信息找到的源无法加载或处理本地符号。

如果这是正确的方法,那么这个问题将变成“是否存在有关TDS / TD32文件格式的文档,并且是否有任何代码示例加载局部变量?”

代码示例不是必不可少的,但即使非常少也可能非常有用。


2
我实际上并没有使用Jedi JCL单元来访问TD32信息-为此,我拥有自己的专有库,但它确实看起来像您需要的所有基本管道都在JclTD32.pas中。虽然没有找到用于访问变量信息的演示代码,但是那里的示例(在.. \ jcl \ examples \ windows \ debug \ sourceloc中)显示了如何从TD32数据中获取行号信息,因此您应该能够在此基础上获得所需的东西。请在此处报告发现的内容:)
500-内部服务器错误

2
@ 500-InternalServerError谢谢。行号信息很容易(甚至在地图文件中也是如此)-但是您能提供有关您在JCL代码中看到的专门与本地符号相关的信息吗?此外,出于好奇,您的TD32专有库是什么,它是已发布/可公开使用还是仅在内部使用?
戴维(David)

3
它下面的每个过程/功能/方法符号又包含一个本地符号列表。大多数定义似乎都存在于绝地部队中,但其中一些已被注释掉。我的建议是创建微型测试应用程序,并查看符号枚举返回的内容。我拥有的代码是专有的,不适合我发布。无论如何,它不涉及局部变量的主题。但是它所基于的信息是半公开的,因此如果您遇到特定的问题,我也许能为您提供帮助。
500-内部服务器错误

4
tds2pdb(code.google.com/p/map2dbg)似乎具有用于tds文件的解析器。它是C#代码。
Graymatter

4
是的,曾经有一个非正式文档,但是,Borland(当时)决定发布一个dll来代替访问调试信息,以便他们可以更改内部格式而不必更新文档。不幸的是,我现在无法找到原始文档或dll。我建议您联系Embarcadero技术支持部门并进行询问。
500-内部服务器错误

Answers:


2

检查是否有任何调试符号都不是二进制的。也可以使用GDB(在Windows上是其端口)。如果找到一个.dbg或.dSYM文件,那就太好了。它们包含源代码,例如。

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 }

如果没有任何调试文件,则可以尝试获取MinGW或Cygwin,并使用nm(1)(手册页)。它将从二进制文件中读取符号名称。它们可能包含一些类型,例如C ++类型:

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

不要忘记添加 --demangle然后选项,否则您将得到类似以下内容的信息:

__ZN11MRasterFont21getRasterForCharacterEh

代替:

MRasterFont::getRasterForCharacter(unsigned char)

2
Jakub,谢谢您的回答。不幸的是,我可能需要阅读特定的调试格式-TDS。在Windows上,Delphi应用程序未使用兼容GDB的调试信息进行编译。我不确定nm是否会有所帮助,因为它将依赖于特定的调试文件格式,而这可能不是Delphi生成的格式。还是我误解了您的答案-例如,GDB可以读取Delphi的符号吗?
大卫

@DavidM,您的评论非常关键。尝试在Windows上找到GNU Binutils或GNU Debugger的端口(我只知道Binutils端口)。有一个用于GDB的BFD库。它也在Binutils中使用。它允许读取多种文件格式并通过其魔幻数字识别它们。如果一切失败,请使用称为的工具strings。它将从任何二进制文件中提取字符串。请参见手册页。这将打印出可能有用但不一定有用的字符串
Top Sekret

0

查看http://download.xskernel.org/docs/file%20formats/omf/borland.txt开放式体系结构手册。它很旧,但是也许您找到了有关文件格式的一些相关信息。


能否请您添加一些上下文,将来链接可能会断开。
Hintham

该链接包含borland的官方文档,其中涉及Borland编译器使用的OMF文件格式以及Borland使用的其他二进制文件格式。几年前,我看了一下TDS文件格式,似乎有些部分与记录的文件格式兼容。尝试从TDS文件收集有关局部变量的任何信息时,应使用或引用链接的文档。如果链接断开,我的答案将无用,所需的信息也会丢失。链接的“开放式体系结构手册”是旧的Turbo Pascal和C版本的一部分。
Muetze1
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.