I have an internal tool we use for debugging purposes.
In this tool I load the FastMMFullDebugMode dll and import the 'GetRawStackTrace' (in 32 bits) and the 'GetFrameBasedStackTrace' function (in 64 bits).
I use this to obtain the callstack.
Later on, if I need to log the callstack I make use of the FastMM_LogStackTrace function.
This all works perfectly in 32 bit.
However in 64 bit calling FastMM_LogStackTrace returns the following string: '#$D#$A'.
The call stack obtained via the imported GetFrameBasedStackTrace seems to be valid.
I found a link to the following post:
viewtopic.php?f=4&t=27329&p=44894&hilit ... ace#p44894
Maybe that is the problem I am facing?
Any idea how I can get this to work?
If I use the exported function 'LogStackTrace' from FastMMFullDebugMode64.dll
I can then obtain a stacktrace. But the names are mangled. Results look like this:
It is somewhat usable, Definitely better than nothing though.
However this is an indication, that the TStackTrace that I obtain is valid, and that the problem is indeed in madStackTrace.FastMM_LogStackTrace.
I really hope you can get it to work in 64 bit. Your output is so much better.
this might be of use for you.
I can get usable callstacks (much better than using the FastMM method I described previously) by using the following function I just implemented.
I make use of madStackTrace.StackAddrToStr.
Code: Select all
function LogStackTrace64_Workaround(preparedStack: pointer; stackTraceDepth: integer; showRelativeAddrs, showRelativeLines: boolean) : string; var i : integer; begin Result := ''; for i := 0 to stackTraceDepth - 1 do begin if TPAPointer(preparedStack)[i] = nil then Exit; Result := Result.Insert(Result.Length, StackAddrToStr (TPAPointer(preparedStack)[i], showRelativeAddrs, showRelativeLines) + sLineBreak); end; end;
May I ask what purpose you use the FastMM debug mode exactly? I'm asking because madExcept has some new features which are probably better than some of the things (but maybe not all) that FastMM's debug mode does. E.g. there's leak reporting and the "instantly crash" features in newer madExcept builds which are quite powerful and better than what FastMM does.
The idea is that certain types of objects should no longer exist, after a calculation is performed.
The tool provides me a list of all surviving types. For each type I can get the instance list.
I can RTTI Inspect any instance and obtain the callstack to how it was created.
You can think of it as a very specialized allocation profiler.
Code: Select all
// You can call "GetLeakReport" at any time to get a leak report in string // form. You can decide if you want the leak report to contain callstacks and // if you want child leaks to be hidden. The reported leaks are *not* cleared. function GetLeakReport (limitedToCurrentThread: boolean = true; includeCallstacks: boolean = true; hideChildLeaks: boolean = true) : UnicodeString; // If you call "GetLeakReport" with "includeCallstacks = false", you can // request the callstack of a specific leak (identified by the allocation // number). function GetLeakCallstack (allocationNumber: int64) : UnicodeString;
Fix in: FastMM_LogStackTrace
if TPAInteger(preparedStack)[i1] = 0 then begin
if TPAPointer(preparedStack)[i1] = nil then begin // return address on x64 is also x64 pointer, not 32bit int
I'm using it for generating stack traces for my own perf-logging, returning addesses (stack frames) I'm getting from RtlCaptureStackBackTrace, so not really FastMM usage in that case
Just in case, if anyone would like to use it with RtlCaptureStackBackTrace, then you should call StackTrace with leak64mode=true, to get better stack traces on x64 like:
Code: Select all
function FastMM_LogStackTrace(preparedStack: pointer; stackTraceDepth: integer; buf: PAnsiChar; hideUglyItems, showRelativeAddrs, showRelativeLines, dumbTrace: boolean) : PAnsiChar; var i1 : integer; s1 : AnsiString; ps : AnsiString; begin for i1 := 0 to stackTraceDepth - 1 do if TPAPointer(preparedStack)[i1] = nil then begin // FIX stackTraceDepth := i1; break; end; SetLength(ps, 4 + stackTraceDepth * sizeOf(TPreparedStackItem)); TPPreparedStack(ps).itemCount := 0; for i1 := stackTraceDepth - 1 downto 0 do begin TPPreparedStack(ps).items[TPPreparedStack(ps).itemCount].dontKill := true; TPPreparedStack(ps).items[TPPreparedStack(ps).itemCount].afterInstr := TPAPointer(preparedStack)[i1]; inc(TPPreparedStack(ps).itemCount); end; s1 := AnsiString(#$D#$A + StackTrace(hideUglyItems, showRelativeAddrs, showRelativeLines, nil, nil, nil, true, false, 0, 0, nil, nil, nil, nil, nil, 0, dumbTrace, false, ps, nil, nil, nil, nil, nil, true, True // leak64mode )); result := buf; Move(pointer(s1)^, result^, Length(s1)); inc(result, Length(s1)); end;