Introduction

Ce didacticiel est destiné aux nouveaux utilisateurs de la Simple Virtual Machine.

Dans ce didacticiel, vous allez manipuler le débugueur depuis le code de manière plus étendue.

Le temps de lecture de ce didacticiel est estimé à 15 minutes si l'utilisation basique du débugueur et les instructions extensions ont été abordées.

Mise en place

Pour commencer, créez le canevas de l'application dans le fichier exécutable points_arret_etendus.svm en utilisant ce code :

#!/usr/bin/env svm
DESCRIPTION
Advanced debug example
END
LOG
DEBUG "Advanced debug" STYLE "default"
PLUGIN "svmcom.so"
PLUGIN "svmstr.so"
PROCESS "application"
	CODE "main" INLINE
		:interruption CASCADE MEMORY failure
		:call function P
		:shutdown
	:label function
		:memory INT/i, STR/s
		0 -> &i
		11 -> &s
		:shift &i
		:str.replace @&s 1 CONST str.pattern "[0-9]" => "x"
		:com.message @&i " " @&s
		:return
	:label failure
		:com.message "Error"
	END
END

Points d'arrêt interruption

Lancez l'application :

./points_arret_etendus.svm
Error

Le résultat indique qu'une interruption mémoire a été levée lors de l'exécution de l'application.

Quand l'application est un peu conséquente, avoir un point d'arrêt sur une interruption peut se révéler efficace pour diagnostiquer dans le débugueur la cause de l'erreur.

Modifiez le code pour ajouter un point d'arrêt sur interruption :

#!/usr/bin/env svm
DESCRIPTION
Advanced debug example
END
LOG
DEBUG "Advanced debug" STYLE "default"
PLUGIN "svmcom.so"
PLUGIN "svmstr.so"
PROCESS "application"
	CODE "main" INLINE
		:debug ADD MEMORY
		:interruption CASCADE MEMORY failure
		:call function P
		:shutdown
	:label function
		:memory INT/i, STR/s
		0 -> &i
		11 -> &s
		:shift &i
		:str.replace @&s 1 CONST str.pattern "[0-9]" => "x"
		:com.message @&i " " @&s
		:return
	:label failure
		:com.message "Error"
	END
END

Puis lancez l'application en mode débugueur. L'application est directement sur un point d'arrêt là où l'interruption a été levée :

Advanced debug
Breakpoint list
Interruption:
At <main:1/6>
With: MEMORY
Code main - K main - P application
:debug ADD MEMORY
:interruption CASCADE MEMORY failure
:call function P
:shutdown
:label function

:memory INT/i , STR/s
0 -> &i
11 -> &s
:shift &i
:str.replace @&s 1 CONST str.pattern "[0-9]" => "x"
:com.message @&i " " @&s
:return
:label failure

:com.message "Error"
Auto-scroll to
Current
with above
Display
Processor - K main - P application
State:
Next instruction: <main:1/7>
Current instruction: <main:1/6>
Code
Current memory: &0*0
Allocated memory: &0*2
Defined aliases: i s
Local interruptions:
Cascaded local interruptions: MEMORY => <main:1/11>
Code
Flags:
Cascaded flags:
Return stack:
State:
Next instruction: <main:1/3>
Current instruction: <main:1/2>
Code
Current memory: &0*0
Allocated memory:
Defined aliases:
Local interruptions:
Cascaded local interruptions: MEMORY => <main:1/11>
Code
Flags:
Cascaded flags:
Global interruptions:
Waiting interruptions: MEMORY

En bas de la fenêtre du processeur, vous pouvez noter que l'interruption mémoire est en attente de traitement.

Points d'arrêt mémoire

Tout comme pour les interruptions, il peut être très pratique de pouvoir arrêter l'application sur une opération mémoire.

Lecture

Corrigez la source de l'interruption et modifiez le code :

#!/usr/bin/env svm
DESCRIPTION
Advanced debug example
END
LOG
DEBUG "Advanced debug" STYLE "default"
PLUGIN "svmcom.so"
PLUGIN "svmstr.so"
PROCESS "application"
	CODE "main" INLINE
		:debug ADD READ &0
		:interruption CASCADE MEMORY failure
		:call function P
		:shutdown
	:label function
		:memory INT/i, STR/s
		0 -> &i
		"11" -> &s
		:shift &i
		:str.replace @&s 1 CONST str.pattern "[0-9]" => "x"
		:com.message @&i " " @&s
		:return
	:label failure
		:com.message "Error"
	END
END

Lancez de nouveau l'application en mode débugueur. Lorsque le second point d'arrêt est atteint, vous devez obtenir :

Advanced debug
Breakpoint list
Memory:
At <main:1/7>
Read at &0:
  Type: INT
  Value: 0
Memory:
At <main:1/9>
Read at &0:
  Type: INT
  Value: 1
Memory - K main - P application
AddressTypeValue
&0INT1
&1STR"x1"
AliasPointer
i&0*1
s&1*1
Address:
Display
Aliases
P
Focus
Back
Clear
Code main - K main - P application
:debug ADD READ &0
:interruption CASCADE MEMORY failure
:call function P
:shutdown
:label function

:memory INT/i , STR/s
0 -> &i
"11" -> &s
:shift &i
:str.replace @&s 1 CONST str.pattern "[0-9]" => "x"
:com.message @&i " " @&s
:return
:label failure

:com.message "Error"
Auto-scroll to
Current
with above
Display

L'application a été arrêtée dans le débugueur lors des deux lectures à l'adresse &0. Notez que l'adresse passée à l'instruction :debug ADD READ peut être calculée comme n'importe quelle adresse.

De plus, le débugueur montre dans la liste des points d'arrêt le type et la valeur pour chacune des lectures.

Ecriture

Modifiez à nouveau le code :

#!/usr/bin/env svm
DESCRIPTION
Advanced debug example
END
LOG
DEBUG "Advanced debug" STYLE "default"
PLUGIN "svmcom.so"
PLUGIN "svmstr.so"
PROCESS "application"
	CODE "main" INLINE
		:interruption CASCADE MEMORY failure
		:call function P
		:shutdown
	:label function
		:memory INT/i, STR/s
		:debug ADD WRITE &s
		0 -> &i
		"11" -> &s
		:shift &i
		:str.replace @&s 1 CONST str.pattern "[0-9]" => "x"
		:com.message @&i " " @&s
		:return
	:label failure
		:com.message "Error"
	END
END

Puis lancez une nouvelle fois l'application avec le débugueur :

Advanced debug
Breakpoint list
Memory:
At <main:1/6>
Write at &1:
  Type: STR
  Value: 
Replaced by:
  Type: STR
  Value: "11"
Memory - K main - P application
AddressTypeValue
&0INT0
&1STR
AliasPointer
i&0*1
s&1*1
Address:
Display
Aliases
P
Focus
Back
Clear
Code main - K main - P application
:interruption CASCADE MEMORY failure
:call function P
:shutdown
:label function

:memory INT/i , STR/s
:debug ADD WRITE &s
0 -> &i
"11" -> &s
:shift &i
:str.replace @&s 1 CONST str.pattern "[0-9]" => "x"
:com.message @&i " " @&s
:return
:label failure

:com.message "Error"
Auto-scroll to
Current
with above
Display

Cette fois, l'application est arrêtée sur l'écriture en mémoire à l'adresse &1. Le point d'arrêt indique l'ancien type, l'ancienne valeur et les nouveaux type et valeur.

Accès

Modifiez encore le code :

#!/usr/bin/env svm
DESCRIPTION
Advanced debug example
END
LOG
DEBUG "Advanced debug" STYLE "default"
PLUGIN "svmcom.so"
PLUGIN "svmstr.so"
PROCESS "application"
	CODE "main" INLINE
		:interruption CASCADE MEMORY failure
		:call function P
		:shutdown
	:label function
		:memory INT/i, STR/s
		:debug ADD ACCESS &s
		0 -> &i
		"11" -> &s
		:shift &i
		:str.replace @&s 1 CONST str.pattern "[0-9]" => "x"
		:com.message @&i " " @&s
		:return
	:label failure
		:com.message "Error"
	END
END

Lancez dans le débugueur pour obtenir :

Advanced debug
Breakpoint list
Memory:
At <main:1/8>
Access at &1:
  Type: STR
  Value: "x1"
Code main - K main - P application
:interruption CASCADE MEMORY failure
:call function P
:shutdown
:label function

:memory INT/i , STR/s
:debug ADD ACCESS &s
0 -> &i
"11" -> &s
:shift &i
:str.replace @&s 1 CONST str.pattern "[0-9]" => "x"
:com.message @&i " " @&s
:return
:label failure

:com.message "Error"
Auto-scroll to
Current
with above
Display
Memory - K main - P application
AddressTypeValue
&0INT1
&1STR"11"
AliasPointer
i&0*1
s&1*1
Address:
Display
Aliases
P
Focus
Back
Clear

L'instruction :str.replace n'arrête pas l'application sur une lecture ou une écriture en mémoire, mais sur un accès à la mémoire.

Un accès en mémoire est une opération qui modifie une valeur directement stockée en mémoire sans écriture explicite. Seuls les nouveaux type et valeur sont indiqués dans le point d'arrêt.

Une seule exception existe : l'instruction :shift réalise un accès mémoire, mais simule une lecture et une écriture sur les points d'arrêt pour des raisons pratiques.

Libération

Modifiez une dernière fois le code :

#!/usr/bin/env svm
DESCRIPTION
Advanced debug example
END
LOG
DEBUG "Advanced debug" STYLE "default"
PLUGIN "svmcom.so"
PLUGIN "svmstr.so"
PROCESS "application"
	CODE "main" INLINE
		:interruption CASCADE MEMORY failure
		:call function P
		:shutdown
	:label function
		:memory INT/i, STR/s
		:debug ADD FREE &s
		0 -> &i
		"11" -> &s
		:shift &i
		:str.replace @&s 1 CONST str.pattern "[0-9]" => "x"
		:com.message @&i " " @&s
		:return
	:label failure
		:com.message "Error"
	END
END

Et lancez l'application avec le débugueur :

Advanced debug
Breakpoint list
Memory:
At <main:1/10>
Delete at &1:
  Type: STR
  Value: "x1"
Memory - K main - P application
AddressTypeValue
&0INT1
&1STR"x1"
AliasPointer
i&0*1
s&1*1
Address:
Display
Aliases
P
Focus
Back
Clear
Code main - K main - P application
:interruption CASCADE MEMORY failure
:call function P
:shutdown
:label function

:memory INT/i , STR/s
:debug ADD FREE &s
0 -> &i
"11" -> &s
:shift &i
:str.replace @&s 1 CONST str.pattern "[0-9]" => "x"
:com.message @&i " " @&s
:return
:label failure

:com.message "Error"
Auto-scroll to
Current
with above
Display

Dans ce cas, l'application s'arrête sur l'instruction qui libère la mémoire à l'adresse &1. Le type et la valeur avant suppression sont indiqués dans le point d'arrêt.

Points d'arrêt extension

Une dernière catégorie de points d'arrêt peut être rencontrée. Créer de tels points d'arrêt est accessible uniquement à des utilisateurs avancés, mais peuvent être rencontrés par des utilisateurs débutants. Ainsi, nous nous contenterons ici de montrer dans le débugueur à quoi ils ressemblent.

Points d'arrêt

Les extensions peuvent contenir des points d'arrêt au beau milieu de leur exécution pour expliciter comment elle se déroule et son impact sur la machine virtuelle. L'exécution de l'application s'arrête sur un tel point d'arrêt :

Advanced debug
Breakpoint list
Plugin:
At <main:1/0>
PROCESS application : INSTRUCTION debug.break:
custom

Notifications

Les extensions peuvent aussi vouloir afficher des informations complémentaires dans le débugueur sans toutefois arrêter l'application.

Ce sont des notifications :

Advanced debug
Breakpoint list
Notification:
At <main:1/0>
PROCESS application : INSTRUCTION debug.notif:
custom

Formulaires

Les extensions peuvent également demander des informations complémentaires permettant de faciliter les investigations, ou destinées à tester le code dans des conditions particulières.

Pour cela, une extension peut soumettre un formulaire directement dans la liste des points d'arrêt :

Advanced debug
Breakpoint list
Form:
At <main:1/0>
PROCESS application : INSTRUCTION debug.form:
form:
checkbox
selection
integer
string
text
Submit

Tant que le formulaire n'est pas validé, l'application reste arrêtée (relancer le processeur n'a aucun effet). Une fois les valeurs remplies et validées en cliquant sur le bouton "Submit", le formulaire se transforme en la liste des valeurs entrées :

Advanced debug
Breakpoint list
Form:
At <main:1/0>
PROCESS application : INSTRUCTION debug.form:
form:
no 
checkbox
selection
plugin.entry
integer
23
string
value bis
text
this is a nice text
on several lines

Conclusion

Vous venez de voir comment utiliser les points d'arrêt étendus du débugueur.

Ces nouveaux points d'arrêt permettent de cibler efficacement les investigations en se focalisant sur les événements importants de l'application indépendamment de leur localisation dans le code.

Les extensions peuvent également interagir avec le débugueur pour apporter des compléments d'information utiles sur leur fonctionnement.