Forum: Compiler & IDEs Bizarrer Firmware crash - ATmega4808. Wie Debuggen?


von Andy P. (andy_p241)


Angehängte Dateien:

Lesenswert?

Es geht um einen Funkempfänger. Die empfangenen Binärdaten werden durch 
einen Decoder geschickt (Deinterleaver, Hamming-Decoder, 
Entschlüsselung) und dann über den seriellen Port ausgegeben. Mein Code 
funktionierte problemlos über Jahre.
Ein kleine Änderung an ganz anderer Stelle führt aber jetzt zum totalen 
Absturz, d.h. die Firmware startet neu. Der Absturz erfolgt wenn ein 
neues Paket empfangen wurde.
Die Änderung ist simpel:
von
1
if (Cfg->InterleaverEnable){...}
auf
1
if (Cfg->FecEnable){...}
Die Stelle im Code wo die Änderung gemacht wurde ist im Sendeteil und 
wird beim Empfangen eines Pakets auch überhaupt nicht durchlaufen. Das 
ist bizarr.
Mein Setup ist Platformio mit MegacoreX im Arduino Framework.
Debuggen, 1. Versuch:
ATMEL-ICE, avr-gdb und VSCode. Die Tatsache, dass der Code im Debug 
Modus kompiliert wird, kaschiert den Absturz, alles läuft problemlos.
Debuggen, 2. Versuch. Im release Modus kompilieren und mit assert() 
herausfinden, wo genau der Absturz passiert: Der Decoder wird problemlos 
durchlaufen, aber der Rücksprung in die Hauptschleife führt zum Absturz. 
Irgendetwas im Decoder scheint den Programmzeiger zu überschreiben. Das 
ist bizarr. Ich vermute ein Problem im Decoder, finde das Leck aber 
nicht. Hier wäre ich für Hilfe und/oder Tipps dankbar. Ich hänge den 
Decoder hier an, das gesamte Projekt ist hier: 
https://github.com/nurazur/TiNo2

Frage: Wie kann ich das Debuggen? Wie kann eine so kleine Änderung an 
komplett anderer Stelle einer Firmware so etwas bewirken? Kann es sein 
dass der Compiler (Version gnu++17) - aus welchem Grund auch immer - 
schuld ist?
von Thorsten S. (thosch)


Lesenswert?

klingt sehr nach Puffer-Überlauf. Also ein Schreiben in ein Array über 
die Länge hinweg.
von Andras H. (andras_h)


Lesenswert?

Stack overflow?

Nmi?
von Udo S. (urschmitt)


Lesenswert?

Andy P. schrieb:
> Frage: Wie kann ich das Debuggen?

Alle Warnings einschalten und die Warnings durchgehen und möglichst alle 
beseitigen.
Parameter "-fsanitize=address" des compilers nutzen
Tools wie cppcheck.
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Andy P. schrieb:
> release Modus kompilieren und mit assert()

Meistens sind im Release Modus die Assertions deaktiviert (NDEBUG 
Makro).
von Andy P. (andy_p241)


Lesenswert?

Niklas G. schrieb:
> Meistens sind im Release Modus die Assertions deaktiviert (NDEBUG
> Makro).
Danke, Assertions sind aktiviert, funktionieren.
von Andy P. (andy_p241)


Lesenswert?

Udo S. schrieb:
> Alle Warnings einschalten und die Warnings durchgehen und möglichst alle
> beseitigen.
> Parameter "-fsanitize=address" des compilers nutzen
> Tools wie cppcheck.

Danke für die Tips.
1
build_flags = -Wall
 ist in platform.ini immer gesetzt.
Alle Warnings sind beseitigt, das mache ich für Releases sowieso.
Die beiden anderen Tips werde ich probieren und hier berichten.
von Nick (b620ys)


Lesenswert?

Andy P. schrieb:
> Frage: Wie kann ich das Debuggen? Wie kann eine so kleine Änderung an
> komplett anderer Stelle einer Firmware so etwas bewirken?

Üblicherweise ein "dangling pointer" oder "out of bounds"-Zugriff.
Indiz für "out of bounds" ist es, wenn der Fehler nicht mehr auftritt, 
nachdem man Variablen umsortiert oder filler dazwischen einfügt. Das ist 
aber schon eine Verzweiflungstat.

Andy P. schrieb:
> Kann es sein
> dass der Compiler (Version gnu++17) - aus welchem Grund auch immer -
> schuld ist?

Die Wahrscheinlichkeit ist 0.0000000000000001%

Dein code ist etwas seltsam geschrieben, ich bekomm da oft Stirnrunzeln.
von Andreas M. (amesser)


Lesenswert?

ich sehe in deinen Funktionen intensive Stacknutzung, das kann in die 
Hose gehen:
1
radio_send:
2
3
unsigned char tinytx_encrypt[datalen];
4
unsigned char tinytx_fec[datalen*2];
5
6
interleave_
7
unsigned char d[rows]; / worstcase rows = datalen *2

Wenn ich richtig sehe ist datalen max. 12, d.h. alleine hier werden 
schon 60 Byte Stack verbraten. Dann die tiefe Verschachtelung... Es kann 
gut sein, das der gcc beim vorherigen code erkannt hat, das der Pfad nie 
aktiv war und deswegen z.B. tinytx_fec immer weg optimiert hat.

Schau Dir mal das gcc flag "-fstack-usage" an. Der GCC erstellt dann 
eine Datei mit Informationen zum Stackbedarf der einzelnen Funktionen. 
Musst du dann entsprechend der Aufrufschachtelung zusammenrechnen, gibt 
auch fertige Tools für: https://github.com/HBehrens/puncover/
: Bearbeitet durch User
von Andy P. (andy_p241)


Lesenswert?

Nick schrieb:

> Üblicherweise ein "dangling pointer" oder "out of bounds"-Zugriff.
> Indiz für "out of bounds" ist es, wenn der Fehler nicht mehr auftritt,
> nachdem man Variablen umsortiert oder filler dazwischen einfügt. Das ist
> aber schon eine Verzweiflungstat.
tatsächlich hilft der Austausch der beiden If statements in meinem 
Eingangs Post. Filler helfen leider nicht. Also haben wir es 
wahrscheinlich mit 'out of bounds' zu tun.
> Dein code ist etwas seltsam geschrieben, ich bekomm da oft Stirnrunzeln.
Ich bin immer offen für Verbesserungsvorschläge und/oder konstruktiver 
Kritik. Du darfst also gerne konkreter werden. Der Code ist über 13 
Jahre von einem kleinen ATtiny84 Projekt über den ATmega328P, den 
ATmega4808, und zuletzt bis zum AVR64DD32 gewachsen und angepasst 
worden, wurde 100+ mal gepatcht und sieht garantiert nicht mehr wie vom 
Reißbrett entwickelt aus. Ursprünglich wollte ich vom ATmega328P 
ausgehend das Projekt auf ATMEL Studio übertragen, aber der Import hat 
überhaupt nicht funktioniert. Was bleibt wäre das Ganze von Grund auf 
neu zu konzipieren, gleich mit MPLAB anzufangen und konsequent in C zu 
programmieren.
von Andy P. (andy_p241)


Lesenswert?

Thorsten S. schrieb:
> klingt sehr nach Puffer-Überlauf. Also ein Schreiben in ein Array über
> die Länge hinweg.
Ok, ich habe die Größe aller infrage kommenden Arrays verdoppelt. Keine 
Veränderung, leider.
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Udo S. schrieb:
> Parameter "-fsanitize=address" des compilers nutzen

Nicht wirklich: ATmega4808
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Andy P. schrieb:
> Debuggen, 2. Versuch. Im release Modus kompilieren und mit assert()
> herausfinden, wo genau der Absturz passiert:

Warum nicht einfach den Release Code debuggen?

Dee Fehler klingt stark nach Buffer Overflow, also Rücksprungadresse auf 
dem Stack überschrieben. Lokale Arrays mit variabler Länge (!!) sind 
tückisch, ganz besonders auf dem AVR.

Vergleiche doch mal das Disassembly der beiden Versionen.Prpfe ob der 
Empfangsteil wirklich unverändert übersetzt wird.

Andy P. schrieb:
> Was bleibt wäre das Ganze von Grund auf neu zu konzipieren, gleich mit
> MPLAB anzufangen und konsequent in C zu programmieren.

C++ ist hier sicherlich nicht schuld... Also wenn schon Neuanfang, dann 
auf ARM Cortex -M, da hast du viel mehr Leistung und kannst komfortabel 
debuggen.

Ist aber wahrscheinlich nicht nötig. Debugge den Release Code (mit -g3 
kompilieren), das sollte helfen.
von Nick (b620ys)


Lesenswert?

Andy P. schrieb:
> tatsächlich hilft der Austausch der beiden If statements in meinem
> Eingangs Post.

Naja, da wird anderer code aufgerufen. Also liegt das Problem in dem neu 
aufgerufenen code.

Andy P. schrieb:
> Du darfst also gerne konkreter werden.

Danke. :-)
Ich geh morgen drauf ein. Dazu wird es mir heute sonst zu spät.

Andy P. schrieb:
> Was bleibt wäre das Ganze von Grund auf
> neu zu konzipieren, gleich mit MPLAB anzufangen und konsequent in C zu
> programmieren.

Hmm ... wenns im Prinzip läuft, warum ändern? Ausser du willst das 
übungshalber machen. Und wenns in C++ ist, dann bleib halt dabei.
Ich hätte es in MPLAB-X aufgesetzt, aber das ist für dein Problem 
absolut nicht relevant.

NB:
Andere haben es auch schon angemerkt. Setz mal den Stack hoch. 
Vorsichtshalber nah ans Maximum bei dem es noch compiliert werden kann.
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.