tl;dr: - Linux debugging works - macOS running works, debugging doesn't.
9.3 KiB
Vérification du 2026-11-02
Reprise des constats du README de 2020, avec la méthode suivie pour chacun, afin de pouvoir la rejouer sur une version ultérieure de Go ou de Delve.
Environnement
| Élément | Version |
|---|---|
| Système hôte | macOS 27.2, arm64 |
| Go | 1.27.3 |
| Delve | 1.27.0, épinglé dans go.mod par la directive tool, lancé par go tool dlv |
| Docker | 29.9.2, image officielle golang:1.27.3, linux/arm64 |
- Delve 1.24.2, installé à part dans
$GOPATH/bin, refuse les binaires Go 1.27 : c'est l'une des raisons de l'épingler dans le module. - GoLand 2026.2.4 embarque de son côté Delve 1.27.0,
dans
GoLand.app/Contents/plugins/go-plugin/lib/dlv/<plateforme>/dlv.
1. Incompatibilité des drapeaux de compilation
Constat de 2020 : un hôte compilé avec -gcflags="all=-N -l" ne charge pas un greffon compilé sans.
make all
./cmd/demo # fonctionne
go build -buildmode=plugin -o plugins/foo/foo.so ./plugins/foo
./cmd/demo # échoue
Résultat : toujours vrai, et le message désigne désormais internal/abi :
plugin was built with a different version of package internal/abi
2. Delve sous macOS
Script : debug/macos-step.dlv, après make all :
go tool dlv exec ./cmd/demo --allow-non-terminal-interactive=true --init debug/macos-step.dlv
Résultats :
librariesne liste aucun greffon, même une fois les deux chargés.break foo.go:19échoue :location "foo.go:19" not found. Delve propose seulement un point d'arrêt "suspendu", en attente d'un chargement qu'il ne voit pas.stepsur l'appel au greffon,res := (*work)(n), s'arrête à la première instruction du greffon, sans source :no source available, cadre???.stepoutdepuis là ne revient pas dansmain.Work: le programme continue jusqu'au point d'arrêt suivant.nextpar-dessus l'appel fonctionne normalement, car il ne demande que la table de lignes de l'hôte et l'adresse de retour.
3. Les informations de déboguage des greffons sous macOS
Hypothèse concurrente à écarter : le greffon macOS serait dépourvu d'informations DWARF.
| Outil et commande | Résultat |
|---|---|
otool -l plugins/foo/foo.so (XCode) |
un segment __DWARF d'environ 90 Kio |
dwarfdump --debug-info plugins/foo/foo.so (XCode) |
0 unité de compilation : ne décode pas les sections compressées __zdebug_* de l'éditeur de liens Go |
go tool nm plugins/foo/foo.so |
les symboles du greffon, préfixés par son chemin d'import |
go run ./tools/dwarfcu cmd/demo plugins/foo/foo.so |
78 unités pour l'hôte, 66 pour le greffon, dont la sienne propre |
Le greffon porte son chemin d'import, code.osinet.fr/fgm/go_plugin_demo/plugins/foo,
parce que le Makefile le construit par paquet :
construit à partir d'une liste de fichiers, il serait nommé plugin/unnamed-<hash>.
Conclusion :
- les informations DWARF du greffon sont complètes ;
- c'est Delve qui ne les charge pas sous macOS,
faute de suivre les bibliothèques chargées dynamiquement, comme le montre
libraries.
4. Delve sous Linux, dans un conteneur
Tout se compile dans le conteneur :
- un greffon a besoin de cgo (
-buildmode=plugin requires external (cgo) linking), donc la compilation croisée depuis macOS demanderait un compilateur C croisé ; - un hôte ne charge de toute façon que des greffons de son propre système.
docker run --rm \
--cap-add=SYS_PTRACE --security-opt seccomp=unconfined \
-v "$PWD":"$PWD" -w "$PWD" \
-v go_plugin_demo-gomod:/go/pkg/mod \
golang:1.27.3 \
sh -c 'make clean all &&
go tool dlv exec ./cmd/demo --allow-non-terminal-interactive=true --init debug/linux-plugin.dlv'
SYS_PTRACEetseccomp=unconfinedpermettent à Delve de contrôler le processus.- Le dépôt est monté au même chemin que sur l'hôte, pour que les chemins des informations de déboguage correspondent aux sources locales.
- Le volume nommé conserve le cache de modules d'une exécution à l'autre.
make clean allremplace les binaires macOS éventuels par des binaires Linux.
Script : debug/linux-plugin.dlv.
Résultats :
librarieslisteplugins/foo/foo.soetplugins/bar/bar.so, informations de déboguage chargées.break foo.go:19se pose dans le greffon, surcode.osinet.fr/fgm/go_plugin_demo/plugins/foo.init.func1(), et s'y arrête.- Dans le greffon,
print netprint InternalNamedonnent leurs valeurs. - La pile remonte du greffon à
main.Workpuismain.main. stepentre dansfmt.Sprintfdepuis le greffon.go run ./tools/dwarfculit aussi ces binaires ELF depuis macOS : 90 unités pour l'hôte, 74 pour le greffon.
5. Valeurs renvoyées par plugin.Lookup
Constat de 2020 : le débogueur n'a pas accès aux valeurs renvoyées par plugin.Lookup
tant qu'elles ne sont pas converties dans des types statiques.
Script : debug/lookup.dlv, lancé comme ceux des sections 2 et 4.
- Il s'arrête juste après
p.Lookup(symbolWork). - Il affiche
workSymbol, de typeplugin.Symbol, c'est-à-direany, avant et après l'assertion de type.
Résultats avant conversion :
- Linux, soit le type dynamique et la fonction désignée :
plugin.Symbol(*code.osinet.fr/fgm/go_plugin_demo.Worker) *code.osinet.fr/fgm/go_plugin_demo/plugins/foo.init.func1. - macOS : le type dynamique est lisible, mais pas la fonction :
*(unreadable could not find function for 0x...).- Une donnée, en revanche, s'affiche entièrement :
dans GoLand,
nameSymbolvaut{plugin.Symbol | *string} "Foo". - La table
symsdu*plugin.PluginmontreInternalName -> Foo, maisWork -> unreadable.
- Une donnée, en revanche, s'affiche entièrement :
dans GoLand,
Résultats après l'assertion workSymbol.(*go_plugin_demo.Worker) : rien ne change.
- Sous macOS,
*workreste illisible. - GoLand montre la même chose :
ok = true;work = {*go_plugin_demo.Worker | 0x...}, avec son adresse ;unreadable: could not find function for 0x...pour la fonction désignée, comme pourworkSymbolavant conversion.
Conclusion : le constat de 2020 ne tient plus.
- Le type dynamique d'un
plugin.Symbols'inspecte sans conversion, puisqu'il vient des informations de type à l'exécution, communes à l'hôte et au greffon. - La seule limite, propre à macOS, concerne les fonctions du greffon, qui relèvent des tables de symboles que Delve n'y charge pas, comme en section 2.
Références
- go-delve/delve#865, "Support plugins" : fermé le 2019-07-11, avec la prise en charge des greffons par Delve, sous Linux.
- go-delve/delve#1628, "Cannot debug go plugins on mac" :
ouvert le 2019-07-22, toujours ouvert au 2026-11-02.
- Le mainteneur ne l'a pas implémenté, en citant golang/go#25841.
- Le constat de 2020 était donc déjà propre à macOS.
- Avant de refaire cette vérification sous macOS, regarder si #1628 est fermé,
puis rejouer
debug/macos-step.dlv.
Conclusion
| Linux | macOS | |
|---|---|---|
plugin.Open |
oui, si hôte et greffons ont les mêmes réglages de compilation | idem |
| Points d'arrêt et pas à pas dans l'hôte | oui | oui |
next par-dessus un appel au greffon |
oui | oui |
| Points d'arrêt, variables et pas à pas dans un greffon | oui | non : Delve ne charge pas les informations du greffon |
Valeurs renvoyées par plugin.Lookup, avant conversion |
oui | données oui, fonctions non |