blob: 316e80e391e8adf20cb7e6274860167b28923d7e [file] [log] [blame]
/*
* debug_utils.h
*
* Debug Utility definitions.
*
* Copyright (C) 2009-2011 Texas Instruments, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _DEBUG_UTILS_H_
#define _DEBUG_UTILS_H_
#include <stdio.h>
/*#define __DEBUG__*/
/*#define __DEBUG_ENTRY__*/
/*#define __DEBUG_ASSERT__*/
/* ---------- Generic Debug Print Macros ---------- */
/**
* Use as:
* P("val is %d", 5);
* ==> val is 5
* DP("val is %d", 15);
* ==> val is 5 at test.c:56:main()
*/
/* debug print (fmt must be a literal); adds new-line. */
#define __DEBUG_PRINT(fmt, ...) do { fprintf(stdout, fmt "\n", ##__VA_ARGS__); fflush(stdout); } while(0)
/* debug print with context information (fmt must be a literal) */
#define __DEBUG_DPRINT(fmt, ...) __DEBUG_PRINT(fmt " at %s(" __FILE__ ":%d)", ##__VA_ARGS__, __FUNCTION__, __LINE__)
#ifdef __DEBUG__
#define P(fmt, ...) __DEBUG_PRINT(fmt, ##__VA_ARGS__)
#define DP(fmt, ...) __DEBUG_DPRINT(fmt, ##__VA_ARGS__)
#else
#define P(fmt, ...)
#define DP(fmt, ...)
#endif
/* ---------- Program Flow Debug Macros ---------- */
/**
* Use as:
* int get5() {
* IN;
* return R_I(5);
* }
* void check(int i) {
* IN;
* if (i == 5) { RET; return; }
* OUT;
* }
* void main() {
* IN;
* check(get5());
* check(2);
* OUT;
* }
* ==>
* in main(test.c:11)
* in get5(test.c:2)
* out(5) at get5(test.c:3)
* in check(test.c:6)
* out() at check(test.c:7)
* in check(test.c:6)
* out check(test.c:8)
* out main(test.c:14)
*/
#ifdef __DEBUG_ENTRY__
/* function entry */
#define IN __DEBUG_PRINT("in %s(" __FILE__ ":%d)", __FUNCTION__, __LINE__)
/* function exit */
#define OUT __DEBUG_PRINT("out %s(" __FILE__ ":%d)", __FUNCTION__, __LINE__)
/* function abort (return;) Use as { RET; return; } */
#define RET __DEBUG_DPRINT("out() ")
/* generic function return */
#define R(val,type,fmt) ({ type __val__ = (type) val; __DEBUG_DPRINT("out(" fmt ")", __val__); __val__; })
#else
#define IN
#define OUT
#define RET
#define R(val,type,fmt) (val)
#endif
/* integer return */
#define R_I(val) R(val,int,"%d")
/* pointer return */
#define R_P(val) R(val,void *,"%p")
/* long return */
#define R_UP(val) R(val,long,"0x%lx")
/* ---------- Assertion Debug Macros ---------- */
/**
* Use as:
* int i = 5;
* // int j = i * 5;
* int j = A_I(i,==,3) * 5;
* // if (i > 3) P("bad")
* if (NOT_I(i,<=,3)) P("bad")
* P("j is %d", j);
* ==> assert: i (=5) !== 3 at test.c:56:main()
* assert: i (=5) !<= 3 at test.c:58:main()
* j is 25
*
*/
/* generic assertion check, A returns the value of exp, CHK return void */
#ifdef __DEBUG_ASSERT__
#define A(exp,cmp,val,type,fmt) ({ \
type __exp__ = (type) (exp); type __val__ = (type) (val); \
if (!(__exp__ cmp __val__)) __DEBUG_DPRINT("assert: %s (=" fmt ") !" #cmp " " fmt, #exp, __exp__, __val__); \
__exp__; \
})
#define CHK(exp,cmp,val,type,fmt) do { \
type __exp__ = (type) (exp); type __val__ = (type) (val); \
if (!(__exp__ cmp __val__)) __DEBUG_DPRINT("assert: %s (=" fmt ") !" #cmp " " fmt, #exp, __exp__, __val__); \
} while(0)
#else
#define A(exp,cmp,val,type,fmt) (exp)
#define CHK(exp,cmp,val,type,fmt)
#endif
/* typed assertions */
#define A_I(exp,cmp,val) A(exp,cmp,val,int,"%d")
#define A_L(exp,cmp,val) A(exp,cmp,val,long,"%ld")
#define A_P(exp,cmp,val) A(exp,cmp,val,void *,"%p")
#define CHK_I(exp,cmp,val) CHK(exp,cmp,val,int,"%d")
#define CHK_L(exp,cmp,val) CHK(exp,cmp,val,long,"%ld")
#define CHK_P(exp,cmp,val) CHK(exp,cmp,val,void *,"%p")
/* generic assertion check, returns true iff assertion fails */
#ifdef __DEBUG_ASSERT__
#define NOT(exp,cmp,val,type,fmt) ({ \
type __exp__ = (type) (exp); type __val__ = (type) (val); \
if (!(__exp__ cmp __val__)) __DEBUG_DPRINT("assert: %s (=" fmt ") !" #cmp " " fmt, #exp, __exp__, __val__); \
!(__exp__ cmp __val__); \
})
#else
#define NOT(exp,cmp,val,type,fmt) (!((exp) cmp (val)))
#endif
/* typed assertion checks */
#define NOT_I(exp,cmp,val) NOT(exp,cmp,val,int,"%d")
#define NOT_L(exp,cmp,val) NOT(exp,cmp,val,long,"%ld")
#define NOT_P(exp,cmp,val) NOT(exp,cmp,val,void *,"%p")
/* system assertions - will use perror to give external error information */
#ifdef __DEBUG_ASSERT__
#define ERR_S(fmt, ...) do { fprintf(stderr, fmt " at %s(" __FILE__ ":%d", ##__VA_ARGS__, __FUNCTION__, __LINE__); perror(")"); fflush(stderr); } while(0)
#define A_S(exp,cmp,val) ({ \
int __exp__ = (int) (exp); int __val__ = (int) (val); \
if (!(__exp__ cmp __val__)) ERR_S("assert: %s (=%d) !" #cmp " %d", #exp, __exp__, __val__); \
__exp__; \
})
#define CHK_S(exp,cmp,val) do { \
int __exp__ = (int) (exp); int __val__ = (int) (val); \
if (!(__exp__ cmp __val__)) ERR_S("assert: %s (=%d) !" #cmp " %d", #exp, __exp__, __val__); \
} while(0)
#define NOT_S(exp,cmp,val) ({ \
int __exp__ = (int) (exp); int __val__ = (int) (val); \
if (!(__exp__ cmp __val__)) ERR_S("assert: %s (=%d) !" #cmp " %d", #exp, __exp__, __val__); \
!(__exp__ cmp __val__); \
})
#else
#define A_S(exp,cmp,val) (exp)
#define CHK_S(exp,cmp,val)
#define NOT_S(exp,cmp,val) (!((exp) cmp (val)))
#endif
/* error propagation macros - these macros ensure evaluation of the expression
even if there was a prior error */
/* new error is accumulated into error */
#define ERR_ADD(err, exp) do { int __error__ = A_I(exp,==,0); err = err ? err : __error__; } while(0)
#define ERR_ADD_S(err, exp) do { int __error__ = A_S(exp,==,0); err = err ? err : __error__; } while(0)
/* new error overwrites old error */
#define ERR_OVW(err, exp) do { int __error__ = A_I(exp,==,0); err = __error__ ? __error__ : err; } while(0)
#define ERR_OVW_S(err, exp) do { int __error__ = A_S(exp,==,0); err = __error__ ? __error__ : err; } while(0)
#endif