devtools-protocol: Debugger breakpoints using incorrect URL for a remote debugging session and therefore failing to pause the process
Symptoms
This is related to the closed ticket #99, which describes the symptoms of this very problem.
You set a breakpoint, but the process isn’t paused when that breakpoint is encountered and carries merrily on.
Environment
This is a remote debugging session between a Windows client (running Chrome devtools) and a remote Linux server (running node with --inspect=0.0.0.0).
What’s wrong
By watching the websocket communication with Wireshark it is apparent that the Chrome Dev tools are using an incorrect filepath/URL when calling Debugger.setBreakpointByUrl.
What I am seeing
Request
{
"id": 17,
"method": "Debugger.setBreakpointByUrl",
"params": {
"lineNumber": 67,
"url": "EFS\\DEV-efsbastion\\username\\application\\projects\\service\\module\\index.js",
"columnNumber": 18,
"condition": ""
}
}
Response
{
"id": 17,
"result": {
"breakpointId": "EFS\\DEV-efsbastion\\username\\application\\projects\\service\\module\\index.js:67:18",
"locations": []
}
}
Note the empty locations array. I am no node debugger expert, but it feels like this locations array should be checked to ensure it is not empty after setting a new breakpoint marker before then showing the marker as active in the UI.
What I should be seeing
Request
{
"id": 17,
"method": "Debugger.setBreakpointByUrl",
"params": {
"lineNumber": 67,
"url": "/EFS/DEV-efsbastion/username/application/projects/service/module/index.js",
"columnNumber": 18,
"condition": ""
}
}
Response
{
"id": 17,
"result": {
"breakpointId": "/EFS/DEV-efsbastion/username/application/projects/service/module/index.js:67:18",
"locations": [{
"scriptId":"104",
"lineNumber":67,
"columnNumber":18
}]
}
}
Note the Linux path separators instead of Windows and the initial root slash on the path.
But isn’t this a node bug?
No, it is not from what I can tell because of the following two discoveries.
PHPStorm
PHPStorm/WebStorm debugger continues to work just fine using it’s URL regexes
Request
{
"id": 17,
"method": "Debugger.setBreakpointByUrl",
"params": {
"lineNumber": 67,
"urlRegex": "[/\\\\][iI][nN][dD][eE][xX]\\.[jJ][sS]([;?#!].*)?$"
}
}
Response
{
"id": 17,
"result": {
"breakpointId": "/[/\\\\][iI][nN][dD][eE][xX]\\.[jJ][sS]([;?#!].*)?$/:67:18",
"locations": [{
"scriptId":"104",
"lineNumber":67,
"columnNumber":18
}]
}
}
Manually recreating the request successfully
If I manually set the breakpoint myself I see a success response back over the websocket. For example consider the following code run from the Chrome console:
let id, key, socket
id = 1000
key = '<debugger-key-goes-here>'
const connect = userSuppliedKey => {
socket = new WebSocket(`ws://<ip-address-goes-here>:9229/${userSuppliedKey || key}`)
socket.addEventListener('message', e => {
const d = JSON.parse(e.data)
if (d) {
if (d.method === 'Debugger.scriptParsed') return console.log('scriptParsed', JSON.stringify({ scriptId: d.params.scriptId, url: d.params.url }))
if (d.method === 'Debugger.breakpointResolved') return console.log('breakpointResolved', JSON.stringify(Object.assign({ breakpointId: d.params.breakpointId }, d.params.location)))
}
console.info(`${e.data}`)
})
}
const send = (method, x) => socket.send(JSON.stringify({ id: ++id, method: `Debugger.${method}`, params: x }))
const _getPossibleBps = (start, end) => send('getPossibleBreakpoints', { start, end })
const getPossibleBps = (scriptId, start, end) => _getPossibleBps({ scriptId, lineNumber: start }, { scriptId, lineNumber: end })
const setBp = (lineNumber, url) => send('setBreakpointByUrl', { lineNumber, url, })
const removeBp = (lineNumber, url, columnNumber) => send('removeBreakpoint', { breakpointId: `${url}:${lineNumber}:${columnNumber || 0}` })
const enable = () => send('enable')
Which gives us this when run in the Chrome console
connect('<debugger-key-goes-here>')
// '<debugger-key-goes-here>'
enable()
// ...
// scriptParsed {"scriptId":"104","url":"/EFS/DEV-efsbastion/username/application/projects/service/module/index.js"}
// ...
getPossibleBps('104', 9, 15)
// {"id":1016,"result":{"locations":[{"scriptId":"104","lineNumber":9,"columnNumber":15},{"scriptId":"104","lineNumber":11,"columnNumber":15},{"scriptId":"104","lineNumber":12,"columnNumber":16},{"scriptId":"104","lineNumber":14,"columnNumber":4},{"scriptId":"104","lineNumber":15,"columnNumber":0},{"scriptId":"104","lineNumber":17,"columnNumber":4},{"scriptId":"104","lineNumber":18,"columnNumber":14}]}}
setBp(11, '/EFS/DEV-efsbastion/username/application/projects/service/module/index.js')
// {"id":1024,"result":{"breakpointId":"/EFS/DEV-efsbastion/username/application/projects/service/module/index.js:11:0","locations":[{"scriptId":"104","lineNumber":11,"columnNumber":15}]}}
removeBp(11, '/EFS/DEV-efsbastion/username/application/projects/service/module/index.js')
// {"id":1019,"result":{}}
Possible introduction of the issue
in combination with https://chromium.googlesource.com/chromium/src/+blame/master/third_party/blink/renderer/devtools/front_end/common/ParsedURL.js#103
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 1
- Comments: 42
Thanks for great report!
Inside V8 on inspector backend side we try to match breakpoint url and script url. In this case we send incorrect url from frontend side and when we receive new parsed script on backend side we do not set breakpoint properly.
I will do following two points next week:
I will update this issue as soon as I get some results.
(PhpStorm actually uses great regexp)
It seems to have gotten worse with the release of chrome 69. The workarounds I posted above no longer work with chrome 69.0.3497.81(stable) and with chrome 71.0.3548.0 (canary). Workstations still running 68.0.3440.106 do work with both workarounds.
fileURL patches were merged to Node 10. So I expect this issue to be fixed in next Node 10 release, I will update this bug when release happens.
Just to corroborate that this is due to a change on the chrome side and provide a workaround. We experienced this recently running windows workstations with a linux development VM. We had 3 versions of chrome(64, 66, 68) connecting one at a time to a debug session and only 64 was working normally. This was true for node 6, 8 and 10.
As a workaround for those who need to debug, we found that using the id and manually visiting the link
chrome-devtools://devtools/bundled/inspector.html?experiments=true&v8only=true&ws=${ip}:${port}/${id}works as expected even in the newer chrome versions. If, for example, you get the messageDebugger listening on ws://0.0.0.0:3020/4dacc23a-f296-4b6d-bb47-18af21dfef67during inspect start, the URL would bechrome-devtools://devtools/bundled/inspector.html?experiments=true&v8only=true&ws=${ip}:3020/4dacc23a-f296-4b6d-bb47-18af21dfef67where ip is the ip of the remote machine. We also found that the plugin nodejs-v8-inspector-manag(https://chrome.google.com/webstore/detail/nodejs-v8-inspector-manag/gnhhdgbaldcilmgcpfddgdbkhjohddkj) seems to still work.I confirm that Chrome
71.0.3578.98works fine.I verified that Chrome release version:
Version 71.0.3578.80 (Official Build) (64-bit)now has this repaired. Maybe should be closed?Could we focus on fixing DevTools and DevTools protocol in this issue please? A lot of workarounds were already mentioned and I believe that now we can focus on finding solution for root issue.
The root of this issue is using platform-specific file paths in our protocol as was mentioned before. I landed V8 patch and close to merging Node patch that will migrate Node starting Node 11 to file urls: https://github.com/nodejs/node/pull/22251. At the same time I am working on better solution for remote debugging as part of ndb project. I will update this issue as soon as it is ready for Node 8 and Node 10.
I downloaded the canary with version: Version 70.0.3508.0 (Official Build) canary (64-bit) and it appears to still have the same problem if that helps.
@ak239,
Looks like canary (v72) fixes the problem! (at least for me).
Environment
Windows 10: Version 1803 (OS Build 17134.345) node: 8.11.3 & 10.12 (using WSL) chrome: 69.0.3497.100 & 72.0.3580.0 (Official Build) canary (64-bit)
Note: I am running WSL on windows, which is the Ubuntu linux subsystem.
node script index.js:
Repro steps
node --inspect-brk index.jschrome://inspect, click onOpen dedicated DevTools for NodeF8)Fails with chrome 69, tested with node 8.11.3 & node 10.12
Result: debugger stops on line 4, missing breakpoint at line 3.
Workaround with NIM tools works because essentially it uses v66 of the devTools.
Verified fixed with chrome 72, tested with node 8.11.3 & node 10.12
Result: debugger stops on breakpoint at line 3 Yay!
Also mentioned in the chromium bug, Chrome Extensions “Inspector Manager” is a simpler workaround for now
https://chrome.google.com/webstore/detail/nodejs-v8-inspector-manag/gnhhdgbaldcilmgcpfddgdbkhjohddkj