X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=bertos%2Fcfg%2Fdebug.h;fp=bertos%2Fcfg%2Fdebug.h;h=a75b4d2d9f9b22f027bc53fd531683469ba534be;hb=791e167e053bdd9250d34a9a5ccae6ccde4d6679;hp=0000000000000000000000000000000000000000;hpb=faf2f6bfd5933ff75e6cc01e3d48f9277f731d8f;p=bertos.git diff --git a/bertos/cfg/debug.h b/bertos/cfg/debug.h new file mode 100644 index 00000000..a75b4d2d --- /dev/null +++ b/bertos/cfg/debug.h @@ -0,0 +1,313 @@ +/** + * \file + * + * + * \brief Simple debug facilities for hosted and embedded C/C++ applications. + * + * Debug output goes to stderr in hosted applications. + * Freestanding (AKA embedded) applications use \c drv/kdebug.c to output + * diagnostic messages to a serial terminal or a JTAG debugger. + * + * \version $Id$ + * \author Bernardo Innocenti + */ + +#ifndef DEVLIB_DEBUG_H +#define DEVLIB_DEBUG_H + +#include +#include + + +/* + * Defaults for rarely used config stuff. + */ +#ifndef CONFIG_KDEBUG_DISABLE_TRACE +#define CONFIG_KDEBUG_DISABLE_TRACE 0 +#endif + +#ifndef CONFIG_KDEBUG_ASSERT_NO_TEXT +#define CONFIG_KDEBUG_ASSERT_NO_TEXT 0 +#endif + +#if defined(__doxygen__) + /** + * Preprocessor symbol defined only for debug builds. + * + * The build infrastructure must arrange for _DEBUG to + * be predefined for all the source files being compiled. + * + * This is compatible with the MSVC convention for the + * default Debug and Release project targets. + */ + #define _DEBUG 1 +#endif + +#ifdef _DEBUG + + // STLport specific: enable extra checks + #define __STL_DEBUG 1 + + // MSVC specific: Enable memory allocation debug + #if defined(_MSC_VER) + #include + #endif + + /* + * On UNIX systems the extabilished practice is to define + * NDEBUG for release builds and nothing for debug builds. + */ + #ifdef NDEBUG + #undef NDEBUG + #endif + + /** + * This macro duplicates the old MSVC trick of redefining + * THIS_FILE locally to avoid the overhead of many duplicate + * strings in ASSERT(). + */ + #ifndef THIS_FILE + #define THIS_FILE __FILE__ + #endif + + /** + * This macro can be used to conditionally exclude one or more + * statements conditioned on \c _DEBUG, avoiding the clutter + * of ifdef/endif pairs. + * + * \code + * struct FooBar + * { + * int foo; + * bool bar; + * DB(int ref_count;) // Track number of users + * + * void release() + * { + * DB(--ref_count;) + * } + * }; + * \endcode + */ + #define DB(x) x + + #include /* CONFIG_KDEBUG_ASSERT_NO_TEXT */ + #include /* CPU_HARVARD */ + + /* These are implemented in drv/kdebug.c */ + void kdbg_init(void); + void kputchar(char c); + int kputnum(int num); + void kdump(const void *buf, size_t len); + void __init_wall(long *wall, int size); + + #if CPU_HARVARD + #include + void kputs_P(const char *PROGMEM str); + void kprintf_P(const char *PROGMEM fmt, ...) FORMAT(__printf__, 1, 2); + int __assert_P(const char *PROGMEM cond, const char *PROGMEM file, int line); + void __trace_P(const char *func); + void __tracemsg_P(const char *func, const char *PROGMEM fmt, ...); + int __invalid_ptr_P(void *p, const char *PROGMEM name, const char *PROGMEM file, int line); + int __check_wall_P(long *wall, int size, const char * PGM_ATTR name, const char * PGM_ATTR file, int line); + #define kputs(str) kputs_P(PSTR(str)) + #define kprintf(fmt, ...) kprintf_P(PSTR(fmt) ,## __VA_ARGS__) + #define __assert(cond, file, line) __assert_P(PSTR(cond), PSTR(file), (line)) + #define __trace(func) __trace_P(func) + #define __tracemsg(func, fmt, ...) __tracemsg_P(func, PSTR(fmt), ## __VA_ARGS__) + #define __invalid_ptr(p, name, file, line) __invalid_ptr_P((p), PSTR(name), PSTR(file), (line)) + #define __check_wall(wall, size, name, file, line) __check_wall_P(wall, size, PSTR(name), PSTR(file), (line)) + #else /* !CPU_HARVARD */ + void kputs(const char *str); + void kprintf(const char *fmt, ...) FORMAT(__printf__, 1, 2); + int __assert(const char *cond, const char *file, int line); + void __trace(const char *func); + void __tracemsg(const char *func, const char *fmt, ...) FORMAT(__printf__, 2, 3); + int __invalid_ptr(void *p, const char *name, const char *file, int line); + int __check_wall(long *wall, int size, const char *name, const char *file, int line); + #endif /* !CPU_HARVARD */ + + #if !CONFIG_KDEBUG_ASSERT_NO_TEXT + #define ASSERT(x) ((void)(LIKELY(x) ? 0 : __assert(#x, THIS_FILE, __LINE__))) + #define ASSERT2(x, help) ((void)(LIKELY(x) ? 0 : __assert(help " (" #x ")", THIS_FILE, __LINE__))) + #else + #define ASSERT(x) ((void)(LIKELY(x) ? 0 : __assert("", THIS_FILE, __LINE__))) + #define ASSERT2(x, help) ((void)ASSERT(x)) + #endif + + /** + * Check that the given pointer is either NULL or pointing to valid memory. + * + * The assumption here is that valid pointers never point to low + * memory regions. This helps catching pointers taken from + * struct/class memebers when the struct pointer was NULL. + */ + #define ASSERT_VALID_PTR(p) ((void)(LIKELY((p) >= 0x200) ? 0 : __invalid_ptr(p, #p, THIS_FILE, __LINE__))) + + /** + * Check that the given pointer is not pointing to invalid memory. + * + * \see ASSERT_VALID_PTR() + */ + #define ASSERT_VALID_PTR_OR_NULL(p) ((void)(LIKELY((p == NULL) || ((p) >= 0x200)) ? 0 : __invalid_ptr((p), #p, THIS_FILE, __LINE__))) + + #if !CONFIG_KDEBUG_DISABLE_TRACE + #define TRACE __trace(__func__) + #define TRACEMSG(msg,...) __tracemsg(__func__, msg, ## __VA_ARGS__) + #else + #define TRACE do {} while(0) + #define TRACEMSG(...) do {} while(0) + #endif + + /** + * \name Walls to detect data corruption + * \{ + */ + #define WALL_SIZE 8 + #define WALL_VALUE (long)0xABADCAFEL + #define DECLARE_WALL(name,size) long name[(size) / sizeof(long)]; + #define FWD_DECLARE_WALL(name,size) extern long name[(size) / sizeof(long)]; + #define INIT_WALL(name) __init_wall((name), countof(name)) + #define CHECK_WALL(name) __check_wall((name), countof(name), #name, THIS_FILE, __LINE__) + /*\}*/ + + /** + * Check that the given pointer actually points to an object + * of the specified type. + */ + #define ASSERT_VALID_OBJ(_t, _o) do { \ + ASSERT_VALID_PTR((_o)); \ + ASSERT(dynamic_cast<_t>((_o)) != NULL); \ + } + + /** + * \name Debug object creation and destruction. + * + * These macros help track some kinds of leaks in C++ programs. + * Usage is as follows: + * + * \code + * class Foo + * { + * DECLARE_INSTANCE_TRACKING(Foo) + * + * Foo() + * { + * NEW_INSTANCE(Foo); + * // ... + * } + * + * ~Foo() + * { + * DELETE_INSTANCE(Foo); + * // ... + * } + * }; + * + * // Put this in the implementation file of the class + * IMPLEMENT_INSTANCE_TRACKING(Foo) + * + * // Client code + * int main(void) + * { + * Foo *foo = new Foo; + * cout << GET_INSTANCE_COUNT(Foo) << endl; // prints "1" + * delete foo; + * ASSERT_ZERO_INSTANCES(Foo); // OK + * } + * \endcode + * \{ + */ + #define NEW_INSTANCE(CLASS) do { ++CLASS::__instances } while (0) + #define DELETE_INSTANCE(CLASS) do { --CLASS::__instances } while (0) + #define ASSERT_ZERO_INSTANCES(CLASS) ASSERT(CLASS::__instances == 0) + #define GET_INSTANCE_COUNT(CLASS) (CLASS::__instances) + #define DECLARE_INSTANCE_TRACKING(CLASS) static int __instances + #define IMPLEMENT_INSTANCE_TRACKING(CLASS) int CLASS::__instances = 0 + /*\}*/ + +#else /* !_DEBUG */ + + /* + * On UNIX systems the extabilished practice is to define + * NDEBUG for release builds and nothing for debug builds. + */ + #ifndef NDEBUG + #define NDEBUG 1 + #endif + + #define DB(x) /* nothing */ + #ifndef ASSERT + #define ASSERT(x) ((void)0) + #endif /* ASSERT */ + #define ASSERT2(x, help) ((void)0) + #define ASSERT_VALID_PTR(p) ((void)0) + #define ASSERT_VALID_PTR_OR_NULL(p) ((void)0) + #define ASSERT_VALID_OBJ(_t, _o) ((void)0) + #define TRACE do {} while (0) + #if COMPILER_VARIADIC_MACROS + #define TRACEMSG(x, ...) do {} while (0) + #else + INLINE void TRACEMSG(UNUSED_ARG(const char *, msg), ...) + { + /* NOP */ + } + #endif + + #define DECLARE_WALL(name, size) /* nothing */ + #define FWD_DECLARE_WALL(name, size) /* nothing */ + #define INIT_WALL(name) do {} while (0) + #define CHECK_WALL(name) do {} while (0) + + #define NEW_INSTANCE(CLASS) do {} while (0) + #define DELETE_INSTANCE(CLASS) do {} while (0) + #define ASSERT_ZERO_INSTANCES(CLASS) do {} while (0) + #define GET_INSTANCE_COUNT(CLASS) ERROR_ONLY_FOR_DEBUG + #define DECLARE_INSTANCE_TRACKING(CLASS) + #define IMPLEMENT_INSTANCE_TRACKING(CLASS) + + INLINE void kdbg_init(void) { /* nop */ } + INLINE void kputchar(UNUSED_ARG(char, c)) { /* nop */ } + INLINE int kputnum(UNUSED_ARG(int, num)) { return 0; } + INLINE void kputs(UNUSED_ARG(const char *, str)) { /* nop */ } + INLINE void kdump(UNUSED_ARG(const void *, buf), UNUSED_ARG(size_t, len)) { /* nop */ } + + #if defined(__cplusplus) && COMPILER_VARIADIC_MACROS + /* G++ can't inline functions with variable arguments... */ + #define kprintf(fmt,...) do { (void)(fmt); } while(0) + #else + /* ...but GCC can. */ + INLINE void kprintf(UNUSED_ARG(const char *, fmt), ...) { /* nop */ } + #endif + +#endif /* _DEBUG */ + +#endif /* DEVLIB_DEBUG_H */