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