<aros/debug.h> - Don't rely on libc's memset()
[AROS.git] / compiler / arossupport / include / debug.h
blob94c2439519065e77846726314987be3260a7661e
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
5 Debugging macros.
6 This include file can be included several times!
7 */
9 #ifndef CLIB_AROSSUPPORT_PROTOS_H
10 # include <proto/arossupport.h>
11 #endif
12 #ifndef PROTO_EXEC_H
13 # include <proto/exec.h> /* For FindTask() */
14 #endif
15 #ifndef EXEC_TASKS_H
16 # include <exec/tasks.h>
17 #endif
18 #ifndef EXEC_ALERTS_H
19 # include <exec/alerts.h>
20 #endif
22 #include <string.h>
24 #ifndef DEBUG
25 # define DEBUG 0
26 #endif
27 #ifndef SDEBUG
28 # define SDEBUG 0
29 #endif
30 #ifndef ADEBUG
31 # define ADEBUG 0
32 #endif
33 #ifndef MDEBUG
34 # define MDEBUG 0
35 #endif
38 /* Remove all macros. They get new values each time this file is
39 included */
40 #undef D
41 #undef DB2
42 #undef ReturnVoid
43 #undef ReturnPtr
44 #undef ReturnStr
45 #undef ReturnInt
46 #undef ReturnXInt
47 #undef ReturnFloat
48 #undef ReturnSpecial
49 #undef ReturnBool
52 /* Macros for "stair debugging" */
53 #undef SDInit
54 #undef EnterFunc
55 #undef Indent
56 #undef ExitFunc
58 /* StegerG */
59 #undef SDEBUG
60 #define SDEBUG 0
62 #if SDEBUG
64 # ifndef SDEBUG_INDENT
65 # define SDEBUG_INDENT 2
66 # endif
68 /* This is some new macros for making debug output more readable,
69 ** by indenting for each functioncall made.
70 ** Usage: Call the SDInit() macro before anything else in your main().
71 ** Start the functions you want to debug with EnterFunc(bug("something"))
72 ** and ALWAYS match these with a Returnxxxx type macro
73 ** at the end of the func.
74 ** Inside the func you can use the normal D(bug()) macro.
76 ** To enable the macros, just add a #define SDEBUG 1
79 /* User macro */
80 #define EnterFunc(x) do { \
81 struct Task *sd_task = FindTask(NULL); \
82 int sd_spaceswritten; \
83 for (sd_spaceswritten = 0; sd_spaceswritten < (ULONG)sd_task->tc_UserData; sd_spaceswritten ++) kprintf(" "); \
84 ((ULONG)sd_task->tc_UserData) += SDEBUG_INDENT; } while(0); \
88 /* User macro. Add into start of your main() routine */
89 # define SDInit() \
90 do { FindTask(NULL)->tc_UserData = NULL; } while(0)
93 /* Internal */
94 # define Indent do { \
95 struct Task *sd_task = FindTask(NULL); \
96 int sd_spaceswritten; \
97 for (sd_spaceswritten = 0; sd_spaceswritten < (ULONG)sd_task->tc_UserData; sd_spaceswritten ++) kprintf(" "); } while(0)
99 /* Internal */
100 #define ExitFunc do { \
101 struct Task *sd_task = FindTask(NULL); \
102 int sd_spaceswritten; \
103 ((ULONG)sd_task->tc_UserData) -= SDEBUG_INDENT; \
104 for (sd_spaceswritten = 0; sd_spaceswritten < (ULONG)sd_task->tc_UserData; sd_spaceswritten ++) kprintf(" "); } while(0)
106 #else
108 # define SDInit()
109 # define Indent
110 # define EnterFunc(x...) D(x)
111 # define ExitFunc
113 #endif /* SDEBUG */
117 /* Sanity check macros
119 * ASSERT(x)
120 * Do nothing if the expression <x> evalutates to a
121 * non-zero value, output a debug message otherwise.
123 * ASSERT_VALID_PTR(x)
124 * Checks that the expression <x> points to a valid memory location, and
125 * outputs a debug message otherwise. A NULL pointer is considered INVALID.
127 * ASSERT_VALID_PTR_OR_NULL(x)
128 * Checks that the expression <x> points to a valid memory location or that
129 * it is NULL, and outputs a debug message otherwise. A NULL pointer is
130 * considered VALID.
132 * ASSERT_VALID_TASK(t)
133 * Checks that the pointer <t> points to a valid Task
134 * structure and outputs a debug message otherwise.
136 * ASSERT_VALID_PROCESS(p)
137 * Checks that the pointer <p> points to a valid Process
138 * structure and outputs a debug message otherwise.
140 * KASSERT(x)
141 * Do nothing if the expression <x> evalutates to a
142 * non-zero value, output a debug message, and cause an
143 * Alert() otherwise. This should only be used in kernel code.
146 #undef DBPRINTF
147 #undef THIS_FILE
148 #undef ASSERT
149 #undef ASSERT_VALID_PTR
150 #undef ASSERT_VALID_PTR_OR_NULL
151 #undef ASSERT_VALID_TASK
152 #undef ASSERT_VALID_PROCESS
154 #if ADEBUG
156 #define DBPRINTF kprintf
158 /* The trick with THIS_FILE allows us to reuse the same static string
159 * instead of allocating a new copy for each invocation of these macros.
161 #define THIS_FILE __FILE__
163 #define ASSERT(x) do { \
164 if (!(x)) { \
165 DBPRINTF("\x07%s:%ld: assertion failed: %s\n", \
166 THIS_FILE, __LINE__, #x); \
167 Alert(AG_BadParm); \
169 } while(0)
171 #define ASSERT_VALID_PTR(x) do { \
172 if (((IPTR)(x) < 1024) || !TypeOfMem((APTR)(x))) { \
173 DBPRINTF("\x07%s, %ld: bad pointer: %s = $%p\n", \
174 THIS_FILE, __LINE__, #x, x); \
175 Alert(AG_BadParm); \
177 } while(0)
179 #define ASSERT_VALID_PTR_OR_NULL(x) do { \
180 if (((x) != NULL) && \
181 (((IPTR)(x) < 1024) || !TypeOfMem((APTR)(x)))) { \
182 DBPRINTF("\x07%s, %ld: bad pointer: %s = $%p\n", \
183 THIS_FILE, __LINE__, #x, x); \
184 Alert(AG_BadParm); \
186 } while(0)
188 #define ASSERT_VALID_TASK(t) do { \
189 ASSERT_VALID_PTR(t); \
190 ASSERT((((t)->tc_Node.ln_Type == NT_TASK) || \
191 (t)->tc_Node.ln_Type == NT_PROCESS)); \
192 } while(0)
194 #define ASSERT_VALID_PROCESS(p) do { \
195 ASSERT_VALID_PTR(p); \
196 ASSERT((p)->pr_Task.tc_Node.ln_Type == NT_PROCESS); \
197 } while(0)
199 #define KASSERT(x) do { \
200 if (!(x)) { \
201 DBPRINTF("\x07%s:%ld: assertion failed: %s\n", \
202 THIS_FILE, __LINE__, #x); \
203 Alert(AG_BadParm); \
205 } while(0)
207 #else /* !ADEBUG */
209 # define ASSERT(x)
210 # define ASSERT_VALID_PTR(x)
211 # define ASSERT_VALID_PTR_OR_NULL(x)
212 # define ASSERT_VALID_TASK(t)
213 # define ASSERT_VALID_PROCESS(p)
214 # define KASSERT(x)
216 #endif /* ADEBUG */
219 /* Memory munging macros
222 /* MUNGWALL_SIZE must be a multiple of MEMCHUNK_TOTAL, otherwise for example
223 rom/exec/allocate complains, because the return value (memory pointer) of
224 AllocMem would not be a multiple of MEMCHUNK_TOTAL anymore.
226 See rom/exec/allocmem and rom/exec/freemem for more info.
228 The "32 *" probably makes sure that you get a multiple of MEMCHUNK_TOTAL on
229 every machine, because on 32 bit machines MEMCHUNK_TOTAL will be 8 and
230 on 64 bit machines it will be 16, and it would even work on 128 bit machines
231 because I guess there MEMCHUNK_TOTAL will be 32 */
233 #define MUNGWALL_SIZE (32 * 1)
235 #define MEMFILL_FREE 0xDEADBEEFL
236 #define MEMFILL_ALLOC 0xC0DEDBADL
237 #define MEMFILL_WALL 0xABADC0DEL
239 #undef MUNGE_BLOCK
240 #undef BUILD_WALL
241 #undef CHECK_WALL
242 #undef MungWallCheck
244 #if MDEBUG
245 /* Fill the memory block pointed by <ptr> of size <size> with <fill>
247 # define MUNGE_BLOCK(ptr, fill, size) do { \
248 ULONG *__p = (ULONG *)(ptr); \
249 ULONG __s = (size) / sizeof(ULONG); \
250 while (__s--) *__p++ = (fill); \
251 } while(0)
253 /* Build a wall over the memory block <ptr> of size <size> with <fill> bricks.
255 # define BUILD_WALL(ptr, fill, size) do { \
256 UBYTE *__p = (UBYTE *)(ptr); \
257 ULONG __s = (size); \
258 while (__s--) *__p++ = (fill); \
259 } while(0)
261 /* Check the integrity of the wall <ptr> of size <size> bytes containing <fill>.
263 # define CHECK_WALL(ptr, fill, size) do { \
264 UBYTE *__p = (UBYTE *)(ptr); \
265 size_t __s = (size); \
266 while (__s--) \
268 if(*__p != (fill)) \
270 struct Task *__t = FindTask(NULL); \
271 kprintf("\x07" "Broken wall detected at %s:%d at 0x%p, " \
272 "Task: 0x%p, Name: %s\n", \
273 __FUNCTION__, __LINE__, \
274 __p, __t, __t->tc_Node.ln_Name);\
276 __p++; \
278 } while(0)
280 # define MungWallCheck() AvailMem(MEMF_CLEAR)
281 #else
283 # define MUNGE_BLOCK(ptr, size, fill)
284 # define BUILD_WALL(ptr, fill, size)
285 # define CHECK_WALL(ptr, fill, size)
286 # define MungWallCheck()
288 #endif /* MDEBUG */
291 #if DEBUG
292 # define D(x...) Indent x
294 # if DEBUG > 1
295 # define DB2(x...) x
296 # else
297 # define DB2(x...) /* eps */
298 # endif
300 /* return-macros. NOTE: I make a copy of the value in __aros_val, because
301 the return-value might have side effects (like return x++;). */
302 # define ReturnVoid(name) { ExitFunc kprintf ("Exit " name "()\n"); return; }
303 # define ReturnPtr(name,type,val) { type __aros_val = (type)val; \
304 ExitFunc kprintf ("Exit " name "=%p\n", \
305 (APTR)__aros_val); return __aros_val; }
306 # define ReturnStr(name,type,val) { type __aros_val = (type)val; \
307 ExitFunc kprintf ("Exit " name "=\"%s\"\n", \
308 __aros_val); return __aros_val; }
309 # define ReturnInt(name,type,val) { type __aros_val = (type)val; \
310 ExitFunc kprintf ("Exit " name "=%ld\n", \
311 (ULONG)__aros_val); return __aros_val; }
312 # define ReturnXInt(name,type,val) { type __aros_val = (type)val; \
313 ExitFunc kprintf ("Exit " name "=%lx\n", \
314 (ULONG)__aros_val); return __aros_val; }
315 # define ReturnFloat(name,type,val) { type __aros_val = (type)val; \
316 ExitFunc kprintf ("Exit " name "=%g\n", \
317 (ULONG)__aros_val); return __aros_val; }
318 # define ReturnSpecial(name,type,val,fmt) { type __aros_val = (type)val; \
319 ExitFunc kprintf ("Exit " name "=" fmt "\n", \
320 (ULONG)__aros_val); return __aros_val; }
321 # define ReturnBool(name,val) { BOOL __aros_val = (val != 0); \
322 ExitFunc kprintf ("Exit " name "=%s\n", \
323 __aros_val ? "TRUE" : "FALSE"); \
324 return __aros_val; }
325 #else /* !DEBUG */
326 # define D(x...) /* eps */
327 # define DB2(x...) /* eps */
329 # define ReturnVoid(name) return
330 # define ReturnPtr(name,type,val) return val
331 # define ReturnStr(name,type,val) return val
332 # define ReturnInt(name,type,val) return val
333 # define ReturnXInt(name,type,val) return val
334 # define ReturnFloat(name,type,val) return val
335 # define ReturnSpecial(name,type,val,fmt) return val
336 # define ReturnBool(name,val) return val
337 #endif /* DEBUG */
339 #undef CHECK_STACK
340 #if AROS_STACK_DEBUG
342 * This works if stack snooping is turned on. One way to do it is to boot AROS
343 * with "stacksnoop" command line argument.
344 * I don't want to care about word length here because ULONG is a part of IPTR and
345 * ULONG test will do here on 64-bit machines too.
347 * TODO: This doesn't work for 'Reversed' stack (growing upwards). If someone will ever
348 * work on such an architecture (SPARC ???) he'll have to fix it.
350 #define CHECK_STACK \
352 struct Task *me = FindTask(NULL); \
353 if (me->tc_Flags & TF_STACKCHK) \
355 ULONG *stktop = me->tc_SPLower; \
357 if (stktop && (*stktop != 0xE1E1E1E1)) \
358 bug("STACK OVERFLOW in %s, line %d\n", __FILE__, __LINE__); \
361 #else
362 #define CHECK_STACK
363 #endif
365 #ifndef AROS_DEBUG_H
366 #define AROS_DEBUG_H
368 #define bug kprintf
369 #define rbug(main,sub,lvl,fmt,args...) \
370 rkprintf (DBG_MAINSYSTEM_ ## main, \
371 DBG_ ## main ## _SUBSYSTEM_ ## sub, \
372 lvl, fmt, ##args)
374 /* Debugging constants. These should be defined outside and this
375 part should be generated. */
376 #define DBG_MAINSYSTEM_INTUITION "intuition"
377 #define DBG_INTUITION_SUBSYSTEM_INPUTHANDLER "inputhandler"
379 #define AROS_FUNCTION_NOT_IMPLEMENTED(library) \
380 kprintf("The function %s/%s() is not implemented.\n", (library), __FUNCTION__)
382 #define AROS_METHOD_NOT_IMPLEMENTED(CLASS, name) \
383 kprintf("The method %s::%s() is not implemented.\n", (CLASS), (name))
385 #define aros_print_not_implemented(name) \
386 kprintf("The function %s() is not implemented.\n", (name))
388 #define ALIVE kprintf("%s - %s line %d\n",__FILE__,__FUNCTION__,__LINE__);
390 #endif /* AROS_DEBUG_H */