diff options
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/debugger/debugger_node.cc | 8 | ||||
-rw-r--r-- | chrome/browser/debugger/debugger_shell.cc | 5 | ||||
-rw-r--r-- | chrome/browser/debugger/debugger_shell.h | 3 | ||||
-rw-r--r-- | chrome/browser/debugger/debugger_wrapper.cc | 5 | ||||
-rw-r--r-- | chrome/browser/debugger/debugger_wrapper.h | 1 | ||||
-rw-r--r-- | chrome/browser/debugger/resources/debugger_shell.js | 167 | ||||
-rw-r--r-- | chrome/browser/render_view_host.cc | 12 | ||||
-rw-r--r-- | chrome/browser/render_view_host.h | 9 | ||||
-rw-r--r-- | chrome/common/render_messages_internal.h | 9 | ||||
-rw-r--r-- | chrome/renderer/debug_message_handler.cc | 54 | ||||
-rw-r--r-- | chrome/renderer/debug_message_handler.h | 5 | ||||
-rw-r--r-- | chrome/renderer/render_view.cc | 2 | ||||
-rw-r--r-- | chrome/test/debugger/test_protocol.js | 4 |
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;", |