Usando la siguiente configuración:
Usando JLinkGDBServer y Eclipse como interfaz de depuración, siempre tengo un seguimiento de pila agradable cuando paso por mi código. Cuando utilizo las herramientas Freertos de Code Confidence (complemento de Eclipse), también veo los seguimientos de pila de todos los subprocesos que no se están ejecutando actualmente (sin ese complemento, solo veo el seguimiento de pila del subproceso activo). Hasta aquí todo bien.
Pero ahora, cuando mi aplicación cae en un error grave, se pierde el seguimiento de la pila. Bueno, conozco la técnica sobre cómo averiguar la dirección del código que causa la falla (como se ve aquí ). Pero esta es una información muy pobre en comparación con el stacktrace completo.
Ok, algunas veces, cuando se cae en una falla grave, no hay forma de retener un seguimiento de la pila, por ejemplo, cuando la pila está dañada por el código defectuoso. Pero si la pila está sana, creo que sería posible obtener un seguimiento de la pila (¿no es así?).
Creo que la razón por la que se pierde el seguimiento de la pila cuando se produce un error grave es que la arquitectura Cortex-M3 cambiaría automáticamente el puntero de la pila de PSP a MSP. Una idea ahora es (tal vez) establecer el MSP en el valor de PSP anterior (¿y tal vez tener que hacer alguna preparación de pila adicional?).
¿Alguna sugerencia sobre cómo hacer eso u otros enfoques para retener un seguimiento de pila cuando hay una falla grave?
Editar 2015-07-07, se agregaron más detalles.
Utilizo este código para provocar una falla grave:
__attribute__((optimize("O0"))) static void checkHardfault() { volatile uint32_t* varAtOddAddress = (uint32_t*)-1; (*varAtOddAddress)++; } Al entrar en checkHardfault() , mi stacktrace se ve bien así:
gdb-> backtrace #0 checkHardfault () at Main.cxx:179 #1 0x100360f6 in GetOneEvent () at Main.cxx:185 #2 0x1003604e in executeMainLoop () at Main.cxx:121 #3 0x1001783a in vMainTask (pvParameters=0x0) at Main.cxx:408 #4 0x00000000 in ?? () Cuando me encuentro con el hardfault (en (*varAtOddAddress)++; ) y me encuentro dentro de HardFault_Handler() , el seguimiento de la pila es:
gdb-> backtrace #0 HardFault_Handler () at Hardfault.c:312 #1 <signal handler called> #2 0x10015f36 in prvPortStartFirstTask () at freertos/portable/GCC/ARM_CM3/port.c:224 #3 0x10015fd6 in xPortStartScheduler () at freertos/portable/GCC/ARM_CM3/port.c:301 Backtrace stopped: previous frame inner to this frame (corrupt stack?)La forma más rápida de hacer que el depurador le brinde los detalles del estado anterior a la falla grave es devolver el procesador al estado anterior a la falla grave.
En el depurador, escriba un script que tome la información de los diversos registros de hardware y restaure PC, LR, R0-R14 al estado justo antes de causar la falla grave, luego realice el volcado de pila.
Por supuesto, esto no siempre es útil cuando terminas en la falla principal debido a que se extraen elementos de una pila volada o se pisotean elementos en la memoria. Por lo general, tiende a corromper un montón de registros importantes, regresar a algún lugar loco en la memoria y luego ejecutar lo que sea que esté allí. Puede terminar fallando mucho miles (¿millones?) De ciclos después de que ocurra su problema real.
Considere usar la siguiente macro gdb para restaurar el contenido del registro:
define hfstack set $frame_ptr = (unsigned *)$sp if $lr & 0x10 set $sp = $frame_ptr + (8 * 4) else set $sp = $frame_ptr + (26 * 4) end set $lr = $frame_ptr[5] set $pc = $frame_ptr[6] bt end document hfstack set the correct stack context after a hard fault on Cortex M end