return this.selected_frame;
};
-ExecutionState.prototype.debugCommandProcessor = function(protocol) {
- return new DebugCommandProcessor(this, protocol);
+ExecutionState.prototype.debugCommandProcessor = function(opt_is_running) {
+ return new DebugCommandProcessor(this, opt_is_running);
};
};
-function DebugCommandProcessor(exec_state) {
+function DebugCommandProcessor(exec_state, opt_is_running) {
this.exec_state_ = exec_state;
- this.running_ = false;
+ this.running_ = opt_is_running || false;
};
this.type = 'event';
}
this.success = true;
- this.running = false;
+ // Handler may set this field to control debugger state.
+ this.running = undefined;
}
if (this.message) {
json.message = this.message;
}
- if (this.running) {
- json.running = true;
- } else {
- json.running = false;
- }
+ json.running = this.running;
return JSON.stringify(json);
}
this.scriptsRequest_(request, response);
} else if (request.command == 'threads') {
this.threadsRequest_(request, response);
+ } else if (request.command == 'suspend') {
+ this.suspendRequest_(request, response);
} else {
throw new Error('Unknown command "' + request.command + '" in request');
}
// Return the response as a JSON encoded string.
try {
- this.running_ = response.running; // Store the running state.
+ if (!IS_UNDEFINED(response.running)) {
+ // Response controls running state.
+ this.running_ = response.running;
+ }
+ response.running = this.running_;
return response.toJSONProtocol();
} catch (e) {
// Failed to generate response - return generic error.
};
+DebugCommandProcessor.prototype.suspendRequest_ = function(request, response) {
+ // TODO(peter.rybin): probably we need some body field here.
+ response.running = false;
+};
+
+
// Check whether the previously processed command caused the VM to become
// running.
DebugCommandProcessor.prototype.isRunning = function() {
return;
}
- // Get the DebugCommandProcessor.
- v8::Local<v8::Object> api_exec_state =
- v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state));
- v8::Local<v8::String> fun_name =
- v8::String::New("debugCommandProcessor");
- v8::Local<v8::Function> fun =
- v8::Function::Cast(*api_exec_state->Get(fun_name));
v8::TryCatch try_catch;
- v8::Local<v8::Object> cmd_processor =
- v8::Object::Cast(*fun->Call(api_exec_state, 0, NULL));
- if (try_catch.HasCaught()) {
- PrintLn(try_catch.Exception());
- return;
+
+ // DebugCommandProcessor goes here.
+ v8::Local<v8::Object> cmd_processor;
+ {
+ v8::Local<v8::Object> api_exec_state =
+ v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state));
+ v8::Local<v8::String> fun_name =
+ v8::String::New("debugCommandProcessor");
+ v8::Local<v8::Function> fun =
+ v8::Function::Cast(*api_exec_state->Get(fun_name));
+
+ v8::Handle<v8::Boolean> running =
+ auto_continue ? v8::True() : v8::False();
+ static const int kArgc = 1;
+ v8::Handle<Value> argv[kArgc] = { running };
+ cmd_processor = v8::Object::Cast(*fun->Call(api_exec_state, kArgc, argv));
+ if (try_catch.HasCaught()) {
+ PrintLn(try_catch.Exception());
+ return;
+ }
}
+ bool running = auto_continue;
+
// Process requests from the debugger.
while (true) {
// Wait for new command in the queue.
// Get the response.
v8::Local<v8::String> response;
- bool running = false;
if (!try_catch.HasCaught()) {
// Get response string.
if (!response_val->IsUndefined()) {
// Return from debug event processing if either the VM is put into the
// runnning state (through a continue command) or auto continue is active
// and there are no more commands queued.
- if (running || (auto_continue && !HasCommands())) {
+ if (running && !HasCommands()) {
return;
}
}
}
+ParsedResponse.prototype.running = function() {
+ return this.response_.running;
+}
+
+
ParsedResponse.prototype.lookup = function(handle) {
return this.refs_[handle];
}
var frame;
var source;
- // Get the debug command processor.
- var dcp = exec_state.debugCommandProcessor();
+ var dcp;
+ // New copy of debug command processor paused state.
+ dcp = exec_state.debugCommandProcessor(false);
// Get the backtrace.
var json;
assertEquals("g", response.lookup(frames[2].func.ref).name);
assertEquals(3, frames[3].index);
assertEquals("", response.lookup(frames[3].func.ref).name);
+ assertFalse(response.running(), "expected not running");
// Get backtrace with two frames.
json = '{"seq":0,"type":"request","command":"backtrace","arguments":{"fromFrame":1,"toFrame":3}}'
source = response.body();
assertEquals(Debug.findScript(f).source, source.source);
+ // New copy of debug command processor in running state.
+ dcp = exec_state.debugCommandProcessor(true);
+ // Get the backtrace.
+ json = '{"seq":0,"type":"request","command":"backtrace"}'
+ resp = dcp.processDebugJSONRequest(json);
+ response = new ParsedResponse(resp);
+ // It might be argueable, but we expect response to have body when
+ // not suspended
+ assertTrue(!!response.body(), "response should be null");
+ assertTrue(response.running(), "expected running");
+
listenerCalled = true;
}
} catch (e) {
try {
if (event == Debug.DebugEvent.Break) {
// Get the debug command processor.
- var dcp = exec_state.debugCommandProcessor();
+ var dcp = exec_state.debugCommandProcessor("unspecified_running_state");
// Test some illegal clearbreakpoint requests.
var request = '{' + base_request + '}'
try {
if (event == Debug.DebugEvent.Break) {
// Get the debug command processor.
- var dcp = exec_state.debugCommandProcessor();
+ var dcp = exec_state.debugCommandProcessor("unspecified_running_state");
// Test some illegal clearbreakpoint requests.
var request = '{' + base_request + '}'
try {\r
if (event == Debug.DebugEvent.Break) {\r
// Get the debug command processor.\r
- var dcp = exec_state.debugCommandProcessor();\r
+ var dcp = exec_state.debugCommandProcessor("unspecified_running_state");\r
\r
// Clear breakpoint group 1.\r
testArguments(dcp, '{"groupId":1}', true);\r
}
}
-function testArguments(dcp, arguments, success) {
+function testArguments(exec_state, arguments, success) {
+ // Get the debug command processor in paused state.
+ var dcp = exec_state.debugCommandProcessor(false);
+
// Generate request with the supplied arguments
var request;
if (arguments) {
function listener(event, exec_state, event_data, data) {
try {
if (event == Debug.DebugEvent.Break) {
- // Get the debug command processor.
- var dcp = exec_state.debugCommandProcessor();
// Test simple continue request.
- testArguments(dcp, void 0, true);
+ testArguments(exec_state, void 0, true);
// Test some illegal continue requests.
- testArguments(dcp, '{"stepaction":"maybe"}', false);
- testArguments(dcp, '{"stepcount":-1}', false);
+ testArguments(exec_state, '{"stepaction":"maybe"}', false);
+ testArguments(exec_state, '{"stepcount":-1}', false);
// Test some legal continue requests.
- testArguments(dcp, '{"stepaction":"in"}', true);
- testArguments(dcp, '{"stepaction":"min"}', true);
- testArguments(dcp, '{"stepaction":"next"}', true);
- testArguments(dcp, '{"stepaction":"out"}', true);
- testArguments(dcp, '{"stepcount":1}', true);
- testArguments(dcp, '{"stepcount":10}', true);
- testArguments(dcp, '{"stepcount":"10"}', true);
- testArguments(dcp, '{"stepaction":"next","stepcount":10}', true);
+ testArguments(exec_state, '{"stepaction":"in"}', true);
+ testArguments(exec_state, '{"stepaction":"min"}', true);
+ testArguments(exec_state, '{"stepaction":"next"}', true);
+ testArguments(exec_state, '{"stepaction":"out"}', true);
+ testArguments(exec_state, '{"stepcount":1}', true);
+ testArguments(exec_state, '{"stepcount":10}', true);
+ testArguments(exec_state, '{"stepcount":"10"}', true);
+ testArguments(exec_state, '{"stepaction":"next","stepcount":10}', true);
// Indicate that all was processed.
listenerComplete = true;
Debug.setBreakPoint(g, 0, 0);
g();
+assertFalse(exception, "exception in listener")
// Make sure that the debug event listener vas invoked.
assertTrue(listenerComplete, "listener did not run to completion");
-assertFalse(exception, "exception in listener")
}
}
-function testRequest(dcp, arguments, success, result) {
+function testRequest(exec_state, arguments, success, result) {
+ // Get the debug command processor in paused state.
+ var dcp = exec_state.debugCommandProcessor(false);
+
// Generate request with the supplied arguments.
var request;
if (arguments) {
assertEquals(1, exec_state.frame(0).evaluate('f()', true).value());
assertEquals(2, exec_state.frame(0).evaluate('g()', true).value());
- // Get the debug command processor.
- var dcp = exec_state.debugCommandProcessor();
-
// Call functions with break using the JSON protocol. Tests that argument
// disable_break is default true.
- testRequest(dcp, '{"expression":"f()"}', true, 1);
- testRequest(dcp, '{"expression":"f()","frame":0}', true, 1);
- testRequest(dcp, '{"expression":"g()"}', true, 2);
- testRequest(dcp, '{"expression":"g()","frame":0}', true, 2);
+ testRequest(exec_state, '{"expression":"f()"}', true, 1);
+ testRequest(exec_state, '{"expression":"f()","frame":0}', true, 1);
+ testRequest(exec_state, '{"expression":"g()"}', true, 2);
+ testRequest(exec_state, '{"expression":"g()","frame":0}', true, 2);
// Call functions with break using the JSON protocol. Tests passing
// argument disable_break is default true.
- testRequest(dcp, '{"expression":"f()","disable_break":true}', true, 1);
- testRequest(dcp, '{"expression":"f()","frame":0,"disable_break":true}',
+ testRequest(exec_state, '{"expression":"f()","disable_break":true}', true, 1);
+ testRequest(exec_state, '{"expression":"f()","frame":0,"disable_break":true}',
true, 1);
- testRequest(dcp, '{"expression":"g()","disable_break":true}', true, 2);
- testRequest(dcp, '{"expression":"g()","frame":0,"disable_break":true}',
+ testRequest(exec_state, '{"expression":"g()","disable_break":true}', true, 2);
+ testRequest(exec_state, '{"expression":"g()","frame":0,"disable_break":true}',
true, 2);
// Indicate that all was processed.
// Cause a debug break event.
debugger;
+assertFalse(exception, "exception in listener")
// Make sure that the debug event listener vas invoked.
assertTrue(listenerComplete);
-assertFalse(exception, "exception in listener")
// Remove the debug event listener.
Debug.setListener(null);
debugger;
+assertFalse(exception, "exception in listener")
// Make sure that the debug event listener vas invoked.
assertTrue(listenerComplete);
-assertFalse(exception, "exception in listener")
assertEquals(2, break_count);
} else {
assertFalse(response.success, request + ' -> ' + response.message);
}
- assertFalse(response.running, request + ' -> expected not running');
+ assertEquals(response.running, "unspecified_running_state",
+ request + ' -> expected not running');
}
function listener(event, exec_state, event_data, data) {
try {
if (event == Debug.DebugEvent.Break) {
// Get the debug command processor.
- var dcp = exec_state.debugCommandProcessor();
+ var dcp = exec_state.debugCommandProcessor("unspecified_running_state");
// Test some illegal evaluate requests.
testRequest(dcp, void 0, false);
Debug.setBreakPoint(f, 2, 0);
g();
+assertFalse(exception, "exception in listener")
// Make sure that the debug event listener vas invoked.
assertTrue(listenerComplete, "listener did not run to completion");
-assertFalse(exception, "exception in listener")
// Send an evaluation request and return the handle of the result.
-function evaluateRequest(dcp, arguments) {
+function evaluateRequest(exec_state, arguments) {
+ // Get the debug command processor.
+ var dcp = exec_state.debugCommandProcessor("unspecified_running_state");
+
// The base part of all evaluate requests.
var base_request = '"seq":0,"type":"request","command":"evaluate"'
// Send a lookup request and return the evaluated JSON response.
-function lookupRequest(dcp, arguments, success) {
+function lookupRequest(exec_state, arguments, success) {
+ // Get the debug command processor.
+ var dcp = exec_state.debugCommandProcessor("unspecified_running_state");
+
// The base part of all lookup requests.
var base_request = '"seq":0,"type":"request","command":"lookup"'
} else {
assertFalse(response.success, request + ' -> ' + response.message);
}
- assertFalse(response.running, request + ' -> expected not running');
+ assertEquals(response.running, dcp.isRunning(), request + ' -> expected not running');
return response;
}
function listener(event, exec_state, event_data, data) {
try {
if (event == Debug.DebugEvent.Break) {
- // Get the debug command processor.
- var dcp = exec_state.debugCommandProcessor();
-
// Test some illegal lookup requests.
- lookupRequest(dcp, void 0, false);
- lookupRequest(dcp, '{"handles":["a"]}', false);
- lookupRequest(dcp, '{"handles":[-1]}', false);
+ lookupRequest(exec_state, void 0, false);
+ lookupRequest(exec_state, '{"handles":["a"]}', false);
+ lookupRequest(exec_state, '{"handles":[-1]}', false);
// Evaluate and get some handles.
- var handle_o = evaluateRequest(dcp, '{"expression":"o"}');
- var handle_p = evaluateRequest(dcp, '{"expression":"p"}');
- var handle_b = evaluateRequest(dcp, '{"expression":"a"}');
- var handle_a = evaluateRequest(dcp, '{"expression":"b","frame":1}');
+ var handle_o = evaluateRequest(exec_state, '{"expression":"o"}');
+ var handle_p = evaluateRequest(exec_state, '{"expression":"p"}');
+ var handle_b = evaluateRequest(exec_state, '{"expression":"a"}');
+ var handle_a = evaluateRequest(exec_state, '{"expression":"b","frame":1}');
assertEquals(handle_o, handle_a);
assertEquals(handle_a, handle_b);
assertFalse(handle_o == handle_p, "o and p have he same handle");
var response;
var count;
- response = lookupRequest(dcp, '{"handles":[' + handle_o + ']}', true);
+ response = lookupRequest(exec_state, '{"handles":[' + handle_o + ']}', true);
var obj = response.body[handle_o];
assertTrue(!!obj, 'Object not found: ' + handle_o);
assertEquals(handle_o, obj.handle);
}
}
assertEquals(2, count, 'Either "o" or "p" not found');
- response = lookupRequest(dcp, '{"handles":[' + handle_p + ']}', true);
+ response = lookupRequest(exec_state, '{"handles":[' + handle_p + ']}', true);
obj = response.body[handle_p];
assertTrue(!!obj, 'Object not found: ' + handle_p);
assertEquals(handle_p, obj.handle);
// Check handles for functions on the stack.
- var handle_f = evaluateRequest(dcp, '{"expression":"f"}');
- var handle_g = evaluateRequest(dcp, '{"expression":"g"}');
- var handle_caller = evaluateRequest(dcp, '{"expression":"f.caller"}');
+ var handle_f = evaluateRequest(exec_state, '{"expression":"f"}');
+ var handle_g = evaluateRequest(exec_state, '{"expression":"g"}');
+ var handle_caller = evaluateRequest(exec_state, '{"expression":"f.caller"}');
assertFalse(handle_f == handle_g, "f and g have he same handle");
assertEquals(handle_g, handle_caller, "caller for f should be g");
- response = lookupRequest(dcp, '{"handles":[' + handle_f + ']}', true);
+ response = lookupRequest(exec_state, '{"handles":[' + handle_f + ']}', true);
obj = response.body[handle_f];
assertEquals(handle_f, obj.handle);
switch (obj.properties[i].name) {
case 'name':
var response_name;
- response_name = lookupRequest(dcp, arguments, true);
+ response_name = lookupRequest(exec_state, arguments, true);
assertEquals('string', response_name.body[ref].type);
assertEquals("f", response_name.body[ref].value);
count++;
break;
case 'length':
var response_length;
- response_length = lookupRequest(dcp, arguments, true);
+ response_length = lookupRequest(exec_state, arguments, true);
assertEquals('number', response_length.body[ref].type);
assertEquals(1, response_length.body[ref].value);
count++;
}
var arguments = '{"handles":[' + refs.join(',') + ']}';
- response = lookupRequest(dcp, arguments, true);
+ response = lookupRequest(exec_state, arguments, true);
count = 0;
for (i in obj.properties) {
var ref = obj.properties[i].ref;
p.p = p;
g(o);
+assertFalse(exception, "exception in listener")
// Make sure that the debug event listener vas invoked.
assertTrue(listenerComplete, "listener did not run to completion: " + exception);
-assertFalse(exception, "exception in listener")
Debug = debug.Debug
listenerCallCount = 0;
-listenerExceptionCount = 0;
+listenerExceptions = [];
function listener(event, exec_state, event_data, data) {
assertEquals(0, debug.next_handle_, "Mirror cache not cleared");
assertEquals(0, debug.mirror_cache_.length, "Mirror cache not cleared");
- // Get the debug command processor.
- var dcp = exec_state.debugCommandProcessor();
+ // Get the debug command processor in paused state.
+ var dcp = exec_state.debugCommandProcessor(false);
// Make a backtrace request to create some mirrors.
var json;
}
} catch (e) {
print(e);
- listenerExceptionCount++;
+ listenerExceptions.push(e);
};
};
debugger;
debugger;
+assertEquals([], listenerExceptions, "Exception in listener");
// Make sure that the debug event listener vas invoked.
assertEquals(2, listenerCallCount, "Listener not called");
-assertEquals(0, listenerExceptionCount, "Exception in listener");
} else {\r
assertFalse(response.success, request + ' -> ' + response.message);\r
}\r
- assertFalse(response.running, request + ' -> expected not running');\r
+ assertEquals(response.running, dcp.isRunning(), request + ' -> expected not running');\r
}\r
\r
function listener(event, exec_state, event_data, data) {\r
try {\r
if (event == Debug.DebugEvent.Break) {\r
// Get the debug command processor.\r
- var dcp = exec_state.debugCommandProcessor();\r
+ var dcp = exec_state.debugCommandProcessor("unspecified_running_state");\r
\r
// Test some illegal references requests.\r
testRequest(dcp, void 0, false);\r
}
// Get the debug command processor.
- var dcp = exec_state.debugCommandProcessor();
+ var dcp = exec_state.debugCommandProcessor("unspecified_running_state");
// Send a scopes request and check the result.
var json;
assertEquals(count, scope_size);
// Get the debug command processor.
- var dcp = exec_state.debugCommandProcessor();
+ var dcp = exec_state.debugCommandProcessor("unspecified_running_state");
// Send a scope request for information on a single scope and check the
// result.
try {
if (event == Debug.DebugEvent.Break) {
// Get the debug command processor.
- var dcp = exec_state.debugCommandProcessor();
+ var dcp = exec_state.debugCommandProcessor("unspecified_running_state");
// Test illegal scripts requests.
testArguments(dcp, '{"types":"xx"}', false);
try {
if (event == Debug.DebugEvent.Break) {
// Get the debug command processor.
- var dcp = exec_state.debugCommandProcessor();
+ var dcp = exec_state.debugCommandProcessor("unspecified_running_state");
// Test some illegal setbreakpoint requests.
var request = '{' + base_request + '}'
--- /dev/null
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+// Simple function which stores the last debug event.
+listenerComplete = false;
+exception = false;
+
+var base_backtrace_request = '"seq":0,"type":"request","command":"backtrace"'
+var base_suspend_request = '"seq":0,"type":"request","command":"suspend"'
+
+function safeEval(code) {
+ try {
+ return eval('(' + code + ')');
+ } catch (e) {
+ assertEquals(void 0, e);
+ return undefined;
+ }
+}
+
+function testArguments(exec_state) {
+ // Get the debug command processor in running state.
+ var dcp = exec_state.debugCommandProcessor(true);
+
+ assertTrue(dcp.isRunning());
+
+ var backtrace_request = '{' + base_backtrace_request + '}'
+ var backtrace_response = safeEval(dcp.processDebugJSONRequest(backtrace_request));
+
+ assertTrue(backtrace_response.success);
+
+ assertTrue(backtrace_response.running, backtrace_request + ' -> expected running');
+
+ assertTrue(dcp.isRunning());
+
+ var suspend_request = '{' + base_suspend_request + '}'
+ var suspend_response = safeEval(dcp.processDebugJSONRequest(suspend_request));
+
+ assertTrue(suspend_response.success);
+
+ assertFalse(suspend_response.running, suspend_request + ' -> expected not running');
+
+ assertFalse(dcp.isRunning());
+}
+
+function listener(event, exec_state, event_data, data) {
+ try {
+ if (event == Debug.DebugEvent.Break) {
+
+ // Test simple suspend request.
+ testArguments(exec_state);
+
+ // Indicate that all was processed.
+ listenerComplete = true;
+ }
+ } catch (e) {
+ exception = e
+ };
+};
+
+// Add the debug event listener.
+Debug.setListener(listener);
+
+// Stop debugger and check that suspend command changes running flag.
+debugger;
+
+assertFalse(exception, "exception in listener")
+// Make sure that the debug event listener vas invoked.
+assertTrue(listenerComplete, "listener did not run to completion");
// 0: [anonymous]
// Get the debug command processor.
- var dcp = exec_state.debugCommandProcessor();
+ var dcp = exec_state.debugCommandProcessor(false);
// Get the backtrace.
var json;
// Ignore the exception "Cannot call method 'x' of undefined"
}
+assertFalse(exception, "exception in listener", exception)
// Make sure that the debug event listener vas invoked.
assertTrue(listenerCalled, "listener not called");
-assertFalse(exception, "exception in listener", exception)