Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Cross-Platform-Entwicklung (https://www.delphipraxis.net/91-cross-platform-entwicklung/)
-   -   StackTrace-Ausgabe unter MacOS (https://www.delphipraxis.net/199955-stacktrace-ausgabe-unter-macos.html)

philipp.hofmann 5. Mär 2019 14:52

StackTrace-Ausgabe unter MacOS
 
Hi,

wie gebt ihr den vollständigen StackTrace unter MacOS aus? Für Windows nutze ich MadExcept, für iOS und Android hatte ich schon mal brauchbaren Code gefunden.
Nur für MacOS (und Linux) fehlt mir noch ein brauchbares Pendant.

Grüße, Philipp

hoika 5. Mär 2019 16:29

AW: StackTrace-Ausgabe unter MacOS
 
Hallo,
das hier vielleicht?

https://stackoverflow.com/questions/...k-trace-on-osx

philipp.hofmann 6. Mär 2019 06:01

AW: StackTrace-Ausgabe unter MacOS
 
Der dort dokumentierte Code ist leider nicht vollständig. Man muss sich die Unit SBMapFiles noch selber zusammenbauen. Und mir scheint, dass die Stacktrace-Ausgabe ohne dieseMapping relativ nutzlos ist. Copy&Paste reicht also nicht aus um dies zu testen.

hoika 6. Mär 2019 06:06

AW: StackTrace-Ausgabe unter MacOS
 
Hallo,
ja, gerade noch mal genauer gelesen.

Es sind ja 2 Ansätze:
1. unit MyExceptionHandler;
2. mit Hilfe der undokumentierten SBxx-Unit.

philipp.hofmann 6. Mär 2019 11:52

AW: StackTrace-Ausgabe unter MacOS
 
So, ich habe mir jetzt den Map-File-Mapper selbst gebaut und damit bekommt man halbwegs aussagekräftige StackTraces ausgegeben.
Aber irgendwie traurig, dass man dafür selbst eine solche Funktion implementieren muss. Sind nur 220 Zeilen, aber trotzdem würde ich mir so etwas von Emba frei Haus wünschen.

Sherlock 6. Mär 2019 13:42

AW: StackTrace-Ausgabe unter MacOS
 
Und wärst Du bereit das mit uns zu teilen? So als eigenes Projekt?

Sherlock

softtouch 10. Mai 2019 19:55

AW: StackTrace-Ausgabe unter MacOS
 
Ich bin auch EWIG auf der Suche nach einem OSX exception handler. Kannst Du Deinen Code nicht mit uns teilen, damit das Rad nicht nochmal erfunden werden muss?

philipp.hofmann 15. Mai 2019 22:48

AW: StackTrace-Ausgabe unter MacOS
 
Hier ist mein Code, ein paar kleinere Anpassungen sind sicherlich notwendig. MyLog ist bei mir ein Wrapper zu TMSLogging.
FileUtils liest einfach nur eine TStringList ein, das sollte einfach zu ersetzen sein. Voraussetzung ist aber, dass du das Map-File erzeugst und mit deployst.

Delphi-Quellcode:
unit MyMacOSExceptionHandler;

interface

var
  mapFilename:String;
function getFunctionNameExt(hexException:String):String;

implementation

uses Posix.Base, SysUtils,
   MyLog, System.Generics.Collections, FileUtils, System.Classes, IntegerStringList;

function backtrace(result: PNativeUInt; size: Integer): Integer; cdecl; external libc name '_backtrace';
function _NSGetExecutablePath(buf: PAnsiChar; BufSize: PCardinal): Integer; cdecl; external libc name '__NSGetExecutablePath';

var
  PrevRaiseException: function(Exc: Pointer): LongBool; cdecl;
  mapDict: TIntegerStringList;

const
  MaxDepth = 20;
  SkipFrames = 3;

procedure LoadMapFile();
var
  //FileName: array[0..255] of AnsiChar;
  //Len: Integer;
  mapFile:TStringList;
  i,firstEntry:integer;
  start1,start2,start3,start4:Int64;
  key:Int64;
  add,value:String;
begin
  if (MapDict = nil) then
  begin
    mapDict:=TIntegerStringList.create();
    //Len := Length(FileName);
    //_NSGetExecutablePath(@FileName[0], @Len);
    //if FileExists(ChangeFileExt(FileName, '.map')) then
    start1:=0;
    start2:=0;
    start3:=0;
    start4:=0;
    //start5:=0;
    if (FileExists(mapFilename)) then
    begin
      //mapFile:=TFileUtils.readFile(ChangeFileExt(FileName, '.map'));
      mapFile:=TFileUtils.readFile(mapFileName);
      firstEntry:=-1;
      for i:=0 to mapFile.count-1 do
      begin
        if (pos('Start',mapFile[i])>0) then
        begin
          start1:=StrToInt('$'+copy(mapFile[i+1],7,8));
          start2:=StrToInt('$'+copy(mapFile[i+2],7,8));
          start3:=StrToInt('$'+copy(mapFile[i+3],7,8));
          start4:=StrToInt('$'+copy(mapFile[i+4],7,8));
          //start5:=StrToInt('$'+copy(mapFile[i+5],7,8));
          break;
        end;
      end;
      for i:=0 to mapFile.count-1 do
      begin
        if (pos('Address',mapFile[i])>0) and (pos('Publics by Name',mapFile[i])>0) then
        begin
          firstEntry:=i+2;
          break;
        end;
      end;
      if (firstEntry>-1) then
      begin
        for i:=firstEntry to mapFile.count-1 do
        begin
          if (mapFile[i]='') then
            break;
          add:=copy(mapFile[i],2,4);
          key:=StrToInt64('$'+copy(mapFile[i],7,8));
          value:=copy(mapFile[i],22);
          if (add='0001') then
            key:=start1+key
          else if (add='0002') then
            key:=start2+key
          else if (add='0003') then
            key:=start3+key
          else if (add='0004') then
            key:=start4+key;
          //else if (add='0005') then
          //  key:=IntToHex(start5+StrToInt64('$'+key),8);
          mapDict.add(TIntegerStringEntry.create(key,value));
        end;
        mapDict.sort(mapDict.comparer);
      end;
    end else
      log.info('Can''t find Map-File: '+mapFilename);
  end;
end;

function getFunctionName(exceptionInt:Int64):String;
var i:integer;
begin
  Result:='???';
  for i:=1 to mapDict.count-1 do
  begin
    if (mapDict[i].key>exceptionInt) then
    begin
      Result:=mapDict[i-1].value;
      break;
    end;
  end;
end;

function getFunctionNameExt(hexException:String):String;
begin
  Result:=getFunctionName(StrToInt64('$'+hexException));
end;

procedure ShowCurrentStack;
var
  StackLog: PNativeUInt; //array[0..10] of Pointer;
  Cnt: Integer;
  I: Integer;
begin
  {$POINTERMATH ON}
  if (mapDict=nil) then
    loadMapFile();
  GetMem(StackLog, SizeOf(Pointer) * MaxDepth);
  try
    Cnt := backtrace(StackLog, MaxDepth);

    for I := SkipFrames to Cnt - 1 do
    begin
      if StackLog[I] = $BE00EF00 then
      begin
        WriteLn('---');
        Break;
      end;
      log.error(IntToHex(StackLog[I],8)+' '+getFunctionName(StackLog[I]));
    end;

   finally
    FreeMem(StackLog);
   end;
  {$POINTERMATH OFF}
end;

procedure InstallExceptionHandler; forward;
procedure UnInstallExceptionHandler; forward;

var
  InRaiseException: Boolean;

function RaiseException(Exc: Pointer): LongBool; cdecl;
begin
  InRaiseException := True;
  ShowCurrentStack;

  Result := PrevRaiseException(Exc);
  InRaiseException := False;
end;

procedure InstallExceptionHandler;
var
  U: TUnwinder;
begin
  GetUnwinder(U);
  Assert(Assigned(U.RaiseException));
  PrevRaiseException := U.RaiseException;
  U.RaiseException := RaiseException;
  SetUnwinder(U);
  mapDict:=nil;
end;

procedure UnInstallExceptionHandler;
var
  U: TUnwinder;
begin
  GetUnwinder(U);
  U.RaiseException := PrevRaiseException;
  SetUnwinder(U);
end;

initialization
  InstallExceptionHandler;
end.
Delphi-Quellcode:
unit IntegerStringList;

interface

uses Generics.Collections,System.SysUtils,System.Classes,
  System.Generics.Defaults, System.Math;

type

  TIntegerStringEntry = class(TObject)
  public
    key:Int64;
    value:String;
    constructor create(key:Int64;value:String);
  end;

  TIntegerStringList = class(TObjectList<TIntegerStringEntry>)
  public
    Comparer: IComparer<TIntegerStringEntry>;
    constructor create(); overload;
  end;

implementation

constructor TIntegerStringEntry.create(key:Int64;value:String);
begin
  self.key:=key;
  self.value:=value;
end;

constructor TIntegerStringList.create();
begin
  Comparer := TDelegatedComparer<TIntegerStringEntry>.Create(
  function(const Left, Right: TIntegerStringEntry): Integer
  begin
    if (left.key<right.key) then
      Result:=-1
    else if (left.key>right.key) then
      Result:=1
    else
      Result := 0;
  end);
  inherited create(true);
end;

end.


Alle Zeitangaben in WEZ +1. Es ist jetzt 20:44 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz