Forum: Compiler & IDEs Stackinhalt ausgeben in WDT-ISR


von Stack (Gast)


Lesenswert?

Hallo zusammen,

ich habe sporadische Hänger eines C-Programms (ein Tag bis eine Woche 
fehlerfreie Laufzeit) und wollte fragen, ob bzw. wie es möglich ist, zur 
Fehlereingrenzung in der Watchdog-ISR den Stackinhalt auszugeben (UART) 
und/oder ins EEPROM zu verschieben, um festzustellen, wo der Absturz 
erfolgt.

Prozessor ist ATMega 168A, Compiler GCC.

Vielen Dank für Eure Hilfe

Heinz

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Klar, sicher geht das.  Den aktuellen Wert des SP-Registers (SPH/SPL)
hast du ja innerhalb der ISR zur Verfügung, und der Initialwert ist
normalerweise das Ende des SRAMs.  Du könntest also den Speicher von
$SP bis Ende des RAMs dumpen.

von Oliver S. (oliverso)


Lesenswert?

Dazu dann noch ins Disassemblerlistig schauen, ob die ISR Anfang 
Register pusht. Hinter den gepushten Register steht dann die 
Rücksprungadresse.

Oliver

: Bearbeitet durch User
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Die (Wort)Adresse kann man auch erhalten mit

  __builtin_return_address (0)

Eine sinnvolle Stelle, um mit dem Dumpen anzufangen, kann sein

  __builtin_frame_address (0)

Damit enthält das Dump nur die Werte aus dem Frame, die gesicherten 
Register und die Return-Adresse --zumindest für die aktuelle Funktion.

Wie groß der Frame ist und wie viele Register gesichert wurden, lässt 
sich nicht so einfach feststellen.

Für die Anzahl der gesicherten Register:
1
uint8_t volatile stack_usage;
2
3
ISR (WDT_vect)
4
{
5
    asm volatile ("ldi %0, .L__stack_usage" : "=d" (stack_usage));
6
}

Dieser Wert enthält nicht PUSHes, die im Body der aktuellen Funktion 
enthalten sind wie z.B. solche um ein printf.

Man kann diese Größen zwar auch direkt im s-File mit -save-temps 
nachlesen, ist aber nervig wenn sich der Code öfter mal ändert. 
Beispiel:
1
/* prologue: Signal */
2
/* frame size = 0 */
3
/* stack size = 6 */
4
.L__stack_usage = 6

von Oliver S. (oliverso)


Lesenswert?

Johann L. schrieb:
> Die (Wort)Adresse kann man auch erhalten mit
>
>   __builtin_return_address (0)

Funktioniert das im AVR-gcc? Irgendwie meine ich mich zu erinnern, daß 
das früher (?) nicht implementiert war.

Oliver

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Oliver S. schrieb:
> Funktioniert das im AVR-gcc?

Wenn Johann das hier schreibt, würde ich ganz stark davon ausgehen. ;-)

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

__builtin_return_address funktioniert für avr nur mit Argument 0, d.h. 
für die aktuelle Funktion.  Tiefer in die Call-Chain kann man damit 
nicht schauen.

Für AVRs mir 3 Bytes an Return-Adresse funktioniert es ebenfalls nicht, 
denn die Return-Adresse passt dann nicht mehr in 16 Bits rein, was 
avr-gcc eine Warnung wert ist.  Dies ist allerdings erst bei Flash > 
128KiB der Fall, also nicht bei einem ATmega168 mit ledigich 16KiB 
Flash.

Analoges gilt auch für ISRs, zumindest für aktuelle avr-gccs.  Da an der 
Funktionalität schon lange nichts mehr geändert worden ist, sollte das 
Gesagte auch für etwas ältlichere Versionen noch Gültigkeit haben, 
zumindest zurück bis 4.5.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Ist noch von Andy vom 2009-11-15, das wär dann für die 4.5.0:

http://gcc.gnu.org/r154188

Die Funktion (avr.c:avr_return_addr_rtx) ist heute wie damals.

von Stack (Gast)


Lesenswert?

Danke für Eure Hilfe!

Heinz

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.