Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorRyan Dahl <ry@tinyclouds.org>2010-12-22 06:14:29 +0300
committerRyan Dahl <ry@tinyclouds.org>2010-12-30 12:35:11 +0300
commit8d82ec21308812132a71afe45c5bc517b4a43354 (patch)
treecd5138d97432387f51332bee46b034ada1cabda8 /lib
parent0df804b9e7b509797e652a0e8657989023a01911 (diff)
Add beginning of build-in debugger
+ test-debugger-client (which is currently broken)
Diffstat (limited to 'lib')
-rw-r--r--lib/_debugger.js221
1 files changed, 221 insertions, 0 deletions
diff --git a/lib/_debugger.js b/lib/_debugger.js
new file mode 100644
index 00000000000..9f95e896ce5
--- /dev/null
+++ b/lib/_debugger.js
@@ -0,0 +1,221 @@
+var net = require('net');
+var readline = require('readline');
+var inherits = require('util').inherits;
+
+exports.port = 5858;
+
+exports.start = function (pid) {
+ if (pid) {
+ process.kill(pid, "SIGUSR1");
+ setTimeout(tryConnect, 100);
+ } else {
+ tryConnect();
+ }
+};
+
+var c;
+
+function tryConnect() {
+ c = new Client();
+
+ process.stdout.write("connecting...");
+ c.connect(exports.port, function () {
+ process.stdout.write("ok\r\n");
+ startInterface();
+ });
+
+}
+
+//
+// Parser/Serializer for V8 debugger protocol
+// http://code.google.com/p/v8/wiki/DebuggerProtocol
+//
+// Usage:
+// p = new Protocol();
+//
+// p.onResponse = function (res) {
+// // do stuff with response from V8
+// };
+//
+// socket.setEncoding('utf8');
+// socket.on('data', function (s) {
+// // Pass strings into the protocol
+// p.execute(s);
+// });
+//
+//
+function Protocol() {
+ this._newRes();
+}
+exports.Protocol = Protocol;
+
+
+Protocol.prototype._newRes = function(raw) {
+ this.res = { raw: raw || '', headers: {} };
+ this.state = 'headers';
+ this.reqSeq = 1;
+};
+
+
+Protocol.prototype.execute = function(d) {
+ var res = this.res;
+ res.raw += d;
+
+ switch (this.state) {
+ case 'headers':
+ var endHeaderIndex = res.raw.indexOf('\r\n\r\n');
+
+ if (endHeaderIndex < 0) break;
+
+ var lines = res.raw.slice(0, endHeaderIndex).split('\r\n');
+ for (var i = 0; i < lines.length; i++) {
+ var kv = lines[i].split(/: +/);
+ res.headers[kv[0]] = kv[1];
+ }
+
+ this.contentLength = +res.headers['Content-Length'];
+ this.bodyStartIndex = endHeaderIndex + 4;
+
+ this.state = 'body';
+ if (res.raw.length - this.bodyStartIndex < this.contentLength) break;
+ // pass thru
+
+ case 'body':
+ if (res.raw.length - this.bodyStartIndex >= this.contentLength) {
+ res.body =
+ res.raw.slice(this.bodyStartIndex,
+ this.bodyStartIndex + this.contentLength);
+ // JSON parse body?
+ res.body = res.body.length ? JSON.parse(res.body) : {};
+
+ // Done!
+ this.onResponse(res);
+
+ this._newRes(res.raw.slice(this.bodyStartIndex + this.contentLength));
+ }
+ break;
+
+ default:
+ throw new Error("Unknown state");
+ break;
+ }
+};
+
+
+Protocol.prototype.serialize = function(req) {
+ req.type = 'request';
+ req.seq = this.reqSeq++;
+ var json = JSON.stringify(req);
+ return 'Content-Length: ' + json.length + '\r\n\r\n' + json;
+};
+
+
+
+
+function Client() {
+ net.Stream.call(this);
+ var protocol = this.protocol = new Protocol(c);
+ this._reqCallbacks = [];
+ var socket = this;
+
+ // Note that 'Protocol' requires strings instead of Buffers.
+ socket.setEncoding('utf8');
+ socket.on('data', function(d) {
+ protocol.execute(d);
+ });
+
+ protocol.onResponse = this._onResponse.bind(this);
+};
+inherits(Client, net.Stream);
+exports.Client = Client;
+
+
+Client.prototype._onResponse = function(res) {
+ console.error(res);
+ for (var i = 0; i < this._reqCallbacks.length; i++) {
+ var cb = this._reqCallbacks[i];
+ if (this._reqCallbacks[i].request_seq == cb.request_seq) break;
+ }
+
+ if (cb) {
+ this._reqCallbacks.splice(i, 1);
+ cb(res.body);
+ } else if (res.headers.Type == 'connect') {
+ // do nothing
+ } else {
+ console.error("unhandled res: %j", res.body);
+ }
+};
+
+
+Client.prototype.req = function(req, cb) {
+ this.write(this.protocol.serialize(req));
+ cb.request_seq = req.seq;
+ this._reqCallbacks.push(cb);
+};
+
+
+Client.prototype.reqVersion = function(cb) {
+ this.req({ command: 'version' } , function (res) {
+ if (cb) cb(res.body.V8Version, res.running);
+ });
+};
+
+
+var helpMessage = "Commands: version, eval, help, quit";
+
+
+function startInterface() {
+
+ var i = readline.createInterface(process.stdout);
+ var stdin = process.openStdin();
+ stdin.addListener('data', function(chunk) {
+ i.write(chunk);
+ });
+
+ var prompt = '> ';
+
+ i.setPrompt(prompt);
+ i.prompt();
+
+ i.on('SIGINT', function() {
+ i.close();
+ });
+
+ i.on('line', function(cmd) {
+ if (cmd == 'quit') {
+ process.exit(0);
+ } else if (/^help/.test(cmd)) {
+ console.log(helpMessage);
+ i.prompt();
+
+ } else if ('version' == cmd) {
+ c.reqVersion(function (v) {
+ console.log(v);
+ i.prompt();
+ });
+
+ } else if (/^eval/.test(cmd)) {
+ var req = {
+ command: 'evaluate',
+ arguments: { 'expression': cmd.slice(5) }
+ };
+
+ c.req(req, function (res) {
+ console.log(res);
+ i.prompt();
+ });
+
+ } else {
+ if (!/^\s*$/.test(cmd)) {
+ // If it's not all white-space print this error message.
+ console.log('Unknown command "%s". Try "help"', cmd);
+ }
+ i.prompt();
+ }
+ });
+
+ i.on('close', function() {
+ stdin.destroy();
+ });
+}