Entwickler-Ecke

Algorithmen, Optimierung und Assembler - Stacktrace erstellen, Callstack ermitteln


Boldar - Fr 11.03.16 20:16
Titel: Stacktrace erstellen, Callstack ermitteln
Hi,
ich möchte gerne einen stack-Trace des Call-stacks in einer x86-Anwendung erstellen.
Mir ist bewusst, dass die Jedi-Libraries das können, ich möchte das aber gerne selber machen.
Ich weiss schon so ungefähr, dass man sich an den return-calls entlanghangelt, und dabei ausnutzt, dass alle Funktionen diese Zeile haben

Quelltext
1:
2:
0 D40224 55                               push ebp
1 D40225 8BEC                             mov ebp, esp

Dass bedeuted, man muss quasi immer den nächsten ebp ermitteln, und dann den return-pointer finden.
Der stack sollte an der stelle dann doch so aussehen:


Quelltext
1:
2:
3:
4:
xxxx
return-pointer
alter ebp
Lokale variablen   <--- Dahin zeigt der neue ebp

d.h. ich benutze den ebp, um den alten ebp zu ermitteln und hangele mich da durch und ermittele jedes mal die return-pointer. Der sollte dann also an [ebp+8] liegen.
Wie sieht dass dan in der Praxis aus? Mir fehlt da so ein bisschen der ansatz. Hat jemand so etwas schonmal gemacht und kann mir da ein paar code-Zeilen (bzw. asm-Zeilen) liefern, mit denen ich anfangen kann?
Ich möchte jetzt nicht unbedingt fertigen Code, sondern eher einen Ansatz, wie man das ganze angeht.
lg Boldar


Boldar - Do 17.03.16 12:21

Ich habs jetzt hinbekommen, falls es jemanden interessiert. Es war eigentlich recht einfach, wenn man erstmal drauf kommt:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
function _isBadReadPtr (p: pointer;size: integer):boolean;
var
  dw: SIZE_T;
  mbi: windows.MEMORY_BASIC_INFORMATION;
begin
  result := false;
  dw := Virtualquery (p, mbi, sizeof (mbi));
  result :=
        (mbi.Protect=PAGE_READONLY         )or
        (mbi.Protect=PAGE_READWRITE        )or
        (mbi.Protect=PAGE_WRITECOPY        )or
        (mbi.Protect=PAGE_EXECUTE_READ     )or
        (mbi.Protect=PAGE_EXECUTE_READWRITE)or
        (mbi.Protect=PAGE_EXECUTE_WRITECOPY);
  if (mbi.Protect = PAGE_GUARD   ) then result := false;
  if (mbi.Protect = PAGE_NOACCESS) then result := false;
  result := not result;
end;

function GetCallStackTrace: AnsiString;
var
    ret, stackwalk: ^pointer;
    conter: integer;
begin
    asm
        mov stackwalk, ebp
    end;
    while Cardinal(stackwalk^) <> 0 do begin
        ret := stackwalk;
        Inc(ret);
        if _isBadReadPtr(ret, 8then break;
        if _isBadReadPtr(stackwalk, 8then break;
        result := result + inspectfunc(ret^);
        stackwalk := stackwalk^;
    end;
end;