From a37ad4eccafec05d48babf8b4197a44eac72aa59 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sun, 23 Mar 2014 10:11:58 -0600 Subject: [PATCH] Add logic to check interrupt stack usage --- arch/arm/src/common/up_checkstack.c | 166 ++++++++++++++++++---------- arch/arm/src/common/up_initialize.c | 30 +++++ arch/avr/src/avr/up_checkstack.c | 82 ++++++++++---- arch/avr/src/common/up_initialize.c | 30 +++++ include/nuttx/arch.h | 8 +- 5 files changed, 238 insertions(+), 78 deletions(-) diff --git a/arch/arm/src/common/up_checkstack.c b/arch/arm/src/common/up_checkstack.c index 9cf4c684f0..02f95f7ba8 100644 --- a/arch/arm/src/common/up_checkstack.c +++ b/arch/arm/src/common/up_checkstack.c @@ -44,27 +44,118 @@ #include #include -#include +#include #include "os_internal.h" #include "up_internal.h" -#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_STACK) +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if !defined(CONFIG_DEBUG) +# undef CONFIG_DEBUG_STACK +#endif + +#if defined(CONFIG_DEBUG_STACK) /**************************************************************************** - * Private Types + * Public Data ****************************************************************************/ /**************************************************************************** * Private Function Prototypes ****************************************************************************/ +/**************************************************************************** + * Name: do_stackcheck + * + * Description: + * Determine (approximately) how much stack has been used be searching the + * stack memory for a high water mark. That is, the deepest level of the + * stack that clobbered some recognizable marker in the stack memory. + * + * Input Parameters: + * alloc - Allocation base address of the stack + * size - The size of the stack in bytes + * + * Returned value: + * The estimated amount of stack space used. + * + ****************************************************************************/ + +size_t do_stackcheck(uintptr_t alloc, size_t size) +{ + FAR uintptr_t start; + FAR uintptr_t end; + FAR uint32_t *ptr; + size_t mark; + + /* Get aligned addresses and adjusted sizes */ + + start = alloc & ~3; + end = (alloc + size + 3) & ~3; + size = end - start; + + /* The ARM uses a push-down stack: the stack grows toward lower addresses + * in memory. We need to start at the lowest address in the stack memory + * allocation and search to higher addresses. The first word we encounter + * that does not have the magic value is the high water mark. + */ + + for (ptr = (FAR uint32_t *)start, mark = (size >> 2); + *ptr == STACK_COLOR && mark > 0; + ptr++, mark--); + + /* If the stack is completely used, then this might mean that the stack + * overflowed from above (meaning that the stack is too small), or may + * have been overwritten from below meaning that some other stack or data + * structure overflowed. + * + * If you see returned values saying that the entire stack is being used + * then enable the following logic to see it there are unused areas in the + * middle of the stack. + */ + +#if 0 + if (mark + 16 > nwords) + { + int i, j; + + ptr = (FAR uint32_t *)start; + for (i = 0; i < size; i += 4*64) + { + for (j = 0; j < 64; j++) + { + int ch; + if (*ptr++ == STACK_COLOR) + { + ch = '.'; + } + else + { + ch = 'X'; + } + + up_putc(ch); + } + + up_putc('\n'); + } + } +#endif + + /* Return our guess about how much stack space was used */ + + return mark << 2; +} + /**************************************************************************** * Global Functions ****************************************************************************/ /**************************************************************************** - * Name: up_check_stack + * Name: up_check_stack and friends * * Description: * Determine (approximately) how much stack has been used be searching the @@ -81,58 +172,7 @@ size_t up_check_tcbstack(FAR struct tcb_s *tcb) { - FAR uint32_t *ptr; - size_t mark; - - /* The ARM uses a push-down stack: the stack grows toward lower addresses - * in memory. We need to start at the lowest address in the stack memory - * allocation and search to higher addresses. The first word we encounter - * that does not have the magic value is the high water mark. - */ - - for (ptr = (FAR uint32_t *)tcb->stack_alloc_ptr, mark = tcb->adj_stack_size/4; - *ptr == STACK_COLOR && mark > 0; - ptr++, mark--); - - /* If the stack is completely used, then this might mean that the stack - * overflowed from above (meaning that the stack is too small), or may - * have been overwritten from below meaning that some other stack or data - * structure overflowed. - * - * If you see returned values saying that the entire stack is being used - * then enable the following logic to see it there are unused areas in the - * middle of the stack. - */ - -#if 0 - if (mark + 16 > tcb->adj_stack_size/4) - { - int i, j; - - ptr = (FAR uint32_t *)tcb->stack_alloc_ptr; - for (i = 0; i < tcb->adj_stack_size; i += 4*64) - { - for (j = 0; j < 64; j++) - { - int ch; - if (*ptr++ == STACK_COLOR) - { - ch = '.'; - } - else - { - ch = 'X'; - } - up_putc(ch); - } - up_putc('\n'); - } - } -#endif - - /* Return our guess about how much stack space was used */ - - return mark*4; + return do_stackcheck((uintptr_t)tcb->stack_alloc_ptr, tcb->adj_stack_size); } ssize_t up_check_tcbstack_remain(FAR struct tcb_s *tcb) @@ -150,4 +190,16 @@ ssize_t up_check_stack_remain(void) return up_check_tcbstack_remain((FAR struct tcb_s*)g_readytorun.head); } -#endif /* CONFIG_DEBUG && CONFIG_DEBUG_STACK */ +#if CONFIG_ARCH_INTERRUPTSTACK > 3 +size_t up_check_intstack(void) +{ + return do_stackcheck((uintptr_t)&g_intstackalloc, (CONFIG_ARCH_INTERRUPTSTACK & ~3)); +} + +size_t up_check_intstack_remain(void) +{ + return (CONFIG_ARCH_INTERRUPTSTACK & ~3) - up_check_intstack(); +} +#endif + +#endif /* CONFIG_DEBUG_STACK */ diff --git a/arch/arm/src/common/up_initialize.c b/arch/arm/src/common/up_initialize.c index feb5011ce8..2d9bb79887 100644 --- a/arch/arm/src/common/up_initialize.c +++ b/arch/arm/src/common/up_initialize.c @@ -87,6 +87,32 @@ static void up_calibratedelay(void) # define up_calibratedelay() #endif +/**************************************************************************** + * Name: up_color_intstack + * + * Description: + * Set the interrupt stack to a value so that later we can determine how + * much stack space was used by interrupt handling logic + * + ****************************************************************************/ + +#if defined(CONFIG_DEBUG_STACK) && CONFIG_ARCH_INTERRUPTSTACK > 3 +static inline void up_color_intstack(void) +{ + uint32_t *ptr = (uint32_t *)&g_intstackalloc; + ssize_t size; + + for (size = (CONFIG_ARCH_INTERRUPTSTACK & ~3); + size > 0; + size -= sizeof(uint32_t)) + { + *ptr++ = INTSTACK_COLOR; + } +} +#else +# define up_color_intstack() +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -118,6 +144,10 @@ void up_initialize(void) up_calibratedelay(); + /* Colorize the interrupt stack */ + + up_color_intstack(); + /* Add any extra memory fragments to the memory manager */ up_addregion(); diff --git a/arch/avr/src/avr/up_checkstack.c b/arch/avr/src/avr/up_checkstack.c index 07b1f9d141..647b1c99bf 100644 --- a/arch/avr/src/avr/up_checkstack.c +++ b/arch/avr/src/avr/up_checkstack.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/avr/src/avr/up_checkstack.c * - * Copyright (C) 2011, 2013 Gregory Nutt. All rights reserved. + * Copyright (C) 2011, 2013-2014 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -44,26 +44,31 @@ #include #include -#include +#include +#include "up_internal.h" #include "os_internal.h" -#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_STACK) +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if !defined(CONFIG_DEBUG) +# undef CONFIG_DEBUG_STACK +#endif + +#if defined(CONFIG_DEBUG_STACK) /**************************************************************************** - * Private Types + * Public Data ****************************************************************************/ /**************************************************************************** - * Private Function Prototypes + * Private Functions ****************************************************************************/ /**************************************************************************** - * Global Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: up_check_stack + * Name: do_stackcheck * * Description: * Determine (approximately) how much stack has been used be searching the @@ -71,14 +76,15 @@ * stack that clobbered some recognizable marker in the stack memory. * * Input Parameters: - * None + * alloc - Allocation base address of the stack + * size - The size of the stack in bytes * * Returned value: * The estimated amount of stack space used. * ****************************************************************************/ -size_t up_check_tcbstack(FAR struct tcb_s *tcb) +size_t do_stackcheck(uintptr_t alloc, size_t size) { FAR uint8_t *ptr; size_t mark; @@ -93,8 +99,8 @@ size_t up_check_tcbstack(FAR struct tcb_s *tcb) * that does not have the magic value is the high water mark. */ - for (ptr = (FAR uint8_t *)tcb->stack_alloc_ptr, mark = tcb->adj_stack_size; - *ptr == 0xaa && mark > 0; + for (ptr = (FAR uint8_t *)alloc, mark = size; + *ptr == STACK_COLOR && mark > 0; ptr++, mark--); /* If the stack is completely used, then this might mean that the stack @@ -108,15 +114,15 @@ size_t up_check_tcbstack(FAR struct tcb_s *tcb) */ #if 0 - if (mark + 16 > tcb->adj_stack_size) + if (mark + 16 > size) { - ptr = (FAR uint8_t *)tcb->stack_alloc_ptr; - for (i = 0; i < tcb->adj_stack_size; i += 64) + ptr = (FAR uint8_t *)alloc; + for (i = 0; i < size; i += 64) { for (j = 0; j < 64; j++) { int ch; - if (*ptr++ == 0xaa) + if (*ptr++ == STACK_COLOR) { ch = '.'; } @@ -138,6 +144,31 @@ size_t up_check_tcbstack(FAR struct tcb_s *tcb) return mark; } +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_check_stack and friends + * + * Description: + * Determine (approximately) how much stack has been used be searching the + * stack memory for a high water mark. That is, the deepest level of the + * stack that clobbered some recognizable marker in the stack memory. + * + * Input Parameters: + * None + * + * Returned value: + * The estimated amount of stack space used. + * + ****************************************************************************/ + +size_t up_check_tcbstack(FAR struct tcb_s *tcb) +{ + return do_stackcheck((uintptr_t)tcb->stack_alloc_ptr, tcb->adj_stack_size); +} + ssize_t up_check_tcbstack_remain(FAR struct tcb_s *tcb) { return (ssize_t)tcb->adj_stack_size - (ssize_t)up_check_tcbstack(tcb); @@ -153,4 +184,17 @@ ssize_t up_check_stack_remain(void) return up_check_tcbstack_remain((FAR struct tcb_s*)g_readytorun.head); } -#endif /* CONFIG_DEBUG && CONFIG_DEBUG_STACK */ +#if CONFIG_ARCH_INTERRUPTSTACK > 3 +size_t up_check_intstack(void) +{ + uintptr_t start = (uintptr_t)g_intstackbase - (CONFIG_ARCH_INTERRUPTSTACK & ~3); + return do_stackcheck(start, (CONFIG_ARCH_INTERRUPTSTACK & ~3)); +} + +size_t up_check_intstack_remain(void) +{ + return (CONFIG_ARCH_INTERRUPTSTACK & ~3) - up_check_intstack(); +} +#endif + +#endif /* CONFIG_DEBUG_STACK */ diff --git a/arch/avr/src/common/up_initialize.c b/arch/avr/src/common/up_initialize.c index 89840dfaf7..69f58ec332 100644 --- a/arch/avr/src/common/up_initialize.c +++ b/arch/avr/src/common/up_initialize.c @@ -132,6 +132,32 @@ static void up_calibratedelay(void) # define up_calibratedelay() #endif +/**************************************************************************** + * Name: up_color_intstack + * + * Description: + * Set the interrupt stack to a value so that later we can determine how + * much stack space was used by interrupt handling logic + * + ****************************************************************************/ + +#if defined(CONFIG_DEBUG_STACK) && CONFIG_ARCH_INTERRUPTSTACK > 3 +static inline void up_color_intstack(void) +{ + uint8_t *ptr = (uint8_t *)&g_intstackalloc; + ssize_t size; + + for (size = (CONFIG_ARCH_INTERRUPTSTACK & ~3); + size > 0; + size -= sizeof(uint8_t)) + { + *ptr++ = INTSTACK_COLOR; + } +} +#else +# define up_color_intstack() +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -163,6 +189,10 @@ void up_initialize(void) up_calibratedelay(); + /* Colorize the interrupt stack */ + + up_color_intstack(); + /* Add any extra memory fragments to the memory manager */ up_addregion(); diff --git a/include/nuttx/arch.h b/include/nuttx/arch.h index 13336ae8ba..dceee8ab15 100644 --- a/include/nuttx/arch.h +++ b/include/nuttx/arch.h @@ -1059,10 +1059,14 @@ void irq_dispatch(int irq, FAR void *context); #if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_STACK) struct tcb_s; -size_t up_check_tcbstack(FAR struct tcb_s *tcb); +size_t up_check_tcbstack(FAR struct tcb_s *tcb); ssize_t up_check_tcbstack_remain(FAR struct tcb_s *tcb); -size_t up_check_stack(void); +size_t up_check_stack(void); ssize_t up_check_stack_remain(void); +#if CONFIG_ARCH_INTERRUPTSTACK > 3 +size_t up_check_intstack(void); +size_t up_check_intstack_remain(void); +#endif #endif /****************************************************************************