3

如何获取保存事件处理程序的变量的地址?

例如

TExample = class(TObject)
private
    FOnChange: TNotifyEvent;
end;

我想要私有成员、事件处理程序、变量的地址。FOnChange


为什么?

我试图找出谁在FOnChange用垃圾覆盖我的处理程序变量。

我正在逐步执行代码:

if Assigned(FOnChange) then
    FOnChange(Self);

没有分配任何事件处理程序,并且有一段时间FOnChange变量nil位于观察窗口中:

@FOnChange: nil
Addr(FOnChange): nil

但后来FOnChange变量变成了垃圾:

@FOnChange: $2C
Addr(FOnChange): $2C

所以我想FOnChange在 CPU 窗口的数据窗格中观察变量,以便我可以从以下位置观察它:

00410018 00000000

00410018 0000002C

除了我不知道的地址FOnChange; 我刚编的$410018

如何找到事件变量的地址?


我尝试过的事情

观察名单

OnChange: nil
@OnChange: nil
@@OnChange: Variable required
@FOnChange: nil
Assigned(OnChange): False
Assigned(FOnChange): False
@@FOnChange: $253B588
addr(addr(FOnChange)): $253B588

Alt+F5

  • 改变: OnChange: TNotifyEvent $253B588
  • FOnChange:检查“FOnChange”时出错:表达式错误
  • Self.FOnChange:检查“Self.FOnChange”时出错:表达式错误
  • @OnChange@OnChange: Pointer $253B588
  • @@OnChange:检查“@@OnChange”时出错:表达式错误
  • @FOnChange@FOnChange: Pointer $253B588
  • @@FOnChange@@FOnChange: ^Untyped (no address) 数据: @@FOnChange $253B588`

共识似乎正在解决0x253B588

然而,当我运行一些示例代码时:

MyControl1.OnChange := TheOnChangeHandler;

这变成:

mov edx,[ebp+$08]         ;move stack variable $08 into edx
mov [eax+$00000208],edx   ;and then into offset $208 of my control

mov edx,[ebp+$0c]         ;move stack variable $0c into edx
mov [eax+$0000020c],edx   ;and then into offset $20c of my control

难怪我找不到地址FOnChange,是两个地址!

4

5 回答 5

6

您可以通过 Debug Inspector 获取地址。要获取字段的地址,请在更改发生之前的某个时间点在代码中放置一个断点,例如在您调用构造函数之后。然后在调试检查器中打开您的对象。不知道你是如何在旧的 IDE 风格中得到它的,但在 D2010 中,你可以通过 Run->Inspect... 菜单命令、Evaluate/Modify 中的按钮或按键盘上的 ALT-F5 来获得它。(注意不要按 ALT-F4!)

调试检查器将向您显示您的对象及其所有字段。双击其中一个字段,它将在新的调试检查器窗口中打开。在顶部的类似编辑框的栏中将是您字段的地址。您可以使用它来设置内存断点以查找值更改的位置。

于 2010-06-21T17:13:05.727 回答
4

在 Delphi 5 中不确定,但您应该能够在 AExample.FOnChange 上放置数据断点(或地址断点)。
只要值发生变化,它就会中断。

于 2010-06-21T17:13:57.890 回答
3

由于您无法使用 François 建议的智能解决方案,因此是时候进行黑客攻击了!在某个地方,任何你可以设置刹车点的地方,编写如下代码:

var X:TExample;
X.OnChange := nil;

在 X.OnChange := nil 线上放一个刹车点;当调试器停在那里时,查看反汇编窗格,您会看到如下内容:

; assembler blah blah to get the address of X
xor EDX ; or whatever the compiler finds appropriate this time of day
mov [eax + $00000288], edx
mov [eax + $0000028c], edx

您不关心编译器使用的寄存器,您关心的是 $288,即用于第一条 MOV 指令的偏移量。这是从“X”地址到 FOnChange 字段的偏移量。记下来。现在回到你的错误程序,在某处设置一个刹车点,按 Alt+F5 调用调试检查器(如果没有空编辑框输入查询,则按 Ctrl+N)并编写“Integer( MyExampleVariable)"; 不管你得到什么,把你在上一步记下的数字加起来,你就得到了 MyExampleVariable 实例的 FOnChange 的地址,你现在可以设置一个地址刹车点。

于 2010-06-21T17:33:24.050 回答
2

我不知道它们是否存在于 Delphi 5 中,但类型TMethod和函数MethodAddress应该会有所帮助。

于 2010-06-21T19:03:17.270 回答
0

为什么?

我试图找出谁在用垃圾覆盖我的 FOnChange 处理程序变量。

我可以回答这一点 - 你是!或者您正在查看未正确创建的错误实例?没有正确引用?会是这样的。Delphi 调试器擅长使一些不存在的东西看起来像它确实存在,直到...

退后一点,试着看看树林而不是树木。我去过你的地方很多次,你可能是在叫错树(对不起,双关语),很快就会给自己起各种各样的名字:)

于 2010-06-21T20:09:07.887 回答