call-stack unwinding in ARM-cortex-m3
Ich würde gern ein debugging-tool, das mir helfen wird, mich besser Debuggen meiner Anwendung.
Ich arbeite bare-bones - (ohne Betriebssystem). mit Hilfe der IAR embedded workbench für Atmel SAM3.
Habe ich ein Watchdog-timer, die fordert, einen bestimmten IRQ im Falle einer Zeitüberschreitung (Dieser wird ersetzt durch einen software-reset on release).
In der IRQ-handler, die ich ausdrucken möchten (UART) der stack-trace, wo genau sich der Watchdog-timeout ist aufgetreten.
Sah ich im web, und ich fand keine Umsetzung dieser Funktionalität.
Jemand eine Idee, wie man zu nähern, diese Art der Sache ?
EDIT: OK, ich habe es geschafft, greifen die return-Adresse vom stack, so dass ich genau weiß, wo die WDT timeout aufgetreten ist.
Abwickeln des gesamten Stapels ist nicht einfach, wie es zunächst erscheint, denn jede Funktion schiebt die unterschiedliche Menge der lokalen Variablen in den stack.
Den code, den ich am Ende dieses (für andere, die finden es vielleicht nützlich)
void WDT_IrqHandler( void )
{
uint32_t * WDT_Address;
Wdt *pWdt = WDT ;
volatile uint32_t dummy ;
WDT_Address = (uint32_t *) __get_MSP() + 16 ;
LogFatal ("Watchdog Timer timeout,The Return Address is %#X", *WDT_Address);
/* Clear status bit to acknowledge interrupt */
dummy = pWdt->WDT_SR ;
}
Du musst angemeldet sein, um einen Kommentar abzugeben.
Es sollte ziemlich geradlinig, um die Folgen der Ausführung. Nicht programmgesteuert in deiner isr...
Wissen wir aus der ARM-ARM, der auf einem Cortex-M3 drückt es xPSR,
ReturnAddress, LR (R14), R12, R3, R2, R1 und R0 auf dem stack. mangles die lr so kann es erkennen, eine Rückkehr vom interrupt ruft dann den Einstiegspunkt aufgelistet in der Vektor-Tabelle. wenn Sie bei der Umsetzung Ihrer isr in asm zu kontrollieren, den stack, können Sie haben eine einfache Schleife, die deaktiviert die interrupt-Quelle (schaltet die wdt, was auch immer, das wird einige Zeit in Anspruch nehmen) geht dann in eine Schleife dump ein Teil des Stapels.
Aus, dass dump sehen Sie die lr - /return-Adresse der Funktion/Anweisung, die unterbrochen wurde, von einer Demontage Ihres Programms können Sie dann sehen, was der compiler hat auf dem Stapel abgelegt, die für jede Funktion, subtrahieren Sie, dass Sie in jeder Phase und gehen so weit zurück, wie Sie möchten oder wie weit zurück, wie Sie abgedruckt haben, der stack-Inhalte.
Könnten Sie auch eine Kopie der stack im ram und sezieren Sie es später eher als solche Dinge tun in eine isr (die Kopie noch zu viel Zeit kostet, aber ist weniger aufdringlich als das warten auf den uart).
Wenn man nach der Adresse der Anweisung, die unterbrochen wurde, das ist die trivialste Aufgabe, gerade gelesen, dass aus dem stack, es wird an einem bekannten Ort, und drucken Sie es aus.
ARM legt ein paar Abschnitte .ARM.exidx und .ARM.extbl, dass genügend Informationen enthalten, um zu entspannen den stack ohne debug-Symbole. Diese Abschnitte existieren für exception-handling, aber Sie können verwenden Sie zum ausführen einer Ablaufverfolgung zu erstellen, wie gut. Add-funwind-Tabellen zu erzwingen, GCC, um diese Abschnitte.
Hörte ich meinen Namen? 🙂
Werden Sie wahrscheinlich benötigen, ein kleines bisschen von inline-assembly. Finden Sie einfach heraus, das format des stack-frames, und die register enthält die gewöhnlichen1 stack-pointer, und übertragen Sie die entsprechenden Werte in C Variablen, aus denen Sie format-strings für die Ausgabe auf den UART.
Sollte es nicht allzu schwierig, aber der Kurs (eher low-level) Sie müssen die Aufmerksamkeit auf die details.
1Als in "nicht-Ausnahme"; nicht sicher, ob der ARM hat verschiedene stacks für ordentlichen code und Ausnahmen, eigentlich.
Dazu mit ARM, Sie müssen, sagen Sie Ihrem compiler generiert stack-frames. Zum Beispiel mit gcc, aktivieren Sie die option
-mapcs-frame
. Es kann nicht die sein, die Sie brauchen, aber dies wird der Anfang sein.Wenn Sie nicht haben, wird es fast unmöglich, sich zu "entrollen" auf dem stack, weil Sie müssen für jede Funktion die genaue stack-Nutzung je nach Parameter und lokale Variablen.
Wenn Sie suchen für einige Beispiel-code, können Sie überprüfen
dump_stack()
im Linux-kernel-Quellen, und finden Sie wieder den zugehörigen Codeabschnitt ausgeführt, für ARM.Ihre watchdog-Zeitgeber ausgelöst werden können an jedem beliebigen Punkt, auch wenn der stack nicht genügend Informationen, um zu entspannen (z.B. stack-Speicher wurde reserviert für register spill, aber die Register nicht kopiert noch).
Für richtig optimierte code, müssen Sie die debug-info, Zeit. Alles, was Sie tun können, von einem watchdog-timer ist ein register und stack-dump in ein format ist maschinenlesbar genug, um die Umwandlung in ein core-dump für
gdb
.