Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "bin/dbg_connection.h" | 5 #include "bin/dbg_connection.h" |
| 6 #include "bin/dartutils.h" | 6 #include "bin/dartutils.h" |
| 7 #include "bin/socket.h" | 7 #include "bin/socket.h" |
| 8 #include "bin/thread.h" | 8 #include "bin/thread.h" |
| 9 #include "bin/utils.h" | 9 #include "bin/utils.h" |
| 10 | 10 |
| 11 #include "platform/globals.h" | 11 #include "platform/globals.h" |
| 12 #include "platform/json.h" | 12 #include "platform/json.h" |
| 13 #include "platform/thread.h" | 13 #include "platform/thread.h" |
| 14 #include "platform/utils.h" | 14 #include "platform/utils.h" |
| 15 | 15 |
| 16 #include "include/dart_api.h" | 16 #include "include/dart_api.h" |
| 17 | 17 |
| 18 | 18 |
| 19 int DebuggerConnectionHandler::listener_fd_ = -1; | 19 int DebuggerConnectionHandler::listener_fd_ = -1; |
| 20 int DebuggerConnectionHandler::debugger_fd_ = -1; | 20 int DebuggerConnectionHandler::debugger_fd_ = -1; |
| 21 dart::Monitor DebuggerConnectionHandler::is_connected_; | 21 dart::Monitor DebuggerConnectionHandler::is_connected_; |
| 22 MessageBuffer* DebuggerConnectionHandler::msgbuf_ = NULL; | 22 MessageBuffer* DebuggerConnectionHandler::msgbuf_ = NULL; |
| 23 | 23 |
| 24 bool DebuggerConnectionHandler::handler_started_ = false; | 24 bool DebuggerConnectionHandler::handler_started_ = false; |
| 25 bool DebuggerConnectionHandler::request_resume_ = false; | |
| 25 | 26 |
| 26 | 27 |
| 27 // TODO(hausner): Need better error handling. | 28 // TODO(hausner): Need better error handling. |
| 28 #define ASSERT_NOT_ERROR(handle) \ | 29 #define ASSERT_NOT_ERROR(handle) \ |
| 29 ASSERT(!Dart_IsError(handle)) | 30 ASSERT(!Dart_IsError(handle)) |
| 30 | 31 |
| 32 typedef void (*CommandHandler)(const char* json_cmd); | |
| 33 | |
| 34 struct JSONDebuggerCommand { | |
| 35 const char* cmd_string; | |
| 36 CommandHandler handler_function; | |
| 37 }; | |
| 38 | |
| 31 | 39 |
| 32 class MessageBuffer { | 40 class MessageBuffer { |
| 33 public: | 41 public: |
| 34 explicit MessageBuffer(int fd); | 42 explicit MessageBuffer(int fd); |
| 35 ~MessageBuffer(); | 43 ~MessageBuffer(); |
| 36 void ReadData(); | 44 void ReadData(); |
| 37 bool IsValidMessage() const; | 45 bool IsValidMessage() const; |
| 38 void PopMessage(); | 46 void PopMessage(); |
| 39 int MessageId() const; | 47 int MessageId() const; |
| 48 const char* Params() const; | |
| 40 char* buf() const { return buf_; } | 49 char* buf() const { return buf_; } |
| 41 bool Alive() const { return connection_is_alive_; } | 50 bool Alive() const { return connection_is_alive_; } |
| 42 | 51 |
| 43 private: | 52 private: |
| 44 static const int kInitialBufferSize = 256; | 53 static const int kInitialBufferSize = 256; |
| 45 char* buf_; | 54 char* buf_; |
| 46 int buf_length_; | 55 int buf_length_; |
| 47 int fd_; | 56 int fd_; |
| 48 int data_length_; | 57 int data_length_; |
| 49 bool connection_is_alive_; | 58 bool connection_is_alive_; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 88 dart::JSONReader r(buf_); | 97 dart::JSONReader r(buf_); |
| 89 r.Seek("id"); | 98 r.Seek("id"); |
| 90 if (r.Type() == dart::JSONReader::kInteger) { | 99 if (r.Type() == dart::JSONReader::kInteger) { |
| 91 return atoi(r.ValueChars()); | 100 return atoi(r.ValueChars()); |
| 92 } else { | 101 } else { |
| 93 return -1; | 102 return -1; |
| 94 } | 103 } |
| 95 } | 104 } |
| 96 | 105 |
| 97 | 106 |
| 107 const char* MessageBuffer::Params() const { | |
| 108 dart::JSONReader r(buf_); | |
| 109 r.Seek("param"); | |
| 110 if (r.Type() == dart::JSONReader::kObject) { | |
| 111 return r.ValueChars(); | |
| 112 } else { | |
| 113 return NULL; | |
| 114 } | |
| 115 } | |
| 116 | |
| 117 | |
| 98 void MessageBuffer::ReadData() { | 118 void MessageBuffer::ReadData() { |
| 99 ASSERT(data_length_ >= 0); | 119 ASSERT(data_length_ >= 0); |
| 100 ASSERT(data_length_ < buf_length_); | 120 ASSERT(data_length_ < buf_length_); |
| 101 int max_read = buf_length_ - data_length_ - 1; | 121 int max_read = buf_length_ - data_length_ - 1; |
| 102 if (max_read == 0) { | 122 if (max_read == 0) { |
| 103 // TODO(hausner): | 123 // TODO(hausner): |
| 104 // Buffer is full. What should we do if there is no valid message | 124 // Buffer is full. What should we do if there is no valid message |
| 105 // in the buffer? This might be possible if the client sends a message | 125 // in the buffer? This might be possible if the client sends a message |
| 106 // that's larger than the buffer, of if the client sends malformed | 126 // that's larger than the buffer, of if the client sends malformed |
| 107 // messages that keep piling up. | 127 // messages that keep piling up. |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 138 } | 158 } |
| 139 } | 159 } |
| 140 | 160 |
| 141 | 161 |
| 142 static bool IsValidJSON(const char* msg) { | 162 static bool IsValidJSON(const char* msg) { |
| 143 dart::JSONReader r(msg); | 163 dart::JSONReader r(msg); |
| 144 return r.EndOfObject() != NULL; | 164 return r.EndOfObject() != NULL; |
| 145 } | 165 } |
| 146 | 166 |
| 147 | 167 |
| 148 void DebuggerConnectionHandler::HandleResumeCmd() { | 168 void DebuggerConnectionHandler::SendError(int msg_id, |
| 169 const char* format, ...) { | |
| 170 dart::TextBuffer msg(64); | |
| 171 msg.Printf("{\"id\": %d, \"error\": \"", msg_id); | |
| 172 va_list args; | |
| 173 va_start(args, format); | |
| 174 msg.Printf(format, args); | |
| 175 va_end(args); | |
| 176 msg.Printf("\"}"); | |
| 177 Socket::Write(debugger_fd_, msg.buf(), msg.length()); | |
| 178 // TODO(hausner): Error checking. Probably just shut down the debugger | |
| 179 // session if we there is an error while writing. | |
| 180 } | |
| 181 | |
| 182 | |
| 183 void DebuggerConnectionHandler::HandleResumeCmd(const char* json_msg) { | |
| 184 int msg_id = msgbuf_->MessageId(); | |
| 185 dart::JSONReader r(json_msg); | |
|
siva
2012/05/10 20:08:36
This r object appears to be unused.
hausner
2012/05/10 22:36:28
Done.
| |
| 186 dart::TextBuffer msg(64); | |
| 187 msg.Printf("{ \"id\": %d }", msg_id); | |
| 188 Socket::Write(debugger_fd_, msg.buf(), msg.length()); | |
| 189 // TODO(hausner): Error checking. Probably just shut down the debugger | |
| 190 // session if we there is an error while writing. | |
| 191 request_resume_ = true; | |
| 192 } | |
| 193 | |
| 194 | |
| 195 void DebuggerConnectionHandler::HandleStepIntoCmd(const char* json_msg) { | |
| 196 Dart_Handle res = Dart_SetStepInto(); | |
| 197 ASSERT_NOT_ERROR(res); | |
| 198 HandleResumeCmd(json_msg); | |
| 199 } | |
| 200 | |
| 201 | |
| 202 void DebuggerConnectionHandler::HandleStepOutCmd(const char* json_msg) { | |
| 203 Dart_Handle res = Dart_SetStepOut(); | |
| 204 ASSERT_NOT_ERROR(res); | |
| 205 HandleResumeCmd(json_msg); | |
| 206 } | |
| 207 | |
| 208 | |
| 209 void DebuggerConnectionHandler::HandleStepOverCmd(const char* json_msg) { | |
| 210 Dart_Handle res = Dart_SetStepOver(); | |
| 211 ASSERT_NOT_ERROR(res); | |
| 212 HandleResumeCmd(json_msg); | |
| 213 } | |
| 214 | |
| 215 | |
| 216 void DebuggerConnectionHandler::HandleGetScriptURLsCmd(const char* json_msg) { | |
| 149 int msg_id = msgbuf_->MessageId(); | 217 int msg_id = msgbuf_->MessageId(); |
| 150 dart::TextBuffer msg(64); | 218 dart::TextBuffer msg(64); |
| 151 msg.Printf("{ \"id\": %d }", msg_id); | 219 const char* params = msgbuf_->Params(); |
| 220 ASSERT(params != NULL); | |
| 221 dart::JSONReader pr(params); | |
| 222 pr.Seek("library"); | |
| 223 ASSERT(pr.Type() == dart::JSONReader::kString); | |
| 224 char lib_url_chars[128]; | |
| 225 pr.GetValueChars(lib_url_chars, sizeof(lib_url_chars)); | |
| 226 Dart_Handle lib_url = Dart_NewString(lib_url_chars); | |
|
siva
2012/05/10 20:08:36
ASSERT(!Dart_IsError(lib_url));
hausner
2012/05/10 22:36:28
Done.
| |
| 227 Dart_Handle urls = Dart_GetScriptURLs(lib_url); | |
| 228 if (Dart_IsError(urls)) { | |
| 229 SendError(msg_id, "Error: '%s'.", Dart_GetError(urls)); | |
| 230 return; | |
| 231 } | |
| 232 ASSERT(Dart_IsList(urls)); | |
| 233 intptr_t num_urls = 0; | |
| 234 Dart_ListLength(urls, &num_urls); | |
| 235 msg.Printf("{ \"id\": %d, ", msg_id); | |
| 236 msg.Printf("\"result\": { \"urls\": ["); | |
| 237 for (int i = 0; i < num_urls; i++) { | |
| 238 Dart_Handle script_url = Dart_ListGetAt(urls, i); | |
| 239 ASSERT(Dart_IsString(script_url)); | |
| 240 char const* chars; | |
| 241 Dart_StringToCString(lib_url, &chars); | |
|
siva
2012/05/10 20:08:36
See comments below about allocation of chars.
hausner
2012/05/10 22:36:28
Done.
| |
| 242 msg.Printf("%s\"%s\"", (i == 0) ? "" : ", ", chars); | |
| 243 } | |
| 244 msg.Printf("] }}"); | |
| 245 Socket::Write(debugger_fd_, msg.buf(), msg.length()); | |
| 246 // TODO(hausner): Error checking. Probably just shut down the debugger | |
| 247 // session if we there is an error while writing. | |
| 248 } | |
| 249 | |
| 250 | |
| 251 void DebuggerConnectionHandler::HandleGetLibraryURLsCmd(const char* json_msg) { | |
| 252 int msg_id = msgbuf_->MessageId(); | |
| 253 dart::TextBuffer msg(64); | |
| 254 msg.Printf("{ \"id\": %d, \"result\": { \"urls\": [", msg_id); | |
|
siva
2012/05/10 20:08:36
Does msg.Printf handle buffer overruns?
hausner
2012/05/10 22:36:28
Yes, it dynamically reallocs buffer space.
| |
| 255 Dart_Handle urls = Dart_GetLibraryURLs(); | |
|
siva
2012/05/10 20:08:36
ASSERT(!Dart_IsError(urls));
hausner
2012/05/10 22:36:28
Done.
| |
| 256 intptr_t num_libs; | |
| 257 Dart_ListLength(urls, &num_libs); | |
| 258 for (int i = 0; i < num_libs; i++) { | |
| 259 Dart_Handle lib_url = Dart_ListGetAt(urls, i); | |
| 260 ASSERT(Dart_IsString(lib_url)); | |
| 261 char const* chars; | |
| 262 Dart_StringToCString(lib_url, &chars); | |
|
siva
2012/05/10 20:08:36
chars is allocated in the ApiScope, do you create
hausner
2012/05/10 22:36:28
Thanks for this tip. Added a scope around the call
| |
| 263 msg.Printf("%s\"%s\"", (i == 0) ? "" : ", ", chars); | |
| 264 } | |
| 265 msg.Printf("] }}"); | |
| 152 Socket::Write(debugger_fd_, msg.buf(), msg.length()); | 266 Socket::Write(debugger_fd_, msg.buf(), msg.length()); |
| 153 // TODO(hausner): Error checking. Probably just shut down the debugger | 267 // TODO(hausner): Error checking. Probably just shut down the debugger |
| 154 // session if we there is an error while writing. | 268 // session if we there is an error while writing. |
| 155 } | 269 } |
| 156 | 270 |
| 157 | 271 |
| 158 void DebuggerConnectionHandler::HandleMessages() { | 272 void DebuggerConnectionHandler::HandleMessages() { |
| 273 static JSONDebuggerCommand debugger_commands[] = { | |
| 274 { "resume", HandleResumeCmd }, | |
| 275 { "getLibraryURLs", HandleGetLibraryURLsCmd}, | |
| 276 { "getScriptURLs", HandleGetScriptURLsCmd }, | |
| 277 { "stepInto", HandleStepIntoCmd }, | |
| 278 { "stepOut", HandleStepOutCmd }, | |
| 279 { "stepOver", HandleStepOverCmd }, | |
| 280 { NULL, NULL } | |
| 281 }; | |
| 282 | |
| 159 for (;;) { | 283 for (;;) { |
| 160 while (!msgbuf_->IsValidMessage() && msgbuf_->Alive()) { | 284 while (!msgbuf_->IsValidMessage() && msgbuf_->Alive()) { |
| 161 msgbuf_->ReadData(); | 285 msgbuf_->ReadData(); |
| 162 } | 286 } |
| 163 if (!msgbuf_->Alive()) { | 287 if (!msgbuf_->Alive()) { |
| 164 return; | 288 return; |
| 165 } | 289 } |
| 166 dart::JSONReader r(msgbuf_->buf()); | 290 dart::JSONReader r(msgbuf_->buf()); |
| 167 bool found = r.Seek("command"); | 291 bool found = r.Seek("command"); |
| 168 if (r.Error()) { | 292 if (r.Error()) { |
| 169 FATAL("Illegal JSON message received"); | 293 FATAL("Illegal JSON message received"); |
| 170 } | 294 } |
| 171 if (!found) { | 295 if (!found) { |
| 172 printf("'command' not found in JSON message: '%s'\n", msgbuf_->buf()); | 296 printf("'command' not found in JSON message: '%s'\n", msgbuf_->buf()); |
| 173 msgbuf_->PopMessage(); | 297 msgbuf_->PopMessage(); |
| 174 } else if (r.IsStringLiteral("resume")) { | 298 } |
| 175 HandleResumeCmd(); | 299 int i = 0; |
| 176 msgbuf_->PopMessage(); | 300 bool is_handled = false; |
| 177 return; | 301 request_resume_ = false; |
| 178 } else { | 302 while (debugger_commands[i].cmd_string != NULL) { |
| 303 if (r.IsStringLiteral(debugger_commands[i].cmd_string)) { | |
| 304 is_handled = true; | |
| 305 (*debugger_commands[i].handler_function)(msgbuf_->buf()); | |
| 306 msgbuf_->PopMessage(); | |
| 307 if (request_resume_) { | |
| 308 return; | |
| 309 } | |
| 310 break; | |
| 311 } | |
| 312 i++; | |
| 313 } | |
| 314 if (!is_handled) { | |
|
siva
2012/05/10 20:08:36
It appears that the loop above could handle multip
hausner
2012/05/10 22:36:28
If a message is handled, the break statement in li
| |
| 179 printf("unrecognized command received: '%s'\n", msgbuf_->buf()); | 315 printf("unrecognized command received: '%s'\n", msgbuf_->buf()); |
| 180 msgbuf_->PopMessage(); | 316 msgbuf_->PopMessage(); |
| 181 } | 317 } |
| 182 } | 318 } |
| 183 } | 319 } |
| 184 | 320 |
| 185 | 321 |
| 186 void DebuggerConnectionHandler::SendBreakpointEvent(Dart_Breakpoint bpt, | 322 void DebuggerConnectionHandler::SendBreakpointEvent(Dart_Breakpoint bpt, |
| 187 Dart_StackTrace trace) { | 323 Dart_StackTrace trace) { |
| 188 dart::TextBuffer msg(128); | 324 dart::TextBuffer msg(128); |
| 189 intptr_t trace_len = 0; | 325 intptr_t trace_len = 0; |
| 190 Dart_Handle res = Dart_StackTraceLength(trace, &trace_len); | 326 Dart_Handle res = Dart_StackTraceLength(trace, &trace_len); |
| 191 ASSERT_NOT_ERROR(res); | 327 ASSERT_NOT_ERROR(res); |
| 192 msg.Printf("{ \"command\" : \"paused\", \"params\" : "); | 328 msg.Printf("{ \"event\": \"paused\", \"params\": "); |
| 193 msg.Printf("{ \"callFrames\" : [ "); | 329 msg.Printf("{ \"callFrames\" : [ "); |
| 194 for (int i = 0; i < trace_len; i++) { | 330 for (int i = 0; i < trace_len; i++) { |
| 195 Dart_ActivationFrame frame; | 331 Dart_ActivationFrame frame; |
| 196 res = Dart_GetActivationFrame(trace, i, &frame); | 332 res = Dart_GetActivationFrame(trace, i, &frame); |
| 197 ASSERT_NOT_ERROR(res); | 333 ASSERT_NOT_ERROR(res); |
| 198 Dart_Handle func_name; | 334 Dart_Handle func_name; |
| 199 Dart_Handle script_url; | 335 Dart_Handle script_url; |
| 200 intptr_t line_number = 0; | 336 intptr_t line_number = 0; |
| 201 res = Dart_ActivationFrameInfo( | 337 res = Dart_ActivationFrameInfo( |
| 202 frame, &func_name, &script_url, &line_number); | 338 frame, &func_name, &script_url, &line_number); |
| 203 ASSERT_NOT_ERROR(res); | 339 ASSERT_NOT_ERROR(res); |
| 204 ASSERT(Dart_IsString(func_name)); | 340 ASSERT(Dart_IsString(func_name)); |
| 205 const char* func_name_chars; | 341 const char* func_name_chars; |
| 206 Dart_StringToCString(func_name, &func_name_chars); | 342 Dart_StringToCString(func_name, &func_name_chars); |
| 207 msg.Printf("%s { \"functionName\" : \"%s\" , ", | 343 msg.Printf("%s { \"functionName\": \"%s\" , ", |
| 208 i > 0 ? "," : "", | 344 i > 0 ? "," : "", |
| 209 func_name_chars); | 345 func_name_chars); |
| 210 ASSERT(Dart_IsString(script_url)); | 346 ASSERT(Dart_IsString(script_url)); |
| 211 const char* script_url_chars; | 347 const char* script_url_chars; |
| 212 Dart_StringToCString(script_url, &script_url_chars); | 348 Dart_StringToCString(script_url, &script_url_chars); |
| 213 msg.Printf("\"location\": { \"url\": \"%s\", \"lineNumber\": %d }}", | 349 msg.Printf("\"location\": { \"url\": \"%s\", \"lineNumber\": %d }}", |
| 214 script_url_chars, line_number); | 350 script_url_chars, line_number); |
| 215 } | 351 } |
| 216 msg.Printf("]}}"); | 352 msg.Printf("]}}"); |
| 217 Socket::Write(debugger_fd_, msg.buf(), msg.length()); | 353 Socket::Write(debugger_fd_, msg.buf(), msg.length()); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 269 | 405 |
| 270 handler_started_ = true; | 406 handler_started_ = true; |
| 271 DebuggerConnectionImpl::StartHandler(port_number); | 407 DebuggerConnectionImpl::StartHandler(port_number); |
| 272 Dart_SetBreakpointHandler(BreakpointHandler); | 408 Dart_SetBreakpointHandler(BreakpointHandler); |
| 273 } | 409 } |
| 274 | 410 |
| 275 | 411 |
| 276 DebuggerConnectionHandler::~DebuggerConnectionHandler() { | 412 DebuggerConnectionHandler::~DebuggerConnectionHandler() { |
| 277 CloseDbgConnection(); | 413 CloseDbgConnection(); |
| 278 } | 414 } |
| OLD | NEW |