debugging.h: use int 3 on amd64 too
[xonotic/netradiant.git] / libs / debugging / debugging.h
1 /*
2    Copyright (C) 2001-2006, William Joseph.
3    All Rights Reserved.
4
5    This file is part of GtkRadiant.
6
7    GtkRadiant is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    GtkRadiant is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with GtkRadiant; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21
22 #if !defined( INCLUDED_DEBUGGING_DEBUGGING_H )
23 #define INCLUDED_DEBUGGING_DEBUGGING_H
24
25 /// \file
26 /// \brief Debugging macros for fatal error/assert messages.
27
28 #include "stream/textstream.h"
29 #include "warnings.h"
30 #include "generic/static.h"
31
32 #if defined( _MSC_VER ) && ( defined( _M_IX86 ) || defined( _M_AMD64 ) )
33 #define DEBUGGER_BREAKPOINT() __asm { int 3 }
34 #elif ( defined ( __i386__ ) || defined ( __x86_64__ ) ) && defined ( __GNUC__ ) && __GNUC__ >= 2
35 #define DEBUGGER_BREAKPOINT() __asm__ __volatile__ ( "int $03" )
36 #else
37 #include <signal.h>
38
39 #define DEBUGGER_BREAKPOINT() raise( SIGTRAP );
40 #endif
41
42 #define STR( x )  # x
43 #define STR2( x ) STR( x )
44 #define FILE_LINE __FILE__ ":" STR2( __LINE__ )
45
46 #if defined( _DEBUG ) || 1
47 #define DEBUG_ASSERTS
48 #endif
49
50 class DebugMessageHandler
51 {
52 public:
53 virtual TextOutputStream& getOutputStream() = 0;
54 virtual bool handleMessage() = 0;
55 };
56
57 class NullDebugMessageHandler : public NullOutputStream, public DebugMessageHandler
58 {
59 public:
60 virtual TextOutputStream& getOutputStream(){
61         return *this;
62 }
63 virtual bool handleMessage(){
64         return false;
65 }
66 };
67
68 class DefaultDebugMessageHandler : public DebugMessageHandler
69 {
70 public:
71 virtual TextOutputStream& getOutputStream(){
72         return globalErrorStream();
73 }
74 virtual bool handleMessage(){
75 #if defined( _DEBUG )
76         return false; // send debug-break
77 #else
78         return true;
79 #endif
80 }
81 };
82
83 class DebugMessageHandlerRef : public DefaultDebugMessageHandler
84 {
85 DebugMessageHandler* m_handler;
86 public:
87 DebugMessageHandlerRef()
88         : m_handler( this ){
89 }
90 void setHandler( DebugMessageHandler& handler ){
91         m_handler = &handler;
92 }
93 DebugMessageHandler& getHandler(){
94         return *m_handler;
95 }
96 };
97
98 typedef Static<DebugMessageHandlerRef> GlobalDebugMessageHandler;
99
100 inline DebugMessageHandler& globalDebugMessageHandler(){
101         return GlobalDebugMessageHandler::instance().getHandler();
102 }
103
104 #if defined( DEBUG_ASSERTS )
105
106 /// \brief Sends a \p message to the current debug-message-handler text-output-stream if \p condition evaluates to false.
107 #define ASSERT_MESSAGE( condition, message ) do { \
108                 if ( !( condition ) ) \
109                 { \
110                         globalDebugMessageHandler().getOutputStream() << FILE_LINE "\nassertion failure: " << message << "\n"; \
111                         if ( !globalDebugMessageHandler().handleMessage() ) { DEBUGGER_BREAKPOINT(); } \
112                 }} while ( 0 )
113
114 /// \brief Sends a \p message to the current debug-message-handler text-output-stream.
115 #define ERROR_MESSAGE( message ) do { \
116                 globalDebugMessageHandler().getOutputStream() << FILE_LINE "\nruntime error: " << message << "\n"; \
117                 if ( !globalDebugMessageHandler().handleMessage() ) { DEBUGGER_BREAKPOINT(); }} while ( 0 )
118
119 #define ASSERT_NOTNULL( ptr ) ASSERT_MESSAGE( ptr != 0, "pointer \"" # ptr "\" is null" )
120
121 #else
122
123 #define ASSERT_MESSAGE( condition, message )
124 #define ERROR_MESSAGE( message )
125 #define ASSERT_NOTNULL( ptr )
126
127 #endif
128
129 #endif