Add assert macros to aid in debugging.

Adds libopencm3/cm3/assert.h header that provides assertion check macros
similar to those provided by the standard C library.

Thanks to Nicolas Schodet for help.
This commit is contained in:
Tomaz Solc 2012-09-24 12:54:53 +02:00
parent 7851515c5c
commit fc4047e4b4
12 changed files with 191 additions and 19 deletions

View File

@ -0,0 +1,136 @@
/** @defgroup debugging Debugging
@brief Macros and functions to aid in debugging
@version 1.0.0
@date 25 September 2012
Two preprocessor defines control the behavior of assertion check macros in
this module. They allow the choice between generated code size and ease of
debugging.
If NDEBUG is defined, all assertion checks are disabled and macros do not
generate any code.
If CM3_ASSERT_VERBOSE is defined, information regarding the position of
assertion checks will be stored in the binary, allowing for more
informative error messages, but also significantly increased code size. As
default assertion checks do not use this information it is only useful if
the application linked with libopencm3 defines its own
cm3_assert_failed_verbose() implementation.
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Tomaz Solc <tomaz.solc@tablix.org>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#ifndef LIBOPENCM3_CM3_ASSERT_H
#define LIBOPENCM3_CM3_ASSERT_H
#include <libopencm3/cm3/common.h>
#define CM3_LIKELY(expr) (__builtin_expect (!!(expr), 1))
#ifdef NDEBUG
# define cm3_assert(expr) do { (void)0; } while(0)
# define cm3_assert_not_reached() while(1)
#else
# ifdef CM3_ASSERT_VERBOSE
# define cm3_assert(expr) do { \
if(CM3_LIKELY(expr)) { (void)0; } else { \
cm3_assert_failed_verbose( \
__FILE__, __LINE__, \
__func__, #expr); \
} \
} while(0)
# define cm3_assert_not_reached() do { \
cm3_assert_failed_verbose( \
__FILE__, __LINE__, \
__func__, 0); \
} while(0)
# else
/** @brief Check if assertion is true.
*
* If NDEBUG macro is defined, this macro generates no code. Otherwise
* cm3_assert_failed() or cm3_assert_failed_verbose() is called if assertion
* is false.
*
* The purpose of this macro is to aid in debugging libopencm3 and
* applications using it. It can be used for example to check if function
* arguments are within expected ranges and stop execution in case an
* unexpected state is reached.
*
* @param expr expression to check */
# define cm3_assert(expr) do { \
if(CM3_LIKELY(expr)) { (void)0; } else { \
cm3_assert_failed(); \
} \
} while(0)
/** @brief Check if unreachable code is reached.
*
* If NDEBUG macro is defined, this macro generates code for an infinite loop.
* Otherwise cm3_assert_failed() or cm3_assert_failed_verbose() is called if
* the macro is ever reached.
*
* The purpose of this macro is to aid in debugging libopencm3 and
* applications using it. It can be used for example to stop execution if an
* unreachable portion of code is reached. */
# define cm3_assert_not_reached() do { \
cm3_assert_failed(); \
} while(0)
# endif
#endif
BEGIN_DECLS
/** @brief Called on a failed assertion.
*
* Halts execution in an infinite loop. This function never returns.
*
* Defined as a weak symbol, so applications can define their own
* implementation. Usually, a custom implementation of this function should
* report an error in some way (print a message to a debug console, display,
* LED, ...) and halt execution or reboot the device. */
void cm3_assert_failed(void) __attribute__ ((__noreturn__));
/** @brief Called on a failed assertion with verbose messages enabled.
*
* Halts execution in an infinite loop. This function never returns.
*
* Defined as a weak symbol, so applications can define their own
* implementation. Usually, a custom implementation of this function should
* report an error in some way (print a message to a debug console, display,
* LED, ...) and halt execution or reboot the device.
*
* @param file File name where the failed assertion occurred
* @param line Line number where the failed assertion occurred
* @param func Name of the function where the failed assertion occurred
* @param assert_expr Expression that evaluated to false (can be NULL) */
void cm3_assert_failed_verbose(const char *file, int line, const char *func,
const char *assert_expr) __attribute__ ((__noreturn__));
END_DECLS
#endif
/**@}*/

34
lib/cm3/assert.c Normal file
View File

@ -0,0 +1,34 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Tomaz Solc <tomaz.solc@tablix.org>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/cm3/assert.h>
void __attribute__((weak)) cm3_assert_failed(void)
{
while(1);
}
void __attribute__((weak)) cm3_assert_failed_verbose(
const char *file __attribute__((unused)),
int line __attribute__((unused)),
const char *func __attribute__((unused)),
const char *assert_expr __attribute__((unused)))
{
cm3_assert_failed();
}

View File

@ -28,8 +28,8 @@ CFLAGS = -Os -g -Wall -Wextra -I../../include -fno-common \
-ffunction-sections -fdata-sections -MD
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS = gpio.o vector.o
OBJS = gpio.o vector.o assert.o
# VPATH += ../usb
VPATH += ../cm3
include ../Makefile.include

View File

@ -28,8 +28,8 @@ CFLAGS = -Os -g -Wall -Wextra -I../../include -fno-common \
-ffunction-sections -fdata-sections -MD
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS = gpio.o
OBJS = gpio.o assert.o
# VPATH += ../usb
VPATH += ../cm3
include ../Makefile.include

View File

@ -28,8 +28,8 @@ CFLAGS = -O0 -g -Wall -Wextra -I../../include -fno-common \
-ffunction-sections -fdata-sections -MD
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS = gpio.o vector.o
OBJS = gpio.o vector.o assert.o
# VPATH += ../usb
VPATH += ../cm3
include ../Makefile.include

View File

@ -31,8 +31,9 @@ CFLAGS = -O2 -g3 -Wall -Wextra -I../../include -fno-common \
-mfloat-abi=hard -mfpu=fpv4-sp-d16
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS = gpio.o vector.o scu.o i2c.o ssp.o nvic.o systick.o
OBJS = gpio.o vector.o scu.o i2c.o ssp.o nvic.o systick.o \
assert.o
# VPATH += ../usb
VPATH += ../cm3
include ../Makefile.include

View File

@ -31,9 +31,9 @@ ARFLAGS = rcs
OBJS = vector.o rcc.o gpio.o usart.o adc.o spi.o flash.o nvic.o \
rtc.o i2c.o dma.o systick.o exti.o scb.o ethernet.o \
usb_f103.o usb.o usb_control.o usb_standard.o can.o \
timer.o usb_f107.o desig.o crc.o
timer.o usb_f107.o desig.o crc.o assert.o
VPATH += ../../usb:../
VPATH += ../../usb:../:../../cm3
include ../../Makefile.include

View File

@ -48,6 +48,7 @@ LGPL License Terms @ref lgpl_license
/**@{*/
#include <libopencm3/cm3/assert.h>
#include <libopencm3/stm32/f1/rcc.h>
#include <libopencm3/stm32/f1/flash.h>
@ -166,8 +167,7 @@ int rcc_osc_ready_int_flag(osc_t osc)
break;
}
/* Shouldn't be reached. */
return -1;
cm3_assert_not_reached();
}
/*-----------------------------------------------------------------------------*/

View File

@ -29,8 +29,8 @@ CFLAGS = -Os -g -Wall -Wextra -I../../../include -fno-common \
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS = vector.o rcc.o gpio.o usart.o spi.o flash.o nvic.o \
i2c.o systick.o exti.o scb.o timer.o \
i2c.o systick.o exti.o scb.o timer.o assert.o
VPATH += ../../usb:../
VPATH += ../../usb:../:../../cm3
include ../../Makefile.include

View File

@ -19,6 +19,7 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/cm3/assert.h>
#include <libopencm3/stm32/f2/rcc.h>
#include <libopencm3/stm32/f2/flash.h>
@ -125,8 +126,7 @@ int rcc_osc_ready_int_flag(osc_t osc)
break;
}
/* Shouldn't be reached. */
return -1;
cm3_assert_not_reached();
}
void rcc_css_int_clear(void)

View File

@ -31,7 +31,8 @@ ARFLAGS = rcs
OBJS = vector.o rcc.o gpio.o usart.o spi.o flash.o nvic.o \
i2c.o systick.o exti.o scb.o pwr.o timer.o \
usb.o usb_standard.o usb_control.o usb_f107.o \
assert.o
VPATH += ../../usb:../
VPATH += ../../usb:../:../../cm3
include ../../Makefile.include

View File

@ -19,6 +19,7 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/cm3/assert.h>
#include <libopencm3/stm32/f4/rcc.h>
#include <libopencm3/stm32/f4/pwr.h>
#include <libopencm3/stm32/f4/flash.h>
@ -139,8 +140,7 @@ int rcc_osc_ready_int_flag(osc_t osc)
break;
}
/* Shouldn't be reached. */
return -1;
cm3_assert_not_reached();
}
void rcc_css_int_clear(void)