Why does the AV say address 004146CF, while the MAP file says 0001:00055498 ?
004146CF
is the actual memory address of the code instruction that crashed at runtime, whereas addresses in the .map
file are relative since the actual load address of the process is not known at compile time.
Even if I subtract the start address of the CODE segment (0001)
0001
is not an address, let alone a starting address. It is merely an ID number defined at the top of the .map
file for a given segment. 0001:00055498
refers to relative address 00055498
within the segment identified as 0001
.
I still get 004146CF-00401000 = 136CF , which is not what I am looking for either.
Usually the load address of a process is $400000
(the actual value is defined in the Project Options and is $400000
by default), but that may be different at runtime due to various reasons, such as re-basing. Once you determine the actual load address, you need to include the actual offset of the code segment within the process. That offset is usually $1000
(the actual value is defined in the compiled executable's PE header). So, to map a memory address at runtime to an address in the .map
file, you usually subtract $401000
from the runtime memory address. Values may be different!
In this case, the resulting value 136CF
would be the item that you want to look for withing the 0001
code segment in the .map
file. You are not likely to find an EXACT match since the code that crashed is most likely in the middle of a function and rarely at the very beginning of the function. So you would look for a .map
item whose starting address is closest to 136CF
without exceeding it.
You did not show the entire .map
file, so there is no item in your snippet that is close to 136CF
. But the actual crash is not in CrashMe
itself, like you are expecting. It is actually inside of another function that CrashMe()
calls internally. Setting the TMemo.Text
property calls TWinControl.SetText()
, which calls TControl.GetText()
, which calls TWinControl.GetTextLen()
, which crashes when trying to access the FHandle
or FText
data member of an invalid TMemo
object:
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;
When diagnosing an AV, if you want to map the crash to CrashMe()
, it is not enough to have the memory address of the AV, since that memory address is not inside of CrashMe()
itself. You need a full stack trace leading up to the AV to show that CrashMe()
was called at some point and made subsequent calls that caused the actual AV. A .map
file will not help you get a stack trace, you need a runtime library that handles that at the time of the crash, such as JclDebug, MadExcept, EurekaLog, etc.
TControl.GetTextLen
. As you can see the problem address is not helpful without a stack trace. – Christopherchristopherso