{"id":1271,"date":"2016-01-15T18:33:41","date_gmt":"2016-01-16T02:33:41","guid":{"rendered":"http:\/\/visualgdb.com\/w\/?p=1271"},"modified":"2022-06-09T10:05:01","modified_gmt":"2022-06-09T17:05:01","slug":"debugging-cc-code-in-docker-containers-with-visualgdb","status":"publish","type":"post","link":"https:\/\/visualgdb.com\/tutorials\/linux\/docker\/","title":{"rendered":"Debugging C\/C++ code in Docker containers with VisualGDB"},"content":{"rendered":"<p>This tutorial shows how to debug applications running in <a href=\"http:\/\/docker.com\/\">Docker<\/a> containers using Visual Studio and VisualGDB.<\/p>\n<p><strong>WARNING: this tutorial features older versions of Docker and VisualGDB. For more recent instructions, please refer to the following tutorials:<\/strong><\/p>\n<ul>\n<li><a href=\"https:\/\/visualgdb.com\/tutorials\/linux\/docker\/toolchains\/\">Using Docker Containers to Manage Toolchains<\/a><\/li>\n<li><a href=\"https:\/\/visualgdb.com\/tutorials\/linux\/docker\/toolchains\/using\/\">Building Projects with Toolchains from Docker Containers<\/a><\/li>\n<\/ul>\n<p>Before we begin with the debugging part, we will show why the Docker containers are needed and how they work based on a simple example. Assume we have two Linux machines, one having glibc (Standard C library) version 2.13 and another one having glibc 2.14. Let&#8217;s create a very simple C program using the memcpy() function:<\/p>\n<pre class=\"\">#include &lt;stdio.h&gt;\r\n#include &lt;memory.h&gt;\r\n\r\nvoid CopyMemory(volatile void *pDest, volatile void *pSrc, volatile int size)\r\n{\r\n\u00a0\u00a0 \u00a0memcpy((void *)pDest, (void *)pSrc, (int)size);\r\n}\r\n\r\nint main()\r\n{\r\n\u00a0\u00a0 \u00a0char str1[256] = \"Hello\", str2[sizeof(str1)];\r\n\u00a0\u00a0 \u00a0CopyMemory(str2, str1, sizeof(str2));\r\n\u00a0\u00a0 \u00a0puts(str2);\r\n\u00a0\u00a0 \u00a0return 0;\r\n}<\/pre>\n<p>If we compile and run it on the machine with glibc 2.14, it will run properly:<a href=\"http:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/01-runok1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1274\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/01-runok1.png\" alt=\"01-runok\" width=\"734\" height=\"371\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/01-runok1.png 734w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/01-runok1-300x152.png 300w\" sizes=\"(max-width: 734px) 100vw, 734px\" \/><\/a>\u00a0 However if we try to run the same binary without recompiling on a machine with glibc 2.13, it will complain that glibc 2.14 was not found. Dumping the symbols imported from the application will show that the memcpy() function explicitly requires glibc 2.14 or later:<a href=\"http:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/02-memcpy1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1275\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/02-memcpy1.png\" alt=\"02-memcpy\" width=\"734\" height=\"371\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/02-memcpy1.png 734w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/02-memcpy1-300x152.png 300w\" sizes=\"(max-width: 734px) 100vw, 734px\" \/><\/a><\/p>\n<p>This happens because the behavior of memcpy() has slightly changed and the glibc maintainers wanted to ensure that programs compiled against the new versions of glibc will not run with the previous incompatible versions of the library. In this simple example we could update glibc on the second machine or recompile our program with the older version, however for bigger programs depending on multiple libraries, especially if they are not backward-compatible, could make shipping Linux binaries nearly impossible.<\/p>\n<p>Docker allows packing an application together with all its dependencies into a single independent container and running it on any other machine with docker. You can view docker containers as lightweight virtual machines that have an independent set of user-mode components, but share the kernel resources of your host Linux machine.<\/p>\n<p>In this tutorial we will use Visual Studio with VisualGDB to create a simple application, place it into a docker container and debug it inside the container.<\/p>\n<ol>\n<li>The first step will be to install the latest version of docker. This can be done by running the following commands:\n<pre class=\"\">sudo su\r\nwget -qO- https:\/\/get.docker.com\/ | sh<\/pre>\n<p><a href=\"http:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/03-getdocker.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1276\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/03-getdocker.png\" alt=\"03-getdocker\" width=\"734\" height=\"371\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/03-getdocker.png 734w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/03-getdocker-300x152.png 300w\" sizes=\"(max-width: 734px) 100vw, 734px\" \/><\/a><\/li>\n<li>Wait until the installation completes and ensure it completes without errors:<a href=\"http:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/04-inst.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1277\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/04-inst.png\" alt=\"04-inst\" width=\"783\" height=\"458\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/04-inst.png 783w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/04-inst-300x175.png 300w\" sizes=\"(max-width: 783px) 100vw, 783px\" \/><\/a><\/li>\n<li>Add the current user to the <strong>docker<\/strong> group by running the following command from a root shell:\n<pre class=\"\">usermod -aG docker &lt;user name&gt;<\/pre>\n<p>Restart the Linux machine afterwards to ensure that the new permissions are applied.<\/li>\n<li>Now we will create a simple container and test it out. The container is a separate environment containing your application and a set of libraries it needs. Docker comes with a set of pre-configured containers that can be useful as starting points. In order to ship the container with your application, we will need to compile it inside the container against the libraries in the container and then delete the source code, only preserving the binaries:<a href=\"http:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/docker.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1278\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/docker.png\" alt=\"docker\" width=\"913\" height=\"470\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/docker.png 913w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/docker-300x154.png 300w\" sizes=\"(max-width: 913px) 100vw, 913px\" \/><\/a>The host libraries and GCC will not be used in our compilation process.<\/li>\n<li>The easiest way to get started with a container is to download one of the existing ones. Run the following command:\n<pre class=\"\">docker run -it debian<\/pre>\n<p>It will download an image called &#8216;docker&#8217; from the docker site and start a new container with it. The -i and -t flags will create an interactive shell into that container. You can run the &#8220;du -h -d0 \/&#8221; command to check the size of the entire container contents:<a href=\"http:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/05-container.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1279\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/05-container.png\" alt=\"05-container\" width=\"783\" height=\"458\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/05-container.png 783w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/05-container-300x175.png 300w\" sizes=\"(max-width: 783px) 100vw, 783px\" \/><\/a>Note that the distro inside the container does not have to be the same as your host distro. E.g. you can run a <strong>centos<\/strong> container inside Debian or vice versa.<\/li>\n<li>Now we can install gcc into the container by running the following commands inside the container:\n<pre class=\"\">apt-get update\r\napt-get install -y gcc<\/pre>\n<p>Then check the gcc version by running &#8216;gcc -v&#8217;:<a href=\"http:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/06-gcc.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1280\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/06-gcc.png\" alt=\"06-gcc\" width=\"783\" height=\"485\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/06-gcc.png 783w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/06-gcc-300x186.png 300w\" sizes=\"(max-width: 783px) 100vw, 783px\" \/><\/a><\/li>\n<li>Now we are almost ready to compile and debug our application inside the container. However if you exit the container shell and start it again, you will see that the changes done by installing gcc have been reverted and gcc is no longer available:<\/li>\n<li>This can be fixed by creating a file called Dockerfile (the name is case-sensitive) with the following contents:\n<pre class=\"\">FROM debian\r\nRUN apt-get update\r\nRUN apt-get install -y g++ gdbserver make<\/pre>\n<\/li>\n<li>Then run the following command in the directory containing Dockerfile:\n<pre class=\"\">sudo docker build -t demo-base .<\/pre>\n<p><a href=\"http:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/09-build.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1282\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/09-build.png\" alt=\"09-build\" width=\"783\" height=\"320\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/09-build.png 783w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/09-build-300x123.png 300w\" sizes=\"(max-width: 783px) 100vw, 783px\" \/><\/a>This will take the original &#8216;debian&#8217; image, install gcc and gdbserver on it and save the resulting image under the <strong>demo-base<\/strong> name. We will use the <strong>demo-base<\/strong> image as a reference point for building containers with our demo application.<\/li>\n<li>Start Visual Studio and begin creating a new project with the VisualGDB Linux project wizard:<a href=\"http:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/10-newprj.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1283\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/10-newprj.png\" alt=\"10-newprj\" width=\"786\" height=\"493\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/10-newprj.png 786w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/10-newprj-300x188.png 300w\" sizes=\"(max-width: 786px) 100vw, 786px\" \/><\/a><\/li>\n<li>Proceed with the default &#8220;Application&#8221; setting:<a href=\"http:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/11-app.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1284\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/11-app.png\" alt=\"11-app\" width=\"822\" height=\"642\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/11-app.png 822w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/11-app-300x234.png 300w\" sizes=\"(max-width: 822px) 100vw, 822px\" \/><\/a><\/li>\n<li>Select the machine running Docker in the &#8220;Remote computer&#8221; field:<a href=\"http:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/12-target.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1285\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/12-target.png\" alt=\"12-target\" width=\"822\" height=\"642\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/12-target.png 822w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/12-target-300x234.png 300w\" sizes=\"(max-width: 822px) 100vw, 822px\" \/><\/a><\/li>\n<li>On the last page of the wizard add &#8220;Dockerfile&#8221; (mind the case) to the list of transferred files:<a href=\"http:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/13-transfer.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1286\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/13-transfer.png\" alt=\"13-transfer\" width=\"822\" height=\"642\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/13-transfer.png 822w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/13-transfer-300x234.png 300w\" sizes=\"(max-width: 822px) 100vw, 822px\" \/><\/a><\/li>\n<li>Click &#8220;Finish&#8221; to create the project. Replace the contents of the main file with the example from the beginning of this tutorial and add a call to gethostname() to replace the &#8216;Hello&#8217; string with the name of the current host:<a href=\"http:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/14-cppfile.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1287\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/14-cppfile.png\" alt=\"14-cppfile\" width=\"802\" height=\"657\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/14-cppfile.png 802w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/14-cppfile-300x246.png 300w\" sizes=\"(max-width: 802px) 100vw, 802px\" \/><\/a><\/li>\n<li>Set a breakpoint on the puts() line and press F5 to run the program. We are not yet running from a docker container, so the gethostname() function will return the host name of your Linux machine:<a href=\"http:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/15-debug.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1288\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/15-debug.png\" alt=\"15-debug\" width=\"802\" height=\"614\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/15-debug.png 802w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/15-debug-300x230.png 300w\" sizes=\"(max-width: 802px) 100vw, 802px\" \/><\/a><\/li>\n<li>Now we will create a separate configuration to build our application in a Docker container and debug it there. We will do this by copying the sources to the container, building them there and removing them afterwards. First open VisualGDB Project Properties and copy the current configuration to a new one called &#8220;Debug (Docker)&#8221;:<a href=\"http:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/16-newcfg.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1296\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/16-newcfg.png\" alt=\"16-newcfg\" width=\"798\" height=\"565\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/16-newcfg.png 798w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/16-newcfg-300x212.png 300w\" sizes=\"(max-width: 798px) 100vw, 798px\" \/><\/a><\/li>\n<li>As we won&#8217;t be building the code on the build machine, change the build system from GNU Make to Custom Build:<a href=\"http:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/17-custombuild.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1297\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/17-custombuild.png\" alt=\"17-custombuild\" width=\"798\" height=\"565\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/17-custombuild.png 798w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/17-custombuild-300x212.png 300w\" sizes=\"(max-width: 798px) 100vw, 798px\" \/><\/a><\/li>\n<li>Press &#8220;Apply&#8221; and go to the new &#8220;Build Settings&#8221; page and set the build command to be &#8220;docker build -t demo .&#8221; launched in $(BuildDir):<a href=\"http:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/18-buildcmd.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1298\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/18-buildcmd.png\" alt=\"18-buildcmd\" width=\"798\" height=\"565\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/18-buildcmd.png 798w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/18-buildcmd-300x212.png 300w\" sizes=\"(max-width: 798px) 100vw, 798px\" \/><\/a>This command will build a new docker container called &#8220;demo&#8221; based on the rules from the Dockerfile in your project directory (we have not created it yet!).<\/li>\n<li>Go to the Debug Settings page and select &#8220;Debug with a custom gdb stub&#8221;. Then specify port 2000 and use the following command to run the stub:\n<pre class=\"\">docker run -it -p 2000:2000 demo<\/pre>\n<p><a href=\"http:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/19-debugcmd.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1299\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/19-debugcmd.png\" alt=\"19-debugcmd\" width=\"725\" height=\"686\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/19-debugcmd.png 725w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/19-debugcmd-300x284.png 300w\" sizes=\"(max-width: 725px) 100vw, 725px\" \/><\/a>The command will launch Docker with the &#8220;demo&#8221; container built during the build phase and redirect port 2000 to the host machine. We will later configure docker to run gdbserver on port 2000 inside the container.<\/li>\n<li>Finally go to the GDB Startup Commands page and enter the following commands in the &#8220;AFTER selecting a target&#8221; field:\n<pre class=\"\">remote get \/usr\/bin\/DockerDemo \/tmp\/DockerDemo\r\nsymbol-file \/tmp\/DockerDemo\r\nset sysroot remote:\/<\/pre>\n<p><a href=\"http:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/20-commands.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1289\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/20-commands.png\" alt=\"20-commands\" width=\"725\" height=\"687\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/20-commands.png 725w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/20-commands-300x284.png 300w\" sizes=\"(max-width: 725px) 100vw, 725px\" \/><\/a>This will save the DockerDemo binary from the container to \/tmp\/DockerDemo on the host machine (gdb supports transferring files from the gdbserver machine), load the symbols from it and configure gdb to automatically download shared libraries from the target machine in order to read their symbols.<\/li>\n<li>Now it&#8217;s the time to create our Dockerfile. Add a new text file to the project and change its name from Dockerfile.txt to just Dockerfile. Then add the following contents to it and build the project:\n<pre class=\"\">FROM demo-base\r\nCOPY * \/usr\/src\/DockerDemo\/\r\nWORKDIR \/usr\/src\/DockerDemo\r\nRUN make CONFIG=Debug\r\nRUN cp Debug\/DockerDemo \/usr\/bin\r\nRUN rm -rf \/usr\/src\r\nEXPOSE 2000\r\nCMD gdbserver :2000 \/usr\/bin\/DockerDemo<\/pre>\n<p><a href=\"http:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/22-dockerfile.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1290\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/22-dockerfile.png\" alt=\"22-dockerfile\" width=\"802\" height=\"658\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/22-dockerfile.png 802w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/22-dockerfile-300x246.png 300w\" sizes=\"(max-width: 802px) 100vw, 802px\" \/><\/a>This script file tells docker make a new image based on the demo-base image (created earlier by adding gcc, gdbserver and make to the debian image) and do the following:<\/p>\n<ul>\n<li>Copy the source code into the container<\/li>\n<li>Build the source code inside the container using container&#8217;s gcc<\/li>\n<li>Install the binary<\/li>\n<li>Remove the source code<\/li>\n<li>Run gdbserver inside the container on port 2000 and make the port exportable so that gdb from the host machine can connect to it. Note that just making the port exportable does not automatically map it and you need to add the &#8216;-p 2000:2000&#8217; argument when running docker to actually make it accessible for the host-side gdb.<\/li>\n<\/ul>\n<\/li>\n<li>Press F5 to start debugging. VisualGDB will ask for the main binary. Enter any arbitrary binary there (e.g. the previous non-docker build) as it will be overridden by the symbol-file command anyway.<a href=\"http:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/23-debugbin.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1291\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/23-debugbin.png\" alt=\"23-debugbin\" width=\"486\" height=\"173\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/23-debugbin.png 486w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/23-debugbin-300x107.png 300w\" sizes=\"(max-width: 486px) 100vw, 486px\" \/><\/a><\/li>\n<li>VisualGDB will report that gdbserver has exited prematurely and the log will complain about insufficient permissions:<a href=\"http:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/24-stopped.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1292\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/24-stopped.png\" alt=\"24-stopped\" width=\"776\" height=\"304\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/24-stopped.png 776w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/24-stopped-300x118.png 300w\" sizes=\"(max-width: 776px) 100vw, 776px\" \/><\/a><\/li>\n<li>This happens because docker restricts the permissions to the code running inside it. In order to fix it, open the \/etc\/apparmor.d\/docker file and add the &#8220;complain&#8221; flag to the default profile:<a href=\"http:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/25-apparmor.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1293\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/25-apparmor.png\" alt=\"25-apparmor\" width=\"880\" height=\"314\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/25-apparmor.png 880w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/25-apparmor-300x107.png 300w\" sizes=\"(max-width: 880px) 100vw, 880px\" \/><\/a><\/li>\n<li>Save the file and run &#8220;sudo service apparmor restart&#8221; to apply the new settings:<a href=\"http:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/26-restart.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1294\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/26-restart.png\" alt=\"26-restart\" width=\"880\" height=\"314\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/26-restart.png 880w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/26-restart-300x107.png 300w\" sizes=\"(max-width: 880px) 100vw, 880px\" \/><\/a><\/li>\n<li>Now you will be able to debug your application by pressing F5. Note that the gethostname() now returns the name of the docker container as our application is running inside it:<a href=\"http:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/28-debug1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1301\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/28-debug1.png\" alt=\"28-debug\" width=\"802\" height=\"594\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/28-debug1.png 802w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/28-debug1-300x222.png 300w\" sizes=\"(max-width: 802px) 100vw, 802px\" \/><\/a><\/li>\n<li>If you want to save the docker image with your app to a file that can be opened on a another machine, replace the &#8220;CMD gdbserver :2000 \/usr\/bin\/DockerDemo&#8221; line in your Dockerfile with simply &#8220;CMD \/usr\/bin\/DockerDemo&#8221;, build your project and run &#8220;docker save demo | bzip2 &gt; demo.tbz&#8221; to save the &#8216;demo&#8217; container to a file:<a href=\"http:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/29-saveimg.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1302\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/29-saveimg.png\" alt=\"29-saveimg\" width=\"825\" height=\"293\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/29-saveimg.png 825w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/29-saveimg-300x107.png 300w\" sizes=\"(max-width: 825px) 100vw, 825px\" \/><\/a><\/li>\n<li>You can now load the container on another machine and run it there: <a href=\"http:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/32-imported.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1307\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/32-imported.png\" alt=\"32-imported\" width=\"825\" height=\"311\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/32-imported.png 825w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/32-imported-300x113.png 300w\" sizes=\"(max-width: 825px) 100vw, 825px\" \/><\/a>Your app with all the dependencies will be automatically launched in an isolated container requiring no extra modifications on the host side.<\/li>\n<li>Finally, if you are using VisualGDB Custom edition or higher, you can create a shortcut to build and download the image to your Windows machine:<a href=\"http:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/30-customaction.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1303\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/30-customaction.png\" alt=\"30-customaction\" width=\"707\" height=\"563\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/30-customaction.png 707w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/30-customaction-300x239.png 300w\" sizes=\"(max-width: 707px) 100vw, 707px\" \/><\/a><\/li>\n<li>Then each time you want to rebuild the package, you can invoke the custom action via the Project menu:<a href=\"http:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/31-runaction.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1304\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/31-runaction.png\" alt=\"31-runaction\" width=\"802\" height=\"595\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/31-runaction.png 802w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2016\/01\/31-runaction-300x223.png 300w\" sizes=\"(max-width: 802px) 100vw, 802px\" \/><\/a>This will save the container to a file image download this file to your project directory. You can create another custom shortcut to deploy the image on a different machine and even test it out.<\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>This tutorial shows how to debug applications running in Docker containers using Visual Studio and VisualGDB. WARNING: this tutorial features<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[10],"tags":[111,33,112],"_links":{"self":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts\/1271"}],"collection":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/comments?post=1271"}],"version-history":[{"count":7,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts\/1271\/revisions"}],"predecessor-version":[{"id":7896,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts\/1271\/revisions\/7896"}],"wp:attachment":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/media?parent=1271"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/categories?post=1271"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/tags?post=1271"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}