TTKMusicPlayer  4.1.3.0
TTKMusicPlayer imitates Kugou UI, the music player uses of qmmp core library based on Qt for windows and linux
ttkdumper.cpp
Go to the documentation of this file.
1 #include "ttkdumper.h"
2 #include "ttkversion.h"
3 #include "miniprocess.h"
4 
5 #ifdef Q_OS_WIN
6 # define WIN32_LEAN_AND_MEAN
7 # include <qt_windows.h>
8 # include <dbghelp.h>
9 #elif defined Q_OS_UNIX
10 # include <signal.h>
11 # include <execinfo.h>
12 # include <unistd.h>
13 # include <fcntl.h>
14 #endif
15 
19 class TTKDumperPrivate : public TTKPrivate<TTKDumper>
20 {
21 public:
22  TTKDumperPrivate() = default;
23 
24 #ifdef Q_OS_WIN
25  typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,
26  CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
27  CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
28  CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
29 
30  static constexpr int MAX_WARNING_MESSAGE_PATH = 1024;
31  static constexpr int MAX_DUMP_FILE_NUMBER = 9999;
32 
33  static LONG WINAPI errorHandler(EXCEPTION_POINTERS *info);
34 #elif defined Q_OS_UNIX
35  static void errorHandler(int id);
36 #endif
37 
38  void initialize();
39 
40  static QString m_name;
41  static QString m_version;
43 };
44 
45 QString TTKDumperPrivate::m_name = {};
46 QString TTKDumperPrivate::m_version = {};
48 
49 #ifdef Q_OS_WIN
51 {
52  ::SetUnhandledExceptionFilter(errorHandler);
53 }
54 
55 LONG TTKDumperPrivate::errorHandler(EXCEPTION_POINTERS *info)
56 {
57  if(m_functor)
58  {
59  m_functor();
60  }
61 
62  LONG retval = EXCEPTION_CONTINUE_SEARCH;
63 
64  // firstly see if dbghelp.dll is around and has the function we need
65  // look next to the EXE first, as the one in System32 might be old
66  // (e.g. Windows 2000)
67  HMODULE instance = nullptr;
68  WCHAR dbgHelpPath[_MAX_PATH];
69 
70  if(GetModuleFileNameW(nullptr, dbgHelpPath, _MAX_PATH))
71  {
72  WCHAR *slash = wcsrchr(dbgHelpPath, L'\\');
73  if(slash)
74  {
75  wcscpy(slash + 1, L"DBGHELP.DLL");
76  instance = LoadLibraryW(dbgHelpPath);
77  }
78  }
79 
80  if(instance == nullptr)
81  {
82  // load any version we can
83  instance = LoadLibraryW(L"DBGHELP.DLL");
84  }
85 
86  if(instance)
87  {
88  MINIDUMPWRITEDUMP dump = TTKVoidCast(MINIDUMPWRITEDUMP)GetProcAddress(instance, "MiniDumpWriteDump");
89  if(dump)
90  {
91  WCHAR dumpPath[_MAX_PATH];
92  WCHAR dumpRootPath[_MAX_PATH];
93  WCHAR scratch[_MAX_PATH];
94 
95  // work out a good place for the dump file
96  if(GetModuleFileNameW(nullptr, dbgHelpPath, _MAX_PATH))
97  {
98  WCHAR *slash = wcsrchr(dbgHelpPath, L'\\');
99  if(slash)
100  {
101  wcscpy(slash + 1, L"");
102  wcscpy(dumpPath, dbgHelpPath);
103  }
104  }
105  else if(!GetTempPathW(_MAX_PATH, dumpPath))
106  {
107  wcscpy(dumpPath, L"c:\\temp\\");
108  }
109  wcscpy(dumpRootPath, dumpPath);
110 
111  // ask the user if they want to save a dump file
112  //if(::MessageBox(nullptr, _T("Something bad happened in your program, would you like to save a diagnostic file?"), m_szAppName, MB_YESNO)==IDYES)
113  {
114  HANDLE file = INVALID_HANDLE_VALUE;
115  int i = 1;
116  WCHAR fileNumber[_MAX_PATH];
117  while(file == INVALID_HANDLE_VALUE)
118  {
119  swprintf(fileNumber, sizeof(fileNumber), L"_%04d",i);
120  wcscpy(dumpPath, dumpRootPath);
121  wcscat(dumpPath, m_name.toStdWString().c_str());
122  wcscat(dumpPath, L"_");
123  wcscat(dumpPath, m_version.toStdWString().c_str());
124  wcscat(dumpPath, fileNumber);
125  wcscat(dumpPath, L".dmp");
126 
127  file = ::CreateFileW(dumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
128  i++;
129  if(i > MAX_DUMP_FILE_NUMBER)
130  {
131  file = ::CreateFileW(dumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
132  break;
133  }
134  }
135  // create the file
136  if(file != INVALID_HANDLE_VALUE)
137  {
138  MINIDUMP_EXCEPTION_INFORMATION exInfo;
139  exInfo.ThreadId = ::GetCurrentThreadId();
140  exInfo.ExceptionPointers = info;
141  exInfo.ClientPointers = 0;
142 
143  // write the dump
144  BOOL ok = dump(GetCurrentProcess(), GetCurrentProcessId(), file, MiniDumpNormal, &exInfo, nullptr, nullptr);
145  if(ok)
146  {
147  swprintf(scratch, sizeof(scratch), L"Saved dump file to '%s'", dumpPath);
148  retval = EXCEPTION_EXECUTE_HANDLER;
149  }
150  else
151  {
152  swprintf(scratch, sizeof(scratch), L"Failed to save dump file to '%s' (error %d)", dumpPath, GetLastError());
153  }
154  ::CloseHandle(file);
155 
156  WCHAR outMessage[MAX_WARNING_MESSAGE_PATH];
157  swprintf(outMessage, sizeof(outMessage), outMessage, m_name.toStdWString().c_str(), dumpPath);
158  }
159  else
160  {
161  swprintf(scratch, sizeof(scratch), L"Failed to create dump file '%s' (error %d)", dumpPath, GetLastError());
162  }
163  }
164  }
165  }
166  return retval;
167 }
168 #elif defined Q_OS_UNIX
169 void TTKDumperPrivate::errorHandler(int id)
170 {
171  TTK_INFO_STREAM("Application error occurred, error code " << id);
172  if(m_functor)
173  {
174  m_functor();
175  }
176 
177  char stamp[50];
178  sprintf(stamp, "%ld", time(nullptr));
179  const TTKString &file_name = (m_name + '_' + m_version).toStdString() + "." + stamp + ".dmp";
180 
181  constexpr int size = 512;
182  void* array[size];
183  const int fd = open(file_name.c_str(), O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
184  backtrace_symbols_fd(array, backtrace(array, size), fd);
185  close(fd);
186 
187  raise(id);
188  exit(0);
189 }
190 
192 {
193  signal(SIGPIPE, errorHandler);
194  signal(SIGSEGV, errorHandler);
195  signal(SIGFPE, errorHandler);
196  signal(SIGABRT, errorHandler);
197  signal(SIGBUS, errorHandler);
198  signal(SIGILL, errorHandler);
199  signal(SIGINT, errorHandler);
200  signal(SIGTERM, errorHandler);
201 }
202 #endif
203 
204 
205 
207 {
208  TTKDumperPrivate::m_name = "TTK";
210 }
211 
213 {
214  TTKDumperPrivate::m_name = "TTK";
216  TTKDumperPrivate::m_functor = functor;
217 }
218 
220 {
222  {
224  }
225 }
226 
228 {
229  TTK_D(TTKDumper);
230  d->initialize();
231 }
#define TTKVoidCast(x)
Definition: ttkqtglobal.h:82
TTKDumperPrivate()=default
The class of the ttk dumper.
Definition: ttkdumper.h:39
voidpf void uLong size
Definition: ioapi.h:136
#define INVALID_HANDLE_VALUE
Definition: iowin32.c:21
The class of the ttk dumper private.
Definition: ttkdumper.cpp:19
std::string TTKString
Definition: ttkglobal.h:121
#define TTK_INFO_STREAM(msg)
Definition: ttklogger.h:68
#define TTK_VERSION_STR
Definition: ttkversion.h:175
static QString m_name
Definition: ttkdumper.cpp:40
static QString m_version
Definition: ttkdumper.cpp:41
std::function< void(void)> TTKDumperFunctor
Definition: ttkdumper.h:34
static TTKDumperFunctor m_functor
Definition: ttkdumper.cpp:42
void run()
Definition: ttkdumper.cpp:227
The class of the ttk private base.
Definition: ttkprivate.h:48
#define TTK_D(Class)
Definition: ttkprivate.h:41