- rapports de plantage
- esp32
- débogage
- trace d’appels
- logiciel embarqué
Lire une trace d’appels après un plantage : comprendre les panics ESP32 sans deviner

Un rapport de panic semble assez précis pour inviter aux suppositions : un nom d’exception, une valeur de registre et une colonne d’adresses hexadécimales. La réponse utile est plus ciblée : déterminez ce que l’exception prouve, faites correspondre la trace d’appels à l’image exacte du micrologiciel, puis vérifiez la cause probable la moins coûteuse avant de changer du matériel.
Capturez d’abord le rapport de plantage complet
Conservez la sortie série depuis la première ligne du panic jusqu’au message de redémarrage. Une trace d’appels partielle est souvent pire que l’absence de trace, parce qu’elle encourage un diagnostic affirmé fondé sur des éléments manquants.
Pour un rapport Guru Meditation ESP32, conservez ces champs :
- Le type d’exception, comme
LoadProhibited,StoreProhibited,LoadStoreErrorouIllegalInstruction. PC, le compteur de programme où le processeur s’est arrêté.EXCVADDR, l’adresse concernée par l’exception sur les cibles ESP32 fondées sur Xtensa.- Le vidage des registres.
- Chaque ligne de
Backtrace. - L’identifiant de compilation du micrologiciel, la cible de la carte, les paramètres du compilateur et la révision du code source.
Les noms exacts des champs varient selon la famille de puces et le cadre logiciel. Les ESP32 classiques, ESP32-S2, ESP32-S3 et ESP32-C3 n’utilisent pas tous le même cœur de processeur; n’appliquez donc pas une interprétation Xtensa à un rapport RISC-V. Le principe reste le même : capturez le rapport d’exception du processeur et faites-le correspondre au micrologiciel qui était en cours d’exécution.
Ne commencez pas par accuser le dernier périphérique que vous avez branché. Un mauvais capteur peut déclencher un chemin de code qui révèle un problème de pointeur, mais le rapport de panic fournit des éléments sur l’instruction qui a échoué, pas une liste de pièces.
Faites correspondre la trace d’appels au binaire exact
Une trace d’appels après un plantage est une liste d’adresses qui doit être résolue avec le binaire exact qui était en cours d’exécution pour être utile. Une compilation différente, même à partir d’un code source inchangé, peut déplacer suffisamment les fonctions pour produire de mauvais noms ou numéros de ligne. Les indicateurs de compilation, la disposition à l’édition de liens, la version du compilateur, la disposition des partitions et l’optimisation comptent tous.
Conservez le fichier ELF produit par la même compilation que le micrologiciel téléversé. Le fichier .bin est celui que l’appareil démarre, mais l’ELF contient normalement les symboles et les informations de lignes de débogage nécessaires à un décodeur de trace d’appels. Si le système de compilation possède un décodeur d’exception intégré, donnez-lui l’ELF correspondant plutôt qu’une recompilation ultérieure.
Pour une vérification manuelle, la forme générale est :
xtensa-esp32-elf-addr2line -pfiaC -e firmware.elf 0x4008xxxx 0x400dxxxx
Utilisez la chaîne d’outils qui correspond à la cible. Un ESP32-C3 nécessite le addr2line RISC-V approprié, et non un exécutable Xtensa. Les adresses d’un panic peuvent comprendre des régions de ROM, de chargeur de démarrage, de cadre logiciel et d’application. Les adresses de l’application devraient être résolues vers votre code source lorsque les symboles correspondent; les trames de ROM peuvent être résolues uniquement vers une étiquette de bibliothèque ou rester opaques.
La première trame n’est pas toujours le problème. Le compteur de programme identifie l’instruction qui s’est arrêtée. Les trames suivantes montrent comment l’exécution y est arrivée. Une chaîne d’appels qui se termine dans une fonction de journalisation peut signifier que le journaliseur a échoué, ou qu’il s’agit du chemin qui a signalé une erreur antérieure. Lisez l’instruction et la chaîne d’appels ensemble.
Si chaque adresse est résolue en ??:0, vérifiez les éléments suivants avant d’interpréter le résultat :
- Vous avez utilisé l’ELF d’une autre compilation.
- Le décodeur d’adresses vise la mauvaise variante ESP32.
- Le micrologiciel a été téléversé avec un décalage ou une image qui ne correspond pas au fichier décodé.
- Les symboles de débogage ou les tables de lignes ont été supprimés.
- Le texte du panic a été copié incorrectement.
Lisez l’exception comme un indice pour réduire les possibilités
Le type d’exception ne nomme pas le problème complet. Il identifie la catégorie d’opération du processeur qui n’a pas pu être effectuée. Utilisez-le pour choisir le premier test, et non pour éviter les tests.
| Type d’exception ou indice | Indice technique sur l’adresse | Premier élément à tester | Test de confirmation |
|---|---|---|---|
LoadProhibited | Lecture à partir d’une adresse invalide; une adresse très basse suggère fortement un déréférencement de pointeur nul | Pointeur d’objet non initialisé, effacé ou défaillant | Journalisez le pointeur juste avant l’appel qui échoue et ajoutez une vérification explicite de valeur nulle |
StoreProhibited | Écriture vers une adresse invalide; une adresse très basse suggère fortement un déréférencement de pointeur nul | Pointeur de destination nul, périmé ou corrompu | Journalisez la destination et vérifiez la durée de vie de l’objet au point d’écriture |
LoadStoreError | Les règles d’alignement, de largeur ou de région mémoire ont été enfreintes sur les cibles qui signalent cette exception | Données compactées (packed), conversions invalides ou largeur d’accès non prise en charge | Remplacez la conversion par un accès à un champ correctement aligné et comparez le comportement |
IllegalInstruction | Le compteur de programme ne contient pas d’instruction valide pour le processeur | Adresse de retour corrompue, pointeur de fonction incorrect, mauvaise image ou binaire incompatible | Confirmez l’image téléversée et examinez la chaîne d’appels autour du retour ou de l’appel indirect |
| Réinitialisation par chien de garde | Habituellement, aucune adresse d’erreur utile; une tâche ou une interruption n’a pas rendu la main | Boucle infinie, section critique bloquée ou travail effectué dans un gestionnaire d’interruption | Ajoutez des marqueurs de progression et mesurez la durée de la tâche ou du gestionnaire |
Une exception de lecture ou d’écriture à une adresse très basse est la signature d’un déréférencement de pointeur nul. Sur un système 32 bits typique, un accès à un membre comme object->field peut échouer à une petite adresse non nulle parce que le décalage du champ est ajouté à une base nulle. Cela pointe d’abord vers object == nullptr, et non vers une puce de mémoire vive défectueuse.
La valeur de EXCVADDR aide à distinguer les cas. Une valeur nulle ou basse appuie la théorie d’une base nulle. Une adresse variable et invraisemblable pointe davantage vers une corruption de mémoire, un indice hors limites, l’utilisation d’un objet après sa libération ou un pointeur de fonction remplacé par des données parasites. Le vidage des registres et l’expression source doivent tout de même concorder avant d’accepter la théorie.
Pour IllegalInstruction, vérifiez l’image du micrologiciel et la cause de la réinitialisation avant de réécrire la logique de l’application. Une image flash corrompue, un appel par l’intermédiaire d’un pointeur de fonction endommagé, une corruption de pile ou une exécution qui revient par une adresse écrasée peuvent tous mener à cette catégorie. Sur une famille de puces dotée d’un jeu d’instructions différent, une image conçue pour la mauvaise cible est une explication particulièrement directe.
Testez les causes dans l’ordre qui permet d’économiser les pièces
Commencez par le changement le moins coûteux qui peut réfuter la cause la plus probable. Notre séquence habituelle est la suivante :
- Reproduisez le problème avec la même entrée. Notez si le plantage nécessite un démarrage à froid, une commande particulière, une activité Wi-Fi, une réponse de capteur ou une longue durée de fonctionnement. Une erreur qui survient pendant la même opération est plus facile à isoler qu’une erreur qui apparaît simplement après une heure.
- Ajoutez une journalisation ciblée. Affichez les valeurs des pointeurs, les longueurs de tampons, les indices, les changements d’état et les codes de retour immédiatement avant la ligne source résolue. Évitez de journaliser dans une interruption soupçonnée ou dans du code qui pourrait déjà manquer d’espace sur la pile.
- Vérifiez chaque allocation et chaque recherche. Testez le résultat de
malloc, denew, de la création d’une file, de la recherche d’un descripteur, de l’ouverture d’un fichier et de l’initialisation d’un pilote avant de les utiliser. Une allocation échouée ou un descripteur manquant devient souvent un déréférencement de pointeur nul plusieurs appels plus tard. - Vérifiez les limites et les durées de vie. Comparez chaque indice à la longueur réelle du tampon, et non à une constante copiée d’une version précédente. Confirmez qu’une tâche, un rappel ou une interruption ne peut pas utiliser un objet après que la tâche qui le possède l’a libéré ou remplacé.
- Réduisez la concurrence. Désactivez temporairement un rappel, une minuterie, une tâche ou un chemin réseau à la fois. Si le panic disparaît, ajoutez une synchronisation ou placez l’état partagé derrière une règle de propriété définie. Ne considérez pas sa disparition comme une preuve que le périphérique désactivé est défectueux.
- Vérifiez la marge disponible sur la pile. Un écrasement de pile peut corrompre les adresses de retour et donner à l’exception éventuelle une apparence sans rapport. Utilisez la fonction de marque de niveau maximal du cadre logiciel pour chaque tâche et effectuez des tests avec la vérification de pile activée lorsque la cible et le cadre logiciel la prennent en charge.
- Examinez le matériel seulement ensuite. Confirmez la tension d’alimentation sous charge, la cause de la réinitialisation, les branchements des câbles et les niveaux de signal. Remplacez un module uniquement lorsque le test logiciel isole ce module ou qu’une mesure indépendante montre qu’il est défaillant.
Un test contrôlé utile consiste à remplacer une entrée réelle par une valeur fixe tout en laissant le même chemin de code actif. Si le plantage demeure à la même instruction résolue, le périphérique d’entrée est moins probablement en cause que la gestion du pointeur ou du tampon. Si le plantage se déplace ou disparaît, examinez l’analyse, les unités, les vérifications de plage et la synchronisation autour de cette entrée.
Ne « corrigez » pas un pointeur nul en ajoutant une protection qui ignore silencieusement l’opération et poursuit l’exécution. Cela peut convenir à un objet facultatif, mais peut aussi dissimuler une initialisation échouée et laisser le système dans un état qui corrompra ensuite les données. Faites en sorte que la protection signale la dépendance manquante ou arrête délibérément la tâche concernée.
Rendez le prochain rapport plus utile
Une fois l’erreur immédiate comprise, améliorez les éléments probants pour la prochaine erreur. Conservez les artefacts de compilation avec l’image de production, incluez une révision du code source dans le journal de démarrage et intégrez la cause de la réinitialisation aux diagnostics de démarrage. Un petit identifiant de compilation affiché au démarrage évite de passer des heures à décoder le mauvais ELF.
Pour les erreurs qui ne se reproduisent pas avec la journalisation normale, utilisez un tampon circulaire en mémoire vive ou flash pour de courts enregistrements d’événements plutôt que d’afficher chaque opération. Enregistrez les changements d’état, les échecs de file, les échecs d’allocation et les marqueurs de progression du chien de garde. La journalisation modifie la synchronisation, l’utilisation de la pile et la pression exercée sur les tampons; traitez donc un plantage qui disparaît comme un indice de synchronisation plutôt que comme une réparation.
La meilleure correction se trouve généralement à la première hypothèse invalide : vérifiez la valeur de retour, définissez la propriété, imposez la limite du tampon ou corrigez la compilation cible. Remplacer la carte est la réponse coûteuse à un rapport qui pointe déjà vers un problème au niveau du code source.
Questions fréquentes
Que signifie EXCVADDR: 0x00000000 sur un ESP32?
Sur les cibles ESP32 fondées sur Xtensa, cela signifie que l’opération mémoire interrompue faisait référence à l’adresse zéro. Avec LoadProhibited ou StoreProhibited, c’est une preuve solide d’un déréférencement de pointeur nul. Résolvez le compteur de programme et examinez le pointeur utilisé par cette instruction avant de remplacer le matériel.
Puis-je décoder une trace d’appels ESP32 sans le code source original?
Vous pouvez souvent récupérer les noms de fonctions et les numéros de ligne à partir de l’ELF correspondant, même sans les fichiers source sur la machine actuelle. Sans symboles de débogage correspondants, vous pourriez n’obtenir que des adresses. Un ELF recompilé ne constitue pas un remplacement sûr, à moins qu’il provienne exactement des mêmes intrants de compilation et de la même configuration cible.
Pourquoi l’ESP32 plante-t-il seulement après un certain temps de fonctionnement?
Les plantages différés sont souvent liés à une condition cumulative : une fuite, une écriture hors limites, l’épuisement de la pile, l’accumulation dans une file ou une situation de concurrence entre des tâches et des rappels. Capturez au fil du temps la mémoire libre, les marques de niveau maximal de la pile des tâches, la profondeur des files et la cause de la réinitialisation. Le délai indique le moment où l’état corrompu devient visible, pas nécessairement celui où il a été créé.
Nous fabriquons des appareils électroniques et des logiciels sur mesure, faits sur commande par l’intermédiaire de The Boss Factory.
Services associés
Tous les services →Vous avez un projet en tête?
Dites-nous ce que vous voulez faire fabriquer — nous répondons en 24 à 48 heures.
