microsoft / vscode-cpptools

Official repository for the Microsoft C/C++ extension for VS Code.
Other
5.4k stars 1.52k forks source link

Remote debugging not possible #321

Open csholmq opened 7 years ago

csholmq commented 7 years ago

Trying to attach to a GDB server with no luck. All I want is to connect to the GDB server, run target remote localhost:4444 and start sending some monitor commands.

As soon as I uncomment miDebuggerServerAddress I get

Unable to start debugging. Cannot access a disposed object.

Also, why am I required to specify a process id? I am trying to debug on a embedded target, so my GDB server, that I run through, speaks with it over JTAG. Which process id is referred to?

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "C++ Attach",
            "type": "cppdbg",
            "request": "attach",
            "program": "${workspaceRoot}/Sw/A_XMC/out/use/A_Myriad_A_6_13.elf",
            "processId": "${command.pickProcess}",
            "MIMode": "gdb",
            // "miDebuggerServerAddress": "localhost:4444",
            "miDebuggerPath": "C:/dev/ELF/GDB/gdb.exe"
        }
    ]
}
pieandcakes commented 7 years ago

@csholmq I think you need to start with the C++ Launch scenario to do remote GDB. Can you recreate your launch.json using that section and see if it works for you? I know with the type of attach we only look for specific properties to do a local attach.

csholmq commented 7 years ago

@pieandcakes Ah, good to know. I have attempted a few approaches using launch and gotten a bit further. At least with calling a script that executes GDB directly. I'll post a new launch.json as soon as I have tried it again.

Is there anyway to "debug the debugger"? I'm troubleshooting a bit in the dark here.

pieandcakes commented 7 years ago

@csholmq - You can enable logging through the logging tag in launch.json. I would look at either trace\traceResponse or engineLogging. The engineLogging are the MICommands we send to the debugger and the responses we get back. You can switch gdb into MI mode by specifying --interpreter=mi as a command line parameter.

One of the intermediary components, the MIEngine, is open-sourced.

csholmq commented 7 years ago

Still having issues even though I can now connect to the gdb server.

1: (186) LaunchOptions<LocalLaunchOptions xmlns='http://schemas.microsoft.com/vstudio/MDDDebuggerOptions/2014'
1: (198) LaunchOptions  ExePath='c:\dev\xxx\HPC_XMC\HPC_XMC_A_6_2\Sw\A_XMC\out\use\A_HPC_XMC_A_6_2.elf'
1: (198) LaunchOptions  WorkingDirectory='c:\dev\xxx\HPC_XMC\HPC_XMC_A_6_2\Sw\A_XMC\out\obj'
1: (198) LaunchOptions  TargetArchitecture='arm'
1: (198) LaunchOptions  ExeArguments=''
1: (198) LaunchOptions MIMode='gdb'
1: (198) LaunchOptions  MIDebuggerPath='C:/dev/GDB/gdb.exe'
1: (198) LaunchOptions  WaitDynamicLibLoad='false'
1: (198) LaunchOptions  MIDebuggerServerAddress='localhost:4444'
1: (198) LaunchOptions  ExternalConsole='true'
1: (198) LaunchOptions>
1: (198) LaunchOptions    <SetupCommands>
1: (198) LaunchOptions        <Command IgnoreFailures='false' Description=''>target remote localhost:4444</Command>
1: (198) LaunchOptions        <Command IgnoreFailures='false' Description=''>monitor interface=0</Command>
1: (198) LaunchOptions        <Command IgnoreFailures='false' Description=''>monitor port=0</Command>
1: (198) LaunchOptions        <Command IgnoreFailures='false' Description=''>monitor speed=500000</Command>
1: (198) LaunchOptions        <Command IgnoreFailures='false' Description=''>monitor type=0</Command>
1: (198) LaunchOptions        <Command IgnoreFailures='false' Description=''>monitor unit=2</Command>
1: (199) LaunchOptions        <Command IgnoreFailures='false' Description=''>monitor connect</Command>
1: (199) LaunchOptions    </SetupCommands>
1: (199) LaunchOptions    <CustomLaunchSetupCommands>
1: (199) LaunchOptions    </CustomLaunchSetupCommands>
1: (199) LaunchOptions    <LaunchCompleteCommand>None</LaunchCompleteCommand>
1: (199) LaunchOptions</LocalLaunchOptions>
1: (271) Starting: "C:/dev/GDB/gdb.exe" --interpreter=mi

Why is it still doing all these other commands that I don't support?

1: (487) <-1011-interpreter-exec console "info sharedlibrary"
1: (488) ->~"No shared libraries loaded at this time.\n"
1: (488) ->1011^done
1: (488) ->(gdb)
1: (488) 1011: elapsed time 1
E output: {"category":"console","output":"Loaded 'shared libraries loaded at this time.'. Cannot find or open the symbol file.\r\n","data":null,"type":"output"}
Loaded 'shared libraries loaded at this time.'. Cannot find or open the symbol file.
1: (506) <-1012-thread-info
1: (510) ->1012^done,threads=[{id="1",target-id="Thread 1",details="A",frame={level="0",addr="0x02b32208",func="??",args=[]},state="stopped"}],current-thread-id="1"
1: (510) ->=thread-selected,id="1"
1: (510) ->(gdb)
1: (511) 1012: elapsed time 4
1: (522) <-1013-stack-list-frames 0 1000
E output: {"category":"stdout","output":"=thread-selected,id=\"1\"\n","data":null,"type":"output"}
=thread-selected,id="1"
1: (531) ->1013^error,msg="Cannot access memory at address 0xa404"
1: (531) ->(gdb)
1: (531) 1013: elapsed time 9
1: (532) Stack walk failed on thread: 1
E output: {"category":"stderr","output":"ERROR: Unable to start debugging. Failed to find thread 1 for break event\r\n","data":null,"type":"output"}
ERROR: Unable to start debugging. Failed to find thread 1 for break event
1: (543) <--gdb-exit
pieandcakes commented 7 years ago

@paulmaybee @jacdavis Can either of you provide any insight?

jacdavis commented 7 years ago

The MI Engine is executing our normal command set during startup because setupcommands only appends to the standard set of commands executed during startup. If you want to replace them, use customSetupCommands. However, I must warn you that this can completely break the debugger if events and/or requests are not sent as expected by the debugger.

The UI expects certain functionalities that some gdb implementations do not support, even outside the standard command set. For instance, in the example above, whatever gdb is being spoken to, cannot support "info sharedlibraries". This command is not a startup command and will be executed when the debug ui is trying to determine what is loaded. I can only speculate on the the next error "cannot access memory at addres 0xa404" but it seems likely that the version of gdb being used has a bug that -stack-list-frames crashes.

The requirement of setting processid is a bug that will be resolved in our next update

paulmaybee commented 7 years ago

From the part of the log you have included above the sequence looks like normal post setup execution of the MIEngine. Although you can customize the setup sequence for your device, you have very little control over the debugger interactions with gdb. I believe that from the way you have this configured the MIEngine will expect that the process is stopped and ready to inspect when the launch sequence is complete. It will, for example, automatically attempt to determine the process state by looking at the stack trace and local variable contents. If this is not that case then you might want to place a breakpoint at your entry point and do something to make your application ready to run. On an Arduino, for example, I have a customLaunchSetupCommand "monitor reset init" and LaunchCompleteCommand set to "exec-continue".

csholmq commented 7 years ago

This was my launch.json which actually already included an empty customLaunchSetupCommands.

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "C++ Launch",
            "type": "cppdbg",
            "request": "launch",
            "program": "C:/dev/GDB/gdb.exe",
            "args": [],
            "stopAtEntry": true,
            "cwd": "${workspaceRoot}/Sw/A_XMC/out/obj",
            "environment": [],
            "externalConsole": true,
            "windows": {
                "MIMode": "gdb",
                "miDebuggerPath": "C:/dev/GDB/gdb.exe",
                "miDebuggerServerAddress": "localhost:4444"
            },
            "launchCompleteCommand": "None",
            "customLaunchSetupCommands": [],
            "setupCommands": [
                {"text": "target remote localhost:4444"},
                {"text": "monitor interface=0"},
                {"text": "monitor port=0"},
                {"text": "monitor speed=500000"},
                {"text": "monitor type=0"},
                {"text": "monitor unit=2"},
                {"text": "monitor connect"},
                {"text": "add-symbol-file C:/dev/Sw/A_XMC/out/use/A_Myriad_A_6_13.elf 0x8020000"}
            ],
            "logging": {
                "engineLogging": true,
                "traceResponse": true
            },
            "targetArchitecture": "arm"
        }
    ]
}

Here's the end snippet of the debugger log. After the configuration part.

 R: {"success":true,"message":null,"request_seq":6,"command":"threads","body":{"threads":[]},"running":false,"refs":null,"seq":0,"type":"response"}
1: (706) <-1012-interpreter-exec console "info sharedlibrary"
1: (710) ->~"No shared libraries loaded at this time.\n"
1: (710) ->1012^done
1: (711) ->(gdb)
1: (712) 1012: elapsed time 5
E output: {"category":"console","output":"Loaded 'shared libraries loaded at this time.'. Cannot find or open the symbol file.\r\n","data":null,"type":"output"}
Loaded 'shared libraries loaded at this time.'. Cannot find or open the symbol file.
1: (733) <-1013-thread-info
1: (744) ->1013^done,threads=[{id="1",target-id="Thread 1",details="A",frame={level="0",addr="0x01272208",func="??",args=[]},state="stopped"}],current-thread-id="1"
1: (744) ->=thread-selected,id="1"
1: (746) ->(gdb)
1: (747) 1013: elapsed time 14
1: (765) <-1014-stack-list-frames 0 1000
E output: {"category":"stdout","output":"=thread-selected,id=\"1\"\n","data":null,"type":"output"}
=thread-selected,id="1"
1: (778) ->1014^done,stack=[frame={level="0",addr="0x01272208",func="??"},frame={level="1",addr="0x00000000",func="??"}]
1: (779) ->(gdb)
1: (779) 1014: elapsed time 14
E thread: {"reason":"started","threadId":1,"type":"thread"}
C threads: null
 R: {"success":true,"message":null,"request_seq":7,"command":"threads","body":{"threads":[]},"running":false,"refs":null,"seq":0,"type":"response"}
1: (787) <--exec-continue
1: (789) ->^running
1: (790) ->*running,thread-id="all"
1: (790) ->(gdb)
1: (790) ->~"Can't send signals to this remote system.  SIGILL not sent.\n"
E output: {"category":"stdout","output":"Can't send signals to this remote system.  SIGILL not sent.\n","data":null,"type":"output"}
Can't send signals to this remote system.  SIGILL not sent.

All my monitor commands are successfully executed. But somehow, exec-continue is still executed and I am unable to poll anything due to Unable to perform this action because the process is running..

I understand that my lack of understanding for the GDB debugging experience isn't ideal, but all I want is to connect to a remote target using target remote localhost:4444, fire off some monitor commands and then do some polling. Not interested in breakpoints or stack traces. Just polling. This works using Eclipse and I've previously succeeded using another VScode extension. So it should work...

csholmq commented 7 years ago

Still not working on VSCode 1.8 and C/C++ extension 0.9.3. But this time I can't even seem to connect.

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "C++ Attach",
            "type": "cppdbg",
            "request": "attach",
            "program": "${workspaceRoot}/Sw/out.elf",
            "windows": {
                "MIMode": "gdb",
                "setupCommands": [
                    {
                        "description": "Enable pretty-printing for gdb",
                        "text": "-enable-pretty-printing",
                        "ignoreFailures": true
                    }
                ],
                "miDebuggerServerAddress": "localhost:4444",
                "miDebuggerPath": "C:/dev/GDB/gdb.exe"
            }
        }
    ]
}

First off, both type and request are dimmed as if they are not supported. Why?

Secondly, I get this: image

Roughly translated to "... can not perform binding to a null reference"

therealkenc commented 7 years ago

I would like to use this scenario also. The Linux-ish platform I am using is WSL, which is capable of running gdbserver but not VS Code. I have tried using Visual C++ for Linux but haven't had a lot of luck with that yet either; the documentation seems to be geared toward new Visual Studio solutions as opposed to classic Linux configure/make packages. In any case the debug experience with vscode-cpptools on native Ubuntu better matches my workflow. Any help moving this forward would be greatly appreciated, because debugging C/C++ on WSL is a bear right now.

pieandcakes commented 7 years ago

@csholmq You want to use the "request": "launch" option within the launch.json with the miDebuggerServerAddress and miDebuggerPath options. The dimming is something that VSCode does and I think it means its a required parameter, which seems to be new.

@therealkenc I don't think communication from Windows into the WSL subsystem will allow those calls but I'm not sure. There is plans to enable the C++ extension to work with the WSL subsystem but there are changes necessary within WSL to support our scenario.

therealkenc commented 7 years ago

Remote gdb debugging (old school) to WSL works well, as does VC++ for Linux. I should have been more clear; it works, I just haven't had "much luck" because there's no way to get VC++ for Linux to work without a Visual Studio solution; which normally one doesn't have on Linux (WSL or otherwise).

Visual Studio Code itself does not run on WSL right now, unfortunately (though I did give it my best). But assuming I can get VSCode in a Linux VM to talk to a remote gdb debugging session in WSL, that would be a great start. There is no telling when WSL will support libchromiumcontent, but remote gdb should be no problem. That is, if you give me a recipe to do remote debugging in VSCode with vscode-cpptools from one Real Ubuntu Linux machine to another, I can take it from there and fill in any gaps with the WSL folks (if there are any).

There's a good demo of VC++ for Linux debugging an executable in WSL at 53:00 minutes into the talk here:

https://www.youtube.com/watch?v=MBmp1gxCu9k

pieandcakes commented 7 years ago

@therealkenc we have added the ability for pipeTransport with the 0.10.0 update. You can read more about it here. This should allow you do the remote debugging with SSH using our extension.

csholmq commented 7 years ago

@pieandcakes pipeTransport didn't solve anything for the original topic of this issue I'm afraid. Still unable to get debugging running.

Not entirely sure, but despite setting customLaunchSetupCommands to blank and launchCompleteCommand to None, there still are some commands being fired off after my last monitor connect command.

Here is my configuration.

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "C++ Launch",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceRoot}/Sw/A_XMC/out/use/A_Myriad_A_6_13.elf",
            "cwd": "${workspaceRoot}/Sw/A_XMC/out/obj",
            "miDebuggerPath": "C:/dev/GDB/gdb.exe",
            // "miDebuggerServerAddress": "localhost:4441",
            "setupCommands": [
                {"text": "add-symbol-file C:/dev/Myriad/Myriad_trunk/Sw/A_XMC/out/use/A_Myriad_A_6_13.elf 0x8020000"},
                {"text": "target remote localhost:4444"},
                {"text": "monitor interface=0"},
                {"text": "monitor port=0"},
                {"text": "monitor speed=500000"},
                {"text": "monitor type=0"},
                {"text": "monitor unit=3"},
                {"text": "monitor unlockcode=5afePW"},
                {"text": "monitor connect"}
            ],
            "customLaunchSetupCommands": [],
            "launchCompleteCommand": "None",
            "logging": {
                "engineLogging": true
            },
            "targetArchitecture": "arm"
        }
    ]
}

Why is this present?

1: (561) <-1014-stack-list-frames 0 1000
=thread-selected,id="1"
1: (568) ->1014^error,msg="Cannot access memory at address 0xa404"
1: (568) ->(gdb)
1: (568) 1014: elapsed time 7
1: (569) Stack walk failed on thread: 1
ERROR: Unable to start debugging. Failed to find thread 1 for break event
1: (578) <--gdb-exit
csholmq commented 7 years ago

Unwanted commands still being fired are:

gdb-set target-async on gdb-set solib-search-path [path] interpreter-exec console "info sharedlibrary" stack-list-frames 0 1000 (which fails for me as there is no stack nor stopped target) gdb-exit (due to previous error I assume) logout

pieandcakes commented 7 years ago

@csholmq Those unwanted commands are part of the MIEngine setup. You can see the code here is where the target-async is fired. When we launch, we break at the first possible moment and setup the debug engine and during that process it does a stack-list-frames to walk the stack and then continues. As per @jacdavis 's comment above, there are commands that we expect that are not considered setup commands.

If you can provide more insight into your setup, I can try and see if we can duplicate the issue to help solve your issue. The other option is to download MIEngine and build it and debug into it. Since that project is open source, you are welcome to contribute back to it.

csholmq commented 7 years ago

@pieandcakes I see. Thank you for the explanation! I will look into modifying the MIEngine to better fit my needs. I'll get back to this issue once I have collected some more info.

anpilog commented 7 years ago

@csholmq check out my launch.json from #107

csholmq commented 7 years ago

@anpilog Very similar case. I think my issue is that the debugger (or MIEngine) assumes that the target is stopped and tries to fetch the stack frame when there is none. In my case specifically, I connect to a custom monitor (i.e not gdbserver) where all I want is to setup using a few monitor commands and then be able to manually p My_Variable.

ghost commented 3 years ago

Although pipeTransport is indeed a useful setting, the issue here is not being able to attach to an existing remote debugging session.

In such a case, gdb is already connected to the process that is being debugged and it would use a local gdb binary to connect to the remote target.

I have been trying to get this to work but always with no success. If I pass attach a processId is requested, whilst if I try launch then vscode tries to launch the (ARM) elf and fail. I also tried setting processId to some bad value and vscode would refuse to launch because I can't have processId and miDebuggerServerAddress at the same time (with attach)

In short: how is one supposed to connect to a gdbserver instead of launching the whole thing from vscode?

DrTerror commented 5 months ago

Sadly @ghost's account was deleted, but is there any progress concerning this issue?

mrx23dot commented 18 hours ago

Just use simple remote debugger over IP, thus remote OS env shouldn't matter: (don't provide processId) https://stackoverflow.com/questions/53519668/how-to-attach-to-remote-gdb-with-vscode