/* $Id: logstrict.h 1315 2004-03-17 03:59:28Z bird $ */ /** @file * * InnoTek LIBC - Debug Logging and Strict Checking Features. * * InnoTek Systemberatung GmbH confidential * * Copyright (c) 2004 InnoTek Systemberatung GmbH * Author: knut st. osmundsen * * All Rights Reserved * */ #ifndef __InnoTekLIBC_LOG_H__ #define __InnoTekLIBC_LOG_H__ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include /* size_t */ #include /* NULL */ /** @defgroup __libc_log Debug Logging and Strict Checking Features * * The logging feature is not accessible unless DEBUG_LOGGING is #defined. * * The strict checking feature is not accessible unless __LIBC_STRICT is #defined. * * The user of this feature must #define __LIBC_LOG_GROUP to a valid group * number before including this file. * * The user may also #define __LIBC_LOG_INSTANCE if it doesn't want to use * the default logging device. * * Note that all everything but the main logger & strict macros are using the * default prefix to avoid too much namespace pollution. The main logger and * strict macros are not prefixed with the double underscore because that * would make the code less readable (and mean more typing which is painful). * * @{ */ /******************************************************************************* * Defined Constants And Macros * *******************************************************************************/ /** * The user may also #define __LIBC_LOG_INSTANCE if it doesn't want to use * the default logging device. */ #ifdef DEBUG_LOGGING #ifndef __LIBC_LOG_INSTANCE #define __LIBC_LOG_INSTANCE NULL #endif #endif /** * The user of this feature must #define __LIBC_LOG_GROUP to a valid group * number before including this file. */ #ifdef DEBUG_LOGGING #ifndef __LIBC_LOG_GROUP #define __LIBC_LOG_GROUP 0 #error "__LIBC_LOG_GROUP must be defined before including InnoTekLIBC/log.h" #endif #endif /** Macro to log a function entry. */ #ifdef DEBUG_LOGGING #define LIBCLOG_ENTER(...) \ unsigned __libclog_uEnterTS__ = __libc_LogEnter(__LIBC_LOG_INSTANCE, __LIBC_LOG_GROUP, __PRETTY_FUNCTION__, __VA_ARGS__) #else #define LIBCLOG_ENTER(...) //hmm #endif /** Macro to log a generic message within a function entered by LIBCLOG_ENTER(). */ #ifdef DEBUG_LOGGING #define LIBCLOG_MSG(...) \ __libc_LogMsg(__libclog_uEnterTS__, __LIBC_LOG_INSTANCE, __LIBC_LOG_GROUP, __PRETTY_FUNCTION__, __VA_ARGS__) #else #define LIBCLOG_MSG(...) do {} while (0) #endif /** Macro to log a generic message within a functionw. */ #ifdef DEBUG_LOGGING #define LIBCLOG_MSG2(...) \ __libc_LogMsg(~0, __LIBC_LOG_INSTANCE, __LIBC_LOG_GROUP, __PRETTY_FUNCTION__, __VA_ARGS__) #else #define LIBCLOG_MSG2(...) do {} while (0) #endif /** Macro to log a raw message. */ #ifdef DEBUG_LOGGING #define LIBCLOG_RAW(string, maxlen) \ __libc_LogRaw(__LIBC_LOG_INSTANCE, __LIBC_LOG_GROUP, string, maxlen) #else #define LIBCLOG_RAW(...) do {} while (0) #endif /** Macro to log a function exit. */ #ifdef DEBUG_LOGGING #define LIBCLOG_LEAVE(...) \ __libc_LogLeave(__libclog_uEnterTS__, __LIBC_LOG_INSTANCE, __LIBC_LOG_GROUP, __PRETTY_FUNCTION__, __VA_ARGS__) #else #define LIBCLOG_LEAVE(...) do {} while (0) #endif /** Macro to log a custom message and return. */ #define LIBCLOG_RETURN_MSG(rc,...) do { LIBCLOG_LEAVE(__VA_ARGS__); return (rc); } while (0) /** Macro to log a custom message and return. */ #define LIBCLOG_RETURN_MSG_VOID(...) do { LIBCLOG_LEAVE(__VA_ARGS__); return; } while (0) /** Macro to log a void return and do the return. */ #define LIBCLOG_RETURN_VOID() LIBCLOG_RETURN_MSG_VOID( "ret void\n") /** Macro to log an int return and do the return. */ #define LIBCLOG_RETURN_INT(rc) LIBCLOG_RETURN_MSG((rc), "ret %d (%#x)\n", (rc), (rc)) /** Macro to log an unsigned int return and do the return. */ #define LIBCLOG_RETURN_UINT(rc) LIBCLOG_RETURN_MSG((rc), "ret %u (%#x)\n", (rc), (rc)); /** Macro to log an long int return and do the return. */ #define LIBCLOG_RETURN_LONG(rc) LIBCLOG_RETURN_MSG((rc), "ret %ld (%#lx)\n", (rc), (rc)); /** Macro to log an unsigned long int return and do the return. */ #define LIBCLOG_RETURN_ULONG(rc) LIBCLOG_RETURN_MSG((rc), "ret %lu (%#lx)\n", (rc), (rc)); /** Macro to log a pointer return and do the return. */ #define LIBCLOG_RETURN_P(rc) LIBCLOG_RETURN_MSG((rc), "ret %p\n", (void*)(rc)); /** @defgroup __libc_log_flags Message Flags (to be combined with group) * * In source files which uses the logger you can or these flags together * with a group specification in the __LIBC_LOG_GROUP #define. * @{ */ /** Forces a flush of the output file after the message have been written. */ #define __LIBC_LOG_MSGF_FLUSH 0x00010000 /** @} */ /** @defgroup __libc_log_groups Default Logging Groups * * In source files which uses the default logger you must #define * __LIBC_LOG_GROUP to one of these defines. * * @{ */ /** whatever. */ #define __LIBC_LOG_GRP_NOGROUP 0 /*-- LIBC --*/ /** Process APIs. */ #define __LIBC_LOG_GRP_PROCESS 1 /** Heap APIs. */ #define __LIBC_LOG_GRP_HEAP 2 /** File stream APIs. */ #define __LIBC_LOG_GRP_STREAM 3 /** Other I/O APIs. */ #define __LIBC_LOG_GRP_IO 4 /** String APIs. */ #define __LIBC_LOG_GRP_STRING 5 /** Locale APIs. */ #define __LIBC_LOG_GRP_LOCALE 6 /** Regular expression APIs. */ #define __LIBC_LOG_GRP_REGEX 7 /** Math APIs. */ #define __LIBC_LOG_GRP_MATH 8 /** Time APIs. */ #define __LIBC_LOG_GRP_TIME 9 /** BSD DB APIs. */ #define __LIBC_LOG_GRP_BSD_DB 10 /** GLIBC POSIX APIs. */ #define __LIBC_LOG_GRP_GLIBC_POSIX 11 /** Thread APIs. */ #define __LIBC_LOG_GRP_THREAD 12 /** Mutex Semaphores. */ #define __LIBC_LOG_GRP_MUTEX 13 /** Signal APIs and events. */ #define __LIBC_LOG_GRP_SIGNAL 14 /** Environment APIs. */ #define __LIBC_LOG_GRP_ENV 15 /** Init/Term APIs and Events. */ #define __LIBC_LOG_GRP_INITTERM 27 /** Backend APIs. */ #define __LIBC_LOG_GRP_BACKEND 28 /** Misc APIs. */ #define __LIBC_LOG_GRP_MISC 29 /** BSD Gen APIs. */ #define __LIBC_LOG_GRP_BSD_GEN 30 /** GLIBC Misc APIs. */ #define __LIBC_LOG_GRP_GLIBC_MISC 31 /*-- other libraries/APIs --*/ /** Socket APIs. */ #define __LIBC_LOG_GRP_SOCKET 32 /** Other TCP/IP APIs. */ #define __LIBC_LOG_GRP_TCPIP 33 /** iconv APIs. */ #define __LIBC_LOG_GRP_ICONV 34 /** Dynamic Library (libdl) APIs. */ #define __LIBC_LOG_GRP_DLFCN 35 /** Posix thread APIs. */ #define __LIBC_LOG_GRP_PTHREAD 36 /** @todo complete this */ #define __LIBC_LOG_GRP_MAX 36 /** @} */ /** @defgroup __libc_log_strict Strict Assertions * @{ */ /** Generic assertion. * @param expr Boolean expression, */ #ifdef __LIBC_STRICT #define LIBC_ASSERT(expr) ((expr) ? (void)0 \ : __libc_LogAssert(__LIBC_LOG_INSTANCE, __LIBC_LOG_GROUP, __PRETTY_FUNCTION__, __FILE__, __LINE__, #expr, NULL)) #else #define LIBC_ASSERT(expr) ((void)0) #endif /** Generic assertion failed. * (Yeah, this always fails.) */ #ifdef __LIBC_STRICT #define LIBC_ASSERT_FAILED() __libc_LogAssert(__LIBC_LOG_INSTANCE, __LIBC_LOG_GROUP, __PRETTY_FUNCTION__, __FILE__, __LINE__, "0", NULL) #else #define LIBC_ASSERT_FAILED() ((void)0) #endif /** Assert that a memory buffer is readable. * @param pv Pointer to buffer. * @param cb Size of buffer. */ #ifdef __LIBC_STRICT #define LIBC_ASSERT_MEM_R(pv, cb) (__libc_StrictMemoryR((pv), (cb)) ? (void)0 \ : __libc_LogAssert(__LIBC_LOG_INSTANCE, __LIBC_LOG_GROUP, __PRETTY_FUNCTION__, __FILE__, __LINE__, #pv "; " #cb, \ "Memory buffer at %p of %d bytes isn't readable!\n", (pv), (cb))) #else #define LIBC_ASSERT_MEM_R(pv, cb) ((void)0) #endif /** Assert that a memory buffer is readable and writable. * @param pv Pointer to buffer. * @param cb Size of buffer. */ #ifdef __LIBC_STRICT #define LIBC_ASSERT_MEM_RW(pv, cb) (__libc_StrictMemoryRW((pv), (cb)) ? (void)0 \ : __libc_LogAssert(__LIBC_LOG_INSTANCE, __LIBC_LOG_GROUP, __PRETTY_FUNCTION__, __FILE__, __LINE__, #pv "; " #cb, \ "Memory buffer at %p of %d bytes isn't readable and writable!\n", (pv), (cb))) #else #define LIBC_ASSERT_MEM_RW(pv, cb) ((void)0) #endif /** Assert that a zero terminated string is readable. * @param psz Pointer to buffer. */ #ifdef __LIBC_STRICT #define LIBC_ASSERT_STR(psz) (__libc_StrictStringR((psz), ~0) ? (void)0 \ : __libc_LogAssert(__LIBC_LOG_INSTANCE, __LIBC_LOG_GROUP, __PRETTY_FUNCTION__, __FILE__, __LINE__, #psz, \ "String at %p isn't readable!\n", (psz))) #else #define LIBC_ASSERT_STR(psz) ((void)0) #endif /** Assert that a zero terminated string with a maximum lenght is readable. * @param psz Pointer to buffer. * @param cchMax Max string length. */ #ifdef __LIBC_STRICT #define LIBC_ASSERT_NSTR(psz, cchMax) (__libc_StrictStringR((psz), cchMax) ? (void)0 \ : __libc_LogAssert(__LIBC_LOG_INSTANCE, __LIBC_LOG_GROUP, __PRETTY_FUNCTION__, __FILE__, __LINE__, #psz " " #cchMax, \ "String at %p of maximum %d bytes isn't readable!\n", (psz), (cchMax))) #else #define LIBC_ASSERT_NSTR(psz, cchMax) ((void)0) #endif /** Generic assertion, custom message. * @param expr Boolean expression, * @param ... Custom error message. */ #ifdef __LIBC_STRICT #define LIBC_ASSERTM(expr, ...) ((expr) ? (void)0 \ : __libc_LogAssert(__LIBC_LOG_INSTANCE, __LIBC_LOG_GROUP, __PRETTY_FUNCTION__, __FILE__, __LINE__, #expr, \ __VA_ARGS__)) #else #define LIBC_ASSERTM(expr, ...) ((void)0) #endif /** Generic assertion failed, custom message. * (Yeah, this always fails.) * @param ... Custom error message. */ #ifdef __LIBC_STRICT #define LIBC_ASSERTM_FAILED(...) __libc_LogAssert(__LIBC_LOG_INSTANCE, __LIBC_LOG_GROUP, __PRETTY_FUNCTION__, __FILE__, __LINE__, "0", __VA_ARGS__) #else #define LIBC_ASSERTM_FAILED(...) ((void)0) #endif /** Assert that a memory buffer is readable, custom message * @param pv Pointer to buffer. * @param cb Size of buffer. */ #ifdef __LIBC_STRICT #define LIBC_ASSERTM_MEM_R(pv, cb, ...) (__libc_StrictMemoryR((pv), (cb)) ? (void)0 \ : __libc_LogAssert(__LIBC_LOG_INSTANCE, __LIBC_LOG_GROUP, __PRETTY_FUNCTION__, __FILE__, __LINE__, #pv "; " #cb, \ __VA_ARGS__)) #else #define LIBC_ASSERTM_MEM_R(pv, cb, ...) ((void)0) #endif /** Assert that a memory buffer is readable and writable, custom message * @param pv Pointer to buffer. * @param cb Size of buffer. */ #ifdef __LIBC_STRICT #define LIBC_ASSERTM_MEM_RW(pv, cb, ...) (__libc_StrictMemoryRW((pv), (cb)) ? (void)0 \ : __libc_LogAssert(__LIBC_LOG_INSTANCE, __LIBC_LOG_GROUP, __PRETTY_FUNCTION__, __FILE__, __LINE__, #pv "; " #cb, \ __VA_ARGS__)) #else #define LIBC_ASSERTM_MEM_RW(pv, cb, ...) ((void)0) #endif /** Assert that a zero terminated string is readable, custom message * @param psz Pointer to buffer. */ #ifdef __LIBC_STRICT #define LIBC_ASSERTM_STR(psz, ...) (__libc_StrictStringR((psz), ~0) ? (void)0 \ : __libc_LogAssert(__LIBC_LOG_INSTANCE, __LIBC_LOG_GROUP, __PRETTY_FUNCTION__, __FILE__, __LINE__, #psz, \ __VA_ARGS__)) #else #define LIBC_ASSERTM_STR(psz, ...) ((void)0) #endif /** Assert that a zero terminated string with a maximum lenght is readable, custom message * @param psz Pointer to buffer. * @param cchMax Max string length. */ #ifdef __LIBC_STRICT #define LIBC_ASSERTM_NSTR(psz, cchMax, ...) (__libc_StrictStringR((psz), cchMax) ? (void)0 \ : __libc_LogAssert(__LIBC_LOG_INSTANCE, __LIBC_LOG_GROUP, __PRETTY_FUNCTION__, __FILE__, __LINE__, #psz " " #cchMax, \ __VA_ARGS__)) #else #define LIBC_ASSERTM_NSTR(psz, cchMax, ...) ((void)0) #endif /** Extracts the group from the fGroupAndFlags argument. */ #define __LIBC_LOG_GETGROUP(fGroupAndFlags) ((fGroupAndFlags) & 0xffff) /** @} */ /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** Logging group. */ typedef struct __libc_log_group { /** Set if logging for the group is enabled, clear if it's disabled. */ int fEnabled; /** Group name */ const char * pszGroupName; } __LIBC_LOGGROUP, *__LIBC_PLOGGROUP; /** Ordered collection of logging groups. */ typedef struct __libc_log_groups { /** Group index base. This value is subtracted from the group part of the * fFlagsAndGroups arguments to make an index into paGroups. */ unsigned uBase; /** Number of groups in the array. */ unsigned cGroups; /** Array of log groups. */ __LIBC_PLOGGROUP paGroups; } __LIBC_LOGGROUPS, *__LIBC_PLOGGROUPS; /******************************************************************************* * External Functions * *******************************************************************************/ __BEGIN_DECLS /** * Create a logger. * * @returns Pointer to a logger instance on success. * @returns NULL on failure. errno is set. * @param fFlags Flags reserved for future use. Set to zero. * @param pGroups Pointer to a table of logging groups used for this * logger instance. * @param pszFilenameFormat Format string for making up the log filename. * @param ... Arguments to the format string. */ extern void *__libc_LogInit(unsigned fFlags, __LIBC_PLOGGROUPS pGroups, const char *pszFilenameFormat, ...) __printflike(3, 4); /** * Parses the given environment variable and sets the group * flags accordingly. * * The environment variable is a sequence of group idendifiers with * a prefix which determins whether or not that group is enabled. * A special group 'all' can be used to address all groups. * * If the environment variable is not present no changes will be * performed. * * @param pGroups Pointer to groups to init. * @param pszEnvVar Name of the environment variable. * This is taken from the initial environment of the process * and not from the current!! */ extern void __libc_LogGroupInit(__LIBC_PLOGGROUPS pGroups, const char *pszEnvVar); /** * Terminate (or close if you like) a logger instance. * This means flushing any buffered messages and writing a termination * message before closing the log file. * * @returns 0 on succes. * @returns -1 on failure, error is set. * @param pvInstance Logger instance. */ extern int __libc_LogTerm(void *pvInstance); /** * Output an enter function log message. * An enter message is considered to be one line and is appended a newline if * none was given. * * @returns Current timestamp. * @param pvInstance Logger instance. If NULL the message goes to the * default log instance. * @param fGroupAndFlags Logging group and logging flags. * @param pszFunction Name of the function which was entered. * @param pszFormat Format string to display arguments. * @param ... Arguments to the format string. */ extern unsigned __libc_LogEnter(void *pvInstance, unsigned fGroupAndFlags, const char *pszFunction, const char *pszFormat, ...) __printflike(4, 5); /** * Output a leave function log message. * A leave message is considered to be one line and is appended a newline if * none was given. * * @param uEnterTS The timestamp returned by LogEnter. * @param pvInstance Logger instance. If NULL the message goes to the * default log instance. * @param fGroupAndFlags Logging group and logging flags. * @param pszFunction Name of the function which was entered. * @param pszFormat Format string to display the result. * @param ... Arguments to the format string. */ extern void __libc_LogLeave(unsigned uEnterTS, void *pvInstance, unsigned fGroupAndFlags, const char *pszFunction, const char *pszFormat, ...) __printflike(5, 6); /** * Output a log message. * A log message is considered to be one line and is appended a newline if * none was given. * * @param uEnterTS The timestamp returned by LogEnter. * @param pvInstance Logger instance. If NULL the message goes to the * default log instance. * @param fGroupAndFlags Logging group and logging flags. * @param pszFunction Name of the function which was entered. * @param pszFormat Format string for the message to log. * @param ... Arguments to the format string. */ extern void __libc_LogMsg(unsigned uEnterTS, void *pvInstance, unsigned fGroupAndFlags, const char *pszFunction, const char *pszFormat, ...) __printflike(5, 6); /** * Output a raw log message. * Nothing is prepended. No newline is appended. * * @param uEnterTS The timestamp returned by LogEnter. * @param pvInstance Logger instance. If NULL the message goes to the * default log instance. * @param fGroupAndFlags Logging group and logging flags. * @param pszFunction Name of the function which was entered. * @param pszString Pointer to raw log message. * @param cchMax Maximum number of bytes to write. */ extern void __libc_LogRaw(void *pvInstance, unsigned fGroupAndFlags, const char *pszString, unsigned cchMax); /** * Assertion helper. * Logs and displays (stderr) an assertion failed message. * * @param pvInstance Logger instance. If NULL the message goes to the * default log instance. * @param pszFunction Name of the function which was entered. * @param pszFile Source filename. * @param uLine Line number. * @param pszExpression Expression. * @param pszFormat Format string for the message to log. * @param ... Arguments to the format string. */ extern void __libc_LogAssert(void *pvInstance, unsigned fGroupAndFlags, const char *pszFunction, const char *pszFile, unsigned uLine, const char *pszExpression, const char *pszFormat, ...) __printflike(7, 8); /** * Validate a memory area for read access. * @returns 1 if readable. * @returns 0 if not entirely readable. * @param pv Pointer to memory area. * @param cb Size of memory area. */ extern int __libc_StrictMemoryR(const void *pv, size_t cb); /** * Validate a memory area for read & write access. * @returns 1 if readable and writable. * @returns 0 if not entirely readable and writable. * @param pv Pointer to memory area. * @param cb Size of memory area. */ extern int __libc_StrictMemoryRW(void *pv, size_t cb); /** * Validate a zero terminated string for read access. * @returns 1 if readable. * @returns 0 if not entirely readable. * @param psz Pointer to string. * @param cchMax Max string length. Use ~0 if to very all the * way to the terminator. */ extern int __libc_StrictStringR(const char *psz, size_t cchMax); __END_DECLS /** @} */ #endif