Permalink
Browse files

Add stack monitor

Monitors maximum stack usage by painting memory with a known canary at
startup. Worst-case stack usage scenario can be found by periodically
cycling through the RAM and looking for discontinuity in the stack
canary.

This implementation assumes NO memory is allocated on the heap and
will break if you attempt to allocate using malloc() or such.
  • Loading branch information...
blastur committed Dec 21, 2010
1 parent b7f763d commit 109353d27d67f79fe28b7ccf1497878fcb63e7f9
Showing with 96 additions and 2 deletions.
  1. +1 −1 sw/Makefile
  2. +18 −1 sw/main.c
  3. +68 −0 sw/stackmon.c
  4. +9 −0 sw/stackmon.h
View
@@ -30,7 +30,7 @@ PROG=windnode
IHEX=windnode.ihex
BIN=windnode.bin
SRCS=main.c hwparam.c uart.c adc.c wind.c eeprom_cfg.c swuart.c ringbuf.c \
command.c time.c timer_queue.c gsm.c
command.c time.c timer_queue.c gsm.c stackmon.c
OBJS=$(SRCS:%.c=%.o)
DEPS=$(SRCS:%.c=%.d)
FUSES=$(PROG).fuses
View
@@ -28,9 +28,24 @@
#include "swuart.h"
#include "gsm.h"
#include "time.h"
#include "stackmon.h"
static FILE f_debug;
static int cmd_stackdepth(char *arg, char *buf, size_t buflen)
{
char tmp[30];
sprintf(tmp, "Depth %d Limit %d", stackmon_maxdepth(),
stackmon_stacksize());
if (buflen >= strlen(tmp)) {
strcat(buf, tmp);
return strlen(tmp);
} else
return -ENOMEM;
}
static int cmd_gsmpwr(char *arg, char *buf, size_t buflen)
{
int ret;
@@ -88,6 +103,7 @@ static int cmd_gsmcfg(char *arg, char *buf, size_t buflen)
/* Sorted by priority */
static struct command *commandlist[] = {
CREATE_COMMAND("STACK", cmd_stackdepth),
CREATE_COMMAND("GSMAT", cmd_gsmat),
CREATE_COMMAND("GSMPWR", cmd_gsmpwr),
CREATE_COMMAND("GSMRST", cmd_gsmrst),
@@ -136,7 +152,8 @@ int main(void)
sei();
printf("WindNode initialized.\n");
printf("WindNode initialized, startup stack %d bytes\n",
stackmon_maxdepth());
cmdline_loop();
View
@@ -0,0 +1,68 @@
/* Copyright (C) 2010-2011 Magnus Olsson
*
* This file is part of Windnode
* Windnode is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Windnode 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Windnode. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include "stackmon.h"
/* NOTE! This stack monitor assumes no memory is allocated using malloc(), and
* thus all dynamic memory (from heap start to RAMEND) is used for stack.
*/
extern uint8_t __heap_start;
extern uint8_t __stack;
void stackmon_paint(void) __attribute__ ((naked))
__attribute__ ((section (".init1")));
void stackmon_paint(void)
{
__asm volatile (" ldi r30,lo8(__heap_start)\n"
" ldi r31,hi8(__heap_start)\n"
" ldi r24,lo8(0xAC)\n"
" ldi r25,hi8(__stack)\n"
" rjmp .cmp\n"
".loop:\n"
" st Z+,r24\n"
".cmp:\n"
" cpi r30,lo8(__stack)\n"
" cpc r31,r25\n"
" brlo .loop\n"
" breq .loop"::);
}
static uint16_t stackmon_minfree(void)
{
const uint8_t *p = &__heap_start;
uint16_t minfree = 0;
while(*p == 0xAC && p <= &__stack) {
p++;
minfree++;
}
return minfree;
}
uint16_t stackmon_stacksize(void)
{
return &__stack - &__heap_start;
}
uint16_t stackmon_maxdepth(void)
{
return stackmon_stacksize() - stackmon_minfree();
}
View
@@ -0,0 +1,9 @@
#ifndef _STACKMON_H_
#define _STACKMON_H_
#include <stdint.h>
uint16_t stackmon_maxdepth(void);
uint16_t stackmon_stacksize(void);
#endif

0 comments on commit 109353d

Please sign in to comment.