Page 1 of 1

FastMM_LogStackTrace returning empty string (64 bit only)

Posted: Thu Jun 06, 2019 5:55 pm
by santiago
Hello madschi,

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?

Thanks!

Re: FastMM_LogStackTrace returning empty string (64 bit only

Posted: Thu Jun 06, 2019 9:45 pm
by santiago
Hello madschi,

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:

409744 [System][_ZN6System7_GetMemEx]
410A91 [System][_ZN6System7TObject11NewInstanceEv]
41D269 [System][_ZN6System17TInterfacedObject11NewInstanceEv]
4117D1 [System][_ZN6System12_ClassCreateEPva]
9ED578 [MatFace3D.pas][MatFace3D][_ZN9Matface3d7TFace3dC3Ev]


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. :-)

Thanks!

sb

Re: FastMM_LogStackTrace returning empty string (64 bit only

Posted: Thu Jun 06, 2019 11:35 pm
by santiago
madschi,

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;
The only issue with this approach is that the 'columns' do not line up nicely.

Re: FastMM_LogStackTrace returning empty string (64 bit only

Posted: Fri Jun 07, 2019 3:07 pm
by madshi
I guess that nobody actually tested this in 64bit yet, including myself.

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.

Re: FastMM_LogStackTrace returning empty string (64 bit only

Posted: Fri Jun 07, 2019 5:44 pm
by santiago
My tool keeps track of which objects were allocated between a certain time span.
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.

Re: FastMM_LogStackTrace returning empty string (64 bit only

Posted: Fri Jun 07, 2019 5:51 pm
by madshi
You may be able to create something somewhat similar by using madExcept's leak checking, maybe?

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;
The advantage of madExcept's leak checking is that it isn't limited to just the Delphi memory manager. It also finds leaks in OS memory allocations (e.g. VirtualAlloc, LocalAlloc, HeapAlloc etc), and all kinds of resource leaks (user/gdi/kernel handles etc).

Re: FastMM_LogStackTrace returning empty string (64 bit only)

Posted: Thu Jan 21, 2021 12:13 pm
by Krystian
I've had same problem, on Win64 stack is empty.

Fix in: FastMM_LogStackTrace
change:
if TPAInteger(preparedStack)[i1] = 0 then begin
to:
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;

Re: FastMM_LogStackTrace returning empty string (64 bit only)

Posted: Thu Jan 21, 2021 1:24 pm
by madshi
Good catch, thank you!

Re: FastMM_LogStackTrace returning empty string (64 bit only

Posted: Fri Jan 22, 2021 7:13 am
by Krystian
santiago wrote: Thu Jun 06, 2019 11:35 pm I make use of madStackTrace.StackAddrToStr.
This is exactly what I looked for, to make easy use of RtlCaptureStackBackTrace, thanks :D