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 } };
41 StackFrame
.AddrPC
.Mode
= AddrModeFlat
;
42 StackFrame
.AddrReturn
.Mode
= AddrModeFlat
;
43 StackFrame
.AddrFrame
.Mode
= AddrModeFlat
;
44 StackFrame
.AddrStack
.Mode
= AddrModeFlat
;
45 StackFrame
.AddrBStore
.Mode
= AddrModeFlat
;
49 MachineType
= IMAGE_FILE_MACHINE_I386
;
50 StackFrame
.AddrPC
.Offset
= thread
.Context
.Eip
;
51 StackFrame
.AddrStack
.Offset
= thread
.Context
.Esp
;
52 StackFrame
.AddrFrame
.Offset
= thread
.Context
.Ebp
;
53 #elif defined(_M_AMD64)
54 MachineType
= IMAGE_FILE_MACHINE_AMD64
;
55 StackFrame
.AddrPC
.Offset
= thread
.Context
.Rip
;
56 StackFrame
.AddrStack
.Offset
= thread
.Context
.Rsp
;
57 StackFrame
.AddrFrame
.Offset
= thread
.Context
.Rbp
;
59 MachineType
= IMAGE_FILE_MACHINE_ARMNT
;
60 StackFrame
.AddrPC
.Offset
= thread
.Context
.Pc
;
61 StackFrame
.AddrStack
.Offset
= thread
.Context
.Sp
;
62 StackFrame
.AddrFrame
.Offset
= thread
.Context
.R11
;
63 #elif defined(_M_ARM64)
64 MachineType
= IMAGE_FILE_MACHINE_ARM64
;
65 StackFrame
.AddrPC
.Offset
= thread
.Context
.Pc
;
66 StackFrame
.AddrStack
.Offset
= thread
.Context
.Sp
;
67 StackFrame
.AddrFrame
.Offset
= thread
.Context
.u
.s
.Fp
;
69 #error "Unknown architecture"
72 #define STACKWALK_MAX_NAMELEN 512
73 char buf
[sizeof(SYMBOL_INFO
) + STACKWALK_MAX_NAMELEN
] = {0};
74 SYMBOL_INFO
* sym
= (SYMBOL_INFO
*)buf
;
75 IMAGEHLP_MODULE64 Module
= { 0 };
76 LONG RecursionDepth
= 0;
77 sym
->SizeOfStruct
= sizeof(sym
);
79 /* FIXME: dump x bytes at PC here + disasm it! */
81 xfprintf(output
, NEWLINE
"*----> Stack Back Trace <----*" NEWLINE NEWLINE
);
83 while (StackWalk64(MachineType
, data
.ProcessHandle
, thread
.Handle
, &StackFrame
, &thread
.Context
,
84 NULL
, SymFunctionTableAccess64
, SymGetModuleBase64
, NULL
))
86 if (StackFrame
.AddrPC
.Offset
== StackFrame
.AddrReturn
.Offset
)
88 if (RecursionDepth
++ > STACK_MAX_RECURSION_DEPTH
)
90 xfprintf(output
, "- Aborting stackwalk -" NEWLINE
);
101 xfprintf(output
, "FramePtr ReturnAd Param#1 Param#2 Param#3 Param#4 Function Name" NEWLINE
);
105 Module
.SizeOfStruct
= sizeof(Module
);
106 DWORD64 ModBase
= SymGetModuleBase64(data
.ProcessHandle
, StackFrame
.AddrPC
.Offset
);
107 if (!ModBase
|| !SymGetModuleInfo64(data
.ProcessHandle
, ModBase
, &Module
))
108 strcpy(Module
.ModuleName
, "<nomod>");
110 memset(sym
, '\0', sizeof(*sym
) + STACKWALK_MAX_NAMELEN
);
111 sym
->SizeOfStruct
= sizeof(*sym
);
112 sym
->MaxNameLen
= STACKWALK_MAX_NAMELEN
;
113 DWORD64 displacement
= 0;
115 if (!StackFrame
.AddrPC
.Offset
|| !SymFromAddr(data
.ProcessHandle
, StackFrame
.AddrPC
.Offset
, &displacement
, sym
))
116 strcpy(sym
->Name
, "<nosymbols>");
118 xfprintf(output
, "%p %p %p %p %p %p %s!%s +0x%I64x" NEWLINE
,
119 (ULONG_PTR
)StackFrame
.AddrFrame
.Offset
, (ULONG_PTR
)StackFrame
.AddrPC
.Offset
,
120 (ULONG_PTR
)StackFrame
.Params
[0], (ULONG_PTR
)StackFrame
.Params
[1],
121 (ULONG_PTR
)StackFrame
.Params
[2], (ULONG_PTR
)StackFrame
.Params
[3],
122 Module
.ModuleName
, sym
->Name
, displacement
);
125 UCHAR stackData
[0x10 * 10];
128 ULONG_PTR stackPointer
= thread
.Context
.Esp
;
129 #elif defined(_M_AMD64)
130 ULONG_PTR stackPointer
= thread
.Context
.Rsp
;
131 #elif defined(_M_ARM) || defined(_M_ARM64)
132 ULONG_PTR stackPointer
= thread
.Context
.Sp
;
134 #error Unknown architecture
136 if (!ReadProcessMemory(data
.ProcessHandle
, (PVOID
)stackPointer
, stackData
, sizeof(stackData
), &sizeRead
))
139 xfprintf(output
, NEWLINE
"*----> Raw Stack Dump <----*" NEWLINE NEWLINE
);
140 for (size_t n
= 0; n
< sizeof(stackData
); n
+= 0x10)
142 char HexData1
[] = "?? ?? ?? ?? ?? ?? ?? ??";
143 char HexData2
[] = "?? ?? ?? ?? ?? ?? ?? ??";
144 char AsciiData1
[] = "????????";
145 char AsciiData2
[] = "????????";
147 for (size_t j
= 0; j
< 8; ++j
)
152 HexData1
[j
* 3] = ToChar(stackData
[idx
] >> 4);
153 HexData1
[j
* 3 + 1] = ToChar(stackData
[idx
] & 0xf);
154 AsciiData1
[j
] = isprint(stackData
[idx
]) ? stackData
[idx
] : '.';
159 HexData2
[j
* 3] = ToChar(stackData
[idx
] >> 4);
160 HexData2
[j
* 3 + 1] = ToChar(stackData
[idx
] & 0xf);
161 AsciiData2
[j
] = isprint(stackData
[idx
]) ? stackData
[idx
] : '.';
165 xfprintf(output
, "%p %s - %s %s%s" NEWLINE
, stackPointer
+n
, HexData1
, HexData2
, AsciiData1
, AsciiData2
);