{"id":7847,"date":"2026-10-07T06:00:00","date_gmt":"2026-10-07T05:00:00","guid":{"rendered":"https:\/\/www.blaess.fr\/christophe\/?p=7847"},"modified":"2026-10-07T06:09:28","modified_gmt":"2026-10-07T05:09:28","slug":"debug-applicatif-avec-eris-linux","status":"publish","type":"post","link":"https:\/\/www.blaess.fr\/christophe\/2026\/10\/07\/debug-applicatif-avec-eris-linux\/","title":{"rendered":"Debug applicatif avec Eris Linux"},"content":{"rendered":"<div class=\"wp-block-image\">\n<figure class=\"alignright size-full is-resized\"><a href=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2026\/10\/thumb-06-4.png\"><img loading=\"lazy\" decoding=\"async\" width=\"721\" height=\"468\" src=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2026\/10\/thumb-06-4.png\" alt=\"\" class=\"wp-image-7956\" style=\"width:300px;height:auto\" srcset=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2026\/10\/thumb-06-4.png 721w, https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2026\/10\/thumb-06-4-300x195.png 300w\" sizes=\"auto, (max-width: 721px) 100vw, 721px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">Une fois <a href=\"https:\/\/www.blaess.fr\/christophe\/2026\/09\/15\/developper-du-code-personnalise-pour-eris-linux\/\" data-type=\"post\" data-id=\"7318\">l&rsquo;application m\u00e9tier d\u00e9velopp\u00e9e<\/a>, le container correspondant <a href=\"https:\/\/www.blaess.fr\/christophe\/2026\/09\/08\/deployer-des-containers-sur-eris-linux\/\" data-type=\"post\" data-id=\"7232\">construit et d\u00e9ploy\u00e9<\/a> sur une carte (ou un groupe de cartes) de test, il est souvent n\u00e9cessaire de passer \u00e0 une \u00e9tape moins r\u00e9jouissante&nbsp;: le <em>debug<\/em> !<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Analyser le comportement d&rsquo;une application fonctionnant dans un container, s&rsquo;ex\u00e9cutant lui-m\u00eame dans une machine distante &#8211; qui est pr\u00e9vue pour emp\u00eacher toute intrusion pour des raisons de s\u00e9curit\u00e9 &#8211; est assez compliqu\u00e9. Toutefois <strong><a href=\"https:\/\/www.blaess.fr\/christophe\/2026\/08\/25\/eris-linux\/\" data-type=\"post\" data-id=\"7123\">Eris Linux<\/a><\/strong> nous propose deux m\u00e9thodes simples pour suivre l&rsquo;ex\u00e9cution de notre code applicatif. (D&rsquo;autres m\u00e9thodes verront probablement le jour, cet article sera modifi\u00e9 en cons\u00e9quence quand ce sera le cas).<\/p>\n\n\n\n<!--more-->\n\n\n\n<p class=\"wp-block-paragraph\">Le premier moyen d&rsquo;analyse de l&rsquo;ex\u00e9cution d&rsquo;un programme sous Linux est de <strong>r\u00e9cup\u00e9rer les messages<\/strong> qu&rsquo;il peut envoyer sur la sortie standard (<code>stdout<\/code>) et la sortie interactive (<code>stderr<\/code>). La seconde m\u00e9thode consistera \u00e0 ex\u00e9cuter le programme sous le contr\u00f4le d&rsquo;un <strong>d\u00e9bogueur distant<\/strong>. Commen\u00e7ons par r\u00e9cup\u00e9rer les messages de sortie d&rsquo;un ex\u00e9cutable.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Quand le programme s&rsquo;ex\u00e9cute dans un <em>container<\/em> sur un syst\u00e8me embarqu\u00e9, le moyen le plus simple est d&rsquo;envoyer les messages sur une machine distante, o\u00f9 l&rsquo;on pourra les r\u00e9cup\u00e9rer et les \u00e9tudier.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u00c0 noter&nbsp;: pour que les m\u00e9thodes d\u00e9crites ci-dessous fonctionnent, vous devrez utiliser au minimum <strong>Eris Linux version 1.2.0<\/strong>. Si vous avez des syst\u00e8mes dans une version pr\u00e9c\u00e9dente, ils peuvent se mettre \u00e0 jour automatiquement si vous avez coch\u00e9 les cases \u00ab\u00a0<em>Automatic system update<\/em>\u00a0\u00bb et \u00ab\u00a0<em>Automatic reboot after update<\/em>\u00a0\u00bb de la configuration \u00ab\u00a0<em>Group setup<\/em>\u00a0\u00bb .<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Programme d&rsquo;exemple<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Je vous conseille de commencer par t\u00e9l\u00e9charger le <em>repository<\/em> suivant, qui contient les exemples que nous avons d\u00e9j\u00e0 utilis\u00e9s dans l&rsquo;article sur le d\u00e9veloppement applicatif&nbsp;: <strong><a href=\"https:\/\/github.com\/eris-linux\/eris-linux-containers\">https:\/\/github.com\/eris-linux\/eris-linux-containers<\/a><\/strong>. Ce d\u00e9p\u00f4t \u00e9tant amen\u00e9 \u00e0 changer r\u00e9guli\u00e8rement, je vous propose de v\u00e9rifier que vous \u00eates bien sur le bon <em>tag<\/em>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;~]$ <strong>git  clone  <a href=\"https:\/\/github.com\/eris-linux\/eris-linux-containers\">https:\/\/github.com\/eris-linux\/eris-linux-containers<\/a><\/strong>\nCloning into 'eris-linux-containers'...\n  &#91;...]\n\n&#91;~]$ <strong>cd  eris-linux-containers\/<\/strong>\n\n&#91;eris-linux-containers]$ <strong>git  checkout  1.1.0<\/strong>\nNote: switching to '1.1.0'.\n  &#91;...]<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Pour tester notre premi\u00e8re possibilit\u00e9 de <em>debug<\/em>, je vous propose d&rsquo;utiliser le programme C suivant, qui \u00e9crit des messages sur ses sorties r\u00e9guli\u00e8rement.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>cat test-debug-stdio\/test-debug-stdio.c <\/strong>\n\n#include &lt;stdio.h&gt;\n#include &lt;stdlib.h&gt;\n#include &lt;unistd.h&gt;\n\nint main(void)\n{\n\tint i = 0;\n\tfor (;;) {\n\t\tfprintf(stderr, \"This message goes to stderr (%d)\\n\", i);\n\t\tfprintf(stdout, \"This message goes to stdout (%d)\\n\", i);\n\t\tsleep(1);\n\t\tif (++i &gt; 5) {\n\t\t\tfflush(stdout);\n\t\t\ti = 0;\n\t\t}\n\t}\n\treturn 0;\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Je place ce fichier dans un sous-r\u00e9pertoire <code>test-debug-stdio\/<\/code> qui contient \u00e9galement le fichier <code>Makefile<\/code> suivant&nbsp;: <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>cat test-debug-stdio\/Makefile<\/strong>\n\nAPP = test-debug-stdio\n\nOBJS = test-debug-stdio.o\n\nCFLAGS += -Wall -g\nLDFLAGS =\n\n\nall: $(APP)\n\n$(APP): $(OBJS)\n\t$(CC) $(CFLAGS) $(LDFLAGS)  $^ -o $@ $(LDLIBS)\n\n%o: %c $(INC)\n\t$(CC) -c $(CFLAGS) $&lt;\n\nclean:\n\trm -rf out *.o $(APP)\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Et le fichier <code>Dockerfile<\/code> :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;eris-linux-containers (master)]$ cat test-debug-stdio\/Dockerfile \n\n\n################### Build container #########################################\nFROM  alpine:latest AS build\nRUN apk add --no-cache build-base file\nWORKDIR \/src\nCOPY test-debug-stdio.c Makefile .\nRUN make\n\n\n################### Final container #########################################\nFROM alpine:latest\nCOPY --from=build \/src\/test-debug-stdio  \/test-debug-stdio\nCMD &#91;\"\/test-debug-stdio\"]\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Le <code>Makefile<\/code> et le <code>Dockerfile<\/code> sont directement adapt\u00e9s de l&rsquo;exemple <code>05-hello-world-in-c<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Nous compilons le programme applicatif et cr\u00e9ons un container avec la commande&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>.\/create-container  arm64  test-debug-stdio\/  test-debug-stdio<\/strong><\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Le container est \u00ab\u00a0<em>upload\u00e9<\/em>\u00a0\u00bb sur le serveur Eris Linux et d\u00e9ploy\u00e9 vers un syst\u00e8me de test gr\u00e2ce aux onglets \u00ab\u00a0<em>My devices<\/em>\u00a0\u00bb et \u00ab\u00a0<em>My containers<\/em>\u00a0\u00bb du <em>Device Manager<\/em>.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Redirections des messages<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Dans l&rsquo;onglet \u00ab\u00a0<em>My devices<\/em>\u00a0\u00bb nous cliquons ensuite sur le bouton \u00ab\u00a0<strong>Setup<\/strong>\u00a0\u00bb (en bas \u00e0 droite de l&rsquo;\u00e9cran) correspondant au <em>Device<\/em> (pas au groupe). La fen\u00eatre suivante s&rsquo;ouvre&nbsp;:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><a href=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2026\/09\/fig-6.01.png\"><img loading=\"lazy\" decoding=\"async\" width=\"614\" height=\"465\" src=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2026\/09\/fig-6.01.png\" alt=\"\" class=\"wp-image-7877\" srcset=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2026\/09\/fig-6.01.png 614w, https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2026\/09\/fig-6.01-300x227.png 300w\" sizes=\"auto, (max-width: 614px) 100vw, 614px\" \/><\/a><figcaption class=\"wp-element-caption\">Fig. 1 &#8211; Fen\u00eatre de <em>setup<\/em> d&rsquo;un <em>device<\/em>.<\/figcaption><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">Dans le bas de cette fen\u00eatre, des cases \u00e0 cocher permettent d&rsquo;activer certaines fonctionnalit\u00e9s de d\u00e9bogage pour l&rsquo;\u00e9quipement concern\u00e9&nbsp;:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>redirection des messages sur <em>stdout<\/em> et <em>stderr<\/em> vers un port UDP distant,<\/li>\n\n\n\n<li>utilisation d&rsquo;un d\u00e9bogueur GDB distant.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Nous activons la premi\u00e8re case et remplissons les deux champs qui apparaissent avec l&rsquo;adresse IP de la machine qui recevra les traces (votre poste de d\u00e9veloppement) et un num\u00e9ro de port de base UDP. Par d\u00e9faut ce num\u00e9ro de port est 10001, ce qui signifie que les messages du container se trouvant dans le slot num\u00e9ro 1 seront redirig\u00e9s vers ce port, les messages du slot 2 vers le port 10002, ceux du slot 3 vers le port 10003 et ceux du slot 4 vers le port UDP 10004.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><a href=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2026\/09\/fig-6.02.png\"><img loading=\"lazy\" decoding=\"async\" width=\"625\" height=\"190\" src=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2026\/09\/fig-6.02.png\" alt=\"\" class=\"wp-image-7878\" srcset=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2026\/09\/fig-6.02.png 625w, https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2026\/09\/fig-6.02-300x91.png 300w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><\/a><figcaption class=\"wp-element-caption\">Fig. 2 &#8211; Configuration de la redirection de messages.<\/figcaption><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">Sur la machine se trouvant \u00e0 l&rsquo;adresse indiqu\u00e9e nous allons recevoir les messages redirig\u00e9s. Pour les visualiser, on peut employer divers utilitaires. L&rsquo;un des plus courants est <code>socat<\/code>. On le lance ainsi&nbsp;:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>$ <strong>socat  udp-recv:  &lt;port-recept&gt;  &lt;dest-redirection&gt;<\/strong><\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Comme on souhaite visualiser les messages et pas les r\u00e9\u00e9mettre, on indique <code><strong>STDOUT<\/strong><\/code> pour <code>&lt;dest-redirection&gt;<\/code><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;~]$ <strong>socat  -u  UDP-RECV:10001  STDOUT  <\/strong>\n&lt;27&gt;Sep 24 12:09:45 eris-1&#91;668]: This message goes to stderr (5)\n&lt;30&gt;Sep 24 12:09:45 eris-1&#91;668]: This message goes to stdout\n&lt;27&gt;Sep 24 12:09:46 eris-1&#91;668]: This message goes to stderr (0)\n&lt;27&gt;Sep 24 12:09:47 eris-1&#91;668]: This message goes to stderr (1)\n&lt;27&gt;Sep 24 12:09:48 eris-1&#91;668]: This message goes to stderr (2)\n&lt;27&gt;Sep 24 12:09:49 eris-1&#91;668]: This message goes to stderr (3)\n&lt;27&gt;Sep 24 12:09:50 eris-1&#91;668]: This message goes to stderr (4)\n&lt;27&gt;Sep 24 12:09:51 eris-1&#91;668]: This message goes to stderr (5)\n&lt;30&gt;Sep 24 12:09:51 eris-1&#91;668]: This message goes to stdout (0)\n&lt;30&gt;Sep 24 12:09:51 eris-1&#91;668]: This message goes to stdout (1)\n&lt;30&gt;Sep 24 12:09:51 eris-1&#91;668]: This message goes to stdout (2)\n&lt;30&gt;Sep 24 12:09:51 eris-1&#91;668]: This message goes to stdout (3)\n&lt;30&gt;Sep 24 12:09:51 eris-1&#91;668]: This message goes to stdout (4)\n&lt;27&gt;Sep 24 12:09:51 eris-1&#91;668]: This message goes to stderr (5)\n&lt;27&gt;Sep 24 12:09:52 eris-1&#91;668]: This message goes to stderr (1)\n&lt;27&gt;Sep 24 12:09:53 eris-1&#91;668]: This message goes to stderr (2)\n&lt;27&gt;Sep 24 12:09:54 eris-1&#91;668]: This message goes to stderr (3)\n&lt;27&gt;Sep 24 12:09:55 eris-1&#91;668]: This message goes to stderr (4)\n&lt;27&gt;Sep 24 12:09:56 eris-1&#91;668]: This message goes to stderr (5)\n&lt;30&gt;Sep 24 12:09:56 eris-1&#91;668]: This message goes to stdout (0)\n&lt;30&gt;Sep 24 12:09:56 eris-1&#91;668]: This message goes to stdout (1)\n&lt;30&gt;Sep 24 12:09:56 eris-1&#91;668]: This message goes to stdout (2)\n&lt;30&gt;Sep 24 12:09:56 eris-1&#91;668]: This message goes to stdout (3)\n&lt;30&gt;Sep 24 12:09:56 eris-1&#91;668]: This message goes to stdout (4)\n&lt;30&gt;Sep 24 12:09:56 eris-1&#91;668]: This message goes to stdout (5)\n&lt;27&gt;Sep 24 12:09:57 eris-1&#91;668]: This message goes to stderr (0)\n&#91;...]<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Nous voyons les messages sur <code>stderr<\/code> qui arrivent chaque seconde, ceux sur <code>stdout<\/code> sont mis en buffer et envoy\u00e9s uniquement lors du <code>fflush()<\/code>, c&rsquo;est un comportement tout-\u00e0-fait normal pour des sorties redirig\u00e9es.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Utilisation de Gdb<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Le <em>GNU debugger<\/em> Gdb est tr\u00e8s utile pour suivre finement l&rsquo;ex\u00e9cution de certaines portions de code, examiner les variables, le contenu de la m\u00e9moire ou de la pile, ou analyser le comportement des threads.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">On l&#8217;emploie habituellement par le biais d&rsquo;un environnement de d\u00e9veloppement int\u00e9gr\u00e9 (IDE) qui offre la possibilit\u00e9 de placer un point d&rsquo;arr\u00eat d&rsquo;un clic de souris ou de visualiser le contenu d&rsquo;une variable en la survolant. Dans l&rsquo;exemple ci-dessous je vais me contenter d&rsquo;une utilisation beaucoup plus fruste en ligne de commande pour \u00eatre facilement r\u00e9p\u00e9table et adaptable \u00e0 votre environnement de travail.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Lorsque nous s\u00e9lectionnons la case \u00ab\u00a0<em>Remote GDB on container<\/em>\u00a0\u00bb deux zones de saisie apparaissent&nbsp;:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><a href=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2026\/09\/fig-6.03.png\"><img loading=\"lazy\" decoding=\"async\" width=\"626\" height=\"119\" src=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2026\/09\/fig-6.03.png\" alt=\"\" class=\"wp-image-7916\" srcset=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2026\/09\/fig-6.03.png 626w, https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2026\/09\/fig-6.03-300x57.png 300w\" sizes=\"auto, (max-width: 626px) 100vw, 626px\" \/><\/a><figcaption class=\"wp-element-caption\">Fig. 3 &#8211; Configuration du <em>debug<\/em> distant.<\/figcaption><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">La premi\u00e8re case s\u00e9lectionne le slot dans lequel se trouve le container \u00e0 d\u00e9boguer. En g\u00e9n\u00e9ral on va indiquer un slot vide, et c&rsquo;est lorsqu&rsquo;on y ins\u00e8rera un container que le <em>debug<\/em> commencera.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">La seconde zone indique un port TCP\/IP \u00e0 utiliser pour la connexion au d\u00e9bogueur local.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Le principe de fonctionnement est le suivant.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><a href=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2026\/09\/fig-6.04.png\"><img loading=\"lazy\" decoding=\"async\" width=\"664\" height=\"263\" src=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2026\/09\/fig-6.04.png\" alt=\"\" class=\"wp-image-7921\" srcset=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2026\/09\/fig-6.04.png 664w, https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2026\/09\/fig-6.04-300x119.png 300w\" sizes=\"auto, (max-width: 664px) 100vw, 664px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">Un petit agent nomm\u00e9 <code>gdbserver<\/code>, install\u00e9 dans l&rsquo;image Eris Linux est pr\u00e9sent sur l&rsquo;\u00e9quipement embarqu\u00e9 et \u00e9coute sur le port TCP\/IP indiqu\u00e9 ci-dessus. Il est capable de piloter l&rsquo;application se trouvant dans le container plac\u00e9 dans le slot mentionn\u00e9. <code>gdbserver<\/code> n&rsquo;est pas install\u00e9 dans le container applicatif mais dans Eris Linux lui-m\u00eame. Lorsqu&rsquo;un slot est plac\u00e9 en mode Gdb, Eris identifie le processus applicatif correspondant puis y attache <code>gdbserver<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Depuis le PC de d\u00e9veloppement, on fait tourner le d\u00e9bogueur Gdb complet,  qui peut se connecter sur l&rsquo;agent <code>gdbserver<\/code> et lui envoyer des commandes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Point important&nbsp;: sur la machine de d\u00e9veloppement (PC), on doit utiliser une version de Gdb capable de comprendre les instructions assembleur et le format binaire de l&rsquo;\u00e9quipement embarqu\u00e9. Sur certains syst\u00e8mes, la version <code>gdb<\/code> install\u00e9e ne conna\u00eet que le format x86.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Je vous recommande d&rsquo;installer les packages suivants&nbsp;:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>sur distribution Debian, Ubuntu ou une distribution WSL bas\u00e9e sur Debian ou Ubuntu&nbsp;: le package <code><strong>gdb-multiarch<\/strong><\/code> install\u00e9 avec la commande <code>sudo apt install gdb-multiarch<\/code>,<\/li>\n\n\n\n<li>sur distribution Fedora, le package <code>gdb<\/code> standard (install\u00e9 avec <code>dnf install <strong>gdb<\/strong><\/code>) est suffisant, il connait les cibles embarqu\u00e9es support\u00e9es par Eris.<\/li>\n\n\n\n<li>sur distribution Arch, le package <code><strong>gdb<\/strong><\/code> standard fonctionne \u00e9galement pour les cibles embarqu\u00e9es. On l&rsquo;installe avec <code>pacman -S gdb<\/code>.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"> J&rsquo;utiliserai pour la suite des exemples de cet article <code><strong>gdb-multiarch<\/strong><\/code>, \u00e0 remplacer par <code>gdb<\/code> sur Fedora ou Arch Linux.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Attention&nbsp;:<\/strong> le mode de d\u00e9bogage utilisant Gdb doit rester une <strong>fonctionnalit\u00e9 temporaire de d\u00e9veloppement<\/strong>. Gdbserver ne fournit <strong>aucun m\u00e9canisme d&rsquo;authentification<\/strong>. Le port de <em>debug<\/em> ne doit donc \u00eatre accessible que depuis un r\u00e9seau de d\u00e9veloppement ma\u00eetris\u00e9 et le mode de d\u00e9bogage doit \u00eatre d\u00e9sactiv\u00e9 d\u00e8s que la session de mise au poiunt est achev\u00e9e.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Quelques instants apr\u00e8s avoir recharg\u00e9 mon container, je vois les deux premi\u00e8res lignes de traces arriver sur <code>socat<\/code>, c&rsquo;est normal <code>gdbserver<\/code> n&rsquo;est d\u00e9marr\u00e9 qu&rsquo;au bout de quelques dixi\u00e8mes de secondes, pour \u00eatre s\u00fbr que le container a bien lanc\u00e9 l&rsquo;application.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>                    &#91;~]$ <strong><strong>socat  -u  UDP-RECV:10001  STDOUT<\/strong><\/strong>\n                    2026\/10\/06 13:19:25 socat&#91;16746] W address is opened in read-write mode but only supports read-only\n                    &lt;30&gt;Oct  6 11:21:06 eris-1&#91;667]: This message goes to stdout (0)\n                    &lt;27&gt;Oct  6 11:21:06 eris-1&#91;667]: This message goes to stderr (0)\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Dans un autre terminal je d\u00e9marre <code>gdb-multiarch<\/code> en me pla\u00e7ant au pr\u00e9alable dans le r\u00e9pertoire des sources de l&rsquo;ex\u00e9cutable. Une fois le <em>prompt<\/em> de <code>gdb<\/code> affich\u00e9, je lui indique que la machine \u00e0 d\u00e9boguer se trouve \u00e0 l&rsquo;adresse IP de la cible (<code>192.168.3.6<\/code> visible sur le <em>Device Manager<\/em>) et nous attend sur le port TCP\/IP <code>15000<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;eris-linux-containers]$ <strong>cd  test-debug-stdio\/<\/strong>\n\n&#91;test-debug-stdio)]$ <strong>ls<\/strong>\nDockerfile  Makefile  test-debug-stdio.c\n\n&#91;test-debug-stdio]$ <strong>gdb-multiarch <\/strong>\n  &#91;...]\n(gdb) <strong>target  remote  192.168.3.6:15000<\/strong>\nRemote debugging using 192.168.3.6:15000\nReading \/test-debug-stdio from remote target...\n&#x26a0;&#xfe0f; warning: File transfers from remote targets can be slow. Use \"set sysroot\" to access files locally instead.\nReading \/test-debug-stdio from remote target...\nReading symbols from target:\/test-debug-stdio...\nReading \/lib\/ld-musl-aarch64.so.1 from remote target...\nReading symbols from target:\/lib\/ld-musl-aarch64.so.1...\n   &#91;...]\n0x0000007fa8c0bd04 in ?? () from target:\/lib\/ld-musl-aarch64.so.1\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Nous voyons que <code>gdb<\/code> r\u00e9cup\u00e8re le code ex\u00e9cutable depuis la cible. Pour une application plus volumineuse, il sera g\u00e9n\u00e9ralement plus rapide de conserver localement une copie non stripp\u00e9e de l&rsquo;ex\u00e9cutable et de lancer directement <code><strong>gdb-multiarch  .\/test-debug-stdio<\/strong><\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>gdb<\/code> nous indique que le programme est suspendu dans une fonction de la biblioth\u00e8que C (probablement <code>printf<\/code>) dont il n&rsquo;a pas le nom (c&rsquo;est la signification de <code>??()<\/code>). Demandons-lui de placer un point d&rsquo;arr\u00eat au d\u00e9but de la boucle, puis de s&rsquo;y rendre.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>(gdb) <strong>list  main<\/strong>\n2\t#include &lt;stdio.h&gt;\n3\t#include &lt;stdlib.h&gt;\n4\t#include &lt;unistd.h&gt;\n5\t\n6\tint main(void)\n7\t{\n8\t\tint i = 0;\n9\t\tfor (;;) {\n10\t\t\tfprintf(stderr, \"This message goes to stderr (%d)\\n\", i);\n11\t\t\tfprintf(stdout, \"This message goes to stdout (%d)\\n\", i);\n(gdb) <strong>break  10<\/strong>\nBreakpoint 1 at 0x55666808ec: file test-debug-stdio.c, line 10.\n(gdb) <strong>continue<\/strong>\nContinuing.\n\nBreakpoint 1, main () at test-debug-stdio.c:10\n10\t\t\tfprintf(stderr, \"This message goes to stderr (%d)\\n\", i);\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Nous sommes arr\u00eat\u00e9s sur la ligne 10. Nous allons l&rsquo;ex\u00e9cuter&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>(gdb) <strong>next<\/strong><\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Sur l&rsquo;autre terminal, nous voyons le message apparaitre&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>          &lt;27&gt;Oct  6 11:24:44 eris-1&#91;667]: This message goes to stderr (1)<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>\n11\t\t\tfprintf(stdout, \"This message goes to stdout (%d)\\n\", i);\n(gdb) <strong>next<\/strong>\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Cette fois pas de message, c&rsquo;est normal, les donn\u00e9es \u00e9crites sur<code> stdout<\/code> patientent dans le buffer.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>12\t\t\tsleep(1);\n(gdb) <strong>next<\/strong>\n13\t\t\tif (++i &gt; 5) {\n(gdb) <strong>next<\/strong>\n\nBreakpoint 1, main () at test-debug-stdio.c:10\n10\t\t\tfprintf(stderr, \"This message goes to stderr (%d)\\n\", i);<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Nous voici revenus au d\u00e9but de la boucle. Nous pouvons refaire un tour complet simplement avec&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>(gdb) <strong>continue<\/strong>\nContinuing.\n\nBreakpoint 1, main () at test-debug-stdio.c:10\n10\t\t\tfprintf(stderr, \"This message goes to stderr (%d)\\n\", i);\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Une ligne est bien apparue sur l&rsquo;autre terminal&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>          &lt;27&gt;Oct  6 11:39:51 eris-1&#91;667]: This message goes to stderr (2)<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Et nous sommes \u00e0 nouveau au d\u00e9but de la boucle. Nous pouvons regarder la valeur de la variable <code>i<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>(gdb) <strong>print  i<\/strong>\n$1 = 3\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Le <code>$1<\/code> correspond au num\u00e9ro de l&rsquo;\u00e9valuation d&rsquo;expression. La valeur est bien <code>3<\/code>. Modifions-la&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>(gdb) <strong>set  var  i=300<\/strong>\n(gdb) <strong>print  i<\/strong>\n$2 = 300\n(gdb) <strong>next<\/strong>\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">En avan\u00e7ant d&rsquo;une ligne on voit bien appara\u00eetre&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>          &lt;27&gt;Oct  6 11:43:00 eris-1&#91;667]: This message goes to stderr (300)\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">En revanche l&rsquo;ex\u00e9cution de la ligne suivante est silencieuse, car on n&rsquo;a pas encore atteint le <code>fflush()<\/code><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>11\t\t\tfprintf(stdout, \"This message goes to stdout (%d)\\n\", i);\n(gdb) <strong>next<\/strong>\n12\t\t\tsleep(1);\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">On peut restaurer la valeur pr\u00e9c\u00e9dente de <code>i<\/code> :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>(gdb) <strong>set var i=3<\/strong>\n\n(gdb) <strong>continue<\/strong>\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">En ex\u00e9cutant \u00e0 quelques reprises <code>continue<\/code> on voit les traces suivantes&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>          &lt;27&gt;Oct  6 11:46:30 eris-1&#91;667]: This message goes to stderr (4)\n          &lt;27&gt;Oct  6 11:46:31 eris-1&#91;667]: This message goes to stderr (5)\n          &lt;30&gt;Oct  6 11:46:32 eris-1&#91;667]: This message goes to stdout (0)\n          &lt;30&gt;Oct  6 11:46:32 eris-1&#91;667]: This message goes to stdout (1)\n          &lt;30&gt;Oct  6 11:46:32 eris-1&#91;667]: This message goes to stdout (2)\n          &lt;30&gt;Oct  6 11:46:32 eris-1&#91;667]: This message goes to stdout (300)\n          &lt;30&gt;Oct  6 11:46:32 eris-1&#91;667]: This message goes to stdout (4)\n          &lt;30&gt;Oct  6 11:46:32 eris-1&#91;667]: This message goes to stdout (5)\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Nous pouvons bien piloter notre application en pas-\u00e0-pas, consulter, et m\u00eame modifier le contenu de sa m\u00e9moire.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Lorsque nous quittons le d\u00e9bogueur, l&rsquo;application reprend son ex\u00e9cution normale&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>(gdb) <strong>quit<\/strong>\nA debugging session is active.\n\n\tInferior 1 &#91;process 5348] will be detached.\n\nQuit anyway? (y or n) <strong>y<\/strong>\nDetaching from program: target:\/test-debug-stdio, process 5348\nEnding remote debugging.\n&#91;Inferior 1 (process 5348) detached]\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>          &lt;27&gt;Oct  6 11:54:43 eris-1&#91;667]: This message goes to stderr (0)\n          &lt;27&gt;Oct  6 11:54:44 eris-1&#91;667]: This message goes to stderr (1)\n          &lt;27&gt;Oct  6 11:54:45 eris-1&#91;667]: This message goes to stderr (2)\n          &lt;27&gt;Oct  6 11:54:46 eris-1&#91;667]: This message goes to stderr (3)\n          &lt;27&gt;Oct  6 11:54:47 eris-1&#91;667]: This message goes to stderr (4)\n          &lt;27&gt;Oct  6 11:54:48 eris-1&#91;667]: This message goes to stderr (5)\n          &lt;27&gt;Oct  6 11:54:49 eris-1&#91;667]: This message goes to stderr (0)\n          &lt;30&gt;Oct  6 11:54:49 eris-1&#91;667]: This message goes to stdout (0)\n          &lt;30&gt;Oct  6 11:54:49 eris-1&#91;667]: This message goes to stdout (1)\n          &lt;30&gt;Oct  6 11:54:49 eris-1&#91;667]: This message goes to stdout (2)\n          &lt;30&gt;Oct  6 11:54:49 eris-1&#91;667]: This message goes to stdout (3)\n          &lt;30&gt;Oct  6 11:54:49 eris-1&#91;667]: This message goes to stdout (4)\n          &lt;30&gt;Oct  6 11:54:49 eris-1&#91;667]: This message goes to stdout (5)\n          &lt;27&gt;Oct  6 11:54:50 eris-1&#91;667]: This message goes to stderr (1)\n          &lt;27&gt;Oct  6 11:54:51 eris-1&#91;667]: This message goes to stderr (2)\n          &lt;27&gt;Oct  6 11:54:52 eris-1&#91;667]: This message goes to stderr (3)\n          &lt;27&gt;Oct  6 11:54:53 eris-1&#91;667]: This message goes to stderr (4)\n          &lt;27&gt;Oct  6 11:54:54 eris-1&#91;667]: This message goes to stderr (5)\n<\/code><\/pre>\n\n\n\n<h1 class=\"wp-block-heading\">Conclusion<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Nous avons vu deux m\u00e9thodes pour d\u00e9boguer une application s&rsquo;ex\u00e9cutant dans un container. Pour l&rsquo;instant nous nous sommes limit\u00e9s au C\/C++, mais d&rsquo;autres m\u00e9thodes pour d&rsquo;autres langages seront disponibles dans l&rsquo;avenir.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Nous avons d\u00e9j\u00e0 remarqu\u00e9 qu&rsquo;Eris Linux permettait de d\u00e9velopper du code applicatif sans n\u00e9cessiter l&rsquo;installation de cha\u00eene de cross-compilation. Nous voyons \u00e0 pr\u00e9sent que la m\u00eame image applicative peut \u00eatre utilis\u00e9e normalement ou d\u00e9bogu\u00e9e \u00e0 distance sans embarquer d&rsquo;outils sp\u00e9cifiques de debug dans le container.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Eris Linux est un projet vivant, en cours d&rsquo;\u00e9volution, et vos interrogations, retours et commentaires sont les bienvenus. N&rsquo;h\u00e9sitez pas \u00e0 me contacter si vous avez des questions ou des suggestions d&rsquo;am\u00e9lioration.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>","protected":false},"excerpt":{"rendered":"<p>Une fois l&rsquo;application m&eacute;tier d&eacute;velopp&eacute;e, le container correspondant construit et d&eacute;ploy&eacute; sur une carte (ou un groupe de cartes) de test, il est souvent n&eacute;cessaire de passer &agrave; une &eacute;tape moins r&eacute;jouissante&nbsp;: le debug&nbsp;! Analyser le comportement d&rsquo;une application fonctionnant dans un container, s&rsquo;ex&eacute;cutant lui-m&ecirc;me dans une machine distante &ndash; qui est pr&eacute;vue pour [&hellip;]<\/p>","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[],"class_list":["post-7847","post","type-post","status-publish","format-standard","hentry","category-linux-2"],"_links":{"self":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/7847","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/comments?post=7847"}],"version-history":[{"count":34,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/7847\/revisions"}],"predecessor-version":[{"id":7963,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/7847\/revisions\/7963"}],"wp:attachment":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/media?parent=7847"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/categories?post=7847"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/tags?post=7847"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}