(Multiple methods) VSCode debugs programs in docker containers

overview

Sometimes we need to debug the c++ program in the docker container. We can use the command line to run gdb debugging, but it is not as intuitive as the graphical interface of vscode. How to use VSCode to debug c++ programs in docker containers.

Currently, I know of three methods:

1. Through the remote-container plugin of vscode

  • Advantages: Through this plug-in, it will make you feel like you are directly operating when developing, and you can hardly feel the existence of the container.
  • Disadvantages: (1) I don't know if the server is a bit spicy, but I always feel that after opening this, ssh keeps disconnecting, and I feel that the overhead may be relatively high. (2) Sometimes when installing the vscode server, there will be permission problems, and permissions need to be changed.
  • ps: If you want to debug the container on the remote server, you need to use remote-ssh to connect to the remote server first, and then use the remote-container plug-in.

2. Remotely debug inside the container via ssh

When starting the container, set up port mapping so that the host can access the docker container through the ssh service. Then, using the remote debugging function of gdb, you can debug the code in the docker container on the host. Reference: https://lemariva.com/blog/2020/10/vscode-c-development-and-debugging-containers

  • Pros: less expensive
  • Disadvantage: The sshd service needs to be installed when installing the container. Other than that, not as powerful as the remote-container plugin.

3. ( Personal feeling is the optimal solution ) Through the pipeTransport function of vscode

Reference documentation: https://code.visualstudio.com/docs/cpp/pipe-transport .

Method 1. Through the remote-container plug-in of vscode

Just search for the plug-in in the app store, the method is very simple, basically the same as the remote-ssh plug-in.
After running docker on the host ( docker run ..., you can use --namethe specified noun), the remote-container plug-in can retrieve the container, right-click the container, and find the corresponding option to connect to the inside of the container. Specific slightly.
You can refer to the blog

Method 2. Remotely debug inside the container via ssh

2.1. Based on your original image, add another layer. This layer is mainly to install gdb, openssh-server, and then open the sshd service to expose port 22.

Refer to dockerfile ( reference link )

# 原始镜像
FROM debian:bullseye

LABEL description="Container for use with VSCode" 

# install build dependencies to build and debug 
RUN apt-get update \
    && apt-get install -y g++ build-essential make cmake gdb gdbserver \
       rsync zip openssh-server git 

# configure SSH for communication with VSCode
RUN mkdir -p /var/run/sshd

# chpasswd用来更改root用户的密码,"root:root"即将root用户密码设置为root
# 然后使用sed修改sshd_config文件里的"PermitRootLogin prohibit-password"为"PermitRootLogin yes"
# 再修改/etc/pam.d/sshd里的“session\s*required\s*pam_loginuid.so”为"session optional pam_loginuid.so"??
RUN echo 'root:root' | chpasswd \
    && sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config \
    && sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd
    
WORKDIR /

CMD ["/usr/sbin/sshd", "-D"]

# 开放22端口
EXPOSE 22

2.2. Compiler

2.2.1 Scheme

From the compilation method, there are two methods: (1) Compile
directly by entering the container (2) Compile by entering the container through ssh From the compilation method, there are two methods: (1) Manually enter the command, or write a The shell script compiles. (2) I personally like to write a script using task.json of vscode , which is used for compilation, but the method of pasting task.json is still used, because I feel that it may be used somewhere in the future.docker run




docker run ...

2.2.2 [Manual] Configure tasks.json file to compile automatically

( reference link )

2.2.2.1 Enter the container through ssh to compile" configuration
  1. The host needs to install the sshpass tool. This tool can directly enter the user password through parameters on the command line -pand then log in with ssh (of course, other methods are also available, such as setting password-free login and the like)
sudo apt-get install sshpass
  1. Write
    the content of the configuration file tasks.json as follows (note that the compilation command needs to be set by itself):
{
    
    
    "version": "2.0.0",
    "tasks": [
        {
    
    
            "label": "build-in-container",
            "type": "shell",
            "command": "/usr/bin/sshpass",
            "args": [
                "-p",
                "root", // "-p"参数指定密码
                "ssh",
                "root@localhost", // user@ip
                "-p",
                "2222", // 端口映射
                "/source/build.sh" // 这里的编译命令需要自行设置
            ],
            "problemMatcher": [
                "$gcc"
            ],
            "group": {
    
    
                "kind": "build",
                "isDefault": true
            }
        }
    ]
}
2.2.2.2 "Compile by docker runentering the container" configuration

In theory, you can also configure the commands in task.json, let him pass docker runto compile, the details are omitted

2.3 Configure the launch.json file

Launch.json file template example (still through sshpass, and then use vscode's Pipe transport, vscode official docker example ):

{
    
    
    "version": "0.2.0",
    "configurations": [
        {
    
    
            "name": "(gdb) Launch",
            "type": "cppdbg",
            "request": "launch",
            "program": "build/app", // [需修改] 目标文件
            "args": [],
            "stopAtEntry": true, // 默认在程序入口处,即main函数处停下来
            "cwd": "/source", // [需修改] 工作目录
            "environment": [],
            "externalConsole": true,  
            // [可选] sourceFileMap是用来做主机与客机的路径映射
            // 参考 https://code.visualstudio.com/docs/cpp/pipe-transport
            "sourceFileMap": {
    
     "/source": "${workspaceFolder}" },       
            "pipeTransport": {
    
     // 
                "debuggerPath": "/usr/bin/gdb",
                "pipeProgram": "/usr/bin/sshpass", // 类似task.json里面的
                "pipeArgs": [
                    "-p",
                    "root",
                    "ssh",
                    "root@localhost",
                    "-p",
                    "2222"
                ],
                "pipeCwd": ""
            },           
            "MIMode": "gdb"         
        }
    ]
}

2.4. Running the container

docker run -d -p 2222:22 --security-opt seccomp:unconfined -v $PWD:/source --name gdb-cpp-image gdb-cpp-image

2.5, debug code

key F5

Method 3 through the pipeTransport function of vscode

3.1 Running the container

sudo docker run -d --security-opt seccomp:unconfined -v $hostPath:$guestpath --name gdb-cpp-image imagename

3.2 Configure launch.json

The launch.json file is similar to method 2, the difference is the pipeTransport parameter inside, here is not through ssh, but directly through docker

"pipeTransport": {
    
    
    "pipeCwd": "${workspaceFolder}",
    "pipeProgram": "docker",
    "pipeArgs": [
        "exec",
        "-i",
        "hello_gdb",
        "sh",
        "-c"
    ],
    "debuggerPath": "/usr/bin/gdb"
},

3.3 launch.json reference example

3.3.1 Reference example 1 (run an existing container through docker exec)
{
    
    
    "version": "0.2.0",
    "configurations": [
        {
    
    
            "name": "(gdb) Launch",
            "type": "cppdbg",
            "request": "launch",
            "program": "build/a.out", // [需修改] 目标文件
            "args": ["arg1", "arg2"], // 参数
            "stopAtEntry": true,
            "cwd": "/home/...", // [需修改] 工作目录
            "environment": [],
            "externalConsole": true,  
            // [可选] sourceFileMap是用来做主机与客机的路径映射
            // 参考 https://code.visualstudio.com/docs/cpp/pipe-transport
            "sourceFileMap": {
    
     "/source": "${workspaceFolder}" },       
            "pipeTransport": {
    
    
                "pipeCwd": "${workspaceFolder}",
                "pipeProgram": "docker",
                "pipeArgs": [
                    "exec", // exec是运行已有的容器,也可以使用docker run,原理差不多
                    "-i",
                    "gdb-cpp-image", // 镜像名字
                    "sh",
                    "-c"
                ],
                "debuggerPath": "/usr/bin/gdb"
            },        
            "MIMode": "gdb"         
        }
    ]
}
3.3.2 Reference example 2 (start a new container via docker run)
{
    
    
    "version": "0.2.0",
    "configurations": [
        {
    
    
            "name": "(gdb) Launch",
            "type": "cppdbg",
            "request": "launch",
            "program": "build/GCN3_X86/gem5.opt", // [需修改] 目标文件
            "args": [""], // 参数
            "stopAtEntry": true,
            "cwd": "/home/lmy/gem5-gcn3/gem5-default", // [需修改] 工作目录
            "environment": [],
            "externalConsole": true,  
            // [可选] sourceFileMap是用来做主机与客机的路径映射
            // 参考 https://code.visualstudio.com/docs/cpp/pipe-transport
            "sourceFileMap": {
    
     "/source": "${workspaceFolder}" },       
            "pipeTransport": {
    
    
                "pipeCwd": "${workspaceFolder}",
                "pipeProgram": "docker",
                "pipeArgs": [
                    "run",
                    "-i",
                    "--security-opt","seccomp=unconfined",
                    "--volume","/home/lmy/gem5-gcn3:/home/lmy/gem5-gcn3",
                    "-w","/home/lmy/gem5-gcn3/gem5-default",
                    "gem5-debug-image", # [需修改] 镜像名称
                    "sh",
                    "-c"
                ],
                "debuggerPath": "/usr/bin/gdb"
            },        
            "MIMode": "gdb"         
        }
    ]
}

3.4 Debugging

key F5

Solution for breakpoints not working

When I tested method 3, sometimes a breakpoint was set, but the breakpoint could not be triggered accurately. It seems that vscode did not retrieve the location of the breakpoint at the beginning, so I tried to use it directly in the debugging console and found that it was normal -exec b 断点位置. trigger.
As shown in the figure below, vscode promptsModule containing this breaknoint has not vet loaded or the breaknoint address could not be obtained

insert image description here
As shown in the figure below, the breakpoint is successfully triggered. Although the display is abnormal, it does not affect it.
But this needs to be entered once after each debugging run. (In terms of convenience, the remote-container plugin is more powerful)
insert image description here

Guess you like

Origin blog.csdn.net/qq_29809823/article/details/128445308