revert between 56095 -> 55830 in arch
[AROS.git] / compiler / arossupport / include / debug.h
blobf7a4c0a1cbc54965435ecbbc145ad437372b02a7
1 /*
2 Copyright © 1995-2017, 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 #ifndef __SRCFILENAME__
162 #define THIS_FILE __FILE__
163 #else
164 #define THIS_FILE __SRCFILENAME__
165 #endif
167 #define ASSERT(x) do { \
168 if (!(x)) { \
169 DBPRINTF("\x07%s:%ld: assertion failed: %s\n", \
170 THIS_FILE, __LINE__, #x); \
171 Alert(AG_BadParm); \
173 } while(0)
175 #define ASSERT_VALID_PTR(x) do { \
176 if (((IPTR)(x) < 1024) || !TypeOfMem((APTR)(x))) { \
177 DBPRINTF("\x07%s, %ld: bad pointer: %s = $%p\n", \
178 THIS_FILE, __LINE__, #x, x); \
179 Alert(AG_BadParm); \
181 } while(0)
183 #define ASSERT_VALID_PTR_OR_NULL(x) do { \
184 if (((x) != NULL) && \
185 (((IPTR)(x) < 1024) || !TypeOfMem((APTR)(x)))) { \
186 DBPRINTF("\x07%s, %ld: bad pointer: %s = $%p\n", \
187 THIS_FILE, __LINE__, #x, x); \
188 Alert(AG_BadParm); \
190 } while(0)
192 #define ASSERT_VALID_TASK(t) do { \
193 ASSERT_VALID_PTR(t); \
194 ASSERT((((t)->tc_Node.ln_Type == NT_TASK) || \
195 (t)->tc_Node.ln_Type == NT_PROCESS)); \
196 } while(0)
198 #define ASSERT_VALID_PROCESS(p) do { \
199 ASSERT_VALID_PTR(p); \
200 ASSERT((p)->pr_Task.tc_Node.ln_Type == NT_PROCESS); \
201 } while(0)
203 #define KASSERT(x) do { \
204 if (!(x)) { \
205 DBPRINTF("\x07%s:%ld: assertion failed: %s\n", \
206 THIS_FILE, __LINE__, #x); \
207 Alert(AG_BadParm); \
209 } while(0)
211 #else /* !ADEBUG */
213 # define ASSERT(x)
214 # define ASSERT_VALID_PTR(x)
215 # define ASSERT_VALID_PTR_OR_NULL(x)
216 # define ASSERT_VALID_TASK(t)
217 # define ASSERT_VALID_PROCESS(p)
218 # define KASSERT(x)
220 #endif /* ADEBUG */
223 /* Memory munging macros
226 /* MUNGWALL_SIZE must be a multiple of MEMCHUNK_TOTAL, otherwise for example
227 rom/exec/allocate complains, because the return value (memory pointer) of
228 AllocMem would not be a multiple of MEMCHUNK_TOTAL anymore.
230 See rom/exec/allocmem and rom/exec/freemem for more info.
232 The "32 *" probably makes sure that you get a multiple of MEMCHUNK_TOTAL on
233 every machine, because on 32 bit machines MEMCHUNK_TOTAL will be 8 and
234 on 64 bit machines it will be 16, and it would even work on 128 bit machines
235 because I guess there MEMCHUNK_TOTAL will be 32 */
237 #define MUNGWALL_SIZE (32 * 1)
239 #define MEMFILL_FREE 0xDEADBEEFL
240 #define MEMFILL_ALLOC 0xC0DEDBADL
241 #define MEMFILL_WALL 0xABADC0DEL
243 #undef MUNGE_BLOCK
244 #undef BUILD_WALL
245 #undef CHECK_WALL
246 #undef MungWallCheck
248 #if MDEBUG
249 /* Fill the memory block pointed by <ptr> of size <size> with <fill>
251 # define MUNGE_BLOCK(ptr, fill, size) do { \
252 ULONG *__p = (ULONG *)(ptr); \
253 ULONG __s = (size) / sizeof(ULONG); \
254 while (__s--) *__p++ = (fill); \
255 } while(0)
257 /* Build a wall over the memory block <ptr> of size <size> with <fill> bricks.
259 # define BUILD_WALL(ptr, fill, size) do { \
260 UBYTE *__p = (UBYTE *)(ptr); \
261 ULONG __s = (size); \
262 while (__s--) *__p++ = (fill); \
263 } while(0)
265 /* Check the integrity of the wall <ptr> of size <size> bytes containing <fill>.
267 # define CHECK_WALL(ptr, fill, size) do { \
268 UBYTE *__p = (UBYTE *)(ptr); \
269 size_t __s = (size); \
270 while (__s--) \
272 if(*__p != (fill)) \
274 struct Task *__t = FindTask(NULL); \
275 kprintf("\x07" "Broken wall detected at %s:%d at 0x%p, " \
276 "Task: 0x%p, Name: %s\n", \
277 __FUNCTION__, __LINE__, \
278 __p, __t, __t->tc_Node.ln_Name);\
280 __p++; \
282 } while(0)
284 # define MungWallCheck() AvailMem(MEMF_CLEAR)
285 #else
287 # define MUNGE_BLOCK(ptr, size, fill)
288 # define BUILD_WALL(ptr, fill, size)
289 # define CHECK_WALL(ptr, fill, size)
290 # define MungWallCheck()
292 #endif /* MDEBUG */
295 #if DEBUG
296 # define D(x...) Indent x
298 # if DEBUG > 1
299 # define DB2(x...) x
300 # else
301 # define DB2(x...) /* eps */
302 # endif
304 /* return-macros. NOTE: I make a copy of the value in __aros_val, because
305 the return-value might have side effects (like return x++;). */
306 # define ReturnVoid(name) { ExitFunc kprintf ("Exit " name "()\n"); return; }
307 # define ReturnPtr(name,type,val) { type __aros_val = (type)val; \
308 ExitFunc kprintf ("Exit " name "=%p\n", \
309 (APTR)__aros_val); return __aros_val; }
310 # define ReturnStr(name,type,val) { type __aros_val = (type)val; \
311 ExitFunc kprintf ("Exit " name "=\"%s\"\n", \
312 __aros_val); return __aros_val; }
313 # define ReturnInt(name,type,val) { type __aros_val = (type)val; \
314 ExitFunc kprintf ("Exit " name "=%ld\n", \
315 (ULONG)__aros_val); return __aros_val; }
316 # define ReturnXInt(name,type,val) { type __aros_val = (type)val; \
317 ExitFunc kprintf ("Exit " name "=%lx\n", \
318 (ULONG)__aros_val); return __aros_val; }
319 # define ReturnFloat(name,type,val) { type __aros_val = (type)val; \
320 ExitFunc kprintf ("Exit " name "=%g\n", \
321 (ULONG)__aros_val); return __aros_val; }
322 # define ReturnSpecial(name,type,val,fmt) { type __aros_val = (type)val; \
323 ExitFunc kprintf ("Exit " name "=" fmt "\n", \
324 (ULONG)__aros_val); return __aros_val; }
325 # define ReturnBool(name,val) { BOOL __aros_val = (val != 0); \
326 ExitFunc kprintf ("Exit " name "=%s\n", \
327 __aros_val ? "TRUE" : "FALSE"); \
328 return __aros_val; }
329 #else /* !DEBUG */
330 # define D(x...) /* eps */
331 # define DB2(x...) /* eps */
333 # define ReturnVoid(name) return
334 # define ReturnPtr(name,type,val) return val
335 # define ReturnStr(name,type,val) return val
336 # define ReturnInt(name,type,val) return val
337 # define ReturnXInt(name,type,val) return val
338 # define ReturnFloat(name,type,val) return val
339 # define ReturnSpecial(name,type,val,fmt) return val
340 # define ReturnBool(name,val) return val
341 #endif /* DEBUG */
343 #undef CHECK_STACK
344 #if AROS_STACK_DEBUG
346 * This works if stack snooping is turned on. One way to do it is to boot AROS
347 * with "stacksnoop" command line argument.
348 * I don't want to care about word length here because ULONG is a part of IPTR and
349 * ULONG test will do here on 64-bit machines too.
351 * TODO: This doesn't work for 'Reversed' stack (growing upwards). If someone will ever
352 * work on such an architecture (SPARC ???) he'll have to fix it.
354 #define CHECK_STACK \
356 struct Task *me = FindTask(NULL); \
357 if (me->tc_Flags & TF_STACKCHK) \
359 ULONG *stktop = me->tc_SPLower; \
361 if (stktop && (*stktop != 0xE1E1E1E1)) \
362 bug("STACK OVERFLOW in %s, line %d\n", __FILE__, __LINE__); \
365 #else
366 #define CHECK_STACK
367 #endif
369 #ifndef AROS_DEBUG_H
370 #define AROS_DEBUG_H
372 #define bug kprintf
373 #define rbug(main,sub,lvl,fmt,args...) \
374 rkprintf (DBG_MAINSYSTEM_ ## main, \
375 DBG_ ## main ## _SUBSYSTEM_ ## sub, \
376 lvl, fmt, ##args)
378 /* Debugging constants. These should be defined outside and this
379 part should be generated. */
380 #define DBG_MAINSYSTEM_INTUITION "intuition"
381 #define DBG_INTUITION_SUBSYSTEM_INPUTHANDLER "inputhandler"
383 #define AROS_FUNCTION_NOT_IMPLEMENTED(library) \
384 kprintf("The function %s/%s() is not implemented.\n", (library), __FUNCTION__)
386 #define AROS_METHOD_NOT_IMPLEMENTED(CLASS, name) \
387 kprintf("The method %s::%s() is not implemented.\n", (CLASS), (name))
389 #define aros_print_not_implemented(name) \
390 kprintf("The function %s() is not implemented.\n", (name))
392 #define ALIVE kprintf("%s - %s line %d\n",__FILE__,__FUNCTION__,__LINE__);
394 #endif /* AROS_DEBUG_H */