UFO: Alien Invasion
Loading...
Searching...
No Matches
win_backtrace.cpp
Go to the documentation of this file.
1/*
2 * Copyright (c) 2010 ,
3 * Cloud Wu . All rights reserved.
4 *
5 * http://www.codingnow.com
6 *
7 * Use, modification and distribution are subject to the "New BSD License"
8 * as listed at <url: http://www.opensource.org/licenses/bsd-license.php >.
9 */
10
11#include "win_local.h"
12#include "../../common/http.h"
13#ifdef HAVE_BFD_H
14#include "../../shared/bfd.h"
15
16#include <excpt.h>
17#include <imagehlp.h>
18#include <psapi.h>
19
20#if defined _M_AMD64
21 #define ARCH_SW(x86, amd64) amd64
22#elif defined _M_IX86
23 #define ARCH_SW(x86, amd64) x86
24#endif
25
26static void _backtrace (struct output_buffer* ob, struct bfd_set* set, int depth, LPCONTEXT context)
27{
28 char procname[MAX_PATH];
29 struct bfd_ctx* bc = nullptr;
30 HANDLE process = GetCurrentProcess();
31 HANDLE thread = GetCurrentThread();
32 STACKFRAME frame;
33 char symbol_buffer[sizeof(IMAGEHLP_SYMBOL) + 255];
34 char module_name_raw[MAX_PATH];
35
36 GetModuleFileNameA(nullptr, procname, sizeof(procname));
37
38 OBJZERO(frame);
39
40 frame.AddrPC.Offset = context->ARCH_SW(Eip, Rip);
41 frame.AddrPC.Mode = AddrModeFlat;
42 frame.AddrStack.Offset = context->ARCH_SW(Esp, Rsp);
43 frame.AddrStack.Mode = AddrModeFlat;
44 frame.AddrFrame.Offset = context->ARCH_SW(Ebp, Rbp);
45 frame.AddrFrame.Mode = AddrModeFlat;
46
47 while (StackWalk(ARCH_SW(IMAGE_FILE_MACHINE_I386, IMAGE_FILE_MACHINE_AMD64), process, thread, &frame, context,
48 0, SymFunctionTableAccess, SymGetModuleBase, 0)) {
49 const char* file = nullptr;
50 const char* func = nullptr;
51 unsigned line = 0;
52 DWORD module_base = SymGetModuleBase(process, frame.AddrPC.Offset);
53 const char* module_name = "[unknown module]";
54 IMAGEHLP_SYMBOL* symbol = (IMAGEHLP_SYMBOL*) symbol_buffer;
55
56 --depth;
57 if (depth < 0)
58 break;
59
60 symbol->SizeOfStruct = sizeof(*symbol) + 255;
61 symbol->MaxNameLength = 254;
62
63 if (module_base && GetModuleFileNameA((HINSTANCE) module_base, module_name_raw, MAX_PATH)) {
64 module_name = module_name_raw;
65 bc = get_bc(ob, set, module_name);
66 }
67
68 if (bc) {
69 find(bc, frame.AddrPC.Offset, &file, &func, &line);
70 }
71
72 if (file == nullptr) {
73 ARCH_SW(DWORD, DWORD64) dummy = 0;
74 if (SymGetSymFromAddr(process, frame.AddrPC.Offset, &dummy, symbol)) {
75 file = symbol->Name;
76 } else {
77 file = "[unknown file]";
78 }
79 }
80 if (func == nullptr) {
81 output_print(ob, "0x%x : %s : %s \n", frame.AddrPC.Offset,
82 module_name, file);
83 } else {
84 output_print(ob, "0x%x : %s : %s (%d) : in function (%s) \n",
85 frame.AddrPC.Offset, module_name, file, line, func);
86 }
87 }
88}
89
90static LPTOP_LEVEL_EXCEPTION_FILTER g_prev = nullptr;
91#define BUFFER_MAX (16*1024)
92static char* g_output = nullptr;
93
94static LONG WINAPI exception_filter (LPEXCEPTION_POINTERS info)
95{
96 struct output_buffer ob;
97 SYSTEMTIME timeInfo;
98 OSVERSIONINFOEX osInfo;
99 const char* dumpFile = "crashdump.txt";
100
101 GetSystemTime(&timeInfo);
102
103 OBJZERO(osInfo);
104 osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
105 if (!GetVersionEx((OSVERSIONINFO*)&osInfo)) {
106 osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
107 GetVersionEx((OSVERSIONINFO*)&osInfo);
108 }
109
110 output_init(&ob, g_output, BUFFER_MAX);
111
112 if (!SymInitialize(GetCurrentProcess(), 0, TRUE)) {
113 output_print(&ob, "Failed to init symbol context\n");
114 } else {
115 struct bfd_set* set = (struct bfd_set *)calloc(1, sizeof(*set));
116 bfd_init();
117 _backtrace(&ob, set, 128, info->ContextRecord);
118 release_set(set);
119
120 SymCleanup(GetCurrentProcess());
121 }
122
123 FILE* crash = Sys_Fopen(dumpFile, "w");
124 if (crash != nullptr) {
125 fprintf(crash, "======start======\n");
126 fprintf(crash, "Date: %.4d-%.2d-%.2d\n",
127 timeInfo.wYear, timeInfo.wMonth, timeInfo.wDay);
128 fprintf(crash, "Windows version %lu.%lu (Build %lu) %s\n",
129 osInfo.dwMajorVersion, osInfo.dwMinorVersion, osInfo.dwBuildNumber, osInfo.szCSDVersion);
130 fprintf(crash, BUILDSTRING ", cpu: " CPUSTRING ", version: " UFO_VERSION "\n\n");
131 fprintf(crash, "%s", g_output);
132 fprintf(crash, "======end========\n");
133 fclose(crash);
134 }
135 fputs(g_output, stderr);
136
137 return 0;
138}
139
140static void backtrace_register (void)
141{
142 if (g_output == nullptr) {
143 g_output = (char*)malloc(BUFFER_MAX);
144 g_prev = SetUnhandledExceptionFilter(exception_filter);
145 }
146}
147
148static void backtrace_unregister (void)
149{
150 if (g_output) {
151 free(g_output);
152 SetUnhandledExceptionFilter(g_prev);
153 g_prev = nullptr;
154 g_output = nullptr;
155 }
156}
157#endif
158
160{
161#ifdef HAVE_BFD_H
162 backtrace_register();
163#endif
164}
165
167{
168#ifdef HAVE_BFD_H
169 backtrace_unregister();
170#endif
171}
#define CPUSTRING
Definition common.h:109
#define UFO_VERSION
Definition common.h:36
#define BUILDSTRING
Definition common.h:121
#define OBJZERO(obj)
Definition shared.h:178
FILE * Sys_Fopen(const char *filename, const char *mode)
#define FILE
void Sys_BacktraceShutdown(void)
void Sys_BacktraceInit(void)
Win32-specific UFO header file.