PTVS icon indicating copy to clipboard operation
PTVS copied to clipboard

Remote debug attach does not support path mapping

Open rchiodo opened this issue 3 years ago • 11 comments

Following the directions here: https://docs.microsoft.com/en-us/visualstudio/python/debugging-python-code-on-remote-linux-machines?view=vs-2019

I cannot get breakpoints to bind.

Internally debugpy is returning this:

1> [DebugAdapter] <-- R (setBreakpoints-12) [20 ms]: {"type":"response","request_seq":12,"success":true,"command":"setBreakpoints","body":{"breakpoints":[{"verified":false,"message":"Breakpoint in file that does not exist.","source":{"path":"c:\\Users\\aku91\\source\\repos\\PythonApplication3\\PythonApplication3\\test.py","sources":[],"checksums":[]},"line":7}]},"seq":15}

This really means we need path mapping for the remote machine. There was some discussion in the past of VSCodeDebugAdapterHost supporting a launch.json that could provide that mapping. Short of that, we'd have to provide that here:

https://github.com/microsoft/PTVS/blob/984cd41766ea27a9b6ac304b437031e7d880899d/Python/Product/PythonTools/PythonTools/Debugger/DebugAdapter/DebugAdapterLauncher.cs#L167

We need to pass the attach request the path mappings like VS code does:

image

rchiodo avatar Jul 16 '21 22:07 rchiodo

Note: this repros in D16 too.

rchiodo avatar Jul 16 '21 22:07 rchiodo

Need to involve PM as there is potentially a UI component involved. @savannahostrowski

greazer avatar Aug 18 '21 22:08 greazer

To be specific, we need to decide what the appropriate UX for defining path mappings is. In VSCode, this is done by editing launch.json directly. We could expose it in a similar manner here (which would also have a benefit of giving users access to the complete panoply of debugpy configuration knobs).

However, traditionally, PTVS used GUI dialogs to configure such things. If we do that, it should probably go into the Debugging tab in project properties, and we need to figure out how that UI will look. It's basically a list of entries, each mapping one local absolute path to one remote path; so the UI needs to provide some way to specify project-relative paths there, that would then be automatically expanded before they're handed over to debugpy (debugpy itself can't do this because it doesn't know anything about VS projects).

int19h avatar Aug 19 '21 21:08 int19h

@ijoosong

int19h avatar Oct 13 '21 22:10 int19h

This worked before we moved to debugpy, so this should be treated as a regression since we can't support remote debugging without the ability to modify the json that is passed to the debug adapter. We probably need a generic way to do this. Pavel mentioned that the C++ team did some work around this, so we might be able to re-use what they did. Needs PM involvement here to decide what the best path is. /cc @cwebster-99

AdamYoblick avatar Jan 26 '23 22:01 AdamYoblick

C++ has something called launch.vs.json, which is roughly equivalent to launch.json in VSCode: https://learn.microsoft.com/en-us/cpp/build/launch-vs-schema-reference-cpp?view=msvc-170

And we actually have a separate issue asking for it to be supported for Python: https://github.com/microsoft/PTVS/issues/7269

If we do that, it would provide a way to specify path mappings, although we might still want a UI long-term.

int19h avatar Jan 27 '23 00:01 int19h

If we are able to re-use some of the work done by the C++ team to support launch.vs.json, I think that is a good approach (at least to begin with). We can do more investigation, if there is a need, for a GUI long-term solution. I infer users may be familiar with this approach if they are C++ users or even VS Code users familiar with launch.json

cwebster-99 avatar Mar 06 '23 17:03 cwebster-99

I doubt we'd be able to reuse the actual code, since C++ project system is very different from ours. But we can reuse their spec (i.e. where to look for the file and how to combine it with project settings), and to some extent probably the documentation.

int19h avatar Mar 06 '23 19:03 int19h

Since launch.vs.json would do more than just fix this issue, I think it would be best to track it separately - #7434

int19h avatar Mar 06 '23 19:03 int19h

Hi, I seem to be having a similar issue.

My host is running on MacOS 13.3 with Visual Code Studio 1.81.1 The app I'm working on is a Dockerized Stackstorm installation. Using the devcontainers extension from https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers, version v0.304.0 The debugger is being attached to a remote container whose hostname is "st2sensorcontainer". Debugpy is running and the listen() instruction is being called in the code of this file: ./packages/stackstorm/src/stackstorm/events/dispatch/server/app.py

        import multiprocessing

        if multiprocessing.current_process().pid > 1:
            import debugpy

            debugpy.listen(("0.0.0.0", 5678))
            print("Debugger is ready to be attached, press F5", flush=True)
            debugpy.wait_for_client()
            print("Visual Studio Code debugger is now attached", flush=True)

launch.json

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Python: Attach to sensor",
            "type": "python",
            "request": "attach",
            "logToFile": true,
            "connect": {
                "host": "st2sensorcontainer",
                "port": 5678
            },
            "clientOS": "Unix",
            "pathMappings": [
                {
                    "localRoot": "${workspaceFolder}",
                    "remoteRoot": "/opt/project/"
                }
            ]
        },
    ]
}

This issue I am having is that I can't place breakpoints in the debugger as it says "Breakpoint in file that does not exist".

If I hover over a file in the IDE, such as app.py, I get this path (which is the path in the devcontainer): /opt/project/packages/stackstorm/src/stackstorm/events/dispatch/server/app.py

However, since the debugger attaches to the remote container st2sensorcontainer, I went to look up that path. In ST2 Python packages are setup in a virtualenv. So the path of that file inside st2sensorcontainer is: /opt/stackstorm/virtualenvs/gcx/lib/python3.8/site-packages/stackstorm/events/dispatch/server/app.py

I've tried to tweak the pathMappings in all different ways. I've tried setting remoteRoot to ".", to "/opt/project", "/opt/project/packages/stackstorm/src/stackstorm", and "/opt/stackstorm/virtualenvs/gcx/lib/python3.8/site-packages/stackstorm". No luck.

I'd appreciate your help. Here is the log:


0 Starting Session:
{
    "name": "Python: Attach to sensor",
    "type": "python",
    "request": "attach",
    "logToFile": true,
    "connect": {
        "host": "st2sensorcontainer",
        "port": 5678
    },
    "clientOS": "Unix",
    "pathMappings": [
        {
            "localRoot": "/opt/project",
            "remoteRoot": "/opt/project/"
        }
    ],
    "__configurationTarget": 6,
    "debugOptions": [
        "RedirectOutput",
        "ShowReturnValue"
    ],
    "justMyCode": true,
    "showReturnValue": true,
    "workspaceFolder": "/opt/project"
}
5 Client <-- Adapter:
{
    "seq": 1,
    "type": "event",
    "event": "output",
    "body": {
        "category": "telemetry",
        "output": "ptvsd",
        "data": {
            "packageVersion": "1.6.7.post1"
        }
    }
}
5 Client <-- Adapter:
{
    "seq": 2,
    "type": "event",
    "event": "output",
    "body": {
        "category": "telemetry",
        "output": "debugpy",
        "data": {
            "packageVersion": "1.6.7.post1"
        }
    }
}
52 Client --> Adapter:
{
    "command": "initialize",
    "arguments": {
        "clientID": "vscode",
        "clientName": "Visual Studio Code",
        "adapterID": "python",
        "pathFormat": "path",
        "linesStartAt1": true,
        "columnsStartAt1": true,
        "supportsVariableType": true,
        "supportsVariablePaging": true,
        "supportsRunInTerminalRequest": true,
        "locale": "en",
        "supportsProgressReporting": true,
        "supportsInvalidatedEvent": true,
        "supportsMemoryReferences": true,
        "supportsArgsCanBeInterpretedByShell": true,
        "supportsMemoryEvent": true,
        "supportsStartDebuggingRequest": true
    },
    "type": "request",
    "seq": 1
}
54 Client <-- Adapter:
{
    "seq": 3,
    "type": "response",
    "request_seq": 1,
    "success": true,
    "command": "initialize",
    "body": {
        "supportsCompletionsRequest": true,
        "supportsConditionalBreakpoints": true,
        "supportsConfigurationDoneRequest": true,
        "supportsDebuggerProperties": true,
        "supportsDelayedStackTraceLoading": true,
        "supportsEvaluateForHovers": true,
        "supportsExceptionInfoRequest": true,
        "supportsExceptionOptions": true,
        "supportsFunctionBreakpoints": true,
        "supportsHitConditionalBreakpoints": true,
        "supportsLogPoints": true,
        "supportsModulesRequest": true,
        "supportsSetExpression": true,
        "supportsSetVariable": true,
        "supportsValueFormattingOptions": true,
        "supportsTerminateRequest": true,
        "supportsGotoTargetsRequest": true,
        "supportsClipboardContext": true,
        "exceptionBreakpointFilters": [
            {
                "filter": "raised",
                "label": "Raised Exceptions",
                "default": false,
                "description": "Break whenever any exception is raised."
            },
            {
                "filter": "uncaught",
                "label": "Uncaught Exceptions",
                "default": true,
                "description": "Break when the process is exiting due to unhandled exception."
            },
            {
                "filter": "userUnhandled",
                "label": "User Uncaught Exceptions",
                "default": false,
                "description": "Break when exception escapes into library code."
            }
        ],
        "supportsStepInTargetsRequest": true
    }
}
61 Client --> Adapter:
{
    "command": "attach",
    "arguments": {
        "name": "Python: Attach to sensor",
        "type": "python",
        "request": "attach",
        "logToFile": true,
        "connect": {
            "host": "st2sensorcontainer",
            "port": 5678
        },
        "clientOS": "Unix",
        "pathMappings": [
            {
                "localRoot": "/opt/project",
                "remoteRoot": "/opt/project/"
            }
        ],
        "__configurationTarget": 6,
        "debugOptions": [
            "RedirectOutput",
            "ShowReturnValue"
        ],
        "justMyCode": true,
        "showReturnValue": true,
        "workspaceFolder": "/opt/project",
        "__sessionId": "bc908d13-9507-44bf-b310-4b57df81b90f"
    },
    "type": "request",
    "seq": 2
}
62 Client <-- Adapter:
{
    "seq": 4,
    "type": "event",
    "event": "debugpyWaitingForServer",
    "body": {
        "host": "127.0.0.1",
        "port": 60177
    }
}
117 Client <-- Adapter:
{
    "seq": 5,
    "type": "event",
    "event": "initialized"
}
125 Client --> Adapter:
{
    "command": "setBreakpoints",
    "arguments": {
        "source": {
            "name": "__init__.py",
            "path": "/opt/project/packages/stackstorm/src/stackstorm/events/dispatch/server/__init__.py"
        },
        "lines": [
            17
        ],
        "breakpoints": [
            {
                "line": 17
            }
        ],
        "sourceModified": false
    },
    "type": "request",
    "seq": 3
}
126 Client --> Adapter:
{
    "command": "setBreakpoints",
    "arguments": {
        "source": {
            "name": "app.py",
            "path": "/opt/project/packages/stackstorm/src/stackstorm/events/dispatch/server/app.py"
        },
        "lines": [
            117
        ],
        "breakpoints": [
            {
                "line": 117
            }
        ],
        "sourceModified": false
    },
    "type": "request",
    "seq": 4
}
126 Client --> Adapter:
{
    "command": "setBreakpoints",
    "arguments": {
        "source": {
            "name": "client.py",
            "path": "/opt/project/packages/stackstorm/src/stackstorm/events/dispatch/client/client.py"
        },
        "lines": [
            69
        ],
        "breakpoints": [
            {
                "line": 69
            }
        ],
        "sourceModified": false
    },
    "type": "request",
    "seq": 5
}
126 Client --> Adapter:
{
    "command": "setBreakpoints",
    "arguments": {
        "source": {
            "name": "continuation.py",
            "path": "/opt/project/packages/stackstorm/src/stackstorm/events/models/continuation.py"
        },
        "lines": [
            148
        ],
        "breakpoints": [
            {
                "line": 148
            }
        ],
        "sourceModified": false
    },
    "type": "request",
    "seq": 6
}
126 Client --> Adapter:
{
    "command": "setBreakpoints",
    "arguments": {
        "source": {
            "name": "debugger.py",
            "path": "/opt/project/packages/stackstorm/src/stackstorm/events/dispatch/server/debugger.py"
        },
        "lines": [
            11
        ],
        "breakpoints": [
            {
                "line": 11
            }
        ],
        "sourceModified": false
    },
    "type": "request",
    "seq": 7
}
126 Client --> Adapter:
{
    "command": "setBreakpoints",
    "arguments": {
        "source": {
            "name": "handler_result_action.py",
            "path": "/opt/project/packages/stackstorm/src/stackstorm/events/actions/handler_result_action.py"
        },
        "lines": [
            37
        ],
        "breakpoints": [
            {
                "line": 37
            }
        ],
        "sourceModified": false
    },
    "type": "request",
    "seq": 8
}
126 Client --> Adapter:
{
    "command": "setBreakpoints",
    "arguments": {
        "source": {
            "name": "sandbox.py",
            "path": "/opt/project/packages/stackstorm/sandbox.py"
        },
        "lines": [
            94,
            237
        ],
        "breakpoints": [
            {
                "line": 94
            },
            {
                "line": 237
            }
        ],
        "sourceModified": false
    },
    "type": "request",
    "seq": 9
}
127 Client --> Adapter:
{
    "command": "setFunctionBreakpoints",
    "arguments": {
        "breakpoints": []
    },
    "type": "request",
    "seq": 10
}
127 Client --> Adapter:
{
    "command": "setExceptionBreakpoints",
    "arguments": {
        "filters": [
            "uncaught"
        ]
    },
    "type": "request",
    "seq": 11
}
130 Client <-- Adapter:
{
    "seq": 6,
    "type": "response",
    "request_seq": 3,
    "success": true,
    "command": "setBreakpoints",
    "body": {
        "breakpoints": [
            {
                "verified": false,
                "id": 200,
                "message": "Breakpoint in file that does not exist.",
                "source": {
                    "name": "__init__.py",
                    "path": "/opt/project/packages/stackstorm/src/stackstorm/events/dispatch/server/__init__.py"
                },
                "line": 17
            }
        ]
    }
}
174 Client <-- Adapter:
{
    "seq": 7,
    "type": "response",
    "request_seq": 4,
    "success": true,
    "command": "setBreakpoints",
    "body": {
        "breakpoints": [
            {
                "verified": false,
                "id": 201,
                "message": "Breakpoint in file that does not exist.",
                "source": {
                    "name": "app.py",
                    "path": "/opt/project/packages/stackstorm/src/stackstorm/events/dispatch/server/app.py"
                },
                "line": 117
            }
        ]
    }
}
176 Client <-- Adapter:
{
    "seq": 8,
    "type": "response",
    "request_seq": 5,
    "success": true,
    "command": "setBreakpoints",
    "body": {
        "breakpoints": [
            {
                "verified": false,
                "id": 202,
                "message": "Breakpoint in file that does not exist.",
                "source": {
                    "name": "client.py",
                    "path": "/opt/project/packages/stackstorm/src/stackstorm/events/dispatch/client/client.py"
                },
                "line": 69
            }
        ]
    }
}
179 Client <-- Adapter:
{
    "seq": 9,
    "type": "response",
    "request_seq": 6,
    "success": true,
    "command": "setBreakpoints",
    "body": {
        "breakpoints": [
            {
                "verified": false,
                "id": 203,
                "message": "Breakpoint in file that does not exist.",
                "source": {
                    "name": "continuation.py",
                    "path": "/opt/project/packages/stackstorm/src/stackstorm/events/models/continuation.py"
                },
                "line": 148
            }
        ]
    }
}
222 Client <-- Adapter:
{
    "seq": 10,
    "type": "response",
    "request_seq": 7,
    "success": true,
    "command": "setBreakpoints",
    "body": {
        "breakpoints": [
            {
                "verified": false,
                "id": 204,
                "message": "Breakpoint in file that does not exist.",
                "source": {
                    "name": "debugger.py",
                    "path": "/opt/project/packages/stackstorm/src/stackstorm/events/dispatch/server/debugger.py"
                },
                "line": 11
            }
        ]
    }
}
225 Client <-- Adapter:
{
    "seq": 11,
    "type": "response",
    "request_seq": 8,
    "success": true,
    "command": "setBreakpoints",
    "body": {
        "breakpoints": [
            {
                "verified": false,
                "id": 205,
                "message": "Breakpoint in file that does not exist.",
                "source": {
                    "name": "handler_result_action.py",
                    "path": "/opt/project/packages/stackstorm/src/stackstorm/events/actions/handler_result_action.py"
                },
                "line": 37
            }
        ]
    }
}
231 Client <-- Adapter:
{
    "seq": 12,
    "type": "response",
    "request_seq": 9,
    "success": true,
    "command": "setBreakpoints",
    "body": {
        "breakpoints": [
            {
                "verified": false,
                "id": 206,
                "message": "Breakpoint in file that does not exist.",
                "source": {
                    "name": "sandbox.py",
                    "path": "/opt/project/packages/stackstorm/sandbox.py"
                },
                "line": 94
            },
            {
                "verified": false,
                "id": 207,
                "message": "Breakpoint in file that does not exist.",
                "source": {
                    "name": "sandbox.py",
                    "path": "/opt/project/packages/stackstorm/sandbox.py"
                },
                "line": 237
            }
        ]
    }
}
274 Client <-- Adapter:
{
    "seq": 13,
    "type": "response",
    "request_seq": 10,
    "success": true,
    "command": "setFunctionBreakpoints",
    "body": {
        "breakpoints": []
    }
}
277 Client <-- Adapter:
{
    "seq": 14,
    "type": "response",
    "request_seq": 11,
    "success": true,
    "command": "setExceptionBreakpoints"
}
301 Client --> Adapter:
{
    "command": "configurationDone",
    "type": "request",
    "seq": 12
}
312 Client <-- Adapter:
{
    "seq": 15,
    "type": "response",
    "request_seq": 12,
    "success": true,
    "command": "configurationDone"
}
325 Client --> Adapter:
{
    "command": "threads",
    "type": "request",
    "seq": 13
}
326 Client <-- Adapter:
{
    "seq": 16,
    "type": "response",
    "request_seq": 2,
    "success": true,
    "command": "attach"
}
326 Client <-- Adapter:
{
    "seq": 17,
    "type": "event",
    "event": "process",
    "body": {
        "name": "/opt/stackstorm/st2/lib/python3.8/site-packages/st2reactor/container/sensor_wrapper.py",
        "systemProcessId": 9,
        "isLocalProcess": true,
        "startMethod": "attach"
    }
}
326 Client <-- Adapter:
{
    "seq": 18,
    "type": "event",
    "event": "thread",
    "body": {
        "reason": "started",
        "threadId": 1
    }
}
326 Client <-- Adapter:
{
    "seq": 19,
    "type": "event",
    "event": "thread",
    "body": {
        "reason": "started",
        "threadId": 2
    }
}
326 Client <-- Adapter:
{
    "seq": 20,
    "type": "event",
    "event": "thread",
    "body": {
        "reason": "started",
        "threadId": 3
    }
}
326 Client <-- Adapter:
{
    "seq": 21,
    "type": "event",
    "event": "thread",
    "body": {
        "reason": "started",
        "threadId": 4
    }
}
326 Client <-- Adapter:
{
    "seq": 22,
    "type": "event",
    "event": "thread",
    "body": {
        "reason": "started",
        "threadId": 5
    }
}
326 Client <-- Adapter:
{
    "seq": 23,
    "type": "event",
    "event": "thread",
    "body": {
        "reason": "started",
        "threadId": 6
    }
}
327 Client <-- Adapter:
{
    "seq": 24,
    "type": "event",
    "event": "thread",
    "body": {
        "reason": "started",
        "threadId": 7
    }
}
327 Client <-- Adapter:
{
    "seq": 25,
    "type": "event",
    "event": "thread",
    "body": {
        "reason": "started",
        "threadId": 9
    }
}
327 Client <-- Adapter:
{
    "seq": 26,
    "type": "event",
    "event": "thread",
    "body": {
        "reason": "started",
        "threadId": 8
    }
}
372 Client <-- Adapter:
{
    "seq": 27,
    "type": "response",
    "request_seq": 13,
    "success": true,
    "command": "threads",
    "body": {
        "threads": [
            {
                "id": 1,
                "name": "MainThread"
            },
            {
                "id": 2,
                "name": "pymongo_server_monitor_thread"
            },
            {
                "id": 3,
                "name": "pymongo_kill_cursors_thread"
            },
            {
                "id": 4,
                "name": "pymongo_server_rtt_thread"
            },
            {
                "id": 5,
                "name": "Thread-6"
            },
            {
                "id": 6,
                "name": "ThreadPoolExecutor-0_0"
            },
            {
                "id": 7,
                "name": "pymongo_server_monitor_thread"
            },
            {
                "id": 9,
                "name": "pymongo_kill_cursors_thread"
            },
            {
                "id": 8,
                "name": "pymongo_server_rtt_thread"
            }
        ]
    }
}
472 Client --> Adapter:
{
    "command": "threads",
    "type": "request",
    "seq": 14
}
475 Client <-- Adapter:
{
    "seq": 28,
    "type": "response",
    "request_seq": 14,
    "success": true,
    "command": "threads",
    "body": {
        "threads": [
            {
                "id": 1,
                "name": "MainThread"
            },
            {
                "id": 2,
                "name": "pymongo_server_monitor_thread"
            },
            {
                "id": 3,
                "name": "pymongo_kill_cursors_thread"
            },
            {
                "id": 4,
                "name": "pymongo_server_rtt_thread"
            },
            {
                "id": 5,
                "name": "Thread-6"
            },
            {
                "id": 6,
                "name": "ThreadPoolExecutor-0_0"
            },
            {
                "id": 7,
                "name": "pymongo_server_monitor_thread"
            },
            {
                "id": 9,
                "name": "pymongo_kill_cursors_thread"
            },
            {
                "id": 8,
                "name": "pymongo_server_rtt_thread"
            }
        ]
    }
}
17107 Client --> Adapter:
{
    "command": "setBreakpoints",
    "arguments": {
        "source": {
            "name": "app.py",
            "path": "/opt/project/packages/stackstorm/src/stackstorm/events/dispatch/server/app.py"
        },
        "lines": [
            53,
            117
        ],
        "breakpoints": [
            {
                "line": 53
            },
            {
                "line": 117
            }
        ],
        "sourceModified": false
    },
    "type": "request",
    "seq": 15
}
17113 Client <-- Adapter:
{
    "seq": 29,
    "type": "response",
    "request_seq": 15,
    "success": true,
    "command": "setBreakpoints",
    "body": {
        "breakpoints": [
            {
                "verified": false,
                "id": 208,
                "message": "Breakpoint in file that does not exist.",
                "source": {
                    "name": "app.py",
                    "path": "/opt/project/packages/stackstorm/src/stackstorm/events/dispatch/server/app.py"
                },
                "line": 53
            },
            {
                "verified": false,
                "id": 209,
                "message": "Breakpoint in file that does not exist.",
                "source": {
                    "name": "app.py",
                    "path": "/opt/project/packages/stackstorm/src/stackstorm/events/dispatch/server/app.py"
                },
                "line": 117
            }
        ]
    }
}
17785 Client --> Adapter:
{
    "command": "setBreakpoints",
    "arguments": {
        "source": {
            "name": "app.py",
            "path": "/opt/project/packages/stackstorm/src/stackstorm/events/dispatch/server/app.py"
        },
        "lines": [
            117
        ],
        "breakpoints": [
            {
                "line": 117
            }
        ],
        "sourceModified": false
    },
    "type": "request",
    "seq": 16
}
17789 Client <-- Adapter:
{
    "seq": 30,
    "type": "response",
    "request_seq": 16,
    "success": true,
    "command": "setBreakpoints",
    "body": {
        "breakpoints": [
            {
                "verified": false,
                "id": 210,
                "message": "Breakpoint in file that does not exist.",
                "source": {
                    "name": "app.py",
                    "path": "/opt/project/packages/stackstorm/src/stackstorm/events/dispatch/server/app.py"
                },
                "line": 117
            }
        ]
    }
}

princeydev avatar Aug 25 '23 03:08 princeydev

Well.. I found the issue.

The localRoot should be the path in the devcontainer, and the remoteRoot the path in the remote container (our st2sensorcontainer in this case).

AND there was actually another issue. In this case I had to add the following to my configuration (as by default it is set to true): "justMyCode": false,

princeydev avatar Aug 25 '23 04:08 princeydev