debug.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. /*
  2. Minetest
  3. Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as published by
  6. the Free Software Foundation; either version 2.1 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License along
  13. with this program; if not, write to the Free Software Foundation, Inc.,
  14. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. */
  16. #include "porting.h"
  17. #include "debug.h"
  18. #include "exceptions.h"
  19. #include "threads.h"
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <cstring>
  23. #include <map>
  24. #include "jthread/jmutex.h"
  25. #include "jthread/jmutexautolock.h"
  26. #include "config.h"
  27. /*
  28. Debug output
  29. */
  30. #define DEBUGSTREAM_COUNT 2
  31. FILE *g_debugstreams[DEBUGSTREAM_COUNT] = {stderr, NULL};
  32. #define DEBUGPRINT(...)\
  33. {\
  34. for(int i=0; i<DEBUGSTREAM_COUNT; i++)\
  35. {\
  36. if(g_debugstreams[i] != NULL){\
  37. fprintf(g_debugstreams[i], __VA_ARGS__);\
  38. fflush(g_debugstreams[i]);\
  39. }\
  40. }\
  41. }
  42. void debugstreams_init(bool disable_stderr, const char *filename)
  43. {
  44. if(disable_stderr)
  45. g_debugstreams[0] = NULL;
  46. else
  47. g_debugstreams[0] = stderr;
  48. if(filename)
  49. g_debugstreams[1] = fopen(filename, "a");
  50. if(g_debugstreams[1])
  51. {
  52. fprintf(g_debugstreams[1], "\n\n-------------\n");
  53. fprintf(g_debugstreams[1], " Separator \n");
  54. fprintf(g_debugstreams[1], "-------------\n\n");
  55. }
  56. }
  57. void debugstreams_deinit()
  58. {
  59. if(g_debugstreams[1] != NULL)
  60. fclose(g_debugstreams[1]);
  61. }
  62. class Debugbuf : public std::streambuf
  63. {
  64. public:
  65. Debugbuf(bool disable_stderr)
  66. {
  67. m_disable_stderr = disable_stderr;
  68. }
  69. int overflow(int c)
  70. {
  71. for(int i=0; i<DEBUGSTREAM_COUNT; i++)
  72. {
  73. if(g_debugstreams[i] == stderr && m_disable_stderr)
  74. continue;
  75. if(g_debugstreams[i] != NULL)
  76. (void)fwrite(&c, 1, 1, g_debugstreams[i]);
  77. //TODO: Is this slow?
  78. fflush(g_debugstreams[i]);
  79. }
  80. return c;
  81. }
  82. std::streamsize xsputn(const char *s, std::streamsize n)
  83. {
  84. #ifdef __ANDROID__
  85. __android_log_print(ANDROID_LOG_VERBOSE, PROJECT_NAME, "%s", s);
  86. #endif
  87. for(int i=0; i<DEBUGSTREAM_COUNT; i++)
  88. {
  89. if(g_debugstreams[i] == stderr && m_disable_stderr)
  90. continue;
  91. if(g_debugstreams[i] != NULL)
  92. (void)fwrite(s, 1, n, g_debugstreams[i]);
  93. //TODO: Is this slow?
  94. fflush(g_debugstreams[i]);
  95. }
  96. return n;
  97. }
  98. private:
  99. bool m_disable_stderr;
  100. };
  101. Debugbuf debugbuf(false);
  102. std::ostream dstream(&debugbuf);
  103. Debugbuf debugbuf_no_stderr(true);
  104. std::ostream dstream_no_stderr(&debugbuf_no_stderr);
  105. Nullstream dummyout;
  106. /*
  107. Assert
  108. */
  109. void assert_fail(const char *assertion, const char *file,
  110. unsigned int line, const char *function)
  111. {
  112. DEBUGPRINT("\nIn thread %lx:\n"
  113. "%s:%d: %s: Assertion '%s' failed.\n",
  114. (unsigned long)get_current_thread_id(),
  115. file, line, function, assertion);
  116. debug_stacks_print();
  117. if(g_debugstreams[1])
  118. fclose(g_debugstreams[1]);
  119. abort();
  120. }
  121. /*
  122. DebugStack
  123. */
  124. struct DebugStack
  125. {
  126. DebugStack(threadid_t id);
  127. void print(FILE *file, bool everything);
  128. void print(std::ostream &os, bool everything);
  129. threadid_t threadid;
  130. char stack[DEBUG_STACK_SIZE][DEBUG_STACK_TEXT_SIZE];
  131. int stack_i; // Points to the lowest empty position
  132. int stack_max_i; // Highest i that was seen
  133. };
  134. DebugStack::DebugStack(threadid_t id)
  135. {
  136. threadid = id;
  137. stack_i = 0;
  138. stack_max_i = 0;
  139. memset(stack, 0, DEBUG_STACK_SIZE*DEBUG_STACK_TEXT_SIZE);
  140. }
  141. void DebugStack::print(FILE *file, bool everything)
  142. {
  143. fprintf(file, "DEBUG STACK FOR THREAD %lx:\n",
  144. (unsigned long)threadid);
  145. for(int i=0; i<stack_max_i; i++)
  146. {
  147. if(i == stack_i && everything == false)
  148. break;
  149. if(i < stack_i)
  150. fprintf(file, "#%d %s\n", i, stack[i]);
  151. else
  152. fprintf(file, "(Leftover data: #%d %s)\n", i, stack[i]);
  153. }
  154. if(stack_i == DEBUG_STACK_SIZE)
  155. fprintf(file, "Probably overflown.\n");
  156. }
  157. void DebugStack::print(std::ostream &os, bool everything)
  158. {
  159. os<<"DEBUG STACK FOR THREAD "<<(unsigned long)threadid<<": "<<std::endl;
  160. for(int i=0; i<stack_max_i; i++)
  161. {
  162. if(i == stack_i && everything == false)
  163. break;
  164. if(i < stack_i)
  165. os<<"#"<<i<<" "<<stack[i]<<std::endl;
  166. else
  167. os<<"(Leftover data: #"<<i<<" "<<stack[i]<<")"<<std::endl;
  168. }
  169. if(stack_i == DEBUG_STACK_SIZE)
  170. os<<"Probably overflown."<<std::endl;
  171. }
  172. std::map<threadid_t, DebugStack*> g_debug_stacks;
  173. JMutex g_debug_stacks_mutex;
  174. void debug_stacks_init()
  175. {
  176. }
  177. void debug_stacks_print_to(std::ostream &os)
  178. {
  179. JMutexAutoLock lock(g_debug_stacks_mutex);
  180. os<<"Debug stacks:"<<std::endl;
  181. for(std::map<threadid_t, DebugStack*>::iterator
  182. i = g_debug_stacks.begin();
  183. i != g_debug_stacks.end(); ++i)
  184. {
  185. i->second->print(os, false);
  186. }
  187. }
  188. void debug_stacks_print()
  189. {
  190. JMutexAutoLock lock(g_debug_stacks_mutex);
  191. DEBUGPRINT("Debug stacks:\n");
  192. for(std::map<threadid_t, DebugStack*>::iterator
  193. i = g_debug_stacks.begin();
  194. i != g_debug_stacks.end(); ++i)
  195. {
  196. DebugStack *stack = i->second;
  197. for(int i=0; i<DEBUGSTREAM_COUNT; i++)
  198. {
  199. if(g_debugstreams[i] != NULL)
  200. stack->print(g_debugstreams[i], true);
  201. }
  202. }
  203. }
  204. DebugStacker::DebugStacker(const char *text)
  205. {
  206. threadid_t threadid = get_current_thread_id();
  207. JMutexAutoLock lock(g_debug_stacks_mutex);
  208. std::map<threadid_t, DebugStack*>::iterator n;
  209. n = g_debug_stacks.find(threadid);
  210. if(n != g_debug_stacks.end())
  211. {
  212. m_stack = n->second;
  213. }
  214. else
  215. {
  216. /*DEBUGPRINT("Creating new debug stack for thread %x\n",
  217. (unsigned int)threadid);*/
  218. m_stack = new DebugStack(threadid);
  219. g_debug_stacks[threadid] = m_stack;
  220. }
  221. if(m_stack->stack_i >= DEBUG_STACK_SIZE)
  222. {
  223. m_overflowed = true;
  224. }
  225. else
  226. {
  227. m_overflowed = false;
  228. snprintf(m_stack->stack[m_stack->stack_i],
  229. DEBUG_STACK_TEXT_SIZE, "%s", text);
  230. m_stack->stack_i++;
  231. if(m_stack->stack_i > m_stack->stack_max_i)
  232. m_stack->stack_max_i = m_stack->stack_i;
  233. }
  234. }
  235. DebugStacker::~DebugStacker()
  236. {
  237. JMutexAutoLock lock(g_debug_stacks_mutex);
  238. if(m_overflowed == true)
  239. return;
  240. m_stack->stack_i--;
  241. if(m_stack->stack_i == 0)
  242. {
  243. threadid_t threadid = m_stack->threadid;
  244. /*DEBUGPRINT("Deleting debug stack for thread %x\n",
  245. (unsigned int)threadid);*/
  246. delete m_stack;
  247. g_debug_stacks.erase(threadid);
  248. }
  249. }
  250. #ifdef _MSC_VER
  251. #if CATCH_UNHANDLED_EXCEPTIONS == 1
  252. void se_trans_func(unsigned int u, EXCEPTION_POINTERS* pExp)
  253. {
  254. dstream<<"In trans_func.\n";
  255. if(u == EXCEPTION_ACCESS_VIOLATION)
  256. {
  257. PEXCEPTION_RECORD r = pExp->ExceptionRecord;
  258. dstream<<"Access violation at "<<r->ExceptionAddress
  259. <<" write?="<<r->ExceptionInformation[0]
  260. <<" address="<<r->ExceptionInformation[1]
  261. <<std::endl;
  262. throw FatalSystemException
  263. ("Access violation");
  264. }
  265. if(u == EXCEPTION_STACK_OVERFLOW)
  266. {
  267. throw FatalSystemException
  268. ("Stack overflow");
  269. }
  270. if(u == EXCEPTION_ILLEGAL_INSTRUCTION)
  271. {
  272. throw FatalSystemException
  273. ("Illegal instruction");
  274. }
  275. }
  276. #endif
  277. #endif