Line data Source code
1 :
2 : /* Copyright (c) 2007-2012, Stefan Eilemann <eile@equalizergraphics.com>
3 : * 2013, Daniel Nachbaur <danielnachbaur@gmail.com>
4 : *
5 : * This library is free software; you can redistribute it and/or modify it under
6 : * the terms of the GNU Lesser General Public License version 2.1 as published
7 : * by the Free Software Foundation.
8 : *
9 : * This library is distributed in the hope that it will be useful, but WITHOUT
10 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12 : * details.
13 : *
14 : * You should have received a copy of the GNU Lesser General Public License
15 : * along with this library; if not, write to the Free Software Foundation, Inc.,
16 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 : */
18 :
19 : #ifndef LUNCHBOX_DEBUG_H
20 : #define LUNCHBOX_DEBUG_H
21 :
22 : #include <lunchbox/defines.h>
23 : #include <lunchbox/log.h>
24 :
25 : #include <typeinfo>
26 :
27 : // assertions
28 : // #define LB_RELEASE_ASSERT
29 :
30 : namespace lunchbox
31 : {
32 : /**
33 : * @internal
34 : * Used to trap into an infinite loop to allow debugging of assertions
35 : */
36 : LUNCHBOX_API void abort(bool dumpThreads = false);
37 :
38 : /**
39 : * @internal
40 : * Check the consistency of the heap and abort on error (Win32 only).
41 : */
42 : LUNCHBOX_API void checkHeap();
43 :
44 : /**
45 : * Print a textual description of the current system error.
46 : *
47 : * The current system error is OS-specific, e.g., errno or GetLastError().
48 : * @version 1.0
49 : */
50 : LUNCHBOX_API std::ostream& sysError(std::ostream& os);
51 :
52 : /** @return a textual description of the current system error. @version 1.9.1 */
53 : LUNCHBOX_API std::string sysError();
54 :
55 : /**
56 : * Get the current call stack.
57 : *
58 : * May not be implemented on all platforms.
59 : *
60 : * @param skipFrames the number of most recent stack frames to ignore.
61 : * @version 1.9.1
62 : */
63 : LUNCHBOX_API std::string backtrace(const size_t skipFrames);
64 :
65 : /** Print the current call stack. @version 1.0 */
66 : LUNCHBOX_API std::ostream& backtrace(std::ostream& os);
67 :
68 : LUNCHBOX_API std::string demangleTypeID(const char* mangled); //!< @internal
69 :
70 : #ifdef _WIN32
71 : #pragma warning(disable : 4100) // VS Bug
72 : #endif
73 : /** Print the RTTI name of the given class. @version 1.0 */
74 : template <class T>
75 1663 : inline std::string className(const T& object)
76 : {
77 1663 : return demangleTypeID(typeid(object).name());
78 : }
79 :
80 : /** Print the RTTI name of the given class. @version 1.0 */
81 : template <class T>
82 0 : inline std::string className(const T* object)
83 : {
84 0 : return className(*object);
85 : }
86 :
87 : #ifdef _WIN32
88 : #pragma warning(default : 4100)
89 : #endif
90 :
91 : /**
92 : * Format the given array in a human-readable form.
93 : * Depending on the data type, a different formatting may be used.
94 : *
95 : * @param data The pointer to the data to print.
96 : * @param num The number of elements of T to print, for T==void the number of
97 : * bytes.
98 : * @version 1.9.1
99 : */
100 : template <class T>
101 : inline std::string format(const T* data, const size_t num)
102 : {
103 : std::ostringstream os;
104 : os << num << " " << className(data) << " @ " << std::hex
105 : << (const void*)data << ": 0x";
106 : for (size_t i = 0; i < num; ++i)
107 : {
108 : if ((i % 8) == 0)
109 : os << " " << std::endl;
110 : os << ' ' << data[i];
111 : }
112 : return os.str();
113 : }
114 :
115 : template <>
116 : inline std::string format(const uint8_t* data, const size_t num)
117 : {
118 : std::ostringstream os;
119 : os << num << " bytes @ " << std::hex << (const void*)data << ": 0x";
120 : os.precision(2);
121 : for (size_t i = 0; i < num; ++i)
122 : {
123 : if ((i % 32) == 0)
124 : os << " " << std::endl;
125 : else if ((i % 8) == 0)
126 : os << ' ';
127 : os << ' ' << std::setw(2) << int(data[i]);
128 : }
129 : return os.str();
130 : }
131 :
132 : template <>
133 : inline std::string format(const void* data, const size_t num)
134 : {
135 : return format(reinterpret_cast<const uint8_t*>(data), num);
136 : }
137 :
138 : template <class T>
139 : inline std::string format(const std::vector<T>& data)
140 : {
141 : return format<T>(&data[0], data.size());
142 : }
143 :
144 : } // namespace lunchbox
145 :
146 : #ifdef NDEBUG
147 : #ifdef LB_RELEASE_ASSERT
148 : #define LBASSERT(x) \
149 : { \
150 : if (!(x)) \
151 : LBERROR << "##### Assert: " << #x << " #####" << std::endl \
152 : << lunchbox::forceFlush; \
153 : lunchbox::checkHeap(); \
154 : }
155 : #define LBASSERTINFO(x, info) \
156 : { \
157 : if (!(x)) \
158 : LBERROR << "##### Assert: " << #x << " [" << info << "] #####" \
159 : << std::endl \
160 : << lunchbox::forceFlush; \
161 : lunchbox::checkHeap(); \
162 : }
163 : #define LBCHECK(x) \
164 : { \
165 : const bool eqOk = x; \
166 : LBASSERTINFO(eqOk, #x) \
167 : }
168 : #else
169 : #define LBASSERT(x)
170 : #define LBASSERTINFO(x, info)
171 : #define LBCHECK(x) \
172 : { \
173 : x; \
174 : }
175 : #endif
176 :
177 : #define LBUNIMPLEMENTED \
178 : { \
179 : LBERROR << "Unimplemented code in " << __FILE__ << ":" << __LINE__ \
180 : << std::endl \
181 : << lunchbox::forceFlush; \
182 : }
183 : #define LBUNREACHABLE \
184 : { \
185 : LBERROR << "Unreachable code in " << __FILE__ << ":" << __LINE__ \
186 : << std::endl \
187 : << lunchbox::forceFlush; \
188 : }
189 : #define LBDONTCALL \
190 : { \
191 : LBERROR << "Code is not supposed to be called in this context" \
192 : << std::endl \
193 : << lunchbox::forceFlush; \
194 : }
195 : #define LBABORT(info) \
196 : { \
197 : LBERROR << "##### Abort: " << info << " #####" << std::endl \
198 : << lunchbox::forceFlush; \
199 : }
200 :
201 : #else // NDEBUG
202 :
203 : #define LBASSERT(x) \
204 : { \
205 : if (!(x)) \
206 : { \
207 : LBERROR << "Assert: " << #x << " "; \
208 : lunchbox::abort(); \
209 : } \
210 : lunchbox::checkHeap(); \
211 : }
212 : #define LBASSERTINFO(x, info) \
213 : { \
214 : if (!(x)) \
215 : { \
216 : LBERROR << "Assert: " << #x << " [" << info << "] "; \
217 : lunchbox::abort(); \
218 : } \
219 : lunchbox::checkHeap(); \
220 : }
221 :
222 : #define LBUNIMPLEMENTED \
223 : { \
224 : LBERROR << "Unimplemented code in " << __FILE__ << ":" << __LINE__ \
225 : << " " << lunchbox::className(*this); \
226 : lunchbox::abort(); \
227 : }
228 : #define LBUNREACHABLE \
229 : { \
230 : LBERROR << "Unreachable code in " << __FILE__ << ":" << __LINE__ \
231 : << " " << lunchbox::className(*this); \
232 : lunchbox::abort(); \
233 : }
234 : #define LBDONTCALL \
235 : { \
236 : LBERROR << "Code is not supposed to be called in this context, type " \
237 : << lunchbox::className(*this); \
238 : lunchbox::abort(); \
239 : }
240 :
241 : #define LBCHECK(x) \
242 : { \
243 : const bool eqOk = x; \
244 : LBASSERTINFO(eqOk, #x) \
245 : }
246 : #define LBABORT(info) \
247 : { \
248 : LBERROR << "Abort: " << info; \
249 : lunchbox::abort(); \
250 : }
251 : #endif // NDEBUG
252 :
253 : #define LBSAFECAST(to, in) \
254 : static_cast<to>(in); \
255 : LBASSERT(in == 0 || dynamic_cast<to>(static_cast<to>(in)))
256 :
257 : #endif // LUNCHBOX_DEBUG_H
|