summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/debugger/debugger_node.cc8
-rw-r--r--chrome/browser/debugger/debugger_shell.cc5
-rw-r--r--chrome/browser/debugger/debugger_shell.h3
-rw-r--r--chrome/browser/debugger/debugger_wrapper.cc5
-rw-r--r--chrome/browser/debugger/debugger_wrapper.h1
-rw-r--r--chrome/browser/debugger/resources/debugger_shell.js167
-rw-r--r--chrome/browser/render_view_host.cc12
-rw-r--r--chrome/browser/render_view_host.h9
-rw-r--r--chrome/common/render_messages_internal.h9
-rw-r--r--chrome/renderer/debug_message_handler.cc54
-rw-r--r--chrome/renderer/debug_message_handler.h5
-rw-r--r--chrome/renderer/render_view.cc2
-rw-r--r--chrome/test/debugger/test_protocol.js4
13 files changed, 180 insertions, 104 deletions
diff --git a/chrome/browser/debugger/debugger_node.cc b/chrome/browser/debugger/debugger_node.cc
index 43de519..23b2cef 100644
--- a/chrome/browser/debugger/debugger_node.cc
+++ b/chrome/browser/debugger/debugger_node.cc
@@ -316,7 +316,7 @@ v8::Handle<v8::Value> TabNode::SendToDebugger(const v8::Arguments& args,
v8::Handle<v8::Value> obj;
obj = args[0];
DebuggerShell::ObjectToString(obj, &cmd);
- host->SendToDebugger(cmd);
+ host->DebugCommand(cmd);
}
return v8::Undefined();
}
@@ -340,7 +340,11 @@ v8::Handle<v8::Value> TabNode::Detach(const v8::Arguments& args,
v8::Handle<v8::Value> TabNode::Break(const v8::Arguments& args,
WebContents* web) {
RenderViewHost* host = web->render_view_host();
- host->DebugBreak();
+ bool force = false;
+ if (args.Length() >= 1) {
+ force = args[0]->BooleanValue();
+ }
+ host->DebugBreak(force);
return v8::Undefined();
}
diff --git a/chrome/browser/debugger/debugger_shell.cc b/chrome/browser/debugger/debugger_shell.cc
index b9b9aaa..eae5687 100644
--- a/chrome/browser/debugger/debugger_shell.cc
+++ b/chrome/browser/debugger/debugger_shell.cc
@@ -238,6 +238,11 @@ void DebuggerShell::DebugMessage(const std::wstring& msg) {
}
}
+void DebuggerShell::OnDebugAttach() {
+ v8::HandleScope scope;
+ SubshellFunction("on_attach", 0, NULL);
+}
+
void DebuggerShell::OnDebugDisconnect() {
v8::HandleScope scope;
SubshellFunction("on_disconnect", 0, NULL);
diff --git a/chrome/browser/debugger/debugger_shell.h b/chrome/browser/debugger/debugger_shell.h
index 8614746..31a51af 100644
--- a/chrome/browser/debugger/debugger_shell.h
+++ b/chrome/browser/debugger/debugger_shell.h
@@ -59,6 +59,9 @@ class DebuggerShell : public base::RefCountedThreadSafe<DebuggerShell> {
void DebugMessage(const std::wstring& msg);
// The renderer we're attached to is gone.
+ void OnDebugAttach();
+
+ // The renderer we're attached to is gone.
void OnDebugDisconnect();
// SocketInputOutput callback methods
diff --git a/chrome/browser/debugger/debugger_wrapper.cc b/chrome/browser/debugger/debugger_wrapper.cc
index 847fab7..9b29903 100644
--- a/chrome/browser/debugger/debugger_wrapper.cc
+++ b/chrome/browser/debugger/debugger_wrapper.cc
@@ -32,6 +32,11 @@ void DebuggerWrapper::DebugMessage(const std::wstring& msg) {
debugger_->DebugMessage(msg);
}
+void DebuggerWrapper::OnDebugAttach() {
+ if (debugger_.get())
+ debugger_->OnDebugAttach();
+}
+
void DebuggerWrapper::OnDebugDisconnect() {
if (debugger_.get())
debugger_->OnDebugDisconnect();
diff --git a/chrome/browser/debugger/debugger_wrapper.h b/chrome/browser/debugger/debugger_wrapper.h
index ae4521a..2befe70 100644
--- a/chrome/browser/debugger/debugger_wrapper.h
+++ b/chrome/browser/debugger/debugger_wrapper.h
@@ -36,6 +36,7 @@ class DebuggerWrapper : public base::RefCountedThreadSafe<DebuggerWrapper> {
void DebugMessage(const std::wstring& msg);
+ void OnDebugAttach();
void OnDebugDisconnect();
private:
diff --git a/chrome/browser/debugger/resources/debugger_shell.js b/chrome/browser/debugger/resources/debugger_shell.js
index ab89c0d..6c798b4 100644
--- a/chrome/browser/debugger/resources/debugger_shell.js
+++ b/chrome/browser/debugger/resources/debugger_shell.js
@@ -28,10 +28,10 @@ function DebugCommand(str) {
str = argv.join(' ');
if (DebugCommand.aliases[this.user_command])
this.user_command = DebugCommand.aliases[this.user_command];
- if (this.parseArgs_(str) == 1)
- this.type = "request";
- if (this.command == undefined)
- this.command = this.user_command;
+ if (this.parseArgs_(str) == 1)
+ this.type = "request";
+ if (this.command == undefined)
+ this.command = this.user_command;
};
// Mapping of some control characters to avoid the \uXXXX syntax for most
@@ -211,16 +211,6 @@ DebugCommand.aliases = {
};
/**
- * Parses arguments to simple commands which have no arguments.
- * @see DebugCommand.commands
- * @param {string} str The arguments to be parsed.
- * @return -1 for usage error, 1 for success
- */
-DebugCommand.parseSimpleCommand_ = function(str) {
- return str.length ? -1 : 1;
-};
-
-/**
* Parses arguments to "args" and "locals" command, and initializes
* the underlying DebugCommand (which is a frame request).
* @see DebugCommand.commands
@@ -361,8 +351,8 @@ DebugCommand.prototype.parseBreak_ = function(str) {
}
if (str.length == 0) {
- this.type = "shell";
- return 0;
+ this.command = "break";
+ return 1;
} else {
var parts = str.split(/\s+/);
var condition = null;
@@ -500,6 +490,22 @@ DebugCommand.responseClear_ = function(msg) {
shell_.clearedBreakpoint(parseInt(msg.command.arguments.breakpoint));
}
+
+/**
+ * Parses arguments to "continue" command. See DebugCommand.commands below
+ * for syntax details.
+ * @see DebugCommand.commands
+ * @param {string} str The arguments to be parsed.
+ * @return -1 for usage error, 1 for success
+ */
+DebugCommand.prototype.parseContinueCommand_ = function(str) {
+ this.command = "continue";
+ if (str.length > 0) {
+ return -1;
+ }
+ return 1;
+}
+
/**
* Parses arguments to "frame" command. See DebugCommand.commands below
* for syntax details.
@@ -742,8 +748,13 @@ DebugCommand.prototype.parseArgs_ = function(str) {
} else {
var ret = parse.call(this, str);
if (ret > 0) {
+ // Command gererated a debugger request.
this.type = "request";
+ } else if (ret == 0) {
+ // Command handeled internally.
+ this.type = "handled";
} else if (ret < 0) {
+ // Command error.
this.type = "handled";
DebugCommand.help(this.user_command);
}
@@ -809,7 +820,7 @@ DebugCommand.commands = {
'response': DebugCommand.responseClear_,
'usage': 'clear <breakpoint #>',
'while_running': true },
- 'continue': { 'parse': DebugCommand.parseSimpleCommand_,
+ 'continue': { 'parse': DebugCommand.prototype.parseContinueCommand_,
'usage': 'continue' },
'frame': { 'parse': DebugCommand.prototype.parseFrame_,
'response': DebugCommand.responseFrame_,
@@ -863,9 +874,15 @@ function DebugShell(tab) {
this.running = true;
this.current_command = undefined;
this.pending_commands = [];
+ // The auto continue flag is used to indicate whether the JavaScript execution
+ // should automatically continue after a break event and the processing of
+ // pending commands. This is used to make it possible for the user to issue
+ // commands, e.g. setting break points, without making an explicit break. In
+ // this case the debugger will silently issue a forced break issue the command
+ // and silently continue afterwards.
+ this.auto_continue = false;
this.debug = false;
this.last_msg = undefined;
- this.last_command = undefined;
this.current_line = -1;
this.current_pos = -1;
this.current_frame = 0;
@@ -896,32 +913,50 @@ DebugShell.prototype.set_running = function(running) {
* @param cmd {DebugCommand} - command to execute
*/
DebugShell.prototype.process_command = function(cmd) {
- if (this.current_command) {
- this.pending_commands.push(cmd);
- dprint("pending command: " + DebugCommand.toJSON(cmd));
- } else if (cmd.type == "shell") {
- if (cmd.user_command == "break") {
- if (this.running) {
- this.tab.debugBreak();
- this.set_ready(false);
- } else {
- print(">>already paused");
- }
+ dprint("Running: " + (this.running ? "yes" : "no"));
+
+ // The "break" commands needs to be handled seperatly
+ if (cmd.command == "break") {
+ if (this.running) {
+ // Schedule a break.
+ print("Stopping JavaScript execution...");
+ this.tab.debugBreak(false);
+ } else {
+ print("JavaScript execution already stopped.");
}
- this.last_command = cmd;
- } else if (cmd.type == "request") {
- // If the page is running, then the debugger isn't listening to certain
- // requests.
+ return;
+ }
+
+ // If page is running an break needs to be issued.
+ if (this.running) {
+ // Some requests are not valid when the page is running.
var cmd_info = DebugCommand.commands[cmd.user_command];
- if (this.running && !cmd_info['while_running']) {
+ if (!cmd_info['while_running']) {
print(cmd.user_command + " can only be run while paused");
- } else {
- this.current_command = cmd;
- cmd.sendToDebugger(this.tab);
- this.set_ready(false);
+ return;
}
+
+ // Add the command as pending before scheduling a break.
+ this.pending_commands.push(cmd);
+ dprint("pending command: " + cmd.toJSONProtocol());
+
+ // Schedule a forced break and enable auto continue.
+ this.tab.debugBreak(true);
+ this.auto_continue = true;
+ this.set_ready(false);
+ return;
+ }
+
+ // If waiting for a response add command as pending otherwise send the
+ // command.
+ if (this.current_command) {
+ this.pending_commands.push(cmd);
+ dprint("pending command: " + cmd.toJSONProtocol());
+ } else {
+ this.current_command = cmd;
+ cmd.sendToDebugger(this.tab);
+ this.set_ready(false);
}
- this.last_command = cmd;
};
/**
@@ -931,7 +966,6 @@ DebugShell.prototype.process_command = function(cmd) {
DebugShell.prototype.event_break = function(msg) {
this.current_frame = 0;
this.set_running(false);
- this.set_ready(true);
if (msg.body) {
var body = msg.body;
this.current_script = body.script;
@@ -941,6 +975,8 @@ DebugShell.prototype.event_break = function(msg) {
var source = loc[1];
this.current_line = loc[2];
if (msg.body.breakpoints) {
+ // Always disable auto continue if a real break point is hit.
+ this.auto_continue = false;
var breakpoints = msg.body.breakpoints;
print("paused at breakpoint " + breakpoints.join(",") + ": " +
location);
@@ -954,14 +990,19 @@ DebugShell.prototype.event_break = function(msg) {
if (location != this.last_break_location) {
// We only print the location (function + script) when it changes,
// so as we step, you only see the source line when you transition
- // to a new script and/or function.
- print(location);
+ // to a new script and/or function. Also if auto continue is enables
+ // don't print the break location.
+ if (!this.auto_continue)
+ print(location);
}
}
- if (source)
+ // Print th current source line unless auto continue is enabled.
+ if (source && !this.auto_continue)
print(source);
this.last_break_location = location;
}
+ if (!this.auto_continue)
+ this.set_ready(true);
};
/**
@@ -1037,7 +1078,8 @@ DebugShell.prototype.command = function(str) {
if (str.length) {
var cmd = new DebugCommand(str);
cmd.from_user = true;
- this.process_command(cmd);
+ if (cmd.type == "request")
+ this.process_command(cmd);
}
} else {
print(">>not connected to a tab");
@@ -1064,15 +1106,6 @@ DebugShell.prototype.response = function(str) {
this.event_break(msg);
} else if (ev == "exception") {
this.event_exception(msg);
- } else if (ev == "attach") {
- var title = this.tab.title;
- if (!title)
- title = "Untitled";
- print('attached to ' + title);
- // on attach, we update our current script list
- var cmd = new DebugCommand("scripts");
- cmd.from_user = false;
- this.process_command(cmd);
}
} else if (msg.type == "response") {
if (msg.request_seq != undefined) {
@@ -1098,9 +1131,15 @@ DebugShell.prototype.response = function(str) {
}
}
this.set_ready(true);
- if (this.pending_commands.length) {
- this.process_command(this.pending_commands.shift());
- }
+ }
+
+ // Process next pending command if any.
+ if (this.pending_commands.length) {
+ this.process_command(this.pending_commands.shift());
+ } else if (this.auto_continue) {
+ // If no more pending commands and auto continue is active issue a continue command.
+ this.auto_continue = false;
+ this.process_command(new DebugCommand("continue"));
}
};
@@ -1178,6 +1217,22 @@ DebugShell.prototype.exit = function() {
/**
* Called by the Chrome Shell when the tab that the shell is debugging
+ * have attached.
+ */
+DebugShell.prototype.on_attach = function() {
+ var title = this.tab.title;
+ if (!title)
+ title = "Untitled";
+ print('attached to ' + title);
+ // on attach, we update our current script list
+ var cmd = new DebugCommand("scripts");
+ cmd.from_user = false;
+ this.process_command(cmd);
+};
+
+
+/**
+ * Called by the Chrome Shell when the tab that the shell is debugging
* went away.
*/
DebugShell.prototype.on_disconnect = function() {
diff --git a/chrome/browser/render_view_host.cc b/chrome/browser/render_view_host.cc
index e2edfde..f4fc34b 100644
--- a/chrome/browser/render_view_host.cc
+++ b/chrome/browser/render_view_host.cc
@@ -407,8 +407,8 @@ void RenderViewHost::AddMessageToConsole(
Send(new ViewMsg_AddMessageToConsole(routing_id_, frame_xpath, msg, level));
}
-void RenderViewHost::SendToDebugger(const std::wstring& cmd) {
- Send(new ViewMsg_SendToDebugger(routing_id_, cmd));
+void RenderViewHost::DebugCommand(const std::wstring& cmd) {
+ Send(new ViewMsg_DebugCommand(routing_id_, cmd));
}
void RenderViewHost::DebugAttach() {
@@ -418,14 +418,14 @@ void RenderViewHost::DebugAttach() {
void RenderViewHost::DebugDetach() {
if (debugger_attached_) {
- SendToDebugger(L"quit");
+ Send(new ViewMsg_DebugDetach(routing_id_));
debugger_attached_ = false;
}
}
-void RenderViewHost::DebugBreak() {
+void RenderViewHost::DebugBreak(bool force) {
if (debugger_attached_)
- SendToDebugger(L"break");
+ Send(new ViewMsg_DebugBreak(routing_id_, force));
}
void RenderViewHost::Undo() {
@@ -1100,7 +1100,7 @@ void RenderViewHost::OnDebuggerOutput(const std::wstring& output) {
void RenderViewHost::DidDebugAttach() {
if (!debugger_attached_) {
debugger_attached_ = true;
- SendToDebugger(L"attach");
+ g_browser_process->debugger_wrapper()->OnDebugAttach();
}
}
diff --git a/chrome/browser/render_view_host.h b/chrome/browser/render_view_host.h
index 865ffd6..325ab81 100644
--- a/chrome/browser/render_view_host.h
+++ b/chrome/browser/render_view_host.h
@@ -236,7 +236,7 @@ class RenderViewHost : public RenderWidgetHost {
ConsoleMessageLevel level);
// Send command to the debugger
- void SendToDebugger(const std::wstring& cmd);
+ void DebugCommand(const std::wstring& cmd);
// Attach to the V8 instance for debugging
void DebugAttach();
@@ -244,9 +244,10 @@ class RenderViewHost : public RenderWidgetHost {
// Detach from the V8 instance for debugging
void DebugDetach();
- // Cause the V8 debugger to trigger a breakpoint
- // (even if no JS code is running)
- void DebugBreak();
+ // Cause the V8 debugger to trigger a debug break. If the force flag is set
+ // force a debug break even if no JS code is running (this actually causes a
+ // simple JS script to be executed).
+ void DebugBreak(bool force);
// Edit operations.
void Undo();
diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h
index 3b6a8f3..f6c595d 100644
--- a/chrome/common/render_messages_internal.h
+++ b/chrome/common/render_messages_internal.h
@@ -212,8 +212,15 @@ IPC_BEGIN_MESSAGES(View, 1)
// Initialize the V8 debugger in the renderer.
IPC_MESSAGE_ROUTED0(ViewMsg_DebugAttach)
+ // Shutdown the V8 debugger in the renderer.
+ IPC_MESSAGE_ROUTED0(ViewMsg_DebugDetach)
+
+ // Break V8 execution.
+ IPC_MESSAGE_ROUTED1(ViewMsg_DebugBreak,
+ bool /* force */)
+
// Send a command to the V8 debugger.
- IPC_MESSAGE_ROUTED1(ViewMsg_SendToDebugger,
+ IPC_MESSAGE_ROUTED1(ViewMsg_DebugCommand,
std::wstring /* cmd */)
// Change the text size in the renderer.
diff --git a/chrome/renderer/debug_message_handler.cc b/chrome/renderer/debug_message_handler.cc
index f153661..7faa430 100644
--- a/chrome/renderer/debug_message_handler.cc
+++ b/chrome/renderer/debug_message_handler.cc
@@ -30,42 +30,31 @@ void DebugMessageHandler::EvaluateScriptUrl(const std::wstring& url) {
// all methods below called from the IO thread
void DebugMessageHandler::DebuggerOutput(const std::wstring& out) {
- DCHECK(MessageLoop::current() != view_loop_);
- // When certain commands are sent to the debugger, but we're not paused,
- // it's possible that no JS is running, so these commands can't be processed.
- // In these cases, we force some trivial, no side-effect, JS to be executed
- // so that V8 can process the commands.
- if (((out == L"break set") || (out == L"request queued")) && view_loop_) {
- if (view_loop_) {
- view_loop_->PostTask(FROM_HERE, NewRunnableMethod(
- this, &DebugMessageHandler::EvaluateScriptUrl,
- std::wstring(L"javascript:void(0)")));
- }
- } else if (channel_) {
- channel_->Send(new ViewHostMsg_DebuggerOutput(view_routing_id_, out));
+ channel_->Send(new ViewHostMsg_DebuggerOutput(view_routing_id_, out));
+}
+
+void DebugMessageHandler::OnBreak(bool force) {
+ debugger_->Break(force);
+ if (force && view_loop_) {
+ view_loop_->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &DebugMessageHandler::EvaluateScriptUrl,
+ std::wstring(L"javascript:void(0)")));
}
}
void DebugMessageHandler::OnAttach() {
- DebuggerOutput(L"{'type':'event', 'event':'attach'}");
+ if (!debugger_) {
+ debugger_ = new Debugger(this);
+ }
debugger_->Attach();
}
-void DebugMessageHandler::OnSendToDebugger(const std::wstring& cmd) {
+void DebugMessageHandler::OnCommand(const std::wstring& cmd) {
if (!debugger_) {
- debugger_ = new Debugger(this);
- if (cmd == L"" || cmd == L"attach") {
- OnAttach();
- } else {
- NOTREACHED();
- std::wstring msg =
- StringPrintf(L"before attach, ignored command (%S)", cmd.c_str());
- DebuggerOutput(msg);
- }
- } else if (cmd == L"attach") {
- OnAttach();
- } else if (cmd == L"quit" || cmd == L"detach") {
- OnDetach();
+ NOTREACHED();
+ std::wstring msg =
+ StringPrintf(L"before attach, ignored command (%S)", cmd.c_str());
+ DebuggerOutput(msg);
} else {
debugger_->Command(cmd);
}
@@ -103,7 +92,14 @@ bool DebugMessageHandler::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(DebugMessageHandler, message)
- IPC_MESSAGE_HANDLER(ViewMsg_SendToDebugger, OnSendToDebugger);
+ IPC_MESSAGE_HANDLER_GENERIC(ViewMsg_DebugAttach,
+ OnAttach();
+ handled = false;)
+ IPC_MESSAGE_HANDLER(ViewMsg_DebugBreak, OnBreak)
+ IPC_MESSAGE_HANDLER(ViewMsg_DebugCommand, OnCommand)
+ IPC_MESSAGE_HANDLER_GENERIC(ViewMsg_DebugDetach,
+ OnDetach();
+ handled = false;)
// If the debugger is active, then it's possible that the renderer thread
// is suspended handling a breakpoint. In that case, the renderer will
// hang forever and never exit. To avoid this, we look for close messages
diff --git a/chrome/renderer/debug_message_handler.h b/chrome/renderer/debug_message_handler.h
index ac8a7f1..d7724d0 100644
--- a/chrome/renderer/debug_message_handler.h
+++ b/chrome/renderer/debug_message_handler.h
@@ -27,8 +27,11 @@ class DebugMessageHandler : public IPC::ChannelProxy::MessageFilter,
// Debugger::Delegate callback method to handle debugger output.
void DebuggerOutput(const std::wstring& out);
+ // Schedule a debugger break.
+ void OnBreak(bool force);
+
// Sends a command to the debugger.
- void OnSendToDebugger(const std::wstring& cmd);
+ void OnCommand(const std::wstring& cmd);
// Sends an attach event to the debugger front-end.
void OnAttach();
diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc
index 8d91e58..450b1623 100644
--- a/chrome/renderer/render_view.cc
+++ b/chrome/renderer/render_view.cc
@@ -297,6 +297,7 @@ void RenderView::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(ViewMsg_ScriptEvalRequest, OnScriptEvalRequest)
IPC_MESSAGE_HANDLER(ViewMsg_AddMessageToConsole, OnAddMessageToConsole)
IPC_MESSAGE_HANDLER(ViewMsg_DebugAttach, OnDebugAttach)
+ IPC_MESSAGE_HANDLER(ViewMsg_DebugDetach, OnDebugDetach)
IPC_MESSAGE_HANDLER(ViewMsg_ReservePageIDRange, OnReservePageIDRange)
IPC_MESSAGE_HANDLER(ViewMsg_UploadFile, OnUploadFileRequest)
IPC_MESSAGE_HANDLER(ViewMsg_FormFill, OnFormFill)
@@ -2238,7 +2239,6 @@ void RenderView::OnAddMessageToConsole(const std::wstring& frame_xpath,
}
void RenderView::OnDebugAttach() {
- EvaluateScriptUrl(L"", L"javascript:void(0)");
Send(new ViewHostMsg_DidDebugAttach(routing_id_));
// Tell the plugin host to stop accepting messages in order to avoid
// hangs while the renderer is paused.
diff --git a/chrome/test/debugger/test_protocol.js b/chrome/test/debugger/test_protocol.js
index 91abbf1..d3dcae8 100644
--- a/chrome/test/debugger/test_protocol.js
+++ b/chrome/test/debugger/test_protocol.js
@@ -18,7 +18,6 @@
*/
function shell(sh) {
shell_ = sh;
- shell_.response("{type: 'event', event: 'attach'}");
};
@@ -202,9 +201,6 @@ DebuggerTest.commandList = [
];
DebuggerTest.expectedOutput = [
- "< event:attach",
- "attached to testing",
- "< response:scripts",
"< event:break",
"g(), foo.html",
"60: debugger;",