summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiroslav Bajtoš <miro.bajtos@gmail.com>2013-04-26 08:05:33 +0200
committerBen Noordhuis <info@bnoordhuis.nl>2013-05-02 08:52:58 +0200
commita32a243d5f954ddbb4e7d1eac0b1e88a403a445d (patch)
tree9e71cd595ac6d09160627a0f96bbbbd26a00478b
parent2cf7e5de6f0af289f231ff499ef1acf731e9f3b1 (diff)
downloadnode-a32a243d5f954ddbb4e7d1eac0b1e88a403a445d.tar.gz
debugger: breakpoints in scripts not loaded yet
When developer calls setBreakpoint with an unknown script name, we convert the script name into regular expression matching all paths ending with given name (name can be a relative path too). To create such breakpoint in V8, we use type `scriptRegEx` instead of `scriptId` for `setbreakpoint` request. To restore such breakpoint, we save the original script name send by the user. We use this original name to set (restore) breakpoint in the new child process. This is a back-port of commit 5db936d from the master branch.
-rw-r--r--doc/api/debugger.markdown24
-rw-r--r--lib/_debugger.js55
-rw-r--r--test/fixtures/break-in-module/main.js4
-rw-r--r--test/fixtures/break-in-module/mod.js24
-rw-r--r--test/simple/helper-debugger-repl.js11
-rw-r--r--test/simple/test-debugger-repl-break-in-module.js80
6 files changed, 175 insertions, 23 deletions
diff --git a/doc/api/debugger.markdown b/doc/api/debugger.markdown
index 2c68c1d49..f4f989072 100644
--- a/doc/api/debugger.markdown
+++ b/doc/api/debugger.markdown
@@ -109,6 +109,30 @@ functions body
script.js
* `clearBreakpoint`, `cb(...)` - Clear breakpoint
+It is also possible to set a breakpoint in a file (module) that
+isn't loaded yet:
+
+ % ./node debug test/fixtures/break-in-module/main.js
+ < debugger listening on port 5858
+ connecting to port 5858... ok
+ break in test/fixtures/break-in-module/main.js:1
+ 1 var mod = require('./mod.js');
+ 2 mod.hello();
+ 3 mod.hello();
+ debug> setBreakpoint('mod.js', 23)
+ Warning: script 'mod.js' was not loaded yet.
+ 1 var mod = require('./mod.js');
+ 2 mod.hello();
+ 3 mod.hello();
+ debug> c
+ break in test/fixtures/break-in-module/mod.js:23
+ 21
+ 22 exports.hello = function() {
+ 23 return 'hello from module';
+ 24 };
+ 25
+ debug>
+
### Info
* `backtrace`, `bt` - Print backtrace of current execution frame
diff --git a/lib/_debugger.js b/lib/_debugger.js
index 6367e35f8..8be2d1e62 100644
--- a/lib/_debugger.js
+++ b/lib/_debugger.js
@@ -1385,16 +1385,28 @@ Interface.prototype.setBreakpoint = function(script, line,
scriptId = script;
}
- if (!scriptId) return this.error('Script : ' + script + ' not found');
if (ambiguous) return this.error('Script name is ambiguous');
if (line <= 0) return this.error('Line should be a positive value');
- var req = {
- type: 'scriptId',
- target: scriptId,
- line: line - 1,
- condition: condition
- };
+ var req;
+ if (scriptId) {
+ req = {
+ type: 'scriptId',
+ target: scriptId,
+ line: line - 1,
+ condition: condition
+ };
+ } else {
+ this.print('Warning: script \'' + script + '\' was not loaded yet.');
+ var escapedPath = script.replace(/([/\\.?*()^${}|[\]])/g, '\\$1');
+ var scriptPathRegex = '^(.*[\\/\\\\])?' + escapedPath + '$';
+ req = {
+ type: 'scriptRegExp',
+ target: scriptPathRegex,
+ line: line - 1,
+ condition: condition
+ };
+ }
}
self.pause();
@@ -1411,20 +1423,18 @@ Interface.prototype.setBreakpoint = function(script, line,
// Try load scriptId and line from response
if (!scriptId) {
scriptId = res.script_id;
- line = res.line;
- }
-
- // If we finally have one - remember this breakpoint
- if (scriptId) {
- self.client.breakpoints.push({
- id: res.breakpoint,
- scriptId: scriptId,
- script: (self.client.scripts[scriptId] || {}).name,
- line: line,
- condition: condition
- });
+ line = res.line + 1;
}
+ // Remember this breakpoint even if scriptId is not resolved yet
+ self.client.breakpoints.push({
+ id: res.breakpoint,
+ scriptId: scriptId,
+ script: (self.client.scripts[scriptId] || {}).name,
+ line: line,
+ condition: condition,
+ scriptReq: script
+ });
}
self.resume();
});
@@ -1439,7 +1449,9 @@ Interface.prototype.clearBreakpoint = function(script, line) {
index;
this.client.breakpoints.some(function(bp, i) {
- if (bp.scriptId === script || bp.script.indexOf(script) !== -1) {
+ if (bp.scriptId === script ||
+ bp.scriptReq === script ||
+ (bp.script && bp.script.indexOf(script) !== -1)) {
if (index !== undefined) {
ambiguous = true;
}
@@ -1657,7 +1669,8 @@ Interface.prototype.trySpawn = function(cb) {
// Restore breakpoints
breakpoints.forEach(function(bp) {
- self.setBreakpoint(bp.scriptId, bp.line, bp.condition, true);
+ self.print('Restoring breakpoint ' + bp.scriptReq + ':' + bp.line);
+ self.setBreakpoint(bp.scriptReq, bp.line, bp.condition, true);
});
client.on('close', function() {
diff --git a/test/fixtures/break-in-module/main.js b/test/fixtures/break-in-module/main.js
new file mode 100644
index 000000000..cb7074ed2
--- /dev/null
+++ b/test/fixtures/break-in-module/main.js
@@ -0,0 +1,4 @@
+var mod = require('./mod.js');
+mod.hello();
+mod.hello();
+debugger;
diff --git a/test/fixtures/break-in-module/mod.js b/test/fixtures/break-in-module/mod.js
new file mode 100644
index 000000000..57bf58bb3
--- /dev/null
+++ b/test/fixtures/break-in-module/mod.js
@@ -0,0 +1,24 @@
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+exports.hello = function() {
+ return 'hello from module';
+};
diff --git a/test/simple/helper-debugger-repl.js b/test/simple/helper-debugger-repl.js
index 2ef3ea35a..9a39bbb9f 100644
--- a/test/simple/helper-debugger-repl.js
+++ b/test/simple/helper-debugger-repl.js
@@ -126,16 +126,23 @@ function addTest(input, output) {
expected.push({input: input, lines: output, callback: next});
}
-var initialLines = [
+var handshakeLines = [
/listening on port \d+/,
- /connecting.* ok/,
+ /connecting.* ok/
+];
+
+var initialBreakLines = [
/break in .*:1/,
/1/, /2/, /3/
];
+var initialLines = handshakeLines.concat(initialBreakLines);
+
// Process initial lines
addTest(null, initialLines);
exports.startDebugger = startDebugger;
exports.addTest = addTest;
exports.initialLines = initialLines;
+exports.handshakeLines = handshakeLines;
+exports.initialBreakLines = initialBreakLines;
diff --git a/test/simple/test-debugger-repl-break-in-module.js b/test/simple/test-debugger-repl-break-in-module.js
new file mode 100644
index 000000000..1fe0aba84
--- /dev/null
+++ b/test/simple/test-debugger-repl-break-in-module.js
@@ -0,0 +1,80 @@
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+var repl = require('./helper-debugger-repl.js');
+
+repl.startDebugger('break-in-module/main.js');
+
+// -- SET BREAKPOINT --
+
+// Set breakpoint by file name + line number where the file is not loaded yet
+repl.addTest('sb("mod.js", 23)', [
+ /Warning: script 'mod\.js' was not loaded yet\./,
+ /1/, /2/, /3/, /4/, /5/, /6/
+]);
+
+// Check escaping of regex characters
+repl.addTest('sb(")^$*+?}{|][(.js\\\\", 1)', [
+ /Warning: script '[^']+' was not loaded yet\./,
+ /1/, /2/, /3/, /4/, /5/, /6/
+]);
+
+// continue - the breakpoint should be triggered
+repl.addTest('c', [
+ /break in .*[\\\/]mod\.js:23/,
+ /21/, /22/, /23/, /24/, /25/
+]);
+
+// -- RESTORE BREAKPOINT ON RESTART --
+
+// Restart the application - breakpoint should be restored
+repl.addTest('restart', [].concat(
+ [
+ /terminated/
+ ],
+ repl.handshakeLines,
+ [
+ /Restoring breakpoint mod.js:23/,
+ /Warning: script 'mod\.js' was not loaded yet\./,
+ /Restoring breakpoint \).*:\d+/,
+ /Warning: script '\)[^']*' was not loaded yet\./
+ ],
+ repl.initialBreakLines));
+
+// continue - the breakpoint should be triggered
+repl.addTest('c', [
+ /break in .*[\\\/]mod\.js:23/,
+ /21/, /22/, /23/, /24/, /25/
+]);
+
+// -- CLEAR BREAKPOINT SET IN MODULE TO BE LOADED --
+
+repl.addTest('cb("mod.js", 23)', [
+ /18/, /./, /./, /./, /./, /./, /./, /./, /26/
+]);
+
+repl.addTest('c', [
+ /break in .*[\\\/]main\.js:4/,
+ /2/, /3/, /4/, /5/, /6/
+]);
+
+// -- (END) --
+repl.addTest('quit', []);