Bibliothèque debug

La bibliothèque debug donne accès à l'introspection interne du moteur : métatables, uservalues, upvalues, variables locales, informations d'appel et hooks d'exécution. Elle est chargée automatiquement par OpenLibs(). Réservée à l'outillage (débogueur, profileur, sérialisation) — un script ordinaire n'en a généralement pas besoin.

Reprend la forme de la bibliothèque debug de Lua 5.4, avec quelques écarts assumés :

Vue d'ensemble

Fonction Description
debug.getmetatable(value) Métatable de value, ou nil si elle n'en a pas
debug.setmetatable(value, table) Fixe la métatable de value (nil pour la retirer)
debug.getregistry() La table de registre interne du moteur
debug.getuservalue(u [, n]) n-ième valeur utilisateur attachée à l'userdata u
debug.setuservalue(u, value [, n]) Fixe la n-ième valeur utilisateur de u
debug.getupvalue(f, up) Nom et valeur de la up-ième upvalue de la fonction f
debug.setupvalue(f, up, value) Fixe la up-ième upvalue de f
debug.upvalueid(f, n) Identifiant opaque de la n-ième upvalue de f
debug.upvaluejoin(f1, n1, f2, n2) Fait partager la même upvalue à f1/f2
debug.getlocal([thread,] f\|level, index) Nom (et valeur) de la index-ième variable locale
debug.setlocal([thread,] level, index, value) Fixe la index-ième variable locale de la pile d'appel au niveau level
debug.sethook([thread,] [hook, mask [, count]]) Installe (ou retire) un hook d'exécution
debug.gethook([thread]) Hook actuellement installé, son masque et son compteur
debug.getinfo([thread,] f [, what]) Table d'informations sur une fonction ou un niveau de la pile d'appel
debug.traceback([thread,] [message [, level]]) Chaîne de trace d'appel, avec message en préfixe optionnel

Métatables et registre

debug.getmetatable(value)

Retourne la métatable de value, ou nil si elle n'en a pas (contrairement à getmetatable de la bibliothèque de base, ignore le champ __metatable qui masquerait normalement l'accès).

debug.setmetatable(value, table)

Fixe la métatable de value à table (ou la retire si table est nil). Retourne value.

debug.getregistry()

Retourne la table de registre interne du moteur — l'espace de stockage utilisé par les bibliothèques elles-mêmes (package.loaded, package.preload, hooks enregistrés, etc.). Réservé à un usage très avancé.

Uservalues

debug.getuservalue(u [, n]) / debug.setuservalue(u, value [, n])

Lisent/écrivent la n-ième valeur utilisateur (par défaut 1) attachée à l'userdata u — un emplacement de stockage annexe indépendant de l'objet .NET encapsulé. setuservalue retourne u en cas de succès ; lever n hors des bornes disponibles est une erreur d'argument.

Upvalues

debug.getupvalue(f, up)

Retourne le nom et la valeur de la up-ième upvalue (variable capturée) de la fonction f (1-based). Retourne nil seul si up est hors limites.

debug.setupvalue(f, up, value)

Fixe la valeur de la up-ième upvalue de f. Retourne le nom de l'upvalue en cas de succès, ou nil si up est hors limites.

debug.upvalueid(f, n) / debug.upvaluejoin(f1, n1, f2, n2)

upvalueid retourne un identifiant opaque (light userdata) désignant la cellule d'upvalue elle-même — deux fonctions dont l'upvalue n a le même id partagent la même variable capturée. upvaluejoin force f1's upvalue n1 à partager la cellule de f2's upvalue n2. Un index d'upvalue invalide dans l'un ou l'autre est une erreur d'argument.

Variables locales

debug.getlocal([thread,] f|level, index)

Deux formes selon le deuxième argument :

Retourne nil seul si index ne correspond à aucune variable/paramètre.

debug.setlocal([thread,] level, index, value)

Fixe la valeur de la index-ième variable locale active au niveau level de la pile d'appel. Retourne le nom de la variable en cas de succès, nil sinon. Un level hors limites est une erreur d'argument.

Hooks d'exécution

debug.sethook([thread,] [hook, mask [, count]])

Installe hook (une fonction) comme rappel exécuté selon les évènements listés dans mask, chaîne combinant :

Lettre Évènement déclencheur
c à chaque appel de fonction ("call")
r à chaque retour de fonction ("return")
l à chaque nouvelle ligne exécutée ("line")

count (optionnel, > 0) ajoute un déclenchement périodique tous les count instructions ("count"). Le hook est appelé avec le nom de l'évènement, plus le numéro de ligne pour "line".

Appelé sans hook/mask (juste debug.sethook() ou debug.sethook(thread)), retire le hook installé sur le thread visé.

debug.sethook(function(event, line)
    print(event, line)
end, "l")

debug.gethook([thread])

Retourne trois valeurs : la fonction hook actuellement installée sur thread (par défaut le thread courant) — ou nil si aucune, ou si le hook actif n'a pas été posé par debug.sethook —, le masque d'évènements sous forme de chaîne ("crl"), et le compteur.

Coexistence avec un débogueur externe

Écart par rapport à Lua : debug.sethook/gethook ne voient et ne manipulent qu'un canal de hook propre au script — un éventuel débogueur externe attaché par l'hôte (l'IDE, yeditor.exe, ...) pose ses propres points d'arrêt/pas-à-pas sur un second canal totalement indépendant, réservé à l'hôte et inaccessible depuis un script. Concrètement :

Autrement dit : un script utilisant debug.sethook reste déboguable normalement depuis un outil externe, sans avoir besoin d'être adapté ni désactivé pour ça.

Informations d'appel

debug.getinfo([thread,] f [, what])

Retourne une table décrivant soit la fonction f, soit — si f est un entier — le niveau f de la pile d'appel de thread. what (chaîne, défaut "nSlu") sélectionne les catégories d'informations à remplir :

Lettre Champs ajoutés à la table résultat
n name, namewhat
S source, short_src, linedefined, lastlinedefined, what
l currentline
u nups, nparams, isvararg
f func — la fonction elle-même
L activelines — table des lignes actives

Si f est un niveau de pile hors limites, retourne nil plutôt que la table.

Contrairement à Lua, la lettre t (qui ajoute istailcall) n'est pas reconnue : voir la note en tête de cette page.

debug.traceback([thread,] [message [, level]])

Construit une chaîne de trace de la pile d'appel de thread (par défaut le thread courant), préfixée par message si fourni. level (défaut 1 pour le thread courant, 0 sinon) indique à partir de quel niveau commencer la trace. Si message n'est ni une chaîne ni un nombre, il est retourné tel quel sans construire de trace (permet de laisser passer un objet d'erreur non-textuel sans le convertir).