Skip to content

Setting up Remote Debugging Environment

MinseopChoi edited this page Oct 7, 2024 · 6 revisions

1. Setting up VSCode Remote Debugging Environment

1-1. Installing VSCode Extension for Remote Debugging

1-1-1. Installing 'Remote Development Extension'

  1. Click on Extentions on the left side

  2. Search and install "remote development"

    1

1-1-2. Installing 'C/C++ Extension Pack'

  1. Click on Extentions

  2. Search and install "C/C++ Extention Pack"

    2

1-2. Connecting to Remote Linux environment with VSCode

  • Setting up SSH for connecting to remote Linux environment

    • Open 'Command Palette'(Ctrl+Shift+P), type ssh and select Remote-SSH: Add New SSH Host...

      3

    • Enter in the format [username]@[remote Linux IP].

      4

    • It doesn't matter which option you choose here; in this case, we select the top option.

      5

  • Viewing code stored in remote Linux environment on local VSCode

    • Open 'Command Palette'(Ctrl+Shift+P), type ssh and select Remote-SSH: Add New SSH Host...

      6

    • Select the IP of the remote Linux environment you added earlier.

      7

    • Enter the account password for the remote Linux environment.

      8

2. Creating 'launch.json' for Debugging uftrace with remote GDB

2-1. How to Create launch.json

9

2-2. Add the Following Content to launch.json

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [{
        "name" : "uftrace debugging",
        "type" : "cppdbg",
        "request" : "launch",
        "program" : "${workspaceRoot}/uftrace",
        "args" : [],
        "stopAtEntry" : true,
        "cwd" : "${workspaceFolder}",
        "environment": [],
        "externalConsole": false,
        "MIMode": "gdb",
        "miDebuggerPath": "/usr/bin/gdb",
        "setupCommands": [{
            "description": "gdb pretty print",
            "text" : "-enable-pretty-printing",
            "ignoreFailures": true
        }]
    }]
}

2-3. Introduction to Some Arguments in launch.json

  • “args”

    • "args" is an option used to input arguments when executing the program.
    • This option can be used to input Command lists like record, live, ... that can be entered when executing uftrace.
  • “stopAtEntry”

    • “stopAtEntry”is an option that makes the program stop at the entry point (main function) even without setting a breakpoint. It's useful when starting without breakpoints.

3. Starting Debugging

3-1. Starting uftrace Debugging Without Breakpoints

  • Set “stopAtEntry” to true and press F5 on the keyboard to start debugging. As shown in the screen below, you can see that it stops at the first part of the main() function of uftrace

    10

  • You can proceed with debugging by clicking the debugging buttons at the top of the screen or using the following shortcuts:

    • Continue (F5) : Run the program until it hits a breakpoint
    • Step Over (F10) : Step over functions
    • Step Into (F11) : Step into functions
    • Step Out (Shift + F11) : Step out of the current function
    • Restart (Ctrl + Shift + F5) : Restart the program being debugged
    • Stop (Shift + F5) : Stop the program being debugged
  • As shown in the picture below, you can check the current value of variables by hovering the mouse cursor over the variable name or in the VARIABLES section on the left side of the VSCode screen.

    11

  • Currently, even if you run the debugging, since no agruments corresponding to the uftrace command have been given, the program will terminate after following a few lines.

3-2. Debugging a Specific uftrace Command

3-2-1. Building a Target program for Tracing with uftrace

  • Move to where the source code of uftrace is located in the terminal window and execute the following command:

    $ gcc -pg -g -o t-abc tests/s-abc.c
    
    $ ls -l t-abc
    -rwxrwxr-x 1 minseop minseop 18168 Sep 28 17:09 t-abc
    • The -pg option is for using the tracing function using mcount() of uftrace, and the -g option is for the debugger we will use to utilize debugging information.

3-2-2. Modifying 'launch.json' to Trace the Target Program with uftrace

  • Here, we will debug the process of tracing the target program using the live command among various commands of uftrace

  • The target program build above was build with the executable file name t-abe, and the command to trace it with the live command of uftrace is as follows:

    $ uftrace live t-abc
  • You can put the live t-abc part above command into "args", and the entire content of launch.json is as follows:

        "args" : ["live", "t-abc"]
    {
        // Use IntelliSense to learn about possible attributes.
        // Hover to view descriptions of existing attributes.
        // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
        "version": "0.2.0",
        "configurations": [{
            "name" : "uftrace debugging",
            "type" : "cppdbg",
            "request" : "launch",
            "program" : "${workspaceRoot}/uftrace",
            "args" : ["live", "t-abc"],
            "stopAtEntry" : true,
            "cwd" : "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "miDebuggerPath": "/usr/bin/gdb",
            "setupCommands": [{
                "description": "gdb pretty print",
                "text" : "-enable-pretty-printing",
                "ignoreFailures": true
            }]
        }]
    }
    • If you want to proceed with tracing using the record command, you can change "live" to "record".

3-2-3. Start uftrace Debugging

  • Due to the launch.json set above, this time if you follow it line by line, you can see that it follows to the command_live() function in the cmds/live.c file.

  • If you keep following line by line, you can see that uftrace terminates earlier than expected after following a few lines. This is normal, and it will be explained separetely below.

    12

3-2-4. Why Does uftrace End Earlier Than Expected?

  • If you debug as above, you can see that it ends too early compared to the scale of uftrace code, and the reason for this is as follows.
    • As you may have noticed while following, you can see that uftrace internally executes the fork() funcion to run a child process, and GDB does not follow the code of the child process created by fork() without separate settings.

    • To make GDB follow the code of the child process created by fork(), a separate setting set follow-fork-mode chlid is needed, and in VSCode, you cna set this option by adding an item to setupCommand of launch.json as follow:

          "setupCommands": [{
              ...
          },
          {
              "description": "The new process is debugged after a fork. The parent process runs unimpeded.",
              "text": "-gdb-set follow-fork-mode child",
              "ignoreFailures": true
          }]
      {
          // Use IntelliSense to learn about possible attributes.
          // Hover to view descriptions of existing attributes.
          // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
          "version": "0.2.0",
          "configurations": [{
              "name" : "uftrace debugging",
              "type" : "cppdbg",
              "request" : "launch",
              "program" : "${workspaceRoot}/uftrace",
              "args" : ["record", "t-abc"],
              "stopAtEntry" : true,
              "cwd" : "${workspaceFolder}",
              "environment": [],
              "externalConsole": false,
              "MIMode": "gdb",
              "miDebuggerPath": "/usr/bin/gdb",
              "setupCommands": [{
                  "description": "gdb pretty print",
                  "text" : "-enable-pretty-printing",
                  "ignoreFailures": true
              },
              {
                  "description": "The new process is debugged after a fork. The parent process runs unimpeded.",
                  "text": "-gdb-set follow-fork-mode child",
                  "ignoreFailures": true
              }]
          }]
      }

3-2-5. Debugging from the mcount_init() Function

  • Set a breakpoint at the mcount_startup() function inside mcount_init(), which is the starting point of libmcount.

    13

  • Then, press the F5 key to start the debugger and follow along, and you can see that it stops at the breakpoint you set as shown below.

    14

  • After this, you can debug by following the libmcount code as desired.

4. Appendix

4-1. When Breakpoints Don't Work Properly After Modifying Code in the libmcount Directory

  • If the debugger stops at a different location than the breakpoint after modifying the source code inside the libmcount directory, you can use the following solution.

  • This issue occurs when uftrace has been previously installed on the system suing the make install command. In such cases, while the debugger references the latest modified source code, it still uses the libmcount.so file from the system installation rather than the updated version.

  • Add "--libmcount-path=." to args as shown below:

        "args" : ["live", "--libmcount-path=.", "t-abc"]
    {
        // Use IntelliSense to learn about possible attributes.
        // Hover to view descriptions of existing attributes.
        // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
        "version": "0.2.0",
        "configurations": [{
            "name" : "uftrace debugging",
            "type" : "cppdbg",
            "request" : "launch",
            "program" : "${workspaceRoot}/uftrace",
            "args" : ["live", "--libmcount-path=.", "t-abc"],
            "stopAtEntry" : true,
            "cwd" : "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "miDebuggerPath": "/usr/bin/gdb",
            "setupCommands": [{
                "description": "gdb pretty print",
                "text" : "-enable-pretty-printing",
                "ignoreFailures": true
            }]
        }]
    }
Clone this wiki locally