Symbols loading from the target (via gdb/gdbserver) does not work
Environment
- OS and version:
ОС: Windows_NT x64 10.0.19044 - VS Code:
1.86.0 - C/C++ extension:
1.19.1 - OS and version of remote machine (if applicable):
Linux raspberrypi 4.19.304-v7+ #3 SMP Wed Jan 10 14:46:02 MSK 2024 armv7l GNU/Linux - GDB / LLDB version:
14.1
Bug Summary and Steps to Reproduce
When using remote debugging with extended remote target it is possible to load symbols from the remote target directly using the target:/path-to-executable path for the -file-exec-and-symbols GDB command.
Unfortunately there is a problem in the current cpptools. Steps to reproduce:
- Use any project with the remote debugging (target and host machines should differ)
- Set
programin thelaunch.jsontotarget:/path-to-executable-on-the-remote-target - Enable extended remote
"useExtendedRemote": true - Start remote gdbserver and debugging
cpptools issue GDB -file-exec-and-symbols command before connecting to the remote target, so it looks for the file on the host, fails and debugging can not be started (see the filtered log)
Debugger Configurations
{
//NOTE: remote username, address, project directory and executable name are defined in the config file (.vscode/settings.json)
"version": "0.2.0",
"configurations": [
{
"name": "Remote debug",
"type": "cppdbg",
"request": "launch",
"targetArchitecture": "arm",
"useExtendedRemote": true,
"program": "target:${config:remote.dir}/${config:remote.exec}",
"miDebuggerServerAddress": "${config:remote.addr}:1234",
"args": [],
"stopAtEntry": true,
"cwd": "${workspaceRoot}",
"environment": [],
"externalConsole": true,
"sourceFileMap":{
"/share/OGL" : "$WorkspaceRoot}"
},
"windows": {
"MIMode": "gdb",
"miDebuggerPath": "C:\\gdb-arm-linux\\bin\\arm-linux-gnueabihf-gdb.exe",
"preLaunchTask": "debug"
},
"logging": {
"engineLogging": true,
"trace": true
}
}
]
}
Debugger Logs
1: (202) <-1001-gdb-set mi-async on
1: (233) <-1002-interpreter-exec console "show configuration"
1: (261) <-1003-interpreter-exec console "set pagination off"
1: (276) <-1004-gdb-set auto-solib-add on
1: (291) <-1005-gdb-set solib-search-path target:/share/OGL/build;
1: (308) <-1006-environment-cd D:/Oleg/_Projects/Neon3/Software/Client/CtrlPi
1: (324) <-1007-gdb-set new-console on
1: (347) <-1008-file-exec-and-symbols target:/share/OGL/build/main.elf
1: (355) ->1008^error,msg="/share/OGL/build/main.elf: No such file or directory."
1: (360) <--gdb-exit
1: (363) <-logout
Other Extensions
No response
Additional Information
Possible solutions
- Probably the most correct is to connect to remote target early (before issuing
-file-exec-and-symbolscommand) ifprogramstarts withtarget: - The most simple is to skip checking program existence on the host if path specified in
programstarts withtarget:How it works: It is possible to issuetarget extended-remotecommand explicitly by using thesetupCommands. themiDebuggerServershould not be used, cause we connect to target insetupCommands. Unfortunately whenmiDebuggerServeris not specified cpptools check the existence of the program specified by theprogramand of cause it does not exists on the host (moreover the path is also invalid). If it will not do that check the following configuration will work and load symbols from the target directly:
{
//NOTE: remote username, address, project directory and executable name are defined in the config file (.vscode/settings.json)
"version": "0.2.0",
"configurations": [
{
"name": "Remote debug",
"type": "cppdbg",
"request": "launch",
"targetArchitecture": "arm",
"useExtendedRemote": true,
"program": "target:${config:remote.dir}/${config:remote.exec}",
"args": [],
"stopAtEntry": true,
"cwd": "${workspaceRoot}",
"environment": [],
"externalConsole": true,
"sourceFileMap":{
"/share/OGL" : "$WorkspaceRoot}"
},
"setupCommands": [
{ "text":"target extended-remote ${config:remote.addr}:1234", "ignoreFailure":false }
],
"windows": {
"MIMode": "gdb",
"miDebuggerPath": "C:\\gdb-arm-linux\\bin\\arm-linux-gnueabihf-gdb.exe",
"preLaunchTask": "debug"
},
"logging": {
"engineLogging": true,
"trace": true
}
}
]
}
- The ability to specify fully custom setup commands (so the
-file-exec-and-symbolsand-target-select extended-remoteare specified explicitly) will also solve this problem
Ugly current workaround
Issue target extended-remote command in the setupCommands and do not remove miDebuggerServer from the launch.json. This will result in issuing target extended-remote command twice, but somehow it works :). Not sure it will with the other GDB version:
1: (217) <-1001-gdb-set mi-async on
1: (228) <-1002-interpreter-exec console "show configuration"
1: (256) <-1003-interpreter-exec console "target extended-remote 192.168.122.233:1234"
1: (327) <-1004-interpreter-exec console "set pagination off"
1: (328) <-1005-gdb-set auto-solib-add on
1: (349) <-1006-gdb-set solib-search-path target:/share/OGL/build;
1: (369) <-1007-environment-cd D:/Oleg/_Projects/Neon3/Software/Client/CtrlPi
1: (380) <-1008-gdb-set new-console on
1: (401) <-1009-file-exec-and-symbols target:/share/OGL/build/main.elf
1: (4575) <-1010-interpreter-exec console "show architecture"
1: (4593) <-1011-break-insert -f main
1: (5106) <-1012-target-select extended-remote 192.168.122.233:1234
1: (5180) <-1013-interpreter-exec console "set remote exec-file /share/OGL/build/main.elf"
1: (5199) <-1014-interpreter-exec console "set scheduler-locking step"
<-- C (setBreakpoints-3): {"command":"setBreakpoints","arguments":{"source":{"name":"test.c","path":"d:\\Oleg\\_Projects\\Neon3\\Software\\Client\\CtrlPi\\test.c"},"lines":[243],"breakpoints":[{"line":243}],"sourceModified":false},"type":"request","seq":3}
1: (5273) <-1015-break-insert -f test.c:243
1: (5306) <-1016-symbol-list-lines D:/Oleg/_Projects/Neon3/Software/Client/CtrlPi/test.c
<-- C (setFunctionBreakpoints-4): {"command":"setFunctionBreakpoints","arguments":{"breakpoints":[]},"type":"request","seq":4}
<-- C (setDataBreakpoints-5): {"command":"setDataBreakpoints","arguments":{"breakpoints":[]},"type":"request","seq":5}
<-- C (setInstructionBreakpoints-6): {"command":"setInstructionBreakpoints","arguments":{"breakpoints":[]},"type":"request","seq":6}
<-- C (setExceptionBreakpoints-7): {"command":"setExceptionBreakpoints","arguments":{"filters":[],"filterOptions":[]},"type":"request","seq":7}
<-- C (configurationDone-8): {"command":"configurationDone","type":"request","seq":8}
<-- C (threads-9): {"command":"threads","type":"request","seq":9}
1: (5399) <-1017-exec-run
I looked at the GetInitializeCommands in DebuggedProcess.cs (MIEngine repo) and realized that Option 3 in the possible solutions was already implemented. So, I tried to use fully custom setup and launch gdb commands and it did the trick:
{
//NOTE: remote username, address, project directory and executable name are defined in the config file (.vscode/settings.json)
"version": "0.2.0",
"configurations": [
{
"name": "GDBserver debug",
"type": "cppdbg",
"request": "launch",
"targetArchitecture": "arm",
"useExtendedRemote": true,
"program": "target:${config:remote.dir}/${config:remote.exec}",
"miDebuggerServerAddress": "${config:remote.addr}:1234",
"args": [],
"cwd": "${workspaceRoot}",
"environment": [],
//"externalConsole": true,
"sourceFileMap":{
"/share/OGL" : "{$workspaceRoot}",
"/share" : "D:\\src\\lib"
},
"customLaunchSetupCommands" : [
{ "text":"target extended-remote ${config:remote.addr}:1234", "ignoreFailure":false },
{ "text": "-file-exec-and-symbols target:${config:remote.dir}/${config:remote.exec}", "ignoreFailure":false },
{ "text": "set remote exec-file ${config:remote.dir}/${config:remote.exec}", "ignoreFailure":false },
{ "text":"set scheduler-locking step" }
],
"windows": {
"MIMode": "gdb",
"miDebuggerPath": "C:\\gdb-arm-linux\\bin\\arm-linux-gnueabihf-gdb.exe",
"preLaunchTask": "debug"
},
"logging": {
"engineLogging": true,
"trace": true
}
}
}
And the filtered log:
1: (242) <-1001-gdb-set mi-async on
1: (269) <-1002-interpreter-exec console "set pagination off"
1: (274) <-1003-gdb-set auto-solib-add on
1: (289) <-1004-gdb-set solib-search-path target:/share/OGL/build;
1: (306) <-1005-interpreter-exec console "target extended-remote 192.168.122.233:1234"
1: (382) <-1007-file-exec-and-symbols target:/share/OGL/build/main.elf
1: (4407) <-1008-interpreter-exec console "set remote exec-file /share/OGL/build/main.elf"
1: (4437) <-1010-interpreter-exec console "set scheduler-locking step"
<-- C (setFunctionBreakpoints-3): {"command":"setFunctionBreakpoints","arguments":{"breakpoints":[]},"type":"request","seq":3}
<-- C (setDataBreakpoints-4): {"command":"setDataBreakpoints","arguments":{"breakpoints":[]},"type":"request","seq":4}
<-- C (setInstructionBreakpoints-5): {"command":"setInstructionBreakpoints","arguments":{"breakpoints":[]},"type":"request","seq":5}
<-- C (setExceptionBreakpoints-6): {"command":"setExceptionBreakpoints","arguments":{"filters":[],"filterOptions":[]},"type":"request","seq":6}
<-- C (configurationDone-7): {"command":"configurationDone","type":"request","seq":7}
1: (4526) <-1011-exec-run