3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include "exceptions.h"
29 #include "jthread/jmutex.h"
30 #include "jthread/jmutexautolock.h"
36 #define DEBUGSTREAM_COUNT 2
38 FILE *g_debugstreams[DEBUGSTREAM_COUNT] = {stderr, NULL};
40 #define DEBUGPRINT(...)\
42 for(int i=0; i<DEBUGSTREAM_COUNT; i++)\
44 if(g_debugstreams[i] != NULL){\
45 fprintf(g_debugstreams[i], __VA_ARGS__);\
46 fflush(g_debugstreams[i]);\
51 void debugstreams_init(bool disable_stderr, const char *filename)
54 g_debugstreams[0] = NULL;
56 g_debugstreams[0] = stderr;
59 g_debugstreams[1] = fopen(filename, "a");
63 fprintf(g_debugstreams[1], "\n\n-------------\n");
64 fprintf(g_debugstreams[1], " Separator \n");
65 fprintf(g_debugstreams[1], "-------------\n\n");
69 void debugstreams_deinit()
71 if(g_debugstreams[1] != NULL)
72 fclose(g_debugstreams[1]);
75 class Debugbuf : public std::streambuf
78 Debugbuf(bool disable_stderr)
80 m_disable_stderr = disable_stderr;
85 for(int i=0; i<DEBUGSTREAM_COUNT; i++)
87 if(g_debugstreams[i] == stderr && m_disable_stderr)
89 if(g_debugstreams[i] != NULL)
90 (void)fwrite(&c, 1, 1, g_debugstreams[i]);
92 fflush(g_debugstreams[i]);
97 std::streamsize xsputn(const char *s, std::streamsize n)
100 __android_log_print(ANDROID_LOG_VERBOSE, PROJECT_NAME, "%s", s);
102 for(int i=0; i<DEBUGSTREAM_COUNT; i++)
104 if(g_debugstreams[i] == stderr && m_disable_stderr)
106 if(g_debugstreams[i] != NULL)
107 (void)fwrite(s, 1, n, g_debugstreams[i]);
108 //TODO: Is this slow?
109 fflush(g_debugstreams[i]);
116 bool m_disable_stderr;
119 Debugbuf debugbuf(false);
120 std::ostream dstream(&debugbuf);
121 Debugbuf debugbuf_no_stderr(true);
122 std::ostream dstream_no_stderr(&debugbuf_no_stderr);
129 void assert_fail(const char *assertion, const char *file,
130 unsigned int line, const char *function)
132 DEBUGPRINT("\nIn thread %lx:\n"
133 "%s:%d: %s: Assertion '%s' failed.\n",
134 (unsigned long)get_current_thread_id(),
135 file, line, function, assertion);
137 debug_stacks_print();
139 if(g_debugstreams[1])
140 fclose(g_debugstreams[1]);
151 DebugStack(threadid_t id);
152 void print(FILE *file, bool everything);
153 void print(std::ostream &os, bool everything);
156 char stack[DEBUG_STACK_SIZE][DEBUG_STACK_TEXT_SIZE];
157 int stack_i; // Points to the lowest empty position
158 int stack_max_i; // Highest i that was seen
161 DebugStack::DebugStack(threadid_t id)
166 memset(stack, 0, DEBUG_STACK_SIZE*DEBUG_STACK_TEXT_SIZE);
169 void DebugStack::print(FILE *file, bool everything)
171 fprintf(file, "DEBUG STACK FOR THREAD %lx:\n",
172 (unsigned long)threadid);
174 for(int i=0; i<stack_max_i; i++)
176 if(i == stack_i && everything == false)
180 fprintf(file, "#%d %s\n", i, stack[i]);
182 fprintf(file, "(Leftover data: #%d %s)\n", i, stack[i]);
185 if(stack_i == DEBUG_STACK_SIZE)
186 fprintf(file, "Probably overflown.\n");
189 void DebugStack::print(std::ostream &os, bool everything)
191 os<<"DEBUG STACK FOR THREAD "<<(unsigned long)threadid<<": "<<std::endl;
193 for(int i=0; i<stack_max_i; i++)
195 if(i == stack_i && everything == false)
199 os<<"#"<<i<<" "<<stack[i]<<std::endl;
201 os<<"(Leftover data: #"<<i<<" "<<stack[i]<<")"<<std::endl;
204 if(stack_i == DEBUG_STACK_SIZE)
205 os<<"Probably overflown."<<std::endl;
208 std::map<threadid_t, DebugStack*> g_debug_stacks;
209 JMutex g_debug_stacks_mutex;
211 void debug_stacks_init()
215 void debug_stacks_print_to(std::ostream &os)
217 JMutexAutoLock lock(g_debug_stacks_mutex);
219 os<<"Debug stacks:"<<std::endl;
221 for(std::map<threadid_t, DebugStack*>::iterator
222 i = g_debug_stacks.begin();
223 i != g_debug_stacks.end(); ++i)
225 i->second->print(os, false);
229 void debug_stacks_print()
231 JMutexAutoLock lock(g_debug_stacks_mutex);
233 DEBUGPRINT("Debug stacks:\n");
235 for(std::map<threadid_t, DebugStack*>::iterator
236 i = g_debug_stacks.begin();
237 i != g_debug_stacks.end(); ++i)
239 DebugStack *stack = i->second;
241 for(int i=0; i<DEBUGSTREAM_COUNT; i++)
243 if(g_debugstreams[i] != NULL)
244 stack->print(g_debugstreams[i], true);
249 DebugStacker::DebugStacker(const char *text)
251 threadid_t threadid = get_current_thread_id();
253 JMutexAutoLock lock(g_debug_stacks_mutex);
255 std::map<threadid_t, DebugStack*>::iterator n;
256 n = g_debug_stacks.find(threadid);
257 if(n != g_debug_stacks.end())
263 /*DEBUGPRINT("Creating new debug stack for thread %x\n",
264 (unsigned int)threadid);*/
265 m_stack = new DebugStack(threadid);
266 g_debug_stacks[threadid] = m_stack;
269 if(m_stack->stack_i >= DEBUG_STACK_SIZE)
275 m_overflowed = false;
277 snprintf(m_stack->stack[m_stack->stack_i],
278 DEBUG_STACK_TEXT_SIZE, "%s", text);
280 if(m_stack->stack_i > m_stack->stack_max_i)
281 m_stack->stack_max_i = m_stack->stack_i;
285 DebugStacker::~DebugStacker()
287 JMutexAutoLock lock(g_debug_stacks_mutex);
289 if(m_overflowed == true)
294 if(m_stack->stack_i == 0)
296 threadid_t threadid = m_stack->threadid;
297 /*DEBUGPRINT("Deleting debug stack for thread %x\n",
298 (unsigned int)threadid);*/
300 g_debug_stacks.erase(threadid);
306 #if CATCH_UNHANDLED_EXCEPTIONS == 1
307 void se_trans_func(unsigned int u, EXCEPTION_POINTERS* pExp)
309 dstream<<"In trans_func.\n";
310 if(u == EXCEPTION_ACCESS_VIOLATION)
312 PEXCEPTION_RECORD r = pExp->ExceptionRecord;
313 dstream<<"Access violation at "<<r->ExceptionAddress
314 <<" write?="<<r->ExceptionInformation[0]
315 <<" address="<<r->ExceptionInformation[1]
317 throw FatalSystemException
318 ("Access violation");
320 if(u == EXCEPTION_STACK_OVERFLOW)
322 throw FatalSystemException
325 if(u == EXCEPTION_ILLEGAL_INSTRUCTION)
327 throw FatalSystemException
328 ("Illegal instruction");