2 * PROJECT: Dr. Watson crash reporter
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Print a stacktrace
5 * COPYRIGHT: Copyright 2017,2018 Mark Jansen (mark.jansen@reactos.org)
11 #define STACK_MAX_RECURSION_DEPTH 50
14 void BeginStackBacktrace(DumpData
& data
)
16 DWORD symOptions
= SymGetOptions();
17 symOptions
|= SYMOPT_UNDNAME
| SYMOPT_AUTO_PUBLICS
| SYMOPT_DEFERRED_LOADS
;
18 SymSetOptions(symOptions
);
19 SymInitialize(data
.ProcessHandle
, NULL
, TRUE
);
22 void EndStackBacktrace(DumpData
& data
)
24 SymCleanup(data
.ProcessHandle
);
27 static char ToChar(UCHAR data
)
32 return 'a' + data
- 0xa;
36 void PrintStackBacktrace(FILE* output
, DumpData
& data
, ThreadData
& thread
)
39 STACKFRAME64 StackFrame
= { { 0 } };
42 MachineType
= IMAGE_FILE_MACHINE_AMD64
;
43 StackFrame
.AddrPC
.Offset
= thread
.Context
.Rip
;
44 StackFrame
.AddrPC
.Mode
= AddrModeFlat
;
45 StackFrame
.AddrStack
.Offset
= thread
.Context
.Rsp
;
46 StackFrame
.AddrStack
.Mode
= AddrModeFlat
;
47 StackFrame
.AddrFrame
.Offset
= thread
.Context
.Rbp
;
48 StackFrame
.AddrFrame
.Mode
= AddrModeFlat
;
50 MachineType
= IMAGE_FILE_MACHINE_I386
;
51 StackFrame
.AddrPC
.Offset
= thread
.Context
.Eip
;
52 StackFrame
.AddrPC
.Mode
= AddrModeFlat
;
53 StackFrame
.AddrStack
.Offset
= thread
.Context
.Esp
;
54 StackFrame
.AddrStack
.Mode
= AddrModeFlat
;
55 StackFrame
.AddrFrame
.Offset
= thread
.Context
.Ebp
;
56 StackFrame
.AddrFrame
.Mode
= AddrModeFlat
;
60 #define STACKWALK_MAX_NAMELEN 512
61 char buf
[sizeof(SYMBOL_INFO
) + STACKWALK_MAX_NAMELEN
] = {0};
62 SYMBOL_INFO
* sym
= (SYMBOL_INFO
*)buf
;
63 IMAGEHLP_MODULE64 Module
= { 0 };
64 LONG RecursionDepth
= 0;
65 sym
->SizeOfStruct
= sizeof(sym
);
67 /* FIXME: dump x bytes at EIP here + disasm it! */
69 xfprintf(output
, NEWLINE
"*----> Stack Back Trace <----*" NEWLINE NEWLINE
);
71 while (StackWalk64(MachineType
, data
.ProcessHandle
, thread
.Handle
, &StackFrame
, &thread
.Context
,
72 NULL
, SymFunctionTableAccess64
, SymGetModuleBase64
, NULL
))
74 if (StackFrame
.AddrPC
.Offset
== StackFrame
.AddrReturn
.Offset
)
76 if (RecursionDepth
++ > STACK_MAX_RECURSION_DEPTH
)
78 xfprintf(output
, "- Aborting stackwalk -" NEWLINE
);
89 xfprintf(output
, "FramePtr ReturnAd Param#1 Param#2 Param#3 Param#4 Function Name" NEWLINE
);
93 Module
.SizeOfStruct
= sizeof(Module
);
94 DWORD64 ModBase
= SymGetModuleBase64(data
.ProcessHandle
, StackFrame
.AddrPC
.Offset
);
95 if (!ModBase
|| !SymGetModuleInfo64(data
.ProcessHandle
, ModBase
, &Module
))
96 strcpy(Module
.ModuleName
, "<nomod>");
98 memset(sym
, '\0', sizeof(*sym
) + STACKWALK_MAX_NAMELEN
);
99 sym
->SizeOfStruct
= sizeof(*sym
);
100 sym
->MaxNameLen
= STACKWALK_MAX_NAMELEN
;
101 DWORD64 displacement
;
103 if (!StackFrame
.AddrPC
.Offset
|| !SymFromAddr(data
.ProcessHandle
, StackFrame
.AddrPC
.Offset
, &displacement
, sym
))
104 strcpy(sym
->Name
, "<nosymbols>");
106 xfprintf(output
, "%p %p %p %p %p %p %s!%s" NEWLINE
,
107 (ULONG_PTR
)StackFrame
.AddrFrame
.Offset
, (ULONG_PTR
)StackFrame
.AddrPC
.Offset
,
108 (ULONG_PTR
)StackFrame
.Params
[0], (ULONG_PTR
)StackFrame
.Params
[1],
109 (ULONG_PTR
)StackFrame
.Params
[2], (ULONG_PTR
)StackFrame
.Params
[3],
110 Module
.ModuleName
, sym
->Name
);
113 UCHAR stackData
[0x10 * 10];
116 ULONG_PTR stackPointer
= thread
.Context
.Esp
;
117 #elif defined(_M_AMD64)
118 ULONG_PTR stackPointer
= thread
.Context
.Rsp
;
120 #error Unknown architecture
122 if (!ReadProcessMemory(data
.ProcessHandle
, (PVOID
)stackPointer
, stackData
, sizeof(stackData
), &sizeRead
))
125 xfprintf(output
, NEWLINE
"*----> Raw Stack Dump <----*" NEWLINE NEWLINE
);
126 for (size_t n
= 0; n
< sizeof(stackData
); n
+= 0x10)
128 char HexData1
[] = "?? ?? ?? ?? ?? ?? ?? ??";
129 char HexData2
[] = "?? ?? ?? ?? ?? ?? ?? ??";
130 char AsciiData1
[] = "????????";
131 char AsciiData2
[] = "????????";
133 for (size_t j
= 0; j
< 8; ++j
)
138 HexData1
[j
* 3] = ToChar(stackData
[idx
] >> 4);
139 HexData1
[j
* 3 + 1] = ToChar(stackData
[idx
] & 0xf);
140 AsciiData1
[j
] = isprint(stackData
[idx
]) ? stackData
[idx
] : '.';
145 HexData2
[j
* 3] = ToChar(stackData
[idx
] >> 4);
146 HexData2
[j
* 3 + 1] = ToChar(stackData
[idx
] & 0xf);
147 AsciiData2
[j
] = isprint(stackData
[idx
]) ? stackData
[idx
] : '.';
151 xfprintf(output
, "%p %s - %s %s%s" NEWLINE
, stackPointer
+n
, HexData1
, HexData2
, AsciiData1
, AsciiData2
);