gpt4 book ai didi

delphi - 解析map文件中AccessViolation的地址

转载 作者:行者123 更新时间:2023-12-03 14:47:20 25 4
gpt4 key购买 nike

我的一位用户报告了一些罕见的 AccessViolations,我想对其进行分析。

我有该构建的源代码,因此我可以创建一个 MAP 文件。但我不知道如何在MAP文件中找到AccessViolation提供的地址。

(将来,我们希望使用像 JclDebug 这样的框架来创建可用的堆栈跟踪)。

我设置了一个示例:

procedure CrashMe;
var
k: TMemo; a: TButton;
begin
k.Text := 'abc';
k.Color := clBlack;
k.Assign(a);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
CrashMe;
end;

访问冲突是:

Address 004146CF. Reading from address B2D88B53 .

在 map 文件中,我发现以下内容:

 Start         Length     Name                   Class
0001:00401000 000556A8H .text CODE
0002:00457000 00000770H .itext ICODE
0003:00458000 00001B0CH .data DATA
0004:0045A000 00004CCCH .bss BSS
0005:00000000 00000038H .tls TLS

....

0001:000552F0 Unit1..TForm1
0001:00055498 Unit1.CrashMe
0004:00004CC8 Unit1.Form1
0001:000554C8 Unit1.TForm1.Button1Click

为什么 AV 说地址 004146CF,而 MAP 文件说地址 0001:00055498?

即使我减去 CODE 段的起始地址 (0001),我仍然得到 004146CF-00401000 = 136CF ,这也不是我要找的。

我也尝试通过搜索字符串“:00414”来查找错误地址,但没有找到任何内容。

如何从 MAP 文件中的 AV 中查找地址?

最佳答案

Why does the AV say address 004146CF, while the MAP file says 0001:00055498 ?

004146CF是运行时崩溃的代码指令的实际内存地址,而 .map 中的地址文件是相对的,因为进程的实际加载地址在编译时未知。

Even if I subtract the start address of the CODE segment (0001)

0001不是地址,更不是起始地址。它只是 .map 顶部定义的 ID 号。给定段的文件。 0001:00055498指相对地址00055498在标识为 0001 的段内.

I still get 004146CF-00401000 = 136CF , which is not what I am looking for either.

通常进程的加载地址是 $400000 (实际值在项目选项中定义,默认为$400000),但由于各种原因(例如重新定位),该值在运行时可能会有所不同。一旦确定了实际加载地址,您就需要包含代码段在进程内的实际偏移量。该偏移量通常 $1000 (实际值在编译后的可执行文件的 PE header 中定义)。因此,要在运行时将内存地址映射到 .map 中的地址文件,您通常减去 $401000来自运行时内存地址。值可能不同!

在本例中,结果值 136CF将是您想要在 0001 中查找的项目.map 中的代码段文件。您不太可能找到完全匹配,因为崩溃的代码很可能位于函数的中间,而很少位于函数的开头。所以你会寻找 .map起始地址最接近136CF的项目不超过它。

您没有显示完整的.map文件,因此您的代码片段中没有任何项目接近 136CF 。但实际崩溃并不在 CrashMe本身,就像你所期待的那样。它实际上是在另一个函数的内部 CrashMe()内部调用。设置TMemo.Text属性(property)电话TWinControl.SetText() ,调用 TControl.GetText() ,调用 TWinControl.GetTextLen() ,在尝试访问 FHandle 时崩溃或FText无效 TMemo 的数据成员对象:

procedure TWinControl.SetText(const Value: TCaption);
begin
if GetText <> Value then // <-- here
begin
if WindowHandle <> 0 then
Perform(WM_SETTEXT, 0, string(Value))
else
FText := Value;
Perform(CM_TEXTCHANGED, 0, 0);
end;
end;

function TControl.GetText: TCaption;
{$IF DEFINED(CLR)}
begin
Result := GetTextPiece(GetTextLen);
end;
{$ELSE}
var
Len: Integer;
begin
Len := GetTextLen; // <-- here
SetString(Result, PChar(nil), Len);
if Len <> 0 then
begin
Len := Len - GetTextBuf(PChar(Result), Len + 1);
if Len > 0 then
SetLength(Result, Length(Result) - Len);
end;
end;
{$IFEND}

function TWinControl.GetTextLen: Integer;
begin
if WindowHandle <> 0 then // <-- here
Result := Perform(WM_GETTEXTLENGTH, 0, 0)
else
Result := Length(FText); // <-- or here
end;

诊断 AV 时,如果您想将崩溃映射到 CrashMe() ,仅仅拥有 AV 的内存地址是不够的,因为该内存地址不在 CrashMe() 内。本身。您需要通往 AV 的完整堆栈跟踪来显示 CrashMe()在某个时刻被调用,并进行了导致实际 AV 的后续调用。一个.map文件不会帮助您获取堆栈跟踪,您需要一个在崩溃时处理该问题的运行时库,例如 JclDebug、MadExcept、EurekaLog 等。

关于delphi - 解析map文件中AccessViolation的地址,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38205106/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com