Qu'est-ce qu'un PDB (Program Database) ? — Comprendre les informations de débogage, les symboles et Source Link
· Mis à jour le: · Go Komura · .NET, C#, Visual Studio, PDB, Débogage, Symboles, SourceLink, Diagnostic, Exploitation, Réutilisation des actifs existants
1. Ce qu’il faut retenir en premier
Lorsque vous compilez une application .NET ou C++, un fichier .pdb est parfois généré en même temps que le .dll ou le .exe.
Par exemple, une sortie comme celle-ci :
MyApp.exe
MyApp.dll
MyApp.pdb
Si vous continuez à développer sans savoir ce qu’est ce .pdb, des questions comme celles-ci finissent par se poser :
- Peut-on placer le
.pdben environnement de production ? - L’application ne fonctionne-t-elle pas sans
.pdb? - Est-ce anormal qu’un build Release produise un
.pdb? - Le
.pdbcontient-il tout le code source ? - Un
.pdbgarantit-il de pouvoir poser un point d’arrêt ? - Pourquoi le
.pdbest-il nécessaire pour l’analyse de dumps et l’enquête sur incident ? - Comment traiter le
.pdbdans un package NuGet ? - Quelle est la différence entre Source Link, les serveurs de symboles et le
.snupkg?
Le PDB n’est jamais l’acteur principal du développement au quotidien. Mais pour l’enquête sur incident, l’analyse de dump, la distribution de bibliothèques, la lisibilité des journaux d’exploitation et l’expérience de débogage, il compte énormément.
Commençons par la conclusion.
Le PDB est un fichier d’informations de débogage qui relie un exécutable ou un assembly à son code source. Ce n’est pas le corps de l’application permettant de la faire fonctionner ; il indique au débogueur et aux outils de diagnostic « à quelle ligne source correspond quelle instruction », « ce qu’est telle variable locale » et « quelle source consulter ».
Cet article organise le PDB non pas comme un simple « fichier accessoire de débogage », mais comme un artefact qu’il faut savoir gérer en pratique.
2. Qu’est-ce qu’un PDB ?
PDB est l’abréviation de Program Database, traduit en français par base de données de programme.
Les fichiers .pdb sont aussi souvent appelés fichiers de symboles.
Un symbole, en gros, est une information relative à un nom ou à une position dans un programme. Par exemple :
- Noms de fonctions
- Noms de méthodes
- Noms de variables locales
- Noms de paramètres
- Informations de type
- Noms de fichiers source
- Numéros de ligne source
- La correspondance entre les positions dans la source et les instructions compilées
- Les informations que le débogueur utilise pour placer des points d’arrêt
- Les informations de récupération de source pour Source Link
Lorsque vous écrivez du code source, vous avez ainsi des noms compréhensibles pour un humain :
public decimal CalculateTotalPrice(Order order)
{
var subtotal = order.Lines.Sum(x => x.Price * x.Quantity);
var tax = subtotal * 0.10m;
return subtotal + tax;
}
Mais le .dll ou le .exe issu de la compilation n’est pas le code source lui-même.
En .NET, cela devient de l’IL et des métadonnées ; en C++ natif, cela devient un binaire proche du langage machine.
Résultat : des informations comme celles-ci deviennent insuffisantes, voire impossibles à déterminer, à partir du seul exécutable.
Ce code machine / IL correspond à quelle ligne de quel .cs ?
Cette adresse correspond à quelle position de quelle fonction ?
Quel était le nom de cette variable locale ?
À quelle position d'instruction ce point d'arrêt doit-il réellement être placé ?
À quelle source cette frame de pile correspond-elle ?
Le PDB est le fichier qui comble cet écart.
3. Le PDB est-il nécessaire à l’exécution ?
En temps normal, le PDB n’est pas nécessaire à l’exécution de l’application. Dès lors que le .dll ou le .exe est présent, l’application peut démarrer.
L’absence du .pdb n’empêche pas le traitement normal de s’exécuter.
Sans PDB, en revanche, les choses suivantes deviennent difficiles :
| Ce que vous voulez faire | Ce qui pose problème sans PDB |
|---|---|
| Exécuter pas à pas avec précision dans Visual Studio | Impossible de faire correspondre les lignes source et les positions d’exécution |
| Poser un point d’arrêt | La position d’instruction correspondante est inconnue, et le point d’arrêt peut rester non résolu |
| Afficher le nom de fichier et le numéro de ligne dans les traces de pile d’exceptions | L’information de numéro de ligne n’apparaît pas, ou est insuffisante |
| Analyser un fichier de dump | La lecture de la pile, des variables et des types devient difficile |
| Pénétrer en mode pas à pas dans une bibliothèque externe | Impossible de relier la bibliothèque à sa source |
| Lire un crash natif | On ne dispose que d’adresses, sans nom de fonction ni position |
Autrement dit, le PDB n’est pas « un fichier pour faire fonctionner » mais « un fichier pour enquêter ».
Cette distinction est importante. Lorsqu’un incident de production survient, l’application peut avoir tourné sans PDB, mais l’enquêteur, lui, est bloqué sans PDB. C’est pourquoi, indépendamment de la question de le placer ou non en environnement d’exécution, il faut absolument conserver le PDB comme un artefact de build.
4. Quel est l’intérêt d’avoir un PDB ?
Avec un PDB, le débogueur et les outils de diagnostic parviennent plus facilement à retransformer un binaire en informations lisibles par un humain.
Par exemple, une information de crash sans PDB peut ressembler à ceci :
MyApp.dll!0x00007ff9a1234567
MyApp.dll!0x00007ff9a1234abc
MyApp.dll!0x00007ff9a1234def
Lorsque le PDB est correctement chargé, on parvient à voir ceci :
MyApp.Services.OrderService.CalculateTotalPrice(Order order) Line 42
MyApp.Controllers.OrderController.Post(CreateOrderRequest request) Line 87
MyApp.Program.Main(string[] args) Line 16
La différence est considérable.
Dans le premier cas, il faut commencer l’enquête à partir d’adresses. Dans le second, on arrive d’emblée à « quelle ligne de quelle méthode ».
Dans une enquête sur incident, tout se joue sur la capacité à se rapprocher de la cause dans les 30 premières minutes. Le simple fait de disposer du PDB change complètement le point de départ de l’enquête.
5. Ce que contient un PDB
Les informations contenues dans un PDB varient selon le langage, le compilateur, le format du PDB et les paramètres de build. On ne peut donc pas affirmer simplement « un PDB contient toujours ceci ».
Cela dit, les développeurs .NET s’attendent généralement à trouver à peu près ces informations :
La correspondance entre les fichiers source et le code compilé
Les numéros de ligne source
Les symboles des méthodes et des fonctions
Les noms de variables locales
Les informations de portée (scope)
Les chemins et sommes de contrôle des fichiers source
Les informations Source Link
Dans certains cas, la source intégrée
Ce qui compte particulièrement, c’est la correspondance entre la position dans la source et la position à l’exécution.
Une ligne écrite en C# peut devenir plusieurs instructions en IL ou dans le code natif post-JIT. À l’inverse, une optimisation peut regrouper plusieurs lignes source, les faire disparaître, ou donner l’impression qu’elles ont changé d’ordre.
Le débogueur utilise les informations du PDB pour déterminer « quelle ligne source afficher maintenant ».
6. Ce qui ne se trouve pas dans un PDB
Pour le PDB, comprendre ce qu’il ne contient pas dissipe plus de malentendus que comprendre ce qu’il contient.
Un PDB n’est normalement pas :
- L’application elle-même
- Un fichier d’exécution indispensable au runtime
- Une sauvegarde complète de l’ensemble du code source
- Un substitut au dépôt Git
- Quelque chose qui restaure intégralement tous les paramètres de build et l’environnement
- Quelque chose qui explique automatiquement, à lui seul, la cause d’un bogue
Il y a toutefois un point d’attention.
Un PDB peut contenir des chemins de fichiers source, des noms de types, des noms de fonctions, des noms de variables locales, et parfois des informations Source Link ou de la source intégrée.
On ne peut donc pas dire « ce n’est pas le code source lui-même, on peut donc le publier sans se soucier de rien ».
Il peut contenir des noms de projets internes, des chemins incluant des noms d’utilisateurs, la structure de dossiers de l’entreprise, des noms de types non publiés, ou des noms permettant de deviner la logique métier.
7. Idée reçue n°1 : un PDB ralentit la production
Le simple fait qu’un PDB soit posé à côté du binaire ne ralentit pas le traitement normal de l’application.
Le PDB est utilisé lorsque le débogueur ou un outil de diagnostic a besoin d’informations de symboles. Le traitement normal de l’application ne fonctionne pas en lisant le PDB à chaque opération.
Bien sûr, il est sollicité lors de la résolution des noms de fichiers et des numéros de ligne dans les traces de pile d’exceptions, lors de l’attachement d’un débogueur, ou lorsqu’un profileur ou un outil de diagnostic lit les symboles.
Mais l’idée selon laquelle « poser un PDB ralentit tout le temps, donc il ne faut jamais le mettre en production » est simpliste.
En pratique, il est plus sûr de raisonner ainsi :
Il n'y a guère de raison de supprimer le PDB pour des motifs de performance à l'exécution
La politique de placement se décide selon le périmètre de diffusion, le risque de fuite d'information, la taille des artefacts et la politique opérationnelle
Même en l'absence de déploiement, le PDB du même build doit toujours être conservé
8. Idée reçue n°2 : un build Release n’a pas besoin de PDB
Un PDB est utile même pour un build Release. C’est même précisément le PDB du build Release dont on a besoin pour enquêter sur un incident de production.
Si ce qui tourne en production est un build Release, disposer du PDB d’un build Debug ne sert à rien. Ce dont le débogueur a besoin, c’est du PDB généré au moment même où ce binaire de production a été construit.
La distinction importante ici est celle-ci :
| Élément | Signification |
|---|---|
| Debug / Release | La configuration de build : optimisation, compilation conditionnelle, paramètres de sortie, etc. |
| Présence du PDB | Le fait de générer et de conserver, ou non, des informations de débogage |
| Facilité de débogage | Déterminée par la présence d’optimisation, le contenu du PDB, la correspondance avec la source, le comportement du JIT, etc. |
Les builds Release sont souvent optimisés, ce qui rend l’exécution pas à pas moins lisible qu’en Debug. Des variables locales peuvent disparaître à cause de l’optimisation, ou l’exécution peut ne pas s’arrêter dans l’ordre des lignes source.
Malgré tout, avec un PDB, il devient plus facile d’obtenir des informations comme :
- La ligne source où une exception s’est produite
- Les noms des méthodes sur la pile
- Les positions correspondantes lors de l’analyse d’un dump
- Les noms de fonctions dans les résultats de profilage
- La mise en correspondance des journaux avec la source
Ce n’est pas « c’est du Release, donc pas besoin de PDB ». C’est précisément parce que c’est du Release qu’il faut conserver le PDB correspondant à ce build.
9. Idée reçue n°3 : avec un PDB, on peut déboguer n’importe quel binaire
Un PDB ne peut pas être réutilisé pour n’importe quel .dll ou .exe.
Le débogueur vérifie que le binaire visé et le PDB correspondent bien. Utiliser de force un PDB qui ne correspond pas fausse la correspondance des lignes source, des fonctions et des variables.
Par exemple, dans des situations comme celles-ci, un PDB peut être inutilisable ou inutile même si vous en avez un :
Vous essayez d'appliquer au DLL de production un PDB recompilé en local
Même numéro de version, mais en réalité construit à partir d'un commit différent
Vous essayez de charger, contre un DLL post-hotfix, le PDB d'avant le hotfix
Les paramètres d'optimisation ou la compilation conditionnelle diffèrent
Il ne faut pas penser « même source, donc ça colle à peu près », mais plutôt « le PDB doit correspondre au même artefact de build exactement ».
C’est pourquoi, en CI/CD, la règle de base est de conserver ensemble cet ensemble :
Identifiant de commit
Numéro de build
Version de l'artefact
.dll / .exe
.pdb
Informations de référence de source
L’important est de ne pas rompre cette combinaison.
10. Idée reçue n°4 : avec un PDB, on peut tout lire même sans code source
Même avec un PDB, le code source n’y est pas forcément intégré.
Le PDB porte principalement des informations qui font correspondre la source et le binaire. Il peut contenir les chemins et sommes de contrôle des fichiers source, ainsi que des informations Source Link, mais un PDB ordinaire ne contient pas toujours l’intégralité du texte source.
Si vous voulez donc pénétrer en mode pas à pas dans une bibliothèque externe avec le débogueur, il vous faut l’un des éléments suivants :
Vous disposez localement des mêmes fichiers source
Source Link permet de récupérer la source du bon commit
La source est intégrée dans le PDB
Vous vous contentez d'une source décompilée
Visual Studio dispose aussi d’une fonctionnalité de décompilation des assemblys .NET pour affichage. Mais le résultat de la décompilation n’est pas la source originale. Les commentaires, les espaces, les noms de variables locales, le style d’écriture original ou les conditions du préprocesseur sont perdus ou modifiés.
C’est pratique pour une enquête, mais il ne faut pas trop s’y fier comme substitut de la source d’origine.
11. PDB et traces de pile
Dans les traces de pile d’exceptions .NET, l’affichage change selon la présence ou non d’un PDB.
Même sans PDB, les noms de méthodes et de types peuvent apparaître, car les assemblys .NET contiennent des métadonnées.
Mais si vous voulez aussi le nom de fichier et le numéro de ligne, le PDB devient important.
Par exemple, sans PDB, une trace de pile tend à ressembler à ceci :
System.InvalidOperationException: Order is invalid
at MyApp.Services.OrderService.Validate(Order order)
at MyApp.Controllers.OrderController.Post(CreateOrderRequest request)
Avec un PDB présent et les numéros de ligne résolus, cela devient ceci :
System.InvalidOperationException: Order is invalid
at MyApp.Services.OrderService.Validate(Order order) in /src/MyApp/Services/OrderService.cs:line 42
at MyApp.Controllers.OrderController.Post(CreateOrderRequest request) in /src/MyApp/Controllers/OrderController.cs:line 87
Lorsque cette différence apparaît en exploitation, la vitesse d’enquête change considérablement.
Attention toutefois : le simple fait d’exposer des chemins de fichiers peut lui-même constituer une divulgation d’informations. Il faut aussi d’autres mesures : ne pas renvoyer la trace de pile dans les réponses d’erreur destinées à l’extérieur, et restreindre l’emplacement de stockage des journaux.
12. PDB et analyse de dump
C’est lors de l’analyse de dump que le PDB se révèle le plus précieux.
Supposons que des problèmes comme ceux-ci surviennent en production :
- Le processus a planté
- L’utilisation du CPU est restée bloquée à un niveau élevé
- Cela ressemble à un interblocage (deadlock)
- La mémoire augmente sans cesse
- Aucune réponse n’est renvoyée
- Le plantage se produit à la frontière avec une bibliothèque native
On récupère alors un fichier de dump pour l’analyser.
Mais le dump seul ne suffit pas. Ce que contient le dump, c’est l’état du processus à cet instant précis. Pour transformer la pile et les modules qui y figurent en noms lisibles et en lignes source, il faut le PDB correspondant.
En .NET, on analyse avec dotnet-dump, Visual Studio, WinDbg, SOS, etc.
Lorsque du code natif est impliqué, la configuration des symboles de WinDbg devient importante.
Voici des échecs fréquents lors de l’analyse de dump :
Le DLL de production subsiste, mais il n'y a pas de PDB
Il y a un PDB, mais c'est un autre, recompilé en local
Les symboles de Windows / du runtime .NET ne sont pas chargés
Vous avez le PDB de votre propre application, mais pas les symboles des bibliothèques tierces
Le chemin de symboles n'est pas configuré, et le débogueur ne peut pas trouver le PDB
L’analyse de dump ne laisse parfois pas le temps de se préparer une fois le problème survenu. Il est essentiel de conserver le PDB au moment du build, pour pouvoir le récupérer au moment de l’enquête.
13. Windows PDB et Portable PDB
Il existe plusieurs formats de PDB.
En pratique, les deux formats représentatifs à retenir sont ceux-ci :
| Type | Contexte principal | Caractéristiques |
|---|---|---|
| Windows PDB | Visual C++, débogage Windows traditionnel | Format couramment utilisé dans le développement natif Windows |
| Portable PDB | .NET / .NET Core et versions suivantes | Format orienté .NET, utilisable de façon multiplateforme |
À partir de .NET Core, le Portable PDB est celui qui compte. Le format Portable PDB peut être traité non seulement sous Windows, mais aussi sous Linux et macOS.
Dans les projets de l’ère .NET Framework ou avec d’anciennes configurations de Visual Studio, on rencontre encore des Windows PDB. Dans les projets .NET SDK-style actuels, l’hypothèse de travail est de plus en plus le Portable PDB.
Attention, dans les deux cas, l’extension est .pdb.
L’extension seule ne permet pas de distinguer le format. Quand on vous parle de « PDB », vérifiez de quel contexte il s’agit :
S'agit-il du Portable PDB de .NET ?
S'agit-il du Windows PDB de Visual C++ ?
S'agit-il d'un vieux projet .NET Framework ?
S'agit-il d'un PDB destiné à la distribution NuGet ?
S'agit-il des symboles utilisés dans WinDbg ?
14. Le DebugType de .NET
Dans les projets C#, DebugType permet de spécifier la manière dont les informations de débogage sont générées.
Les valeurs représentatives sont les suivantes :
| DebugType | Signification |
|---|---|
portable |
Génère un Portable PDB comme fichier séparé |
embedded |
Intègre des informations de débogage équivalentes au Portable PDB dans le .dll / .exe |
full |
Génère un PDB dans le format par défaut de la plateforme courante |
pdbonly |
En C# 6.0 et versions ultérieures, ne diffère plus vraiment de full |
none |
Ne génère aucun PDB |
Dans les projets .NET SDK-style actuels, le DebugType de C# vaut par défaut portable, aussi bien en Debug qu’en Release.
Il n’est donc normalement pas nécessaire de spécifier explicitement DebugType juste pour obtenir un Portable PDB.
L’écrire explicitement a un sens lorsque vous voulez, en tant que projet ou organisation, signaler « on fige ce format », rendre plus visible la différence avec d’anciens projets, ou choisir volontairement une politique différente du défaut telle que embedded / none.
Pour une bibliothèque NuGet ou une distribution externe, on examine s’il faut choisir portable, embedded ou .snupkg.
Par exemple, pour générer explicitement un Portable PDB, on écrit ceci :
<PropertyGroup>
<DebugType>portable</DebugType>
</PropertyGroup>
Pour ne pas générer de fichier PDB séparé et l’intégrer plutôt à l’assembly :
<PropertyGroup>
<DebugType>embedded</DebugType>
</PropertyGroup>
Si vous ne voulez vraiment aucun PDB en build Release, vous pouvez écrire ceci :
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<DebugType>none</DebugType>
</PropertyGroup>
Mais cette décision doit être prise avec prudence. Configurer un build Release pour ne produire aucun PDB peut vous mettre vous-même en difficulté lors d’une enquête sur incident de production.
15. DebugSymbols=false suffit-il ?
Pour arrêter la génération de PDB, on voit parfois un exemple où DebugSymbols est mis à false :
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<DebugSymbols>false</DebugSymbols>
</PropertyGroup>
Mais si l’intention est de supprimer la génération de PDB de façon certaine, il est plus clair de mettre DebugType à none :
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<DebugType>none</DebugType>
</PropertyGroup>
Ce paramètre peut être utilisé comme politique de distribution d’une bibliothèque ou d’une application. Mais, répétons-le, ne pas produire de PDB dégrade la capacité d’enquête en cas d’incident.
En pratique, on rencontre souvent cette répartition :
Le PDB est toujours généré en tant qu'artefact de build
La question de le déployer sur le serveur de production se décide séparément
Même sans déploiement, on le conserve dans les artefacts de CI ou sur un serveur de symboles
16. Le PDB en C++ diffère un peu de celui de .NET
Le PDB en C++ se situe dans un contexte un peu différent de celui de .NET.
En Visual C++, les PDB sont générés par des options telles que /Zi ou /ZI.
Le PDB utilisé par le compilateur et celui que l’éditeur de liens (linker) produit finalement pour le .exe / .dll entrent aussi en jeu.
En C++, le PDB est absolument essentiel pour lire les adresses du code natif, les fonctions, les types, les variables locales, l’inlining et les positions post-optimisation.
De plus, lors d’une enquête sur un incident natif, la situation sans PDB tend à ressembler à ceci :
L'adresse de l'exception est connue
Le nom du module est connu
Mais le nom de la fonction et la ligne source ne sont pas connus
Pour les applications qui mélangent C++ et C#, le P/Invoke, le C++/CLI, ou les applications .NET appelant des DLL natives, il faut non seulement le PDB côté .NET, mais aussi le PDB côté natif.
17. Public symbols et private symbols
Dans le monde des symboles Windows, on distingue les public symbols et les private symbols.
Grossièrement, la différence est la suivante :
| Type | Idée des informations contenues |
|---|---|
| private symbols | Informations quasi complètes, incluant variables locales, types, paramètres et détails internes |
| public symbols | Informations réduites en vue d’une publication, telles que noms de fonctions et adresses |
Pour les symboles distribués vers l’extérieur, il arrive qu’on retire les private symbols pour ne conserver que les public symbols.
C’est pour équilibrer la capacité de débogage avec le périmètre de divulgation d’informations.
Par exemple : on veut exposer le minimum de noms de fonctions pour pouvoir analyser les plantages du produit chez les clients, mais on ne veut pas exposer les noms de variables locales ni les informations de type internes. Dans ce genre de cas, on utilise un PDB « stripped » (allégé).
Dans le développement natif orienté Windows, des outils comme PDBCopy servent à produire des PDB dont les private symbols ont été retirés.
À l’inverse, pour l’enquête interne sur incident, il faut conserver le PDB complet. S’il ne reste que le PDB réduit destiné à l’extérieur, une enquête approfondie sera compromise.
18. Où le débogueur cherche-t-il les PDB ?
Visual Studio et WinDbg cherchent les PDB à plusieurs endroits.
Les emplacements représentatifs sont les suivants :
Le dossier de sortie du projet
Le même dossier que le .dll / .exe
Le chemin d'origine du PDB enregistré dans le .dll / .exe
Les dossiers spécifiés dans les paramètres de symboles de Visual Studio
Le cache local de symboles
Un serveur de symboles interne
Microsoft Symbol Server
NuGet.org Symbol Server
Des serveurs de symboles tels que Azure Artifacts
Si un PDB existe mais ne se charge pas, vérifiez les points suivants dans l’ordre :
Le PDB correspond-il au binaire visé ?
Le PDB figure-t-il dans le chemin de recherche du débogueur ?
Le serveur de symboles est-il accessible ?
Une ancienne version subsiste-t-elle dans le cache local ?
Le chargement des symboles est-il désactivé pour le module visé ?
Le paramètre Just My Code le traite-t-il comme du code externe ?
Dans Visual Studio, la fenêtre Modules pendant le débogage permet de vérifier l’état de chargement des symboles de chaque module.
Debug
Windows
Modules
Regardez-y le Symbol Status du DLL visé.
Les quatre affichages courants sont les suivants :
Symbols loaded.
Cannot find or open the PDB file.
PDB does not match image.
Skipped loading symbols.
En cas de blocage lié au PDB, regarder d’abord la fenêtre Modules est le chemin le plus rapide.
19. Qu’est-ce qu’un serveur de symboles ?
Un serveur de symboles est un mécanisme qui permet au débogueur de récupérer des fichiers de symboles tels que des PDB au moment où il en a besoin.
Se contenter de placer les PDB dans un dossier partagé peut fonctionner un certain temps. Mais dès que le nombre de versions augmente, cela s’effondre rapidement.
PDB de MyApp v1.0.0
PDB de MyApp v1.0.1
PDB de MyApp v1.0.1 hotfix
PDB de MyApp v1.1.0-beta
PDB avec des paramètres différents rien que pour le client A
On se retrouve avec des dizaines de fichiers tous nommés MyApp.pdb.
Un serveur de symboles organise les PDB non pas par simple nom de fichier, mais selon leur information de correspondance avec le binaire. Le débogueur peut ainsi trouver plus facilement « le PDB qui convient à ce DLL ».
Voici un exemple de configuration envisageable en pratique :
Microsoft Symbol Server
Utilisé pour récupérer les symboles de Windows, du runtime .NET, etc.
NuGet.org Symbol Server
Utilisé pour récupérer les symboles des packages NuGet publics
Serveur de symboles interne
Stocke les PDB de vos propres applications et bibliothèques
Cache local de symboles
Réutilise les PDB déjà récupérés pour accélérer le débogage
Si vous enquêtez sur des incidents de production dans un service interne, il est très pratique de mettre en place un mécanisme par lequel la CI publie les PDB vers un magasin de symboles interne.
20. Qu’est-ce que Source Link ?
Source Link est un mécanisme qui relie les PDB au système de gestion de source.
Même si le PDB sait que « telle position correspond à tel fichier source », le débogueur ne peut pas l’afficher si ce fichier source n’est pas disponible localement.
Avec Source Link, le débogueur peut utiliser les informations contenues dans le PDB pour récupérer, depuis GitHub, Azure Repos, GitLab, Bitbucket, etc., le fichier source du commit correspondant.
Autrement dit, Source Link résout le problème suivant :
Vous voulez pénétrer en mode pas à pas dans une bibliothèque récupérée via NuGet
Vous n'avez pas cloné localement la source de cette bibliothèque
Mais vous disposez du PDB et des informations du dépôt
Le débogueur va chercher lui-même la source du bon commit
Cela améliore considérablement l’expérience des utilisateurs de la bibliothèque.
Le point clé de Source Link est qu’il fait référence non pas à « la dernière branche main », mais au « commit qui a produit ce binaire ».
C’est le fait d’être relié à la source telle qu’elle était au moment du build — et non à la source la plus récente — qui donne tout son sens à ce mécanisme.
21. Source Link à partir de .NET 8
À partir du SDK .NET 8, la prise en charge de Source Link s’est améliorée.
Pour les fournisseurs couramment utilisés — GitHub, Azure Repos, GitLab, Bitbucket — le mécanisme de Source Link est désormais inclus directement dans le SDK .NET.
L’idée, répandue auparavant, qu’il faut absolument ajouter explicitement Microsoft.SourceLink.GitHub ou équivalent devient donc de plus en plus datée.
Il reste cependant des cas nécessitant une vérification :
Vous compilez avec un SDK antérieur à .NET 8
Il s'agit d'un vieux projet qui n'est pas au format SDK-style
Vous utilisez un hébergement Git personnalisé, on-premise
Vous utilisez un fournisseur Source Link en dehors de l'ensemble standard
Vous voulez aussi peaufiner les métadonnées du package NuGet
Pour faire figurer les informations de dépôt dans le package NuGet, on utilise ce paramètre :
<PropertyGroup>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
</PropertyGroup>
Si vous devez intégrer des fichiers non suivis (untracked) dans le PDB, envisagez ce paramètre :
<PropertyGroup>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
</PropertyGroup>
Attention, l’intégration a un impact sur le périmètre de divulgation d’informations. Ce que l’on inclut dans le PDB doit être décidé en fonction du public visé et de la politique opérationnelle.
22. Qu’est-ce qu’un embedded PDB ?
Lorsque vous spécifiez embedded pour DebugType, les informations de débogage du Portable PDB sont intégrées dans le .dll ou le .exe.
Dans ce cas, aucun fichier .pdb séparé n’est généré.
<PropertyGroup>
<DebugType>embedded</DebugType>
</PropertyGroup>
C’est pratique dans des situations comme celles-ci :
- Vous voulez distribuer quelque chose proche d’un fichier unique
- Vous voulez éviter d’oublier de fournir le PDB
- Un petit outil interne, où vous voulez conserver les informations de débogage avec le reste
- Vous voulez réduire la charge de distribution des PDB pour un package NuGet
Il y a cependant des inconvénients :
- La taille de l’assembly augmente
- Les informations de débogage sont toujours incluses dans le distribué
- Le contrôle du périmètre de divulgation d’informations devient plus grossier
- Pour les grosses bibliothèques, cela affecte la taille du restore et de la distribution
Le PDB embedded est pratique, mais « il suffit de tout mettre en embedded » n’est pas une réponse universelle.
En particulier pour les bibliothèques publiées à l’extérieur, il faut réfléchir à ce qui convient le mieux entre un package de symboles via .snupkg, Source Link, l’inclusion d’un PDB classique, ou l’embedded.
23. Qu’est-ce qu’un .snupkg ?
.snupkg est le format de package de symboles de NuGet.
Un package NuGet classique est un .nupkg.
Un package de symboles est un .snupkg.
MyLibrary.1.2.3.nupkg
MyLibrary.1.2.3.snupkg
Le .nupkg contient la bibliothèque elle-même, référencée par l’utilisateur.
Le .snupkg sert à distribuer le PDB destiné au débogage.
Le point important ici est que le .snupkg est fondamentalement destiné aux Portable PDB de code managé.
Au minimum sur le serveur de symboles de NuGet.org, seuls les Portable PDB sont pris en charge ; les Windows PDB produits par des projets natifs tels que C++ ne sont pas acceptés.
Si vous devez distribuer ou conserver des Windows PDB, envisagez d’autres circuits : le .symbols.nupkg historique, un serveur de symboles interne, ou des artefacts de CI.
Pour en créer un, on écrit par exemple ceci :
<PropertyGroup>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup>
On peut aussi le spécifier en ligne de commande :
dotnet pack -c Release -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg
Pour une bibliothèque NuGet publique, utiliser .snupkg avec Source Link permet de mieux équilibrer la taille de distribution et l’expérience de débogage que d’inclure le PDB directement dans le .nupkg principal.
Attention toutefois à l’état de prise en charge des flux et des outils.
Si votre flux NuGet interne ne prend pas en charge .snupkg, il faudra choisir une autre méthode.
24. Faut-il placer les PDB en production ?
« Faut-il déployer les PDB en production ? » n’est pas un simple oui ou non.
Il y a quatre axes de décision :
La facilité d'enquête en cas d'incident
Le risque de divulgation d'informations
La taille de la distribution
Les règles opérationnelles
Pour un système interne, une pratique où le .dll et le .pdb sont placés dans le même dossier reste réaliste.
Les numéros de ligne apparaissent alors plus facilement dans les journaux d’exceptions, et l’analyse de dump devient elle aussi plus simple.
Pour une application distribuée à l’extérieur, il faut juger avec prudence si le PDB doit être inclus tel quel. La structure interne, les noms de variables locales ou les chemins source peuvent devenir visibles. Si nécessaire, on peut opter pour se limiter aux public symbols, passer par un serveur de symboles, ou se contenter d’une conservation à des fins de support.
Pour un service web, au-delà de la question de placer ou non le PDB sur le serveur, il faut aussi réfléchir au traitement des traces de pile apparaissant dans les journaux. Les traces de pile ne devraient pas être renvoyées dans des réponses externes. On peut les conserver dans les journaux internes, mais il faut alors décider des droits de consultation et de la durée de conservation.
En pratique, voici notre recommandation :
Générer toujours le PDB
Le conserver comme artefact de build
Décider du déploiement en production selon le périmètre de diffusion du système
En cas de publication externe, vérifier le périmètre d'informations divulguées
Le placer dans un endroit récupérable pour l'analyse de dump
25. Le PDB est-il une information confidentielle ?
Le PDB ne nécessite pas forcément le même traitement que le code source lui-même ou une clé privée. Mais le traiter comme un fichier inoffensif est également dangereux.
Voici ce qu’un PDB peut potentiellement révéler :
- Les chemins locaux des développeurs
- La structure des dossiers internes
- Les noms de projets
- Les noms de classes, de méthodes
- Les noms de variables locales
- Les noms d’API internes
- Le vocabulaire métier
- L’URL du dépôt Source Link
- La source intégrée
- La configuration du Source Server
En particulier, avec l’ancien mécanisme Source Server et certaines fonctionnalités des PDB natifs, le débogueur peut se retrouver à exécuter des commandes pour récupérer la source. Il faut éviter d’utiliser sans condition des PDB ou des serveurs de symboles non fiables.
Il faut aussi être prudent lorsqu’on fait analyser un PDB potentiellement malveillant par des outils ou bibliothèques d’analyse. Pour les systèmes qui traitent automatiquement des PDB reçus de l’extérieur, il faut concevoir en considérant l’entrée comme non fiable.
En résumé, voici comment traiter le PDB de façon sûre :
Protéger le PDB interne complet comme un artefact interne
Vérifier le contenu et le périmètre de diffusion de tout PDB publié à l'extérieur
Si la cible de Source Link est un dépôt privé, gérer l'authentification et les droits
Ne pas enregistrer de serveur de symboles non fiable dans le débogueur
26. Politique de conservation des PDB en CI/CD
Un PDB qui ne subsiste que sur le PC local d’un développeur ne sert à rien. Ce dont on a besoin lorsqu’un incident de production survient, c’est du PDB correspondant au build effectivement mis en production.
C’est pourquoi, en CI/CD, on les conserve sous une forme comme celle-ci :
Numéro de build : 2026.06.10.1234
Identifiant de commit : abcdef123456...
Artefacts :
MyApp.dll
MyApp.pdb
MyApp.deps.json
MyApp.runtimeconfig.json
package.zip
digest de l'image de conteneur
Dans la mesure du possible, on relie aussi ces informations :
Commit Git
Tag Git
Numéro de release
Nom de l'environnement
Configuration de build
Framework cible
RID
Digest de l'image de conteneur
Fichier de verrouillage NuGet (lock file)
L’important n’est pas de conserver le PDB de manière isolée, mais de ne jamais perdre la trace de quel PDB correspond à quel binaire.
Une exploitation où l’on continue de remplacer un unique MyApp.pdb sur un partage de fichiers finira par se casser un jour.
Rendez-les récupérables par build, par version, par commit.
27. Schémas de placement des PDB
Il existe plusieurs schémas pratiques pour la gestion des PDB.
Schéma 1 : placer le PDB dans le même dossier que le DLL
Le plus simple.
publish/
MyApp.dll
MyApp.pdb
L’avantage est que la configuration est simple. Le débogueur et le runtime le trouvent facilement, et les numéros de ligne apparaissent aussi plus facilement dans les journaux d’exceptions.
L’inconvénient est que le distribué contient des informations de débogage. Cela peut ne pas convenir à une distribution externe.
Schéma 2 : ne pas déployer le PDB, le conserver dans les artefacts de CI
On garde le PDB hors des serveurs de production, en le conservant dans les artefacts de CI.
release-artifacts/
app.zip
symbols.zip
Lors d’un incident de production, on récupère les dumps et les journaux, on retrouve le PDB du numéro de build correspondant, puis on analyse.
Cela permet de limiter le périmètre de divulgation d’informations, au prix d’une procédure de récupération au moment de l’enquête.
Schéma 3 : publier vers un serveur de symboles interne
Pour les grandes équipes, c’est ce qui se gère le mieux.
La CI publie le PDB vers le magasin de symboles au moment du build. Le Visual Studio / WinDbg des développeurs ou des enquêteurs référence alors ce serveur de symboles.
L’avantage est de pouvoir gérer en sécurité des PDB de nombreuses versions. L’inconvénient est la mise en place initiale et le contrôle d’accès nécessaires.
Schéma 4 : distribuer via le .snupkg de NuGet
Une option solide pour les bibliothèques publiques.
MyLibrary.1.2.3.nupkg
MyLibrary.1.2.3.snupkg
L’utilisateur ne restaure que le package normal, et seuls les symboles nécessaires au moment du débogage sont récupérés.
Combiné à Source Link, cela facilite le passage en mode pas à pas dans la source, même pour des bibliothèques externes.
Schéma 5 : opter pour un PDB embedded
Pratique pour éviter d’oublier le PDB.
<PropertyGroup>
<DebugType>embedded</DebugType>
</PropertyGroup>
Mais attention à la taille de l’assembly et au périmètre de divulgation d’informations.
28. Ce qu’il faut vérifier en premier sur un projet existant
Si vous voulez revoir la gestion des PDB sur un projet .NET existant, commencez par ces vérifications :
Le PDB est-il généré en build Release ?
Où le PDB généré est-il stocké ?
Le DLL mis en production et son PDB sont-ils conservés ensemble, en correspondance ?
Le PDB peut-il être récupéré au moment de l'analyse de dump ?
Source Link est-il activé ?
Pour une bibliothèque NuGet, publiez-vous un .snupkg ?
Le PDB n'inclut-il pas trop d'informations inutiles ?
Dans le csproj, vérifiez des paramètres comme ceux-ci :
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<DebugType>portable</DebugType>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
</PropertyGroup>
Pour un package NuGet, ceci est aussi à envisager :
<PropertyGroup>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup>
Mais il ne suffit pas d’appliquer les mêmes paramètres à tous les projets. La solution optimale diffère entre application interne, bibliothèque externe, produit on-premise, SaaS et OSS.
29. Comment procéder quand le PDB ne se charge pas
Lorsqu’un PDB ne se charge pas, on gagne à décomposer le problème étape par étape plutôt qu’à recompiler à l’instinct.
1. Vérifier le module visé
Dans la fenêtre Modules de Visual Studio, recherchez le DLL / EXE visé.
Debug > Windows > Modules
Les colonnes à examiner sont les suivantes :
Module
Path
Symbol Status
Symbol File
Version
Timestamp
2. Lire l’état des symboles
Chaque affichage se lit à peu près ainsi :
| Affichage | Signification |
|---|---|
| Symbols loaded | Chargé |
| Cannot find or open the PDB file | Le PDB est introuvable |
| PDB does not match image | Un PDB existe, mais il ne correspond pas au binaire visé |
| Skipped loading symbols | Possiblement non chargé à cause d’un paramètre |
3. Vérifier que votre PDB local est bien celui du même build
Une erreur fréquente consiste à utiliser un PDB recompilé en local.
Même avec la même source, des conditions de build différentes peuvent produire un décalage. Récupérez, depuis les artefacts de CI, le PDB exact déployé en production.
4. Vérifier le chemin de symboles
Dans Visual Studio, vérifiez ceci :
Tools > Options > Debugging > Symbols
Dans WinDbg, vérifiez par exemple ainsi :
.sympath
.reload
!sym noisy
Si vous utilisez les symboles publics de Microsoft, spécifier aussi un cache local est pratique :
srv*C:\Symbols*https://msdl.microsoft.com/download/symbols
5. Suspecter le cache
Il se peut que vous récupériez un vieux PDB ou un cache corrompu. Videz le cache de symboles, spécifiez un cache différent, ou examinez en détail les journaux de chargement.
30. Le PDB et « Just My Code »
Visual Studio dispose d’un paramètre appelé Just My Code.
Il consiste à restreindre la cible du débogage à « votre propre code », rendant plus difficile l’exécution pas à pas du code externe. Pratique au quotidien, il peut cependant devenir une source de confusion lors de la vérification des PDB ou de Source Link.
Par exemple, si une bibliothèque NuGet externe dispose d’un PDB et de Source Link mais que vous ne pouvez pas y entrer en mode pas à pas, vérifiez les points suivants :
Just My Code est-il activé et traite-t-il ce code comme externe ?
Enable Source Link support est-il activé ?
Le NuGet.org Symbol Server est-il activé ?
Le package visé publie-t-il un PDB / .snupkg ?
La cible de récupération de la source est-elle accessible ?
Avant de conclure « le PDB est fautif », vérifiez aussi les paramètres du débogueur.
31. PDB et décompilation
Les versions récentes de Visual Studio peuvent décompiler des assemblys .NET et utiliser le résultat pour le débogage.
Cela permet de suivre, dans une certaine mesure, le contenu de bibliothèques externes même sans PDB ni source.
La décompilation n’est cependant pas une solution miracle :
Les commentaires d'origine ne reviennent pas
Les espaces et la structure d'origine ne reviennent pas
Les noms de variables locales peuvent changer
async / itérateurs / pattern matching peuvent apparaître différents de l'original
La correspondance est difficile à suivre dans du code optimisé
Si vous disposez du PDB et de Source Link, il est généralement plus naturel de les utiliser. Considérez la décompilation comme « une solution de repli pour quand il n’y a ni PDB ni source ».
32. Conception des journaux et PDB
Le PDB a aussi un lien avec la conception des journaux (logs).
Par exemple, un journal d’exceptions affichant nom de fichier et numéro de ligne est plus facile à enquêter. Mais s’appuyer uniquement sur les journaux est dangereux.
Lors d’un incident de production, des choses comme celles-ci se produisent :
Le numéro de ligne affiché dans le journal ne correspond pas à la branche main actuelle
Un hotfix a été redéployé sous le même numéro de version
Le PDB n'a pas été conservé, on ne peut donc pas vérifier le sens du numéro de ligne
L'image de conteneur subsiste, mais on ne connaît pas le commit source correspondant
C’est pourquoi il est utile que les journaux affichent, en plus des numéros de ligne, des informations de build :
ApplicationVersion: 1.8.3
GitCommit: abcdef1234567890
BuildNumber: 20260610.12
Environment: Production
Lorsque le PDB, la source, les journaux, les dumps et l’historique de déploiement se relient entre eux, l’enquête sur incident devient considérablement plus simple.
33. Le PDB en exploitation conteneurisée
Lorsqu’on fait tourner une application .NET dans un conteneur, il faut clarifier la gestion du PDB.
Par exemple, la question d’inclure ou non le PDB dans l’image Docker.
FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY publish/ .
ENTRYPOINT ["dotnet", "MyApp.dll"]
Si publish/ contient le PDB, il finit tel quel dans l’image aussi.
Cela présente des avantages :
- Les numéros de ligne apparaissent plus facilement dans les traces de pile à l’intérieur du conteneur
- On le retrouve facilement sur le même système de fichiers au moment de récupérer un dump
- La correspondance lors de l’enquête est simple
Il y a aussi des préoccupations :
- La taille de l’image augmente
- Les informations de débogage sont incluses dans l’image de production
- Si l’image est distribuée à l’extérieur, le périmètre de divulgation s’élargit
Pour un SaaS strictement interne, inclure le PDB dans l’image est un choix tout à fait envisageable. Pour un produit on-premise remis à des clients externes, conserver le PDB séparément peut être préférable.
Dans tous les cas, même si le PDB n’est pas inclus dans l’image, conserver le PDB correspondant comme artefact reste obligatoire.
34. Publication en fichier unique et PDB
.NET propose la publication en fichier unique (single-file).
dotnet publish -c Release -r win-x64 -p:PublishSingleFile=true
Là aussi, il faut vérifier comment les informations de débogage sont traitées.
Passer en fichier unique ne rend pas l’enquête sur incident inutile. Au contraire, plus le mode de distribution devient particulier, plus il devient important de décider comment conserver les symboles et la source correspondants.
Voici ce qu’il faut fixer comme politique :
Faut-il distribuer le PDB comme fichier séparé ?
Faut-il utiliser DebugType=embedded ?
Faut-il conserver les symboles uniquement en interne ?
Comment analyser les dumps de crash ?
Lorsqu’on utilise la publication single-file, le trimming, l’AOT, etc., l’expérience d’enquête peut différer de celle d’un assembly IL classique. Avant la mise en production, il est plus sûr de tester une fois « comment lit-on cela en cas de plantage ? ».
35. PDB, trimming et AOT
Sur .NET actuel, il arrive d’utiliser le trimming ou le Native AOT.
Dans ce cas, ce n’est pas seulement le PDB qui entre en jeu, mais aussi les symboles natifs générés et les informations de débogage propres à chaque plateforme.
Par exemple, sous Linux ce sera le DWARF, sous macOS le dSYM, sous Windows le PDB : il faut aussi penser aux informations de débogage côté natif.
Même pour une application .NET, la conception des symboles se complexifie dans des configurations comme celles-ci :
Native AOT
Publication self-contained
PublishSingleFile
ReadyToRun
Appel de DLL natives via P/Invoke
Inclusion de C++/CLI
Pour une application web ou une bibliothèque de classes ordinaire, comprendre le Portable PDB et Source Link suffit pour commencer. Mais plus le mode de distribution se sophistique, plus « comment analyser ce plantage ? » doit faire partie de la conception du build.
36. Points d’attention pour les projets .NET Framework
Les anciens projets .NET Framework peuvent différer des projets SDK-style en termes de paramètres et de valeurs par défaut.
Par exemple, des différences comme celles-ci :
Le format du csproj est ancien
Le projet utilise packages.config
La valeur par défaut de DebugType diffère du .NET actuel
Le Windows PDB est utilisé
La configuration de Source Link nécessite des packages ou des paramètres MSBuild supplémentaires
La version de MSBuild de la CI est ancienne
Sur .NET Framework aussi, les principes du PDB restent les mêmes :
Non indispensable à l'exécution
Important pour le débogage et l'enquête sur incident
Le PDB doit correspondre au binaire visé
Le PDB du build Release doit être conservé
Mais copier tel quel les explications du .NET actuel peut ne pas se comporter comme attendu sur d’anciens projets.
Pour les actifs existants, commencez par vérifier la sortie effective :
msbuild MyApp.csproj /p:Configuration=Release
Get-ChildItem bin\Release -Filter *.pdb -Recurse
Ensuite seulement, mettez en ordre les paramètres de build et les artefacts de CI.
37. Que faire pour les bibliothèques OSS ?
Pour une bibliothèque .NET OSS, nous recommandons fondamentalement cette configuration :
Générer le PDB même en Release
Utiliser le Portable PDB
Activer Source Link
Publier un .snupkg sur NuGet
Configurer les métadonnées Repository
Viser des builds déterministes
Exemple :
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<DebugType>portable</DebugType>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
</PropertyGroup>
Selon le SDK et l’hébergement, le package Source Link supplémentaire peut ne pas être nécessaire.
Pour un SDK ancien ou un hébergement particulier, ajoutez le package Microsoft.SourceLink.* correspondant.
Dans l’OSS, le fait que les utilisateurs puissent entrer en mode pas à pas dans la bibliothèque constitue en soi une qualité. « Une bibliothèque que l’on peut lire quand quelque chose ne va pas » inspire confiance rien que pour cela.
38. Que faire pour les bibliothèques internes ?
Source Link et le PDB restent pertinents pour les bibliothèques internes aussi.
Ce sont même précisément les bibliothèques internes où pouvoir entrer en mode pas à pas depuis les applications métier aide le plus.
Si vous utilisez un flux NuGet interne, envisagez les points suivants :
Le flux interne prend-il en charge .snupkg ?
Sinon, incluez-vous le PDB dans le .nupkg ?
Mettez-vous en place un serveur de symboles interne ?
Comment gérez-vous l'authentification vers le dépôt Git ?
La source reste-t-elle accessible après un départ ou une mutation ?
Ce n’est pas parce que c’est à usage interne qu’il faut laisser le PDB n’exister que sur un PC local.
Générez-le en CI et stockez-le dans un endroit que l’équipe peut récupérer.
39. Que faire pour les produits on-premise ?
Pour les produits on-premise distribués dans l’environnement des clients, la gestion du PDB devient plus difficile.
Inclure le PDB rend plus faciles à lire les dumps et journaux récupérés chez le client. Mais cela rend aussi la structure interne plus visible.
Voici les options fréquemment envisagées :
Ne pas inclure le PDB, mais conserver la version complète côté éditeur
Ne fournir que des public symbols pour le support client
Récupérer les dumps en cas d'incident et les analyser côté éditeur à l'aide du PDB
Fournir un package de symboles limité aux clients critiques
L’important est de ne pas perdre le PDB après la publication.
Avec les produits on-premise, il arrive d’enquêter sur des incidents concernant une version publiée des années plus tôt. Si le PDB correspondant n’existe plus à ce moment-là, la capacité d’enquête chute fortement.
40. Que se passe-t-il si l’on supprime le PDB ?
Si vous supprimez le PDB, l’application continue de fonctionner. Mais vous en souffrirez plus tard.
On pourrait penser qu’une recompilation depuis le même commit permet de le reproduire. Mais une reproduction parfaite est étonnamment difficile :
La version du SDK diffère
Le résultat de la résolution NuGet diffère
L'heure de build ou les variables d'environnement diffèrent
Le code généré diffère
La compilation conditionnelle diffère
Certains paramètres n'existent qu'en CI
Les outils natifs dont on dépend diffèrent
Des builds déterministes améliorent la reproductibilité, mais même ainsi, « le conserver comme artefact dès le départ » reste la politique la plus sûre.
Le PDB est proche d’une assurance. Sa valeur n’apparaît qu’au moment où l’on en a besoin. Et s’il manque à ce moment-là, il n’y a pas de rattrapage possible.
41. Paramétrage recommandé en pratique
Il n’existe pas de configuration unique qui convienne à tous les projets. Mais pour une application .NET classique, voici une base à laquelle vous pouvez vous référer.
Application interne
<PropertyGroup>
<DebugType>portable</DebugType>
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
</PropertyGroup>
La politique :
Générer le PDB même en Release
Décider du placement en production selon la politique opérationnelle
Toujours le conserver dans les artefacts de CI
Préparer une procédure d'analyse de dump
Bibliothèque NuGet publique
<PropertyGroup>
<DebugType>portable</DebugType>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
</PropertyGroup>
La politique :
Activer Source Link
Publier un .snupkg
Éviter toute intégration de source inutile
Vérifier les métadonnées publiées
Petit outil interne
<PropertyGroup>
<DebugType>embedded</DebugType>
</PropertyGroup>
La politique :
Éviter d'oublier le PDB
Accepter l'augmentation de la taille du distribué
Se limiter à un usage interne
Produit distribué à l’extérieur
Conserver la version complète du PDB en interne
Produire séparément des public symbols si nécessaire
Vérifier le contenu du PDB inclus dans le livrable client
Définir la procédure de récupération et d'analyse des dumps pour le support
42. Liste de contrôle pour examiner un PDB
Pour finir, voici une liste de contrôle à garder sous la main quand la gestion du PDB pose question.
À quel DLL / EXE ce PDB correspond-il ?
Ce DLL / EXE a-t-il été construit à partir de quel commit ?
S'agit-il du PDB du Release de production, et non de celui du build Debug ?
Le PDB est-il conservé comme artefact de CI ?
Existe-t-il un serveur de symboles ou une procédure de récupération ?
Source Link est-il activé ?
Les droits sur la cible de récupération de la source sont-ils appropriés ?
Le PDB contient-il des informations que l'on ne souhaite pas divulguer ?
Pour une distribution externe, existe-t-il une politique public/private symbol ?
A-t-on vérifié que le PDB se charge bien lors de l'analyse de dump ?
Trois points comptent particulièrement :
Le PDB n'est pas un exécutable, mais une information d'enquête
Le PDB doit correspondre au binaire visé
Le PDB doit être conservé avant même qu'un incident de production ne survienne
43. Conclusion
Le PDB n’est pas ce « fichier mystérieux » qui apparaît à côté de votre .dll ou .exe, mais l’information de débogage qui relie le binaire issu du build au code source que les développeurs peuvent lire.
Il n’est pas indispensable à l’exécution normale de l’application. Mais il est essentiel pour le débogage, l’enquête sur les exceptions, l’analyse de dump, le profilage et le passage en mode pas à pas dans des bibliothèques externes.
Le PDB est utile même pour un build Release. C’est même précisément le PDB correspondant au build Release dont on a besoin lors d’un incident de production.
La décision de placer ou non le PDB en environnement de production dépend du périmètre de divulgation d’informations et de la politique opérationnelle. Mais générer le PDB et le conserver comme artefact de build est nécessaire dans la quasi-totalité des projets.
En pratique, voici une politique de base à adopter :
Générer le PDB même en Release
Le conserver comme artefact de CI/CD
Relier binaire, PDB, identifiant de commit et numéro de build
Rendre la source accessible via Source Link
Envisager le .snupkg pour les bibliothèques NuGet
Vérifier les informations de symboles divulguées lors d'une distribution externe
Le PDB ne se fait pas remarquer tant que rien ne va mal. Mais lorsqu’un problème survient, c’est l’indice essentiel qui ramène l’enquêteur jusqu’au code source.
Plutôt que « le PDB peut être supprimé, ça continue de fonctionner », mieux vaut penser ceci :
Le PDB est la carte dont votre future enquête sur incident aura besoin.
Références
- Symbols in .NET - Microsoft Learn
- Specify symbol (.pdb) and source files in the Visual Studio debugger - Microsoft Learn
- C# Compiler Options that control code generation - Microsoft Learn
- Portable PDB Symbols - Microsoft Learn
- Source Link included in the .NET SDK - Microsoft Learn
- dotnet/sourcelink - GitHub
- Creating symbol packages (.snupkg) - Microsoft Learn
- Public and Private Symbols - Microsoft Learn
- Using PDBCopy - Microsoft Learn
- dotnet-symbol diagnostic tool - Microsoft Learn
- dotnet-dump diagnostic tool - Microsoft Learn
Articles associés
Articles récents partageant les mêmes étiquettes, pour approfondir des sujets proches.
Bien gérer les jetons d'emprunt d'identité Windows — emprunt des privilèges par thread et retour sécurisé au contexte d'origine
Un guide pratique des jetons d'emprunt d'identité sous Windows : jetons d'accès, jetons principaux, jetons de thread, niveaux d'emprunt d...
Le malentendu selon lequel TCP renvoie les données dans les mêmes unités que Send — concevoir la réception comme un flux d'octets
Supposer que TCP restitue les données dans les mêmes unités que Send ou Write mène à des fragmentations, des fusions, des données corromp...
Distinguer l'attente du GC d'une fuite mémoire en .NET — Procédure pratique pour observer, comparer et prouver la croissance mémoire
Procédure pour déterminer si la croissance de la mémoire d'une application .NET est une simple attente du ramasse-miettes ou une véritabl...
Jusqu'à quand les applications VB6 continueront-elles de fonctionner ? — état du support du runtime et démarche concrète vers une migration .NET
Jusqu'à quand les applications VB6 continueront-elles de fonctionner ? Cet article clarifie l'asymétrie entre la politique de support du ...
Lire un dump de plantage avec WinDbg + SOS — Guide pratique d'analyse après la collecte
Explique comment lire concrètement un dump de plantage Windows collecté, à l'aide de WinDbg et de l'extension SOS. Couvre la configuratio...
Sujets associés
Ces pages replacent le sujet dans un contexte plus large de services et de décisions.
Thèmes techniques Windows
Portail des sujets sur le développement Windows, l'analyse des incidents et la valorisation des actifs existants.
Services liés à ce sujet
Cet article est directement lié aux services suivants.
Développement d'applications Windows
Applications métier, intégration d'équipements et outils de communication, des besoins au développement.
Questions fréquentes
Questions souvent posées lors d’une consultation sur le sujet de cet article.
- Qu'est-ce qu'un fichier PDB ?
- PDB est l'abréviation de Program Database (base de données de programme) : c'est un fichier d'informations de débogage, aussi appelé fichier de symboles. Son rôle est de relier le `.dll` ou `.exe` issu de la compilation au code source que les développeurs peuvent lire. Il contient les noms de fonctions et de méthodes, les noms de variables locales, les noms de fichiers source et les numéros de ligne, la correspondance entre les positions dans la source et les instructions compilées, ainsi que les informations de récupération de source pour Source Link. Le débogueur et les outils de diagnostic s'en servent pour déterminer « à quelle ligne source correspond cette instruction ».
- L'application fonctionne-t-elle sans fichier PDB ? Peut-on le supprimer sans risque ?
- En temps normal, le PDB n'est pas nécessaire à l'exécution de l'application : dès lors que le `.dll` ou le `.exe` est présent, elle peut démarrer. Mais sans PDB, il devient difficile de poser des points d'arrêt, d'exécuter pas à pas, d'afficher le nom de fichier et le numéro de ligne dans les traces de pile d'exceptions, d'analyser un dump, ou de pénétrer dans une bibliothèque externe en mode pas à pas. Le PDB n'est pas « un fichier pour faire fonctionner » mais « un fichier pour enquêter » : indépendamment de la question de le déployer ou non en environnement de production, il faut absolument le conserver comme un artefact de build. Si on le supprime, une recompilation à partir du même commit ne garantit étonnamment pas une reproduction complète, ce qui peut se révéler irrattrapable lors d'une enquête sur incident.
- Un PDB est-il nécessaire même pour un build Release ?
- Oui, il l'est. C'est même précisément le PDB du build Release dont on a besoin pour enquêter sur un incident de production. Si ce qui tourne en production est un build Release, disposer du PDB du build Debug ne sert à rien : ce dont le débogueur a besoin, c'est du PDB généré au moment même où ce binaire de production a été construit. Le PDB devant correspondre exactement au binaire visé, la règle de base en CI/CD est de conserver ensemble l'identifiant de commit, le numéro de build, le `.dll`/`.exe` et le `.pdb`. Notons que, dans les projets .NET SDK-style actuels, le Portable PDB est généré par défaut aussi bien en Debug qu'en Release.
- Peut-on placer un fichier PDB en environnement de production ?
- Ce n'est pas un simple oui ou non : la décision se prend selon quatre axes — la facilité d'enquête en cas d'incident, le risque de divulgation d'informations, la taille des artefacts distribués et les règles opérationnelles. Pour un système interne, placer le `.dll` et le `.pdb` dans le même dossier est réaliste : les numéros de ligne apparaissent alors plus facilement dans les journaux d'exceptions. Pour une distribution externe, un PDB peut révéler des chemins locaux, la structure des dossiers internes, des noms de types et de variables locales, ou l'URL du dépôt Source Link : il faut donc juger avec prudence, et envisager si besoin de se limiter aux symboles publics (public symbols) ou de passer par un serveur de symboles. Même sans déploiement, la conservation du PDB correspondant au même build reste obligatoire.
Profil de l’auteur
Page de présentation de l’auteur de l’article.
Go Komura
Représentant de KomuraSoft LLC
Spécialisé dans le développement de logiciels Windows, le conseil technique et l’analyse de pannes, notamment pour les systèmes existants et les incidents difficiles à reproduire.
Liens publics