Logiciels Libres et Systèmes Embarqués


4.8. Débogage

L'affichage des informations de débogage est contrôlé par les macros suivantes dans le fichier include/configs/ml300.h :

#define DEBUG           // pour u-boot en générale
#define ET_DEBUG        // pour l'interface réseaux
#define DEBUG_SYSTEMACE // pour le SystemACE

Etant donné que U-Boot est un projet indépendant de Xilinx, on ne peut pas utiliser facilement EDK pour le déboguer, il est préférable de le faire en utilisant directement les outils de base. Donc pour déboguer, il faut avant tout lancer XMD et exécuter les commandes suivantes :

bash# xmd
XMD% ppconnect
XMD% dow u-boot

Puis, il faut lancer GDB que l'on doit attacher à XMD, puis charger la table des symboles de U-Boot pour la phase avant relocation, ensuite placer un point d'arrêt matériel et enfin lancer l'exécution de U-Boot:

bash# powerpc-eabi-gdb --nw
(gdb) target remote :1234
(gdb) add-symbol-file  /U-Boot/u-boot 0x00010000
(gdb) monitor bps 0x00010100 hw
(gdb) continue

Pour avancer dans le code de U-Boot en exécution, il est préférable d'utiliser la commande stepi de GDB qui exécute la prochaine instruction puis s'arrête. Si on souhaite avancer de plusieurs instructions d'un seul coup, il vaut mieux utiliser le couple mon bps hw/continue. La commande mon bps hw permet de placer un point d'arrêt processeur, c'est-à-dire que c'est le PowerPC qui va comparer à chaque pas l'adresse de l'instruction en cours avec celle d'un point d'arrêt. Ces points d'arrêt matériels sont en nombre très limité (quatre) mais sont indispensables car les points d'arrêts logiciels (traps) ne marchent pas dans notre cas.

Bien évidemment, il ne faut pas oublier de compiler U-Boot avec les bonnes options, c'est à dire en changeant les deux lignes suivantes dans le fichier config.mk:

DBGFLAGS= -g
OPTFLAGS= -O0

Le fait de changer les options d'optimisation entraîne des problèmes de compilation. En effet, les fonctions déclarées comme extern inline dans board/xilinx/common/xio.h et include/asm/io.h doivent être alors déclarées comme static inline.

Comme nous l'avons vu dans les sections précédentes, U-Boot se copie vers le haut de la RAM puis s'exécute à partir de là. Cette relocation de code fait que le débogueur n'est plus capable de suivre l'exécution du programme puisque la table des symboles n'est plus à jour. Pour remettre à jour cette table, il suffit de regarder lors du démarrage le message indiquant où se reloge U-Boot :

U-Boot relocated to 01fb6000

A partir de là, on peut mettre à jour la table des symboles et mettre un point d'arrêt matériel au début de la fonction board_init_r (0x01fb62d0 dans notre cas) qui est la première fonction appelée après la relocation :

(gdb) symbol-file
(gdb) add-symbol-file u-boot 0x01fb6000
(gdb) mon bps 0x01fb62d0 hw
(gdb) continue

4.8.1. Machine Check Exception

Lors de mes tests, l'exception critique "Machine Check" était levée lorsqu'on la démasquait. D'après les documentations officielles, il semble que se soit l'accès à une donnée vers un périphérique sur le bus PLB qui produise cette exception. Cependant lorsque je vérifiais les registres d'erreurs, rien d'anormal ne s'était produit... Après de nombreux tests, j'ai remarqué que certaines architectures ne produisaient pas cette erreur, mais sans pour autant trouver une logique précise. Après une tentative désespérée, j'ai trouvé la source de l'erreur : elle était provoquée par le débogueur XMD lui-même !

Il existe un défaut de conception dans U-Boot qui a rendu le débogage de ce problème encore plus difficile. En effet, les exceptions sont activées avant que la table des vecteurs d'interruptions ne soit copiée. De ce fait, U-Boot se branchait à une adresse où aucune instruction cohérente n'était présente... La solution consiste à retarder l'activation de ces exceptions. Pour cela, il faut modifier le fichier cpu/ppc4xx/start.S de la manière suivante :

-       addi    r4,r0,0x1000 /* set ME bit (Machine Exceptions)  */
-       oris    r4,r4,0x0002 /* set CE bit (Critical Exceptions) */
-       mtmsr   r4           /* change MSR */
[...]
        cmplw   0, r7, r8
        blt     4b

+       addi    r7,r0,0x1000 /* set ME bit (Machine Exceptions)  */
+       oris    r7,r7,0x0002 /* set CE bit (Critical Exceptions) */
+       mtmsr   r7           /* change MSR */

        mtlr    r4           /* restore link register            */
        blr

Si on souhaite ne pas avoir de problème avec cette exception "Machine Check" factice, il suffit de commenter la ligne l'activant. Attention, il faut le faire uniquement lors des phases de débogage, je conseille donc d'utiliser une macro à définir dans le fichier de configuration et de modifier le fichier cpu/ppc/start.S :

+ #ifndef USE_DEBUGGER
      addi r7,r0,0x1000 /* set ME bit (Machine Exceptions) */
+ #endif

4.8.2. Compilation avec des outils récents

U-Boot utilise la variable __u_boot_cmd_start pour pointer sur la section contenant la table des commandes, utilisée lors de la relocation. Cependant, les nouvelles versions des outils de développement ajoutent des sections (.data.rel et .data.rel.local) afin d'effectuer certaines optimisations. Cela interfère avec le fonctionnement de U-Boot et le fait donc boguer... Après quelques lectures sur la syntaxe des scripts de l'éditeur de liens, j'ai trouvé une solution, il suffit de modifier board/xilinx/ml300/u-boot.lds de la manière suivante :

- __u_boot_cmd_start = .;
+ __u_boot_cmd_start = ADDR(.u_boot_cmd);
  .u_boot_cmd : { *(.u_boot_cmd) }
  __u_boot_cmd_end = .;

4.8.3. Désactivation du DCR

La macro CFG_CMD_SETGETDCR est mal utilisée, il faut modifier le fichier common/cmd_dcr.c de la manière suivante :

- #if defined(CONFIG_4xx) && defined(CFG_CMD_SETGETDCR)
+ #if defined(CONFIG_4xx) && (CONFIG_COMMANDS & CFG_CMD_SETGETDCR)