Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6)

Side by Side Diff: runtime/bin/dbg_connection.cc

Issue 10990089: First step towards support for being able to interrupt a running Dart Isolate (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/bin/dbg_connection.h ('k') | runtime/bin/dbg_connection_linux.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/dbg_message.h"
6 #include "bin/dartutils.h" 7 #include "bin/dartutils.h"
7 #include "bin/socket.h" 8 #include "bin/socket.h"
8 #include "bin/thread.h" 9 #include "bin/thread.h"
9 #include "bin/utils.h" 10 #include "bin/utils.h"
10 11
11 #include "platform/globals.h" 12 #include "platform/globals.h"
12 #include "platform/json.h" 13 #include "platform/json.h"
13 #include "platform/thread.h" 14 #include "platform/thread.h"
14 #include "platform/utils.h" 15 #include "platform/utils.h"
15 16
16 #include "include/dart_api.h" 17 #include "include/dart_api.h"
17 18
18 19
19 int DebuggerConnectionHandler::listener_fd_ = -1; 20 int DebuggerConnectionHandler::listener_fd_ = -1;
20 int DebuggerConnectionHandler::debugger_fd_ = -1; 21 dart::Monitor DebuggerConnectionHandler::handler_lock_;
21 dart::Monitor DebuggerConnectionHandler::is_connected_;
22 MessageBuffer* DebuggerConnectionHandler::msgbuf_ = NULL;
23 22
24 bool DebuggerConnectionHandler::handler_started_ = false; 23 // TODO(asiva): Remove this once we have support for multiple debugger
25 bool DebuggerConnectionHandler::request_resume_ = false; 24 // connections. For now we just store the single debugger connection
26 25 // handler in a static variable.
27 dart::TextBuffer DebuggerConnectionHandler::queued_messages_(64); 26 static DebuggerConnectionHandler* singleton_handler = NULL;
28
29
30 // TODO(hausner): Need better error handling.
31 #define ASSERT_NOT_ERROR(handle) \
32 ASSERT(!Dart_IsError(handle))
33
34 #define RETURN_IF_ERROR(handle) \
35 if (Dart_IsError(handle)) { \
36 return Dart_GetError(handle); \
37 }
38
39
40 typedef void (*CommandHandler)(const char* json_cmd);
41
42 struct JSONDebuggerCommand {
43 const char* cmd_string;
44 CommandHandler handler_function;
45 };
46 27
47 28
48 class MessageBuffer { 29 class MessageBuffer {
49 public: 30 public:
50 explicit MessageBuffer(int fd); 31 explicit MessageBuffer(int fd);
51 ~MessageBuffer(); 32 ~MessageBuffer();
52 void ReadData(); 33 void ReadData();
53 bool IsValidMessage() const; 34 bool IsValidMessage() const;
54 void PopMessage(); 35 void PopMessage();
55 int MessageId() const; 36 int MessageId() const;
56 const char* Params() const;
57 intptr_t GetIntParam(const char* name) const;
58 intptr_t GetOptIntParam(const char* name, intptr_t default_val) const;
59 // GetStringParam mallocs the buffer that it returns. Caller must free.
60 char* GetStringParam(const char* name) const;
61 char* buf() const { return buf_; } 37 char* buf() const { return buf_; }
62 bool Alive() const { return connection_is_alive_; } 38 bool Alive() const { return connection_is_alive_; }
63 39
64 private: 40 private:
65 static const int kInitialBufferSize = 256; 41 static const int kInitialBufferSize = 256;
66 char* buf_; 42 char* buf_;
67 int buf_length_; 43 int buf_length_;
68 int fd_; 44 int fd_;
69 int data_length_; 45 int data_length_;
70 bool connection_is_alive_; 46 bool connection_is_alive_;
71 47
72 DISALLOW_COPY_AND_ASSIGN(MessageBuffer); 48 DISALLOW_COPY_AND_ASSIGN(MessageBuffer);
73 }; 49 };
74 50
75 51
76 MessageBuffer::MessageBuffer(int fd) 52 MessageBuffer::MessageBuffer(int fd)
77 : buf_(NULL), 53 : buf_(NULL),
78 buf_length_(0), 54 buf_length_(0),
79 fd_(fd), 55 fd_(fd),
80 data_length_(0), 56 data_length_(0),
81 connection_is_alive_(true) { 57 connection_is_alive_(true) {
82 buf_ = reinterpret_cast<char*>(malloc(kInitialBufferSize)); 58 buf_ = reinterpret_cast<char*>(malloc(kInitialBufferSize));
83 if (buf_ == NULL) { 59 if (buf_ == NULL) {
84 FATAL("Failed to allocate message buffer\n"); 60 FATAL("Failed to allocate message buffer\n");
85 } 61 }
86 buf_length_ = kInitialBufferSize; 62 buf_length_ = kInitialBufferSize;
87 buf_[0] = '\0'; 63 buf_[0] = '\0';
88 data_length_ = 0; 64 data_length_ = 0;
89 } 65 }
90 66
91 67
(...skipping 17 matching lines...) Expand all
109 dart::JSONReader r(buf_); 85 dart::JSONReader r(buf_);
110 r.Seek("id"); 86 r.Seek("id");
111 if (r.Type() == dart::JSONReader::kInteger) { 87 if (r.Type() == dart::JSONReader::kInteger) {
112 return atoi(r.ValueChars()); 88 return atoi(r.ValueChars());
113 } else { 89 } else {
114 return -1; 90 return -1;
115 } 91 }
116 } 92 }
117 93
118 94
119 const char* MessageBuffer::Params() const {
120 dart::JSONReader r(buf_);
121 r.Seek("params");
122 if (r.Type() == dart::JSONReader::kObject) {
123 return r.ValueChars();
124 } else {
125 return NULL;
126 }
127 }
128
129
130 intptr_t MessageBuffer::GetIntParam(const char* name) const {
131 const char* params = Params();
132 ASSERT(params != NULL);
133 dart::JSONReader r(params);
134 r.Seek(name);
135 ASSERT(r.Type() == dart::JSONReader::kInteger);
136 return strtol(r.ValueChars(), NULL, 10);
137 }
138
139
140 intptr_t MessageBuffer::GetOptIntParam(const char* name,
141 intptr_t default_val) const {
142 const char* params = Params();
143 ASSERT(params != NULL);
144 dart::JSONReader r(params);
145 r.Seek(name);
146 if (r.Type() == dart::JSONReader::kInteger) {
147 return strtol(r.ValueChars(), NULL, 10);
148 } else {
149 return default_val;
150 }
151 }
152
153
154 char* MessageBuffer::GetStringParam(const char* name) const {
155 const char* params = Params();
156 ASSERT(params != NULL);
157 dart::JSONReader pr(params);
158 pr.Seek(name);
159 if (pr.Type() != dart::JSONReader::kString) {
160 return NULL;
161 }
162 intptr_t buflen = pr.ValueLen() + 1;
163 char* param_chars = reinterpret_cast<char*>(malloc(buflen));
164 pr.GetValueChars(param_chars, buflen);
165 // TODO(hausner): Decode escape sequences.
166 return param_chars;
167 }
168
169 void MessageBuffer::ReadData() { 95 void MessageBuffer::ReadData() {
170 ASSERT(data_length_ >= 0); 96 ASSERT(data_length_ >= 0);
171 ASSERT(data_length_ < buf_length_); 97 ASSERT(data_length_ < buf_length_);
172 int max_read = buf_length_ - data_length_ - 1; 98 int max_read = buf_length_ - data_length_ - 1;
173 if (max_read == 0) { 99 if (max_read == 0) {
174 // TODO(hausner): 100 // TODO(hausner):
175 // Buffer is full. What should we do if there is no valid message 101 // Buffer is full. What should we do if there is no valid message
176 // in the buffer? This might be possible if the client sends a message 102 // in the buffer? This might be possible if the client sends a message
177 // that's larger than the buffer, of if the client sends malformed 103 // that's larger than the buffer, of if the client sends malformed
178 // messages that keep piling up. 104 // messages that keep piling up.
(...skipping 30 matching lines...) Expand all
209 } 135 }
210 } 136 }
211 137
212 138
213 static bool IsValidJSON(const char* msg) { 139 static bool IsValidJSON(const char* msg) {
214 dart::JSONReader r(msg); 140 dart::JSONReader r(msg);
215 return r.EndOfObject() != NULL; 141 return r.EndOfObject() != NULL;
216 } 142 }
217 143
218 144
219 void DebuggerConnectionHandler::SendMsg(dart::TextBuffer* msg) { 145 DebuggerConnectionHandler::DebuggerConnectionHandler(int debug_fd)
220 ASSERT(debugger_fd_ >= 0); 146 : debug_fd_(debug_fd), msgbuf_(NULL) {
221 ASSERT(IsValidJSON(msg->buf())); 147 msgbuf_ = new MessageBuffer(debug_fd_);
222 // Sending messages in short pieces can be used to stress test the
223 // debugger front-end's message handling code.
224 const bool send_in_pieces = false;
225 if (send_in_pieces) {
226 intptr_t remaining = msg->length();
227 intptr_t sent = 0;
228 const intptr_t max_piece_len = 122; // Pretty arbitrary, not a power of 2.
229 dart::Monitor sleep;
230 while (remaining > 0) {
231 intptr_t piece_len = remaining;
232 if (piece_len > max_piece_len) {
233 piece_len = max_piece_len;
234 }
235 intptr_t written =
236 Socket::Write(debugger_fd_, msg->buf() + sent, piece_len);
237 ASSERT(written == piece_len);
238 sent += written;
239 remaining -= written;
240 // Wait briefly so the OS does not coalesce message fragments.
241 {
242 MonitorLocker ml(&sleep);
243 ml.Wait(10);
244 }
245 }
246 return;
247 }
248 intptr_t bytes_written =
249 Socket::Write(debugger_fd_, msg->buf(), msg->length());
250 ASSERT(msg->length() == bytes_written);
251 // TODO(hausner): Error checking. Probably just shut down the debugger
252 // session if we there is an error while writing.
253 } 148 }
254 149
255 150
256 void DebuggerConnectionHandler::QueueMsg(dart::TextBuffer* msg) { 151 DebuggerConnectionHandler::~DebuggerConnectionHandler() {
257 queued_messages_.Printf("%s", msg->buf()); 152 CloseDbgConnection();
153 DebuggerConnectionHandler::RemoveDebuggerConnection(debug_fd_);
258 } 154 }
259 155
260 156
261 void DebuggerConnectionHandler::SendQueuedMsgs() { 157 int DebuggerConnectionHandler::MessageId() {
262 if (queued_messages_.length() > 0) { 158 ASSERT(msgbuf_ != NULL);
263 SendMsg(&queued_messages_); 159 return msgbuf_->MessageId();
264 queued_messages_.Clear();
265 }
266 } 160 }
267 161
268 162
269 void DebuggerConnectionHandler::SendError(int msg_id, 163 void DebuggerConnectionHandler::HandleUnknownMsg() {
270 const char* err_msg) { 164 int msg_id = msgbuf_->MessageId();
271 dart::TextBuffer msg(64); 165 ASSERT(msg_id >= 0);
272 msg.Printf("{\"id\": %d, \"error\": \"Error: %s\"}", msg_id, err_msg); 166 SendError(debug_fd_, msg_id, "unknown debugger command");
273 SendMsg(&msg);
274 } 167 }
275 168
276 169
277 static const char* GetStringChars(Dart_Handle str) { 170 typedef void (*CommandHandler)(DebuggerConnectionHandler* handler);
278 ASSERT(Dart_IsString(str));
279 const char* chars;
280 Dart_Handle res = Dart_StringToCString(str, &chars);
281 ASSERT(!Dart_IsError(res));
282 return chars;
283 }
284 171
285 172 struct JSONDebuggerCommand {
286 static int GetIntValue(Dart_Handle int_handle) { 173 const char* cmd_string;
287 int64_t int64_val = -1; 174 CommandHandler handler_function;
288 ASSERT(Dart_IsInteger(int_handle)); 175 };
289 Dart_Handle res = Dart_IntegerToInt64(int_handle, &int64_val);
290 ASSERT_NOT_ERROR(res);
291 // TODO(hausner): Range check.
292 return int64_val;
293 }
294
295
296 void DebuggerConnectionHandler::HandleResumeCmd(const char* json_msg) {
297 int msg_id = msgbuf_->MessageId();
298 dart::TextBuffer msg(64);
299 msg.Printf("{ \"id\": %d }", msg_id);
300 SendMsg(&msg);
301 request_resume_ = true;
302 }
303
304
305 void DebuggerConnectionHandler::HandleStepIntoCmd(const char* json_msg) {
306 Dart_Handle res = Dart_SetStepInto();
307 ASSERT_NOT_ERROR(res);
308 HandleResumeCmd(json_msg);
309 }
310
311
312 void DebuggerConnectionHandler::HandleStepOutCmd(const char* json_msg) {
313 Dart_Handle res = Dart_SetStepOut();
314 ASSERT_NOT_ERROR(res);
315 HandleResumeCmd(json_msg);
316 }
317
318
319 void DebuggerConnectionHandler::HandleStepOverCmd(const char* json_msg) {
320 Dart_Handle res = Dart_SetStepOver();
321 ASSERT_NOT_ERROR(res);
322 HandleResumeCmd(json_msg);
323 }
324
325
326 static void FormatEncodedString(dart::TextBuffer* buf, Dart_Handle str) {
327 intptr_t str_len = 0;
328 Dart_Handle res = Dart_StringLength(str, &str_len);
329 ASSERT_NOT_ERROR(res);
330 uint32_t* codepoints =
331 reinterpret_cast<uint32_t*>(malloc(str_len * sizeof(uint32_t)));
332 ASSERT(codepoints != NULL);
333 intptr_t actual_len = str_len;
334 res = Dart_StringGet32(str, codepoints, &actual_len);
335 ASSERT_NOT_ERROR(res);
336 ASSERT(str_len == actual_len);
337 buf->AddChar('\"');
338 for (int i = 0; i < str_len; i++) {
339 buf->AddEscapedChar(codepoints[i]);
340 }
341 buf->AddChar('\"');
342 free(codepoints);
343 }
344
345
346 static void FormatErrorMsg(dart::TextBuffer* buf, Dart_Handle err) {
347 // TODO(hausner): Turn message into Dart string and
348 // properly encode the message.
349 ASSERT(Dart_IsError(err));
350 const char* msg = Dart_GetError(err);
351 buf->Printf("\"%s\"", msg);
352 }
353
354
355 void DebuggerConnectionHandler::HandleGetScriptURLsCmd(const char* json_msg) {
356 int msg_id = msgbuf_->MessageId();
357 dart::TextBuffer msg(64);
358 intptr_t lib_id = msgbuf_->GetIntParam("libraryId");
359 Dart_Handle lib_url = Dart_GetLibraryURL(lib_id);
360 ASSERT_NOT_ERROR(lib_url);
361 Dart_Handle urls = Dart_GetScriptURLs(lib_url);
362 if (Dart_IsError(urls)) {
363 SendError(msg_id, Dart_GetError(urls));
364 return;
365 }
366 ASSERT(Dart_IsList(urls));
367 intptr_t num_urls = 0;
368 Dart_ListLength(urls, &num_urls);
369 msg.Printf("{ \"id\": %d, ", msg_id);
370 msg.Printf("\"result\": { \"urls\": [");
371 for (int i = 0; i < num_urls; i++) {
372 Dart_Handle script_url = Dart_ListGetAt(urls, i);
373 if (i > 0) {
374 msg.Printf(",");
375 }
376 FormatEncodedString(&msg, script_url);
377 }
378 msg.Printf("]}}");
379 SendMsg(&msg);
380 }
381
382
383 void DebuggerConnectionHandler::HandleGetSourceCmd(const char* json_msg) {
384 int msg_id = msgbuf_->MessageId();
385 dart::TextBuffer msg(64);
386 intptr_t lib_id = msgbuf_->GetIntParam("libraryId");
387 char* url_chars = msgbuf_->GetStringParam("url");
388 ASSERT(url_chars != NULL);
389 Dart_Handle url = Dart_NewString(url_chars);
390 ASSERT_NOT_ERROR(url);
391 free(url_chars);
392 url_chars = NULL;
393 Dart_Handle source = Dart_ScriptGetSource(lib_id, url);
394 if (Dart_IsError(source)) {
395 SendError(msg_id, Dart_GetError(source));
396 return;
397 }
398 msg.Printf("{ \"id\": %d, ", msg_id);
399 msg.Printf("\"result\": { \"text\": ");
400 FormatEncodedString(&msg, source);
401 msg.Printf("}}");
402 SendMsg(&msg);
403 }
404
405
406 void DebuggerConnectionHandler::HandleGetLibrariesCmd(const char* json_msg) {
407 int msg_id = msgbuf_->MessageId();
408 dart::TextBuffer msg(64);
409 msg.Printf("{ \"id\": %d, \"result\": { \"libraries\": [", msg_id);
410 Dart_Handle lib_ids = Dart_GetLibraryIds();
411 ASSERT_NOT_ERROR(lib_ids);
412 intptr_t num_libs;
413 Dart_Handle res = Dart_ListLength(lib_ids, &num_libs);
414 ASSERT_NOT_ERROR(res);
415 for (int i = 0; i < num_libs; i++) {
416 Dart_Handle lib_id_handle = Dart_ListGetAt(lib_ids, i);
417 ASSERT(Dart_IsInteger(lib_id_handle));
418 int lib_id = GetIntValue(lib_id_handle);
419 Dart_Handle lib_url = Dart_GetLibraryURL(lib_id);
420 ASSERT_NOT_ERROR(lib_url);
421 ASSERT(Dart_IsString(lib_url));
422 msg.Printf("%s{\"id\":%d,\"url\":", (i == 0) ? "" : ", ", lib_id);
423 FormatEncodedString(&msg, lib_url);
424 msg.Printf("}");
425 }
426 msg.Printf("]}}");
427 SendMsg(&msg);
428 }
429
430
431 static void FormatTextualValue(dart::TextBuffer* buf, Dart_Handle object) {
432 Dart_Handle text;
433 if (Dart_IsNull(object)) {
434 text = Dart_Null();
435 } else {
436 Dart_ExceptionPauseInfo savedState = Dart_GetExceptionPauseInfo();
437
438 // TODO(hausner): Check whether recursive/reentrant pauses on exceptions
439 // should be prevented in Debugger::SignalExceptionThrown() instead.
440 if (savedState != kNoPauseOnExceptions) {
441 Dart_Handle res = Dart_SetExceptionPauseInfo(kNoPauseOnExceptions);
442 ASSERT_NOT_ERROR(res);
443 }
444
445 text = Dart_ToString(object);
446
447 if (savedState != kNoPauseOnExceptions) {
448 Dart_Handle res = Dart_SetExceptionPauseInfo(savedState);
449 ASSERT_NOT_ERROR(res);
450 }
451 }
452 buf->Printf("\"text\":");
453 if (Dart_IsNull(text)) {
454 buf->Printf("null");
455 } else if (Dart_IsError(text)) {
456 FormatErrorMsg(buf, text);
457 } else {
458 FormatEncodedString(buf, text);
459 }
460 }
461
462
463 static void FormatValue(dart::TextBuffer* buf, Dart_Handle object) {
464 if (Dart_IsInteger(object)) {
465 buf->Printf("\"kind\":\"integer\",");
466 } else if (Dart_IsString(object)) {
467 buf->Printf("\"kind\":\"string\",");
468 } else if (Dart_IsBoolean(object)) {
469 buf->Printf("\"kind\":\"boolean\",");
470 } else if (Dart_IsList(object)) {
471 intptr_t len = 0;
472 Dart_Handle res = Dart_ListLength(object, &len);
473 ASSERT_NOT_ERROR(res);
474 buf->Printf("\"kind\":\"list\",\"length\":%"Pd",", len);
475 } else {
476 buf->Printf("\"kind\":\"object\",");
477 }
478 FormatTextualValue(buf, object);
479 }
480
481
482 static void FormatValueObj(dart::TextBuffer* buf, Dart_Handle object) {
483 buf->Printf("{");
484 FormatValue(buf, object);
485 buf->Printf("}");
486 }
487
488
489 static void FormatRemoteObj(dart::TextBuffer* buf, Dart_Handle object) {
490 intptr_t obj_id = Dart_CacheObject(object);
491 ASSERT(obj_id >= 0);
492 buf->Printf("{\"objectId\":%"Pd",", obj_id);
493 FormatValue(buf, object);
494 buf->Printf("}");
495 }
496
497
498 static void FormatNamedValue(dart::TextBuffer* buf,
499 Dart_Handle object_name,
500 Dart_Handle object) {
501 ASSERT(Dart_IsString(object_name));
502 buf->Printf("{\"name\":\"%s\",", GetStringChars(object_name));
503 buf->Printf("\"value\":");
504 FormatRemoteObj(buf, object);
505 buf->Printf("}");
506 }
507
508
509 static void FormatNamedValueList(dart::TextBuffer* buf,
510 Dart_Handle obj_list) {
511 ASSERT(Dart_IsList(obj_list));
512 intptr_t list_length = 0;
513 Dart_Handle res = Dart_ListLength(obj_list, &list_length);
514 ASSERT_NOT_ERROR(res);
515 ASSERT(list_length % 2 == 0);
516 buf->Printf("[");
517 for (int i = 0; i + 1 < list_length; i += 2) {
518 Dart_Handle name_handle = Dart_ListGetAt(obj_list, i);
519 ASSERT_NOT_ERROR(name_handle);
520 Dart_Handle value_handle = Dart_ListGetAt(obj_list, i + 1);
521 ASSERT_NOT_ERROR(value_handle);
522 if (i > 0) {
523 buf->Printf(",");
524 }
525 FormatNamedValue(buf, name_handle, value_handle);
526 }
527 buf->Printf("]");
528 }
529
530
531 static const char* FormatClassProps(dart::TextBuffer* buf,
532 intptr_t cls_id) {
533 Dart_Handle name, static_fields;
534 intptr_t super_id = -1;
535 intptr_t library_id = -1;
536 Dart_Handle res =
537 Dart_GetClassInfo(cls_id, &name, &library_id, &super_id, &static_fields);
538 RETURN_IF_ERROR(res);
539 RETURN_IF_ERROR(name);
540 buf->Printf("{\"name\":\"%s\",", GetStringChars(name));
541 if (super_id > 0) {
542 buf->Printf("\"superclassId\":%"Pd",", super_id);
543 }
544 buf->Printf("\"libraryId\":%"Pd",", library_id);
545 RETURN_IF_ERROR(static_fields);
546 buf->Printf("\"fields\":");
547 FormatNamedValueList(buf, static_fields);
548 buf->Printf("}");
549 return NULL;
550 }
551
552
553 static const char* FormatLibraryProps(dart::TextBuffer* buf,
554 intptr_t lib_id) {
555 Dart_Handle url = Dart_GetLibraryURL(lib_id);
556 RETURN_IF_ERROR(url);
557 buf->Printf("{\"url\":");
558 FormatEncodedString(buf, url);
559
560 // Whether debugging is enabled.
561 bool is_debuggable = false;
562 Dart_Handle res = Dart_GetLibraryDebuggable(lib_id, &is_debuggable);
563 RETURN_IF_ERROR(res);
564 buf->Printf(",\"debuggingEnabled\":%s",
565 is_debuggable ? "\"true\"" : "\"false\"");
566
567 // Imports and prefixes.
568 Dart_Handle import_list = Dart_GetLibraryImports(lib_id);
569 RETURN_IF_ERROR(import_list);
570 ASSERT(Dart_IsList(import_list));
571 intptr_t list_length = 0;
572 res = Dart_ListLength(import_list, &list_length);
573 RETURN_IF_ERROR(res);
574 buf->Printf(",\"imports\":[");
575 for (int i = 0; i + 1 < list_length; i += 2) {
576 Dart_Handle lib_id = Dart_ListGetAt(import_list, i + 1);
577 ASSERT_NOT_ERROR(lib_id);
578 buf->Printf("%s{\"libraryId\":%d,",
579 (i > 0) ? ",": "",
580 GetIntValue(lib_id));
581
582 Dart_Handle name = Dart_ListGetAt(import_list, i);
583 ASSERT_NOT_ERROR(name);
584 buf->Printf("\"prefix\":\"%s\"}",
585 Dart_IsNull(name) ? "" : GetStringChars(name));
586 }
587 buf->Printf("],");
588
589 // Global variables in the library.
590 Dart_Handle global_vars = Dart_GetLibraryFields(lib_id);
591 RETURN_IF_ERROR(global_vars);
592 buf->Printf("\"globals\":");
593 FormatNamedValueList(buf, global_vars);
594 buf->Printf("}");
595 return NULL;
596 }
597
598
599 static const char* FormatObjProps(dart::TextBuffer* buf,
600 Dart_Handle object) {
601 intptr_t class_id;
602 if (Dart_IsNull(object)) {
603 buf->Printf("{\"classId\":-1,\"fields\":[]}");
604 return NULL;
605 }
606 Dart_Handle res = Dart_GetObjClassId(object, &class_id);
607 RETURN_IF_ERROR(res);
608 buf->Printf("{\"classId\": %"Pd",", class_id);
609 buf->Printf("\"kind\":\"object\",\"fields\":");
610 Dart_Handle fields = Dart_GetInstanceFields(object);
611 RETURN_IF_ERROR(fields);
612 FormatNamedValueList(buf, fields);
613 buf->Printf("}");
614 return NULL;
615 }
616
617
618 static const char* FormatListSlice(dart::TextBuffer* buf,
619 Dart_Handle list,
620 intptr_t list_length,
621 intptr_t index,
622 intptr_t slice_length) {
623 intptr_t end_index = index + slice_length;
624 ASSERT(end_index <= list_length);
625 buf->Printf("{\"index\":%"Pd",", index);
626 buf->Printf("\"length\":%"Pd",", slice_length);
627 buf->Printf("\"elements\":[");
628 for (intptr_t i = index; i < end_index; i++) {
629 Dart_Handle value = Dart_ListGetAt(list, i);
630 if (i > index) {
631 buf->Printf(",");
632 }
633 FormatValueObj(buf, value);
634 }
635 buf->Printf("]}");
636 return NULL;
637 }
638
639
640 static void FormatCallFrames(dart::TextBuffer* msg, Dart_StackTrace trace) {
641 intptr_t trace_len = 0;
642 Dart_Handle res = Dart_StackTraceLength(trace, &trace_len);
643 ASSERT_NOT_ERROR(res);
644 msg->Printf("\"callFrames\" : [ ");
645 for (int i = 0; i < trace_len; i++) {
646 Dart_ActivationFrame frame;
647 res = Dart_GetActivationFrame(trace, i, &frame);
648 ASSERT_NOT_ERROR(res);
649 Dart_Handle func_name;
650 Dart_Handle script_url;
651 intptr_t line_number = 0;
652 intptr_t library_id = 0;
653 res = Dart_ActivationFrameInfo(
654 frame, &func_name, &script_url, &line_number, &library_id);
655 ASSERT_NOT_ERROR(res);
656 ASSERT(Dart_IsString(func_name));
657 msg->Printf("%s{\"functionName\":", (i > 0) ? "," : "");
658 FormatEncodedString(msg, func_name);
659 msg->Printf(",\"libraryId\": %"Pd",", library_id);
660
661 ASSERT(Dart_IsString(script_url));
662 msg->Printf("\"location\": { \"url\":");
663 FormatEncodedString(msg, script_url);
664 msg->Printf(",\"lineNumber\":%"Pd"},", line_number);
665
666 Dart_Handle locals = Dart_GetLocalVariables(frame);
667 ASSERT_NOT_ERROR(locals);
668 msg->Printf("\"locals\":");
669 FormatNamedValueList(msg, locals);
670 msg->Printf("}");
671 }
672 msg->Printf("]");
673 }
674
675
676 void DebuggerConnectionHandler::HandleGetStackTraceCmd(const char* json_msg) {
677 int msg_id = msgbuf_->MessageId();
678 Dart_StackTrace trace;
679 Dart_Handle res = Dart_GetStackTrace(&trace);
680 ASSERT_NOT_ERROR(res);
681 dart::TextBuffer msg(128);
682 msg.Printf("{ \"id\": %d, \"result\": {", msg_id);
683 FormatCallFrames(&msg, trace);
684 msg.Printf("}}");
685 SendMsg(&msg);
686 }
687
688
689 void DebuggerConnectionHandler::HandleSetBpCmd(const char* json_msg) {
690 int msg_id = msgbuf_->MessageId();
691 char* url_chars = msgbuf_->GetStringParam("url");
692 ASSERT(url_chars != NULL);
693 Dart_Handle url = Dart_NewString(url_chars);
694 ASSERT_NOT_ERROR(url);
695 free(url_chars);
696 url_chars = NULL;
697 intptr_t line_number = msgbuf_->GetIntParam("line");
698 Dart_Handle bp_id = Dart_SetBreakpoint(url, line_number);
699 if (Dart_IsError(bp_id)) {
700 SendError(msg_id, Dart_GetError(bp_id));
701 return;
702 }
703 ASSERT(Dart_IsInteger(bp_id));
704 uint64_t bp_id_value;
705 Dart_Handle res = Dart_IntegerToUint64(bp_id, &bp_id_value);
706 ASSERT_NOT_ERROR(res);
707 dart::TextBuffer msg(64);
708 msg.Printf("{ \"id\": %d, \"result\": { \"breakpointId\": %"Pu64" }}",
709 msg_id, bp_id_value);
710 SendMsg(&msg);
711 }
712
713
714 void DebuggerConnectionHandler::HandlePauseOnExcCmd(const char* json_msg) {
715 int msg_id = msgbuf_->MessageId();
716 char* exc_chars = msgbuf_->GetStringParam("exceptions");
717 Dart_ExceptionPauseInfo info = kNoPauseOnExceptions;
718 if (strcmp(exc_chars, "none") == 0) {
719 info = kNoPauseOnExceptions;
720 } else if (strcmp(exc_chars, "all") == 0) {
721 info = kPauseOnAllExceptions;
722 } else if (strcmp(exc_chars, "unhandled") == 0) {
723 info = kPauseOnUnhandledExceptions;
724 } else {
725 SendError(msg_id, "illegal value for parameter 'exceptions'");
726 return;
727 }
728 Dart_Handle res = Dart_SetExceptionPauseInfo(info);
729 ASSERT_NOT_ERROR(res);
730 dart::TextBuffer msg(32);
731 msg.Printf("{ \"id\": %d }", msg_id);
732 SendMsg(&msg);
733 }
734
735
736 void DebuggerConnectionHandler::HandleRemBpCmd(const char* json_msg) {
737 int msg_id = msgbuf_->MessageId();
738 int bpt_id = msgbuf_->GetIntParam("breakpointId");
739 Dart_Handle res = Dart_RemoveBreakpoint(bpt_id);
740 if (Dart_IsError(res)) {
741 SendError(msg_id, Dart_GetError(res));
742 return;
743 }
744 dart::TextBuffer msg(32);
745 msg.Printf("{ \"id\": %d }", msg_id);
746 SendMsg(&msg);
747 }
748
749
750 void DebuggerConnectionHandler::HandleGetObjPropsCmd(const char* json_msg) {
751 int msg_id = msgbuf_->MessageId();
752 intptr_t obj_id = msgbuf_->GetIntParam("objectId");
753 Dart_Handle obj = Dart_GetCachedObject(obj_id);
754 if (Dart_IsError(obj)) {
755 SendError(msg_id, Dart_GetError(obj));
756 return;
757 }
758 dart::TextBuffer msg(64);
759 msg.Printf("{\"id\":%d, \"result\":", msg_id);
760 const char* err = FormatObjProps(&msg, obj);
761 if (err != NULL) {
762 SendError(msg_id, err);
763 return;
764 }
765 msg.Printf("}");
766 SendMsg(&msg);
767 }
768
769
770 void DebuggerConnectionHandler::HandleGetListCmd(const char* json_msg) {
771 const intptr_t kDefaultSliceLength = 100;
772 int msg_id = msgbuf_->MessageId();
773 intptr_t obj_id = msgbuf_->GetIntParam("objectId");
774 Dart_Handle list = Dart_GetCachedObject(obj_id);
775 if (Dart_IsError(list)) {
776 SendError(msg_id, Dart_GetError(list));
777 return;
778 }
779 if (!Dart_IsList(list)) {
780 SendError(msg_id, "object is not a list");
781 return;
782 }
783 intptr_t list_length = 0;
784 Dart_Handle res = Dart_ListLength(list, &list_length);
785 if (Dart_IsError(res)) {
786 SendError(msg_id, Dart_GetError(res));
787 return;
788 }
789
790 intptr_t index = msgbuf_->GetIntParam("index");
791 if (index < 0) {
792 index = 0;
793 } else if (index > list_length) {
794 index = list_length;
795 }
796
797 // If no slice length is given, get only one element. If slice length
798 // is given as 0, get entire list.
799 intptr_t slice_length = msgbuf_->GetOptIntParam("length", 1);
800 if (slice_length == 0) {
801 slice_length = list_length - index;
802 }
803 if ((index + slice_length) > list_length) {
804 slice_length = list_length - index;
805 }
806 ASSERT(slice_length >= 0);
807 if (slice_length > kDefaultSliceLength) {
808 slice_length = kDefaultSliceLength;
809 }
810 dart::TextBuffer msg(64);
811 msg.Printf("{\"id\":%d, \"result\":", msg_id);
812 if (slice_length == 1) {
813 Dart_Handle value = Dart_ListGetAt(list, index);
814 FormatRemoteObj(&msg, value);
815 } else {
816 FormatListSlice(&msg, list, list_length, index, slice_length);
817 }
818 msg.Printf("}");
819 SendMsg(&msg);
820 }
821
822
823 void DebuggerConnectionHandler::HandleGetClassPropsCmd(const char* json_msg) {
824 int msg_id = msgbuf_->MessageId();
825 intptr_t cls_id = msgbuf_->GetIntParam("classId");
826 dart::TextBuffer msg(64);
827 msg.Printf("{\"id\":%d, \"result\":", msg_id);
828 const char* err = FormatClassProps(&msg, cls_id);
829 if (err != NULL) {
830 SendError(msg_id, err);
831 return;
832 }
833 msg.Printf("}");
834 SendMsg(&msg);
835 }
836
837
838 void DebuggerConnectionHandler::HandleGetLibPropsCmd(const char* json_msg) {
839 int msg_id = msgbuf_->MessageId();
840 intptr_t lib_id = msgbuf_->GetIntParam("libraryId");
841 dart::TextBuffer msg(64);
842 msg.Printf("{\"id\":%d, \"result\":", msg_id);
843 const char* err = FormatLibraryProps(&msg, lib_id);
844 if (err != NULL) {
845 SendError(msg_id, err);
846 return;
847 }
848 msg.Printf("}");
849 SendMsg(&msg);
850 }
851
852
853 void DebuggerConnectionHandler::HandleSetLibPropsCmd(const char* json_msg) {
854 int msg_id = msgbuf_->MessageId();
855 intptr_t lib_id = msgbuf_->GetIntParam("libraryId");
856 const char* enable_request = msgbuf_->GetStringParam("debuggingEnabled");
857 bool enable;
858 if (strcmp(enable_request, "true") == 0) {
859 enable = true;
860 } else if (strcmp(enable_request, "false") == 0) {
861 enable = false;
862 } else {
863 SendError(msg_id, "illegal argument for 'debuggingEnabled'");
864 return;
865 }
866 Dart_Handle res = Dart_SetLibraryDebuggable(lib_id, enable);
867 if (Dart_IsError(res)) {
868 SendError(msg_id, Dart_GetError(res));
869 return;
870 }
871 bool enabled = false;
872 res = Dart_GetLibraryDebuggable(lib_id, &enabled);
873 if (Dart_IsError(res)) {
874 SendError(msg_id, Dart_GetError(res));
875 return;
876 }
877 dart::TextBuffer msg(64);
878 msg.Printf("{\"id\":%d, \"result\": {\"debuggingEnabled\": \"%s\"}}",
879 msg_id,
880 enabled ? "true" : "false");
881 SendMsg(&msg);
882 }
883
884
885 void DebuggerConnectionHandler::HandleGetGlobalsCmd(const char* json_msg) {
886 int msg_id = msgbuf_->MessageId();
887 intptr_t lib_id = msgbuf_->GetIntParam("libraryId");
888 dart::TextBuffer msg(64);
889 msg.Printf("{\"id\":%d, \"result\": { \"globals\":", msg_id);
890 Dart_Handle globals = Dart_GetGlobalVariables(lib_id);
891 ASSERT_NOT_ERROR(globals);
892 FormatNamedValueList(&msg, globals);
893 msg.Printf("}}");
894 SendMsg(&msg);
895 }
896
897
898 void DebuggerConnectionHandler::HandleUnknownMsg(const char* json_msg) {
899 int msg_id = msgbuf_->MessageId();
900 ASSERT(msg_id >= 0);
901 SendError(msg_id, "unknown debugger command");
902 }
903 176
904 177
905 void DebuggerConnectionHandler::HandleMessages() { 178 void DebuggerConnectionHandler::HandleMessages() {
906 static JSONDebuggerCommand debugger_commands[] = { 179 static JSONDebuggerCommand generic_debugger_commands[] = {
907 { "resume", HandleResumeCmd }, 180 { "interrupt", HandleInterruptCmd },
908 { "getLibraries", HandleGetLibrariesCmd }, 181 { "isolates", HandleIsolatesListCmd },
909 { "getClassProperties", HandleGetClassPropsCmd }, 182 { "quit", HandleQuitCmd },
910 { "getLibraryProperties", HandleGetLibPropsCmd },
911 { "setLibraryProperties", HandleSetLibPropsCmd },
912 { "getObjectProperties", HandleGetObjPropsCmd },
913 { "getListElements", HandleGetListCmd },
914 { "getGlobalVariables", HandleGetGlobalsCmd },
915 { "getScriptURLs", HandleGetScriptURLsCmd },
916 { "getScriptSource", HandleGetSourceCmd },
917 { "getStackTrace", HandleGetStackTraceCmd },
918 { "setBreakpoint", HandleSetBpCmd },
919 { "setPauseOnException", HandlePauseOnExcCmd },
920 { "removeBreakpoint", HandleRemBpCmd },
921 { "stepInto", HandleStepIntoCmd },
922 { "stepOut", HandleStepOutCmd },
923 { "stepOver", HandleStepOverCmd },
924 { NULL, NULL } 183 { NULL, NULL }
925 }; 184 };
926 185
927 for (;;) { 186 for (;;) {
928 SendQueuedMsgs(); 187 // Read a message.
929 while (!msgbuf_->IsValidMessage() && msgbuf_->Alive()) { 188 while (!msgbuf_->IsValidMessage() && msgbuf_->Alive()) {
930 msgbuf_->ReadData(); 189 msgbuf_->ReadData();
931 } 190 }
932 if (!msgbuf_->Alive()) { 191 if (!msgbuf_->Alive()) {
933 return; 192 return;
934 } 193 }
194
195 // Parse out the command portion from the message.
935 dart::JSONReader r(msgbuf_->buf()); 196 dart::JSONReader r(msgbuf_->buf());
936 bool found = r.Seek("command"); 197 bool found = r.Seek("command");
937 if (r.Error()) { 198 if (r.Error()) {
938 FATAL("Illegal JSON message received"); 199 FATAL("Illegal JSON message received");
939 } 200 }
940 if (!found) { 201 if (!found) {
941 printf("'command' not found in JSON message: '%s'\n", msgbuf_->buf()); 202 printf("'command' not found in JSON message: '%s'\n", msgbuf_->buf());
942 msgbuf_->PopMessage(); 203 msgbuf_->PopMessage();
943 } 204 }
205
206 // Check if this is a generic command (not isolate specific).
944 int i = 0; 207 int i = 0;
945 bool is_handled = false; 208 bool is_handled = false;
946 request_resume_ = false; 209 while (generic_debugger_commands[i].cmd_string != NULL) {
947 while (debugger_commands[i].cmd_string != NULL) { 210 if (r.IsStringLiteral(generic_debugger_commands[i].cmd_string)) {
948 if (r.IsStringLiteral(debugger_commands[i].cmd_string)) { 211 (*generic_debugger_commands[i].handler_function)(this);
949 is_handled = true; 212 is_handled = true;
950 (*debugger_commands[i].handler_function)(msgbuf_->buf());
951 msgbuf_->PopMessage(); 213 msgbuf_->PopMessage();
952 if (request_resume_) {
953 return;
954 }
955 break; 214 break;
956 } 215 }
957 i++; 216 i++;
958 } 217 }
959 if (!is_handled) { 218 if (!is_handled) {
219 // Check if this is an isolate specific command.
220 int32_t cmd_idx = DbgMessageQueue::LookupIsolateCommand(r.ValueChars(),
221 r.ValueLen());
222 if (cmd_idx != DbgMessageQueue::kInvalidCommand) {
223 // Get debug message queue corresponding to isolate.
224 // TODO(asiva): Need to read the isolate id, map it to the appropriate
225 // isolate and pass it down to GetIsolateMessageQueue to get the
226 // appropriate debug message queue.
227 DbgMessageQueue* queue = DbgMessageQueue::GetIsolateMessageQueue(NULL);
228 ASSERT(queue != NULL);
229 queue->AddMessage(cmd_idx, msgbuf_->buf(), r.EndOfObject(), debug_fd_);
230 msgbuf_->PopMessage();
231 continue;
232 }
233
234 // This is an unrecognized command, report error and move on to next.
960 printf("unrecognized command received: '%s'\n", msgbuf_->buf()); 235 printf("unrecognized command received: '%s'\n", msgbuf_->buf());
961 HandleUnknownMsg(msgbuf_->buf()); 236 HandleUnknownMsg();
962 msgbuf_->PopMessage(); 237 msgbuf_->PopMessage();
963 } 238 }
964 } 239 }
965 } 240 }
966 241
967 242
968 void DebuggerConnectionHandler::WaitForConnection() { 243 void DebuggerConnectionHandler::SendError(int debug_fd,
969 MonitorLocker ml(&is_connected_); 244 int msg_id,
970 while (!IsConnected()) { 245 const char* err_msg) {
971 dart::Monitor::WaitResult res = ml.Wait(dart::Monitor::kNoTimeout); 246 dart::TextBuffer msg(64);
972 ASSERT(res == dart::Monitor::kNotified); 247 msg.Printf("{\"id\": %d, \"error\": \"Error: %s\"}", msg_id, err_msg);
973 } 248 SendMsg(debug_fd, &msg);
974 }
975
976
977 void DebuggerConnectionHandler::SendBreakpointEvent(Dart_StackTrace trace) {
978 dart::TextBuffer msg(128);
979 msg.Printf("{ \"event\": \"paused\", \"params\": { ");
980 msg.Printf("\"reason\": \"breakpoint\", ");
981 FormatCallFrames(&msg, trace);
982 msg.Printf("}}");
983 SendMsg(&msg);
984 }
985
986
987 void DebuggerConnectionHandler::BreakpointHandler(Dart_Breakpoint bpt,
988 Dart_StackTrace trace) {
989 WaitForConnection();
990 Dart_EnterScope();
991 SendQueuedMsgs();
992 SendBreakpointEvent(trace);
993 HandleMessages();
994 if (!msgbuf_->Alive()) {
995 CloseDbgConnection();
996 }
997 Dart_ExitScope();
998 }
999
1000
1001 void DebuggerConnectionHandler::IsolateEventHandler(Dart_Isolate isolate,
1002 Dart_IsolateEvent kind) {
1003 WaitForConnection();
1004 #if 0
1005 if (kind == kCreated) {
1006 printf("Isolate created %p\n", isolate);
1007 } else if (kind == kInterrupted) {
1008 printf("Isolate interrupted %p\n", isolate);
1009 } else if (kind == kShutdown) {
1010 printf("Isolate shutdown %p\n", isolate);
1011 }
1012 #endif
1013 }
1014
1015
1016 void DebuggerConnectionHandler::SendExceptionEvent(
1017 Dart_Handle exception,
1018 Dart_StackTrace stack_trace) {
1019 intptr_t exception_id = Dart_CacheObject(exception);
1020 ASSERT(exception_id >= 0);
1021 dart::TextBuffer msg(128);
1022 msg.Printf("{ \"event\": \"paused\", \"params\": {");
1023 msg.Printf("\"reason\": \"exception\", ");
1024 msg.Printf("\"exception\":");
1025 FormatRemoteObj(&msg, exception);
1026 msg.Printf(", ");
1027 FormatCallFrames(&msg, stack_trace);
1028 msg.Printf("}}");
1029 SendMsg(&msg);
1030 }
1031
1032
1033 void DebuggerConnectionHandler::ExceptionThrownHandler(
1034 Dart_Handle exception,
1035 Dart_StackTrace stack_trace) {
1036 WaitForConnection();
1037 Dart_EnterScope();
1038 SendQueuedMsgs();
1039 SendExceptionEvent(exception, stack_trace);
1040 HandleMessages();
1041 if (!msgbuf_->Alive()) {
1042 CloseDbgConnection();
1043 }
1044 Dart_ExitScope();
1045 }
1046
1047
1048 void DebuggerConnectionHandler::BptResolvedHandler(intptr_t bp_id,
1049 Dart_Handle url,
1050 intptr_t line_number) {
1051 Dart_EnterScope();
1052 dart::TextBuffer msg(128);
1053 msg.Printf("{ \"event\": \"breakpointResolved\", \"params\": {");
1054 msg.Printf("\"breakpointId\": %"Pd", \"url\":", bp_id);
1055 FormatEncodedString(&msg, url);
1056 msg.Printf(",\"line\": %"Pd" }}", line_number);
1057 QueueMsg(&msg);
1058 Dart_ExitScope();
1059 }
1060
1061
1062 void DebuggerConnectionHandler::AcceptDbgConnection(int debugger_fd) {
1063 debugger_fd_ = debugger_fd;
1064 ASSERT(msgbuf_ == NULL);
1065 msgbuf_ = new MessageBuffer(debugger_fd_);
1066 {
1067 MonitorLocker ml(&is_connected_);
1068 ml.Notify();
1069 }
1070 } 249 }
1071 250
1072 251
1073 void DebuggerConnectionHandler::CloseDbgConnection() { 252 void DebuggerConnectionHandler::CloseDbgConnection() {
1074 if (debugger_fd_ >= 0) { 253 if (debug_fd_ >= 0) {
1075 // TODO(hausner): need a Socket::Close() function. 254 // TODO(hausner): need a Socket::Close() function.
1076 } 255 }
1077 if (msgbuf_ != NULL) { 256 if (msgbuf_ != NULL) {
1078 delete msgbuf_; 257 delete msgbuf_;
1079 msgbuf_ = NULL; 258 msgbuf_ = NULL;
1080 } 259 }
1081 // TODO(hausner): Need to tell the VM debugger object to remove all 260 // TODO(hausner): Need to tell the VM debugger object to remove all
1082 // breakpoints. 261 // breakpoints.
1083 } 262 }
1084 263
1085 264
1086 void DebuggerConnectionHandler::StartHandler(const char* address, 265 void DebuggerConnectionHandler::StartHandler(const char* address,
1087 int port_number) { 266 int port_number) {
1088 if (handler_started_) { 267 MonitorLocker ml(&handler_lock_);
1089 return; 268 if (listener_fd_ != -1) {
1090 } 269 return; // The debugger connection handler was already started.
270 }
271
272 // First setup breakpoint, exception and delayed breakpoint handlers.
273 DbgMessageQueue::Initialize();
274
275 // Now setup a listener socket and start a thread which will
276 // listen, accept connections from debuggers, read and handle/dispatch
277 // debugger commands received on these connections.
1091 ASSERT(listener_fd_ == -1); 278 ASSERT(listener_fd_ == -1);
1092 listener_fd_ = ServerSocket::CreateBindListen(address, port_number, 1); 279 listener_fd_ = ServerSocket::CreateBindListen(address, port_number, 1);
1093
1094 handler_started_ = true;
1095 DebuggerConnectionImpl::StartHandler(port_number); 280 DebuggerConnectionImpl::StartHandler(port_number);
1096 Dart_SetIsolateEventHandler(IsolateEventHandler); 281 }
1097 Dart_SetBreakpointHandler(BreakpointHandler); 282
1098 Dart_SetBreakpointResolvedHandler(BptResolvedHandler); 283
1099 Dart_SetExceptionThrownHandler(ExceptionThrownHandler); 284 void DebuggerConnectionHandler::WaitForConnection() {
1100 } 285 MonitorLocker ml(&handler_lock_);
1101 286 while (!IsConnected()) {
1102 287 dart::Monitor::WaitResult res = ml.Wait();
1103 DebuggerConnectionHandler::~DebuggerConnectionHandler() { 288 ASSERT(res == dart::Monitor::kNotified);
1104 CloseDbgConnection(); 289 }
1105 } 290 }
291
292
293 void DebuggerConnectionHandler::SendMsg(int debug_fd, dart::TextBuffer* msg) {
294 MonitorLocker ml(&handler_lock_);
295 SendMsgHelper(debug_fd, msg);
296 }
297
298
299 void DebuggerConnectionHandler::BroadcastMsg(dart::TextBuffer* msg) {
300 MonitorLocker ml(&handler_lock_);
301 // TODO(asiva): Once we support connection to multiple debuggers
302 // we need to send the message to all of them.
303 ASSERT(singleton_handler != NULL);
304 SendMsgHelper(singleton_handler->debug_fd(), msg);
305 }
306
307
308 void DebuggerConnectionHandler::SendMsgHelper(int debug_fd,
309 dart::TextBuffer* msg) {
310 ASSERT(debug_fd >= 0);
311 ASSERT(IsValidJSON(msg->buf()));
312 // Sending messages in short pieces can be used to stress test the
313 // debugger front-end's message handling code.
314 const bool send_in_pieces = false;
315 if (send_in_pieces) {
316 intptr_t remaining = msg->length();
317 intptr_t sent = 0;
318 const intptr_t max_piece_len = 122; // Pretty arbitrary, not a power of 2.
319 dart::Monitor sleep;
320 while (remaining > 0) {
321 intptr_t piece_len = remaining;
322 if (piece_len > max_piece_len) {
323 piece_len = max_piece_len;
324 }
325 intptr_t written =
326 Socket::Write(debug_fd, msg->buf() + sent, piece_len);
327 ASSERT(written == piece_len);
328 sent += written;
329 remaining -= written;
330 // Wait briefly so the OS does not coalesce message fragments.
331 {
332 MonitorLocker ml(&sleep);
333 ml.Wait(10);
334 }
335 }
336 return;
337 }
338 intptr_t bytes_written = Socket::Write(debug_fd, msg->buf(), msg->length());
339 ASSERT(msg->length() == bytes_written);
340 // TODO(hausner): Error checking. Probably just shut down the debugger
341 // session if we there is an error while writing.
342 }
343
344
345 void DebuggerConnectionHandler::AcceptDbgConnection(int debug_fd) {
346 AddNewDebuggerConnection(debug_fd);
347 {
348 MonitorLocker ml(&handler_lock_);
349 ml.NotifyAll();
350 }
351 // TODO(asiva): Once we implement support for multiple connections
352 // we should have a different callback for wakeups on fds which
353 // are not the listener_fd_.
354 // In that callback we would lookup the handler object
355 // corresponding to that fd and invoke HandleMessages on it.
356 // For now we run that code here.
357 DebuggerConnectionHandler* handler = GetDebuggerConnectionHandler(debug_fd);
358 if (handler != NULL) {
359 handler->HandleMessages();
360 delete handler;
361 }
362 }
363
364
365 void DebuggerConnectionHandler::HandleInterruptCmd(
366 DebuggerConnectionHandler* handler) {
367 int msg_id = handler->MessageId();
368 ASSERT(msg_id >= 0);
369 SendError(handler->debug_fd(), msg_id, "interrupt command unimplemented");
370 }
371
372
373 void DebuggerConnectionHandler::HandleIsolatesListCmd(
374 DebuggerConnectionHandler* handler) {
375 int msg_id = handler->MessageId();
376 ASSERT(msg_id >= 0);
377 SendError(handler->debug_fd(), msg_id, "isolate list command unimplemented");
378 }
379
380
381 void DebuggerConnectionHandler::HandleQuitCmd(
382 DebuggerConnectionHandler* handler) {
383 int msg_id = handler->MessageId();
384 ASSERT(msg_id >= 0);
385 SendError(handler->debug_fd(), msg_id, "quit command unimplemented");
386 }
387
388
389 void DebuggerConnectionHandler::AddNewDebuggerConnection(int debug_fd) {
390 // TODO(asiva): Support multiple debugger connections, for now we just
391 // create one handler, store it in a static variable and use it.
392 ASSERT(singleton_handler == NULL);
393 singleton_handler = new DebuggerConnectionHandler(debug_fd);
394 }
395
396
397 void DebuggerConnectionHandler::RemoveDebuggerConnection(int debug_fd) {
398 // TODO(asiva): Support multiple debugger connections, for now we just
399 // set the static handler back to NULL.
400 ASSERT(singleton_handler != NULL);
401 singleton_handler = NULL;
402 }
403
404
405 DebuggerConnectionHandler*
406 DebuggerConnectionHandler::GetDebuggerConnectionHandler(int debug_fd) {
407 // TODO(asiva): Support multiple debugger connections, for now we just
408 // return the one static handler that was created.
409 ASSERT(singleton_handler != NULL);
410 return singleton_handler;
411 }
412
413
414 bool DebuggerConnectionHandler::IsConnected() {
415 // TODO(asiva): Support multiple debugger connections.
416 // Return true if a connection has been established.
417 return singleton_handler != NULL;
418 }
OLDNEW
« no previous file with comments | « runtime/bin/dbg_connection.h ('k') | runtime/bin/dbg_connection_linux.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698