From f9516eae732a58ee28da3da8d8c1f3a91e3ff9f5 Mon Sep 17 00:00:00 2001 From: Atis Elsts Date: Wed, 22 Nov 2017 17:48:39 +0000 Subject: [PATCH 1/2] Add stack check library and example --- arch/cpu/cc2538/cc2538.lds | 7 + arch/cpu/cc26xx-cc13xx/cc26xx.ld | 6 + arch/cpu/msp430/Makefile.msp430 | 3 + arch/cpu/nrf52832/ld/nrf52-pca10036-sd.ld | 6 +- arch/cpu/nrf52832/ld/nrf52-pca10040-sd.ld | 6 +- arch/cpu/nrf52832/ld/nrf52.ld | 6 +- arch/platform/cooja/contiki-conf.h | 2 + arch/platform/jn516x/Makefile.jn516x | 4 + arch/platform/native/contiki-conf.h | 1 + arch/platform/sky/platform-conf.h | 8 + examples/libs/stack-check/Makefile | 5 + examples/libs/stack-check/example-sky.csc | 90 ++++++++++ .../libs/stack-check/example-stack-check.c | 88 ++++++++++ examples/libs/stack-check/project-conf.h | 44 +++++ os/contiki-main.c | 5 + os/sys/stack-check.c | 162 ++++++++++++++++++ os/sys/stack-check.h | 130 ++++++++++++++ 17 files changed, 570 insertions(+), 3 deletions(-) create mode 100644 examples/libs/stack-check/Makefile create mode 100644 examples/libs/stack-check/example-sky.csc create mode 100644 examples/libs/stack-check/example-stack-check.c create mode 100644 examples/libs/stack-check/project-conf.h create mode 100644 os/sys/stack-check.c create mode 100644 os/sys/stack-check.h diff --git a/arch/cpu/cc2538/cc2538.lds b/arch/cpu/cc2538/cc2538.lds index ef465409e..4d5031f15 100644 --- a/arch/cpu/cc2538/cc2538.lds +++ b/arch/cpu/cc2538/cc2538.lds @@ -96,11 +96,18 @@ SECTIONS _ebss = .; } > FRSRAM + _end = .; /* End of the .bss segment. */ + + /* This symbol is used by the stack check library. */ + _stack = .; + .stack (NOLOAD) : { *(.stack) } > FRSRAM + /* This symbol is used by the stack check library. */ + _stack_origin = .; _heap = .; _eheap = ORIGIN(FRSRAM) + LENGTH(FRSRAM); diff --git a/arch/cpu/cc26xx-cc13xx/cc26xx.ld b/arch/cpu/cc26xx-cc13xx/cc26xx.ld index 84601ced6..11bd9ca6f 100644 --- a/arch/cpu/cc26xx-cc13xx/cc26xx.ld +++ b/arch/cpu/cc26xx-cc13xx/cc26xx.ld @@ -90,6 +90,12 @@ SECTIONS _ebss = .; } > SRAM + _end = .; /* End of the .bss segment. */ + + /* These symbols are used by the stack check library. */ + _stack = .; + _stack_origin = ORIGIN(SRAM) + LENGTH(SRAM); + .ccfg : { KEEP(*(.ccfg)) diff --git a/arch/cpu/msp430/Makefile.msp430 b/arch/cpu/msp430/Makefile.msp430 index 97ea7f3f2..82af8d420 100644 --- a/arch/cpu/msp430/Makefile.msp430 +++ b/arch/cpu/msp430/Makefile.msp430 @@ -182,6 +182,9 @@ endif # SMALL endif # IAR +# Define the `_stack` symbol used by the stack check library to be equal to `_end` +LDFLAGS += -Wl,--defsym=_stack=_end + CFLAGS += $(CFLAGSNO) PROJECT_OBJECTFILES += ${addprefix $(OBJECTDIR)/,$(CONTIKI_TARGET_MAIN:.c=.o)} diff --git a/arch/cpu/nrf52832/ld/nrf52-pca10036-sd.ld b/arch/cpu/nrf52832/ld/nrf52-pca10036-sd.ld index 455749e29..f3bc5bc43 100644 --- a/arch/cpu/nrf52832/ld/nrf52-pca10036-sd.ld +++ b/arch/cpu/nrf52832/ld/nrf52-pca10036-sd.ld @@ -9,4 +9,8 @@ MEMORY RAM (rwx) : ORIGIN = 0x08000000, LENGTH = 0x8000 } -INCLUDE "nrf5x_common.ld" \ No newline at end of file +INCLUDE "nrf5x_common.ld" + +/* These symbols are used by the stack check library. */ +_stack = end; +_stack_origin = ORIGIN(RAM) + LENGTH(RAM); diff --git a/arch/cpu/nrf52832/ld/nrf52-pca10040-sd.ld b/arch/cpu/nrf52832/ld/nrf52-pca10040-sd.ld index f30aad455..0bc7349e3 100644 --- a/arch/cpu/nrf52832/ld/nrf52-pca10040-sd.ld +++ b/arch/cpu/nrf52832/ld/nrf52-pca10040-sd.ld @@ -9,4 +9,8 @@ MEMORY RAM (rwx) : ORIGIN = 0x20002800, LENGTH = 0xD800 } -INCLUDE "nrf5x_common.ld" \ No newline at end of file +INCLUDE "nrf5x_common.ld" + +/* These symbols are used by the stack check library. */ +_stack = end; +_stack_origin = ORIGIN(RAM) + LENGTH(RAM); diff --git a/arch/cpu/nrf52832/ld/nrf52.ld b/arch/cpu/nrf52832/ld/nrf52.ld index 268794d04..87fc9152d 100644 --- a/arch/cpu/nrf52832/ld/nrf52.ld +++ b/arch/cpu/nrf52832/ld/nrf52.ld @@ -9,4 +9,8 @@ MEMORY RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x8000 } -INCLUDE "nrf5x_common.ld" \ No newline at end of file +INCLUDE "nrf5x_common.ld" + +/* These symbols are used by the stack check library. */ +_stack = end; +_stack_origin = ORIGIN(RAM) + LENGTH(RAM); diff --git a/arch/platform/cooja/contiki-conf.h b/arch/platform/cooja/contiki-conf.h index 7dea26e17..af7582ab9 100644 --- a/arch/platform/cooja/contiki-conf.h +++ b/arch/platform/cooja/contiki-conf.h @@ -135,4 +135,6 @@ typedef uint64_t rtimer_clock_t; #define RF_CHANNEL 26 #define NETSTACK_RADIO_MAX_PAYLOAD_LEN 125 +#define PLATFORM_CONF_SUPPORTS_STACK_CHECK 0 + #endif /* CONTIKI_CONF_H_ */ diff --git a/arch/platform/jn516x/Makefile.jn516x b/arch/platform/jn516x/Makefile.jn516x index 8664f9f0a..50a008374 100644 --- a/arch/platform/jn516x/Makefile.jn516x +++ b/arch/platform/jn516x/Makefile.jn516x @@ -164,6 +164,10 @@ CFLAGS := $(patsubst -I/cygdrive/c/%,-Ic:/%,$(CFLAGS)) LDFLAGS := $(patsubst -L/cygdrive/c/%,-Lc:/%,$(LDFLAGS)) endif +# These symbols are used by the stack check library +LDFLAGS += -Wl,--defsym=_stack=_stack_low_water_mark +LDFLAGS += -Wl,--defsym=_stack_origin=_ram_top + ######################################################################## MOTELIST = python $(CONTIKI)/tools/jn516x/mote-list.py diff --git a/arch/platform/native/contiki-conf.h b/arch/platform/native/contiki-conf.h index f4f7bb1ba..c315b8e18 100644 --- a/arch/platform/native/contiki-conf.h +++ b/arch/platform/native/contiki-conf.h @@ -101,5 +101,6 @@ int strcasecmp(const char*, const char*); #define PLATFORM_CONF_PROVIDES_MAIN_LOOP 1 #define PLATFORM_CONF_MAIN_ACCEPTS_ARGS 1 +#define PLATFORM_CONF_SUPPORTS_STACK_CHECK 0 #endif /* CONTIKI_CONF_H_ */ diff --git a/arch/platform/sky/platform-conf.h b/arch/platform/sky/platform-conf.h index 7a8c584fe..73f3e7652 100644 --- a/arch/platform/sky/platform-conf.h +++ b/arch/platform/sky/platform-conf.h @@ -230,4 +230,12 @@ for SFD timestamping */ #define CC2420_SPI_DISABLE() (CC2420_CSN_PORT(OUT) |= BV(CC2420_CSN_PIN)) #define CC2420_SPI_IS_ENABLED() ((CC2420_CSN_PORT(OUT) & BV(CC2420_CSN_PIN)) != BV(CC2420_CSN_PIN)) +/* Platform-specific define for the end of the stack region */ +#define STACK_CONF_ORIGIN ((void *)0x3900) + +/* Disable the stack check library by default: .rom overflow otherwise */ +#ifndef STACK_CHECK_CONF_ENABLED +#define STACK_CHECK_CONF_ENABLED 0 +#endif + #endif /* PLATFORM_CONF_H_ */ diff --git a/examples/libs/stack-check/Makefile b/examples/libs/stack-check/Makefile new file mode 100644 index 000000000..243679d51 --- /dev/null +++ b/examples/libs/stack-check/Makefile @@ -0,0 +1,5 @@ +CONTIKI_PROJECT = example-stack-check +all: $(CONTIKI_PROJECT) + +CONTIKI = ../../.. +include $(CONTIKI)/Makefile.include diff --git a/examples/libs/stack-check/example-sky.csc b/examples/libs/stack-check/example-sky.csc new file mode 100644 index 000000000..ae09f50bb --- /dev/null +++ b/examples/libs/stack-check/example-sky.csc @@ -0,0 +1,90 @@ + + + [CONTIKI_DIR]/tools/cooja/apps/mrm + [CONTIKI_DIR]/tools/cooja/apps/mspsim + [CONTIKI_DIR]/tools/cooja/apps/avrora + [CONTIKI_DIR]/tools/cooja/apps/serial_socket + + Stack checker example + 0 + 123456 + 1000000 + + org.contikios.cooja.radiomediums.UDGM + 50.0 + 50.0 + 1.0 + 1.0 + + + 40000 + + + org.contikios.cooja.mspmote.SkyMoteType + node + RPL Root + [CONFIG_DIR]/example-stack-check.c + make example-stack-check.sky TARGET=sky + [CONFIG_DIR]/example-stack-check.sky + org.contikios.cooja.interfaces.Position + org.contikios.cooja.interfaces.RimeAddress + org.contikios.cooja.interfaces.IPAddress + org.contikios.cooja.interfaces.Mote2MoteRelations + org.contikios.cooja.interfaces.MoteAttributes + org.contikios.cooja.mspmote.interfaces.MspClock + org.contikios.cooja.mspmote.interfaces.MspMoteID + org.contikios.cooja.mspmote.interfaces.SkyButton + org.contikios.cooja.mspmote.interfaces.SkyFlash + org.contikios.cooja.mspmote.interfaces.SkyCoffeeFilesystem + org.contikios.cooja.mspmote.interfaces.Msp802154Radio + org.contikios.cooja.mspmote.interfaces.MspSerial + org.contikios.cooja.mspmote.interfaces.SkyLED + org.contikios.cooja.mspmote.interfaces.MspDebugOutput + org.contikios.cooja.mspmote.interfaces.SkyTemperature + + + + + org.contikios.cooja.interfaces.Position + 33.260163187353555 + 30.643217359962595 + 0.0 + + + org.contikios.cooja.mspmote.interfaces.MspMoteID + 1 + + node + + + + org.contikios.cooja.plugins.SimControl + 259 + 4 + 179 + 0 + 0 + + + org.contikios.cooja.plugins.Visualizer + + org.contikios.cooja.plugins.skins.IDVisualizerSkin + org.contikios.cooja.plugins.skins.UDGMVisualizerSkin + org.contikios.cooja.plugins.skins.MoteTypeVisualizerSkin + 2.898638306051894 0.0 0.0 2.898638306051894 -68.40918308040007 -27.82360366026197 + + 258 + 2 + 209 + 0 + 178 + + + org.contikios.cooja.plugins.LogListener + 1024 + 3 + 311 + 0 + 385 + + diff --git a/examples/libs/stack-check/example-stack-check.c b/examples/libs/stack-check/example-stack-check.c new file mode 100644 index 000000000..8f4b0f0ae --- /dev/null +++ b/examples/libs/stack-check/example-stack-check.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2017, University of Bristol - http://www.bris.ac.uk/ + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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. + * + */ + +/** + * \file + * Test of Contiki system's stack checker functionality + * \author + * Atis Elsts + */ + +#include "contiki.h" +#include "sys/stack-check.h" +#include "random.h" + +#include +#include +#include +/*---------------------------------------------------------------------------*/ +PROCESS(example_process, "Stack check example"); +AUTOSTART_PROCESSES(&example_process); +/*---------------------------------------------------------------------------*/ +static void +nested_function(void) +{ + printf("stack usage: %u permitted: %u\n", + stack_check_get_usage(), stack_check_get_reserved_size()); +} +/*---------------------------------------------------------------------------*/ +static void +test_function(void) +{ + void *p; + uint16_t s; + + /* allocate and fill some random bytes */ + s = random_rand() % 1000; + printf("allocating %u bytes on the stack\n", s); + p = alloca(s); + memset(p, 0, s); + + /* call the nested function to print stack usage */ + nested_function(); +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(example_process, ev, data) +{ + static struct etimer et; + + PROCESS_BEGIN(); + + while(1) { + etimer_set(&et, CLOCK_SECOND * 2); + + PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et)); + + test_function(); + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ diff --git a/examples/libs/stack-check/project-conf.h b/examples/libs/stack-check/project-conf.h new file mode 100644 index 000000000..2509dd080 --- /dev/null +++ b/examples/libs/stack-check/project-conf.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2017, University of Bristol - http://www.bris.ac.uk/ + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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. + * + */ + +/** + * \file + * Project config file + * \author + * Atis Elsts + * + */ + +#ifndef __PROJECT_CONF_H__ +#define __PROJECT_CONF_H__ + +#define STACK_CHECK_CONF_ENABLED 1 + +#endif /* __PROJECT_CONF_H__ */ diff --git a/os/contiki-main.c b/os/contiki-main.c index 88bea0a10..0aeaeafa1 100644 --- a/os/contiki-main.c +++ b/os/contiki-main.c @@ -44,6 +44,7 @@ #include "contiki-net.h" #include "sys/platform.h" #include "sys/energest.h" +#include "sys/stack-check.h" #include "dev/watchdog.h" #include "services/orchestra/orchestra.h" @@ -77,6 +78,10 @@ main(void) energest_init(); +#if STACK_CHECK_ENABLED + stack_check_init(); +#endif + platform_init_stage_two(); LOG_INFO("Starting " CONTIKI_VERSION_STRING "\n"); diff --git a/os/sys/stack-check.c b/os/sys/stack-check.c new file mode 100644 index 000000000..61f8d98ab --- /dev/null +++ b/os/sys/stack-check.c @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2017, University of Bristol - http://www.bris.ac.uk/ + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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. + * + */ + +/** + * \addtogroup stack + * @{ + */ + +/** + * \file + * Implementation of the stack checker library. + * \author + * Atis Elsts + */ + +#include "contiki.h" +#include "sys/stack-check.h" +#include "dev/watchdog.h" +#include + +#include "sys/log.h" +#define LOG_MODULE "Stack" +#define LOG_LEVEL LOG_LEVEL_MAIN + +/*---------------------------------------------------------------------------*/ +/* linker will provide a symbol for the end of the .bss segment */ +extern uint8_t _stack; + +#if STACK_CHECK_PERIODIC_CHECKS +PROCESS(stack_check_process, "Stack check"); +#endif +/*---------------------------------------------------------------------------*/ +/* The symbol with which the stack memory is initially filled */ +#define STACK_FILL 0xcd +/*---------------------------------------------------------------------------*/ +#ifdef STACK_ORIGIN +/* use the #defined value */ +#define GET_STACK_ORIGIN() STACK_ORIGIN +#else +/* use the value provided by the linker script */ +extern int _stack_origin; +#define GET_STACK_ORIGIN() (&_stack_origin) +#endif +/*---------------------------------------------------------------------------*/ +void +stack_check_init(void) +{ + uint8_t *p; + + /* Make this static to avoid destroying it in the while loop */ + static void *stack_top; + /* Use address of this local variable as a boundary */ + stack_top = &p; + + /* Note: this is expected to be called before the WDT is started! */ + p = &_stack; + while(p < (uint8_t *)stack_top) { + *p++ = STACK_FILL; + } + +#if STACK_CHECK_PERIODIC_CHECKS + /* Start the periodic checker process */ + process_start(&stack_check_process, NULL); +#endif +} +/*---------------------------------------------------------------------------*/ +uint16_t +stack_check_get_usage(void) +{ + uint8_t *p = &_stack; + + /* Make sure WDT is not triggered */ + watchdog_periodic(); + + /* Skip the bytes used after heap; it's 1 byte by default for _stack, + * more than that means dynamic memory allocation is used somewhere. + */ + while(*p != STACK_FILL && p < (uint8_t *)GET_STACK_ORIGIN()) { + p++; + } + + /* Skip the region of the memory reserved for the stack not used yet by the program */ + while(*p == STACK_FILL && p < (uint8_t *)GET_STACK_ORIGIN()) { + p++; + } + + /* Make sure WDT is not triggered */ + watchdog_periodic(); + + if(p >= (uint8_t*)GET_STACK_ORIGIN()) { + /* This means the stack is screwed. */ + return 0xffff; + } + + return (uint8_t *)GET_STACK_ORIGIN() - p; +} +/*---------------------------------------------------------------------------*/ +uint16_t +stack_check_get_reserved_size(void) +{ + return (uint8_t *)GET_STACK_ORIGIN() - &_stack; +} +/*---------------------------------------------------------------------------*/ +#if STACK_CHECK_PERIODIC_CHECKS +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(stack_check_process, ev, data) +{ + static struct etimer et; + + PROCESS_BEGIN(); + + etimer_set(&et, STACK_CHECK_PERIOD); + + while(1) { + uint16_t actual, allowed; + + PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et)); + + actual = stack_check_get_usage(); + allowed = stack_check_get_reserved_size(); + if(actual > allowed) { + LOG_ERR("Check failed: %u vs. %u\n", actual, allowed); + } else { + LOG_DBG("Check ok: %u vs. %u\n", actual, allowed); + } + + etimer_reset(&et); + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ +#endif /* STACK_CHECK_PERIODIC_CHECKS */ +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/os/sys/stack-check.h b/os/sys/stack-check.h new file mode 100644 index 000000000..a9068f216 --- /dev/null +++ b/os/sys/stack-check.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2017, University of Bristol - http://www.bris.ac.uk/ + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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. + * + */ + +/** + * \file + * Stack checker library header file. + * \author + * Atis Elsts + */ + +/** \addtogroup sys + * @{ */ + +/** + * \defgroup stack Stack checker library + * + * Basic support for stack guards and stack overflow detection. + * On startup, fills the area between the stack and the heap with a known pattern. + * During execution, the fill can be checked in order to find out + * the extent to which the stack has been used. + * + * + * @{ + */ + +#ifndef STACK_CHECK_H_ +#define STACK_CHECK_H_ + +#include "contiki-conf.h" + +/* Determine whether stack checking is supported depending on the plaform. */ +#ifdef PLATFORM_CONF_SUPPORTS_STACK_CHECK +#if !PLATFORM_CONF_SUPPORTS_STACK_CHECK +/* Stack checker cannot be enabled, since the platform does not support it */ +#undef STACK_CHECK_CONF_ENABLED +#define STACK_CHECK_CONF_ENABLED 0 +#endif /* !PLATFORM_CONF_SUPPORTS_STACK_CHECK */ +#endif /* ifdef PLATFORM_CONF_SUPPORTS_STACK_CHECK */ + +/* If this is disabled, the functions are no-ops */ +#ifdef STACK_CHECK_CONF_ENABLED +#define STACK_CHECK_ENABLED STACK_CHECK_CONF_ENABLED +#else +#define STACK_CHECK_ENABLED 1 /* Enable by default */ +#endif + +/* Perform periodic stack integrity checks? */ +#ifdef STACK_CHECK_CONF_PERIODIC_CHECKS +#define STACK_CHECK_PERIODIC_CHECKS STACK_CHECK_CONF_PERIODIC_CHECKS +#else +#define STACK_CHECK_PERIODIC_CHECKS 1 /* Enable by default */ +#endif + +/* How often to do the periodic integrity checks, if enabled? */ +#ifdef STACK_CHECK_CONF_PERIOD +#define STACK_CHECK_PERIOD STACK_CHECK_CONF_PERIOD +#else +#define STACK_CHECK_PERIOD (10 * CLOCK_SECOND) +#endif + +/** + * \brief Initialize the stack area with a known pattern + * + * This function initializes the memory between the stack and heap + * areas. The function should be called by the system + * during boot-up. + */ +void stack_check_init(void); + +/** + * \brief Calculate the maximal stack usage so far. + * + * This function relies on the assumption that the stack memory + * that has been reserved by functions and local variables + * is actually overwritten with new contents. If the stack is + * just reserved, but not used, the function will fail to detect + * that usage. + * In addition, this function can warn if the stack memory range + * has been completely used, but it cannot detect + * and warn if stack overflow has already taken place. + */ +uint16_t stack_check_get_usage(void); + +/** + * \brief Calculate the maximal permitted stack usage. + * + * This function returns the number of bytes between the origin + * of the stack and the end of heap. + */ +uint16_t stack_check_get_reserved_size(void); + +/** + * \brief The origin point from which the stack grows (an optional #define) + * + */ +#ifdef STACK_CONF_ORIGIN +#define STACK_ORIGIN STACK_CONF_ORIGIN +#endif + +#endif /* STACK_CHECK_H_ */ + +/** @} */ +/** @} */ From 7233dfbbdd22418d47e03430946d9f332cd4fff7 Mon Sep 17 00:00:00 2001 From: Atis Elsts Date: Tue, 28 Nov 2017 15:55:35 +0000 Subject: [PATCH 2/2] Add a regression test for the stack check library --- .../07-simulation-base/22-stack-guard-sky.csc | 81 +++++++++++++++++++ tests/07-simulation-base/js/22-stack-check.js | 25 ++++++ 2 files changed, 106 insertions(+) create mode 100644 tests/07-simulation-base/22-stack-guard-sky.csc create mode 100644 tests/07-simulation-base/js/22-stack-check.js diff --git a/tests/07-simulation-base/22-stack-guard-sky.csc b/tests/07-simulation-base/22-stack-guard-sky.csc new file mode 100644 index 000000000..5d57eb148 --- /dev/null +++ b/tests/07-simulation-base/22-stack-guard-sky.csc @@ -0,0 +1,81 @@ + + + + Stack guard test (Sky) + 123456 + 1000000 + + org.contikios.cooja.radiomediums.UDGM + 50.0 + 100.0 + 1.0 + 1.0 + + + 40000 + + + org.contikios.cooja.mspmote.SkyMoteType + sky1 + Sky Mote Type #1 + [CONTIKI_DIR]/examples/libs/stack-check/example-stack-check.c + make -j example-stack-check.sky TARGET=sky + [CONTIKI_DIR]/examples/libs/stack-check/example-stack-check.sky + org.contikios.cooja.interfaces.Position + org.contikios.cooja.interfaces.IPAddress + org.contikios.cooja.interfaces.Mote2MoteRelations + org.contikios.cooja.mspmote.interfaces.MspClock + org.contikios.cooja.mspmote.interfaces.MspMoteID + org.contikios.cooja.mspmote.interfaces.SkyButton + org.contikios.cooja.mspmote.interfaces.SkyFlash + org.contikios.cooja.mspmote.interfaces.Msp802154Radio + org.contikios.cooja.mspmote.interfaces.MspSerial + org.contikios.cooja.mspmote.interfaces.SkyLED + + + + + org.contikios.cooja.interfaces.Position + 64.11203103628397 + 93.06735634828134 + 0.0 + + + org.contikios.cooja.mspmote.interfaces.MspMoteID + 1 + + sky1 + + + + org.contikios.cooja.plugins.ScriptRunner + + [CONFIG_DIR]/js/22-stack-check.js + true + + 541 + 0 + 448 + 299 + 7 + + + org.contikios.cooja.plugins.SimControl + 280 + 2 + 160 + 7 + 10 + + + org.contikios.cooja.plugins.LogListener + + + + 680 + 1 + 240 + 51 + 288 + + diff --git a/tests/07-simulation-base/js/22-stack-check.js b/tests/07-simulation-base/js/22-stack-check.js new file mode 100644 index 000000000..c6915cc66 --- /dev/null +++ b/tests/07-simulation-base/js/22-stack-check.js @@ -0,0 +1,25 @@ +TIMEOUT(100000); + +/* This script checks that the stack usage is dynamically changing */ + +var re = /stack usage: (\d+)/i; + +var minusage = 10000; +var maxusage = 0; + +while(true) { + log.log("> " + msg + "\n"); + + var found = msg.match(re); + + if(found) { + var n = parseInt(found[1]); + minusage = minusage < n ? minusage : n; + maxusage = maxusage > n ? maxusage : n; + + if(minusage < 800 && maxusage >= 1000) { + log.testOK(); + } + } + YIELD(); +}