Ce didacticiel est destiné aux nouveaux utilisateurs de la Simple Virtual Machine.
Dans ce didacticiel, vous allez piloter le débugueur de la machine depuis le code.
Le temps de lecture de ce didacticiel est estimé à 20 minutes si les didacticiels numéros 2 et 3 ont été lus auparavant.
Pour ce didacticiel, nous utiliserons l'application ci-dessous mise dans le fichier exécutable debugueur.svm :
#!/usr/bin/env svm
DESCRIPTION
Debugger control
END
LOG
DEBUG "Debugger" STYLE "default"
PLUGIN "svmcom.so"
PLUGIN "svmint.so"
ARGUMENT INT nb
PROCESS "debugger"
CODE "main" INLINE
:shift &nb
:memory INT/i, INT*@&nb/t
1 -> &i
1 -> &t
:label compute
:int.mul @((t/@&i)-1) @&i -> (t/@&i)
:shift &i
:goto compute :when @&i IN t
1 -> &i
:label display
:com.message @(t/@&i)
:shift &i
:goto display :when @&i IN t
END
MEMORY nb
END
Comme pour le didacticiel 3, ajoutez à cette application un point d'arrêt au début du code de l'application :
#!/usr/bin/env svm
DESCRIPTION
Debugger control
END
LOG
DEBUG "Debugger" STYLE "default"
PLUGIN "svmcom.so"
PLUGIN "svmint.so"
ARGUMENT INT nb
PROCESS "debugger"
CODE "main" INLINE
:debug BREAK
:shift &nb
:memory INT/i, INT*@&nb/t
1 -> &i
1 -> &t
:label compute
:int.mul @((t/@&i)-1) @&i -> (t/@&i)
:shift &i
:goto compute :when @&i IN t
1 -> &i
:label display
:com.message @(t/@&i)
:shift &i
:goto display :when @&i IN t
END
MEMORY nb
END
Maintenant, lancez l'application avec le débugueur :
./debugueur.svm -d 8080 10
Dans la fenêtre des points d'arrêts, on trouve :
Nous avons déjà vu ce mécanisme à l'œuvre dans le didacticiel numéro 3 sans aucune explication.
En réalité, lorsque la machine est lancée en mode débugueur, elle ne s'arrête pas automatiquement avant la première instruction car cela n'est pas toujours souhaitable.
Il faut donc indiquer à la machine où arrêter l'exécution du code. Pour cela, il existe une instruction dédiée : :debug
La forme la plus simple de point d'arrêt est obtenue en ajoutant le paramètre BREAK
comme ci-dessus. Cela indique au processeur de s'arrêter (uniquement lorsque le débugueur est actif) sur cette instruction, et d'afficher ce point d'arrêt dans l'interface utilisateur.
Grâce à ce mécanisme, il est possible de placer un point d'arrêt n'importe où dans le code. En particulier, sur la portion de code dont l'exécution doit être surveillée de près.
Enlevez le point d'arrêt précédent, et placez un autre point d'arrêt comme indiqué ci-dessous :
#!/usr/bin/env svm
DESCRIPTION
Debugger control
END
LOG
DEBUG "Debugger" STYLE "default"
PLUGIN "svmcom.so"
PLUGIN "svmint.so"
ARGUMENT INT nb
PROCESS "debugger"
CODE "main" INLINE
:shift &nb
:memory INT/i, INT*@&nb/t
1 -> &i
1 -> &t
:label compute
:int.mul @((t/@&i)-1) @&i -> (t/@&i)
:shift &i
:goto compute :when @&i IN t
:debug BREAK "display"
1 -> &i
:label display
:com.message @(t/@&i)
:shift &i
:goto display :when @&i IN t
END
MEMORY nb
END
Puis, relancez l'application avec le débugueur :
./debugueur.svm -d 8080 10
Dans la fenêtre des points d'arrêts, on trouve maintenant :
Cette fois, le point d'arrêt affiché contient le texte "display", ce qui est fort utile pour déterminer quel point d'arrêt a été atteint lorsque plusieurs ont été définis.
Ouvrez maintenant le processeur, le code et la mémoire :
L'exécution s'est bien arrêtée au milieu du code, avec en mémoire les valeurs calculées lors de la première partie du code. La seconde partie du code peut immédiatement être exécutée pas à pas !
L'exécution du code peut être arrêtée en insérant l'instruction :debug BREAK
au point voulu dans le code.
Les points d'arrêt peuvent être :
Lancez l'application sans le mode débugueur avec zéro en argument :
./debugueur.svm 0
Et là, le résultat n'est pas celui attendu :
### Simple Virtual Machine 1234 : PROCESS debugger | 2023-01-01 00:00:00 GMT ########################################################################
Kernel interrupted: @(main, line 6) Interruption MEMORY not handled: Index 1 is outside pointer &2*1.
Core dump:
Kernel:
State: I, transmit_interruption, interrupted @(main, line 6) Interruption MEMORY not handled: Index 1 is outside pointer &2*1.
Processor:
State:
Next instruction: <main:1/5> (Current one: <main:1/4>)
Current memory : &0*0
Allocated memory: &1*2
Aliases : i t
Flags :
Cascaded flags :
Local interruption handlers:
Cascaded local interruption handlers:
Saved states:
Global interruption handlers:
Code at <main:1/4>:
:shift &nb # <0> @(main, line 1)
:memory INT/i , INT*@&nb/t # <1> @(main, line 2)
1 -> &i # <2> @(main, line 3)
1 -> &t # <3> @(main, line 4)
:label compute
====== HERE ======
:int.mul @((t/@&i)-1) @&i -> (t/@&i) # <4> @(main, line 6)
==================
:shift &i # <5> @(main, line 7)
:goto compute :when @&i IN t # <6> @(main, line 8)
:debug BREAK "display" # <7> @(main, line 9)
1 -> &i # <8> @(main, line 10)
:label display
:com.message @(t/@&i) # <9> @(main, line 12)
:shift &i # <10> @(main, line 13)
:goto display :when @&i IN t # <11> @(main, line 14)
Labels:
compute -> <4>
display -> <9>
Symbols:
Memory:
&0: INT 1
&1: INT 1
&2: INT 1
Aliases:
i -> &1*1
nb -> &0*1
t -> &2*1
Free space:
### Simple Virtual Machine 1234 : SYSTEM | 2023-01-01 00:00:00 GMT ##################################################################################
Process debugger interrupted: @(main, line 6) Interruption MEMORY not handled: Index 1 is outside pointer &2*1.
Avec ce résultat, on a déjà :
Cependant, sur la ligne, trois valeurs peuvent avoir provoqué l'erreur. Pour déterminer celle qui ne s'évalue pas correctement, enlevez le point d'arrêt précédent, et ajoutez :
#!/usr/bin/env svm
DESCRIPTION
Debugger control
END
LOG
DEBUG "Debugger" STYLE "default"
PLUGIN "svmcom.so"
PLUGIN "svmint.so"
ARGUMENT INT nb
PROCESS "debugger"
CODE "main" INLINE
:shift &nb
:memory INT/i, INT*@&nb/t
1 -> &i
1 -> &t
:label compute
:debug EXPLAIN @((t/@&i)-1)
:debug EXPLAIN @&i
:debug EXPLAIN (t/@&i)
:int.mul @((t/@&i)-1) @&i -> (t/@&i)
:shift &i
:goto compute :when @&i IN t
1 -> &i
:label display
:com.message @(t/@&i)
:shift &i
:goto display :when @&i IN t
END
MEMORY nb
END
Lancez maintenant l'application avec le débugueur :
./debugueur.svm -d 8080 0
Dans l'interface du débugueur, après avoir passé les trois points d'arrêt, vous devez obtenir :
L'expression (t/@&i)
semble être la cause de l'erreur. Dans ce didacticiel, nous ne chercherons pas à corriger cette erreur.
A la place, nous vous invitons à relancer l'application débugueur activé avec une autre valeur que zéro, et de suivre l'exécution au travers des valeurs expliquées.
Les points d'arrêt :debug EXPLAIN
permettent de détailler le calcul de valeurs (ou d'adresses). Le détail du calcul est présenté par la succession de substitutions faites :
:debug EXPLAIN
.Vous venez de voir les interactions basiques avec le débugueur depuis le code de l'application.
Ces interactions permettent de placer des points d'arrêt qui focalisent l'attention sur une portion particulière du code de l'application ou sur des valeurs spéciales calculées.
En outre, ces points d'arrêt perdurent d'une exécution à l'autre (contrairement à ceux placés via l'interface du débugueur) facilitant la rejouabilité d'une investigation sans pour autant gêner l'exécution hors débugueur.