ctkBackTrace.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. /*=========================================================================
  2. Library: CTK
  3. Copyright (c) German Cancer Research Center,
  4. Division of Medical and Biological Informatics
  5. Licensed under the Apache License, Version 2.0 (the "License");
  6. you may not use this file except in compliance with the License.
  7. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0.txt
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. =========================================================================*/
  15. //
  16. // Code taken from http://thread.gmane.org/gmane.comp.lib.boost.devel/209982
  17. // and modified for CTK.
  18. //
  19. // Original Copyright (c) 2010 Artyom Beilis (Tonkikh)
  20. //
  21. // Distributed under the Boost Software License, Version 1.0.
  22. // (See http://www.boost.org/LICENSE_1_0.txt)
  23. //
  24. #include "ctkBackTrace.h"
  25. #include <QList>
  26. #include <vector>
  27. #if defined(__linux) || defined(__APPLE__) || defined(__sun)
  28. #define CTK_HAVE_EXECINFO
  29. #define CTK_HAVE_DLADDR
  30. #endif
  31. #if defined(__GNUC__)
  32. #define CTK_HAVE_ABI_CXA_DEMANGLE
  33. #endif
  34. #ifdef CTK_HAVE_EXECINFO
  35. #include <execinfo.h>
  36. #endif
  37. #ifdef CTK_HAVE_ABI_CXA_DEMANGLE
  38. #include <cxxabi.h>
  39. #endif
  40. #ifdef CTK_HAVE_DLADDR
  41. #include <dlfcn.h>
  42. #endif
  43. #include <stdlib.h>
  44. #include <sstream>
  45. #if defined(Q_CC_MSVC)
  46. #include <windows.h>
  47. #include <stdlib.h>
  48. #include <dbghelp.h>
  49. #endif
  50. // --------------------------------------------------------------------------
  51. size_t const ctkBackTrace::DefaultStackSize = 32;
  52. // --------------------------------------------------------------------------
  53. struct ctkBackTracePrivate
  54. {
  55. std::vector<void *> Frames;
  56. int trace(void** addresses, size_t size) const;
  57. std::string getSymbol(void* address) const;
  58. };
  59. // --------------------------------------------------------------------------
  60. ctkBackTrace::ctkBackTrace(const ctkBackTrace& other)
  61. : d(new ctkBackTracePrivate(*other.d.data()))
  62. {
  63. }
  64. ctkBackTrace::ctkBackTrace(size_t framesNumber)
  65. : d(new ctkBackTracePrivate)
  66. {
  67. if(framesNumber == 0)
  68. return;
  69. d->Frames.resize(framesNumber, 0);
  70. size_t size = d->trace(&d->Frames.front(), framesNumber);
  71. d->Frames.resize(size);
  72. }
  73. // --------------------------------------------------------------------------
  74. ctkBackTrace::~ctkBackTrace() throw()
  75. {
  76. }
  77. // --------------------------------------------------------------------------
  78. size_t ctkBackTrace::stackSize() const
  79. {
  80. return d->Frames.size();
  81. }
  82. // --------------------------------------------------------------------------
  83. void* ctkBackTrace::returnAddress(unsigned frameNumber) const
  84. {
  85. if(frameNumber < stackSize())
  86. return d->Frames[frameNumber];
  87. return 0;
  88. }
  89. // --------------------------------------------------------------------------
  90. QString ctkBackTrace::stackFrame(unsigned frameNumber) const
  91. {
  92. if(frameNumber < d->Frames.size())
  93. return QString::fromStdString(d->getSymbol(d->Frames[frameNumber]));
  94. return QString();
  95. }
  96. // --------------------------------------------------------------------------
  97. QList<QString> ctkBackTrace::stackTrace() const
  98. {
  99. QList<QString> trace;
  100. if(d->Frames.empty())
  101. return trace;
  102. for (std::size_t i = 0; i < d->Frames.size(); ++i)
  103. {
  104. std::string s = d->getSymbol(d->Frames[i]);
  105. if (!s.empty())
  106. {
  107. trace.push_back(QString::fromStdString(s));
  108. }
  109. }
  110. return trace;
  111. //std::ostringstream res;
  112. //d->writeSymbols(&d->Frames.front(), d->Frames.size(), res, framePrefix.toStdString());
  113. //return QString::fromStdString(res.str());
  114. }
  115. #if defined(CTK_HAVE_EXECINFO)
  116. // --------------------------------------------------------------------------
  117. int ctkBackTracePrivate::trace(void** array, size_t n) const
  118. {
  119. return :: backtrace(array,n);
  120. }
  121. #elif defined(Q_CC_MSVC)
  122. USHORT (WINAPI *s_pfnCaptureStackBackTrace)(ULONG, ULONG, PVOID*, PULONG) = 0;
  123. // --------------------------------------------------------------------------
  124. int ctkBackTracePrivate::trace(void** array, size_t n) const
  125. {
  126. if(n>=63)
  127. n=62;
  128. if (s_pfnCaptureStackBackTrace == 0)
  129. {
  130. const HMODULE hNtDll = ::GetModuleHandleW(L"ntdll.dll");
  131. reinterpret_cast<void*&>(s_pfnCaptureStackBackTrace) =
  132. ::GetProcAddress(hNtDll, "RtlCaptureStackBackTrace");
  133. }
  134. if (s_pfnCaptureStackBackTrace != 0) {
  135. return s_pfnCaptureStackBackTrace(0, static_cast<ULONG>(n), array, 0);
  136. }
  137. return 0;
  138. }
  139. #else
  140. // --------------------------------------------------------------------------
  141. int ctkBackTracePrivate::trace(void** /*array*/, size_t /*n*/) const
  142. {
  143. return 0;
  144. }
  145. #endif
  146. #if defined(CTK_HAVE_DLADDR) && defined(CTK_HAVE_ABI_CXA_DEMANGLE)
  147. // --------------------------------------------------------------------------
  148. std::string ctkBackTracePrivate::getSymbol(void* ptr) const
  149. {
  150. if(!ptr)
  151. return std::string();
  152. std::ostringstream res;
  153. res.imbue(std::locale::classic());
  154. res << ptr << ": ";
  155. Dl_info info = {0,0,0,0};
  156. if(dladdr(ptr,&info) == 0)
  157. {
  158. res << "???";
  159. }
  160. else
  161. {
  162. if(info.dli_sname)
  163. {
  164. int status = 0;
  165. char *demangled = abi::__cxa_demangle(info.dli_sname, 0, 0, &status);
  166. if(demangled)
  167. {
  168. res << demangled;
  169. free(demangled);
  170. }
  171. else
  172. {
  173. res << info.dli_sname;
  174. }
  175. }
  176. else
  177. {
  178. res << "???";
  179. }
  180. unsigned offset = reinterpret_cast<char*>(ptr) - reinterpret_cast<char*>(info.dli_saddr);
  181. res << std::hex <<" + 0x" << offset ;
  182. if(info.dli_fname)
  183. res << " in " << info.dli_fname;
  184. }
  185. return res.str();
  186. }
  187. #elif defined(CTK_HAVE_EXECINFO)
  188. // --------------------------------------------------------------------------
  189. std::string ctkBackTracePrivate::getSymbol(void *address) const
  190. {
  191. char ** ptr = backtrace_symbols(&address, 1);
  192. try
  193. {
  194. if(ptr == 0)
  195. return std::string();
  196. std::string res = ptr[0];
  197. free(ptr);
  198. ptr = 0;
  199. return res;
  200. }
  201. catch(...)
  202. {
  203. free(ptr);
  204. throw;
  205. }
  206. }
  207. #elif defined(Q_CC_MSVC)
  208. // --------------------------------------------------------------------------
  209. namespace {
  210. HANDLE hProcess = 0;
  211. bool syms_ready = false;
  212. }
  213. // --------------------------------------------------------------------------
  214. namespace ctk {
  215. bool DebugSymInitialize()
  216. {
  217. if(hProcess == 0)
  218. {
  219. hProcess = GetCurrentProcess();
  220. SymSetOptions(SYMOPT_DEFERRED_LOADS);
  221. if (SymInitialize(hProcess, NULL, TRUE))
  222. {
  223. syms_ready = true;
  224. }
  225. }
  226. return syms_ready;
  227. }
  228. }
  229. // --------------------------------------------------------------------------
  230. std::string ctkBackTracePrivate::getSymbol(void* ptr) const
  231. {
  232. if(ptr==0)
  233. return std::string();
  234. ctk::DebugSymInitialize();
  235. std::ostringstream ss;
  236. ss.imbue(std::locale::classic());
  237. ss << ptr;
  238. if(syms_ready)
  239. {
  240. DWORD64 dwDisplacement = 0;
  241. DWORD64 dwAddress = (DWORD64)ptr;
  242. std::vector<char> buffer(sizeof(SYMBOL_INFO) + MAX_SYM_NAME);
  243. PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)&buffer.front();
  244. pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
  245. pSymbol->MaxNameLen = MAX_SYM_NAME;
  246. if (SymFromAddr(hProcess, dwAddress, &dwDisplacement, pSymbol))
  247. {
  248. ss <<": " << pSymbol->Name << std::hex << " + 0x" << dwDisplacement;
  249. }
  250. else
  251. {
  252. ss << ": ???";
  253. }
  254. std::vector<char> moduleBuffer(sizeof(IMAGEHLP_MODULE64));
  255. PIMAGEHLP_MODULE64 pModuleInfo = (PIMAGEHLP_MODULE64)&moduleBuffer.front();
  256. pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
  257. if (SymGetModuleInfo64(hProcess, pSymbol->ModBase, pModuleInfo))
  258. {
  259. ss << " in " << pModuleInfo->LoadedImageName;
  260. }
  261. }
  262. return ss.str();
  263. }
  264. #else
  265. // --------------------------------------------------------------------------
  266. std::string ctkBackTracePrivate::getSymbol(void* ptr) const
  267. {
  268. if(!ptr)
  269. return std::string();
  270. std::ostringstream res;
  271. res.imbue(std::locale::classic());
  272. res << ptr;
  273. return res.str();
  274. }
  275. #endif