FastMM_LogStackTrace returning empty string (64 bit only)

delphi package - automated exception handling
Post Reply
santiago
Posts: 73
Joined: Thu May 05, 2016 6:01 pm

FastMM_LogStackTrace returning empty string (64 bit only)

Post 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!
santiago
Posts: 73
Joined: Thu May 05, 2016 6:01 pm

Re: FastMM_LogStackTrace returning empty string (64 bit only

Post 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
santiago
Posts: 73
Joined: Thu May 05, 2016 6:01 pm

Re: FastMM_LogStackTrace returning empty string (64 bit only

Post 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.
madshi
Site Admin
Posts: 10753
Joined: Sun Mar 21, 2004 5:25 pm

Re: FastMM_LogStackTrace returning empty string (64 bit only

Post 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.
santiago
Posts: 73
Joined: Thu May 05, 2016 6:01 pm

Re: FastMM_LogStackTrace returning empty string (64 bit only

Post 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.
madshi
Site Admin
Posts: 10753
Joined: Sun Mar 21, 2004 5:25 pm

Re: FastMM_LogStackTrace returning empty string (64 bit only

Post 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).
Krystian
Posts: 5
Joined: Fri Aug 08, 2014 7:19 am

Re: FastMM_LogStackTrace returning empty string (64 bit only)

Post 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;
madshi
Site Admin
Posts: 10753
Joined: Sun Mar 21, 2004 5:25 pm

Re: FastMM_LogStackTrace returning empty string (64 bit only)

Post by madshi »

Good catch, thank you!
Krystian
Posts: 5
Joined: Fri Aug 08, 2014 7:19 am

Re: FastMM_LogStackTrace returning empty string (64 bit only

Post 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
Post Reply