OLD | NEW |
| (Empty) |
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 | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 #include "bin/dbg_connection.h" | |
6 #include "bin/dbg_message.h" | |
7 #include "bin/dartutils.h" | |
8 #include "bin/lockers.h" | |
9 #include "bin/thread.h" | |
10 #include "bin/utils.h" | |
11 | |
12 #include "platform/globals.h" | |
13 #include "platform/json.h" | |
14 #include "platform/utils.h" | |
15 | |
16 #include "include/dart_api.h" | |
17 | |
18 | |
19 namespace dart { | |
20 namespace bin { | |
21 | |
22 bool MessageParser::IsValidMessage() const { | |
23 if (buf_length_ == 0) { | |
24 return false; | |
25 } | |
26 dart::JSONReader msg_reader(buf_); | |
27 return msg_reader.EndOfObject() != NULL; | |
28 } | |
29 | |
30 | |
31 int MessageParser::MessageId() const { | |
32 dart::JSONReader r(buf_); | |
33 r.Seek("id"); | |
34 if (r.Type() == dart::JSONReader::kInteger) { | |
35 return atoi(r.ValueChars()); | |
36 } else { | |
37 return -1; | |
38 } | |
39 } | |
40 | |
41 | |
42 const char* MessageParser::Params() const { | |
43 dart::JSONReader r(buf_); | |
44 r.Seek("params"); | |
45 if (r.Type() == dart::JSONReader::kObject) { | |
46 return r.ValueChars(); | |
47 } else { | |
48 return NULL; | |
49 } | |
50 } | |
51 | |
52 | |
53 bool MessageParser::HasParam(const char* name) const { | |
54 const char* params = Params(); | |
55 ASSERT(params != NULL); | |
56 dart::JSONReader r(params); | |
57 return r.Seek(name); | |
58 } | |
59 | |
60 | |
61 intptr_t MessageParser::GetIntParam(const char* name) const { | |
62 const char* params = Params(); | |
63 ASSERT(params != NULL); | |
64 dart::JSONReader r(params); | |
65 r.Seek(name); | |
66 ASSERT(r.Type() == dart::JSONReader::kInteger); | |
67 return strtol(r.ValueChars(), NULL, 10); | |
68 } | |
69 | |
70 | |
71 int64_t MessageParser::GetInt64Param(const char* name) const { | |
72 const char* params = Params(); | |
73 ASSERT(params != NULL); | |
74 dart::JSONReader r(params); | |
75 r.Seek(name); | |
76 ASSERT(r.Type() == dart::JSONReader::kInteger); | |
77 return strtoll(r.ValueChars(), NULL, 10); | |
78 } | |
79 | |
80 | |
81 intptr_t MessageParser::GetOptIntParam(const char* name, | |
82 intptr_t default_val) const { | |
83 const char* params = Params(); | |
84 ASSERT(params != NULL); | |
85 dart::JSONReader r(params); | |
86 r.Seek(name); | |
87 if (r.Type() == dart::JSONReader::kInteger) { | |
88 return strtol(r.ValueChars(), NULL, 10); | |
89 } else { | |
90 return default_val; | |
91 } | |
92 } | |
93 | |
94 | |
95 static const char* GetStringChars(Dart_Handle str) { | |
96 ASSERT(Dart_IsString(str)); | |
97 const char* chars; | |
98 Dart_Handle res = Dart_StringToCString(str, &chars); | |
99 ASSERT(!Dart_IsError(res)); | |
100 return chars; | |
101 } | |
102 | |
103 | |
104 static int64_t GetIntValue(Dart_Handle int_handle) { | |
105 int64_t int64_val = -1; | |
106 ASSERT(Dart_IsInteger(int_handle)); | |
107 Dart_Handle res = Dart_IntegerToInt64(int_handle, &int64_val); | |
108 ASSERT_NOT_ERROR(res); | |
109 return int64_val; | |
110 } | |
111 | |
112 | |
113 char* MessageParser::GetStringParam(const char* name) const { | |
114 const char* params = Params(); | |
115 ASSERT(params != NULL); | |
116 dart::JSONReader pr(params); | |
117 pr.Seek(name); | |
118 if (pr.Type() != dart::JSONReader::kString) { | |
119 return NULL; | |
120 } | |
121 intptr_t buflen = pr.ValueLen() + 1; | |
122 char* param_chars = reinterpret_cast<char*>(malloc(buflen)); | |
123 pr.GetDecodedValueChars(param_chars, buflen); | |
124 return param_chars; | |
125 } | |
126 | |
127 | |
128 static void FormatEncodedCharsTrunc(dart::TextBuffer* buf, | |
129 Dart_Handle str, | |
130 intptr_t max_chars) { | |
131 intptr_t str_len = 0; | |
132 Dart_Handle res = Dart_StringLength(str, &str_len); | |
133 ASSERT_NOT_ERROR(res); | |
134 intptr_t num_chars = (str_len > max_chars) ? max_chars : str_len; | |
135 uint16_t* codeunits = | |
136 reinterpret_cast<uint16_t*>(malloc(num_chars * sizeof(uint16_t))); | |
137 ASSERT(codeunits != NULL); | |
138 intptr_t actual_len = num_chars; | |
139 res = Dart_StringToUTF16(str, codeunits, &actual_len); | |
140 ASSERT_NOT_ERROR(res); | |
141 ASSERT(num_chars == actual_len); | |
142 for (int i = 0; i < num_chars; i++) { | |
143 buf->EscapeAndAddCodeUnit(codeunits[i]); | |
144 } | |
145 if (str_len > max_chars) { | |
146 buf->Printf("..."); | |
147 } | |
148 free(codeunits); | |
149 } | |
150 | |
151 | |
152 static void FormatEncodedChars(dart::TextBuffer* buf, Dart_Handle str) { | |
153 intptr_t str_len = 0; | |
154 Dart_Handle res = Dart_StringLength(str, &str_len); | |
155 ASSERT_NOT_ERROR(res); | |
156 uint16_t* codeunits = | |
157 reinterpret_cast<uint16_t*>(malloc(str_len * sizeof(uint16_t))); | |
158 ASSERT(codeunits != NULL); | |
159 intptr_t actual_len = str_len; | |
160 res = Dart_StringToUTF16(str, codeunits, &actual_len); | |
161 ASSERT_NOT_ERROR(res); | |
162 ASSERT(str_len == actual_len); | |
163 for (int i = 0; i < str_len; i++) { | |
164 buf->EscapeAndAddCodeUnit(codeunits[i]); | |
165 } | |
166 free(codeunits); | |
167 } | |
168 | |
169 | |
170 static void FormatEncodedString(dart::TextBuffer* buf, Dart_Handle str) { | |
171 buf->AddChar('\"'); | |
172 FormatEncodedChars(buf, str); | |
173 buf->AddChar('\"'); | |
174 } | |
175 | |
176 | |
177 static void FormatTextualValue(dart::TextBuffer* buf, | |
178 Dart_Handle object, | |
179 intptr_t max_chars, | |
180 bool expand_list); | |
181 | |
182 | |
183 static void FormatTextualListValue(dart::TextBuffer* buf, | |
184 Dart_Handle list, | |
185 intptr_t max_chars) { | |
186 intptr_t len = 0; | |
187 Dart_Handle res = Dart_ListLength(list, &len); | |
188 ASSERT_NOT_ERROR(res); | |
189 const intptr_t initial_buffer_length = buf->length(); | |
190 // Maximum number of characters we print for array elements. | |
191 const intptr_t max_buffer_length = initial_buffer_length + max_chars; | |
192 buf->Printf("["); | |
193 for (int i = 0; i < len; i++) { | |
194 if (i > 0) { | |
195 buf->Printf(", "); | |
196 } | |
197 Dart_Handle elem = Dart_ListGetAt(list, i); | |
198 const intptr_t max_element_chars = 50; | |
199 FormatTextualValue(buf, elem, max_element_chars, false); | |
200 if (buf->length() > max_buffer_length) { | |
201 buf->Printf(", ..."); | |
202 break; | |
203 } | |
204 } | |
205 buf->Printf("]"); | |
206 } | |
207 | |
208 | |
209 static void FormatTextualValue(dart::TextBuffer* buf, | |
210 Dart_Handle object, | |
211 intptr_t max_chars, | |
212 bool expand_list) { | |
213 ASSERT(!Dart_IsError(object)); | |
214 if (Dart_IsList(object)) { | |
215 if (expand_list) { | |
216 FormatTextualListValue(buf, object, max_chars); | |
217 } else { | |
218 buf->Printf("[...]"); | |
219 } | |
220 } else if (Dart_IsNull(object)) { | |
221 buf->Printf("null"); | |
222 } else if (Dart_IsString(object)) { | |
223 buf->Printf("\\\""); | |
224 FormatEncodedCharsTrunc(buf, object, max_chars); | |
225 buf->Printf("\\\""); | |
226 } else if (Dart_IsNumber(object) || Dart_IsBoolean(object)) { | |
227 Dart_Handle text = Dart_ToString(object); | |
228 ASSERT(!Dart_IsNull(text) && !Dart_IsError(text)); | |
229 FormatEncodedCharsTrunc(buf, text, max_chars); | |
230 } else { | |
231 Dart_Handle type = Dart_InstanceGetType(object); | |
232 ASSERT_NOT_ERROR(type); | |
233 type = Dart_ToString(type); | |
234 ASSERT_NOT_ERROR(type); | |
235 buf->Printf("object of type "); | |
236 FormatEncodedCharsTrunc(buf, type, max_chars); | |
237 } | |
238 } | |
239 | |
240 | |
241 static void FormatValue(dart::TextBuffer* buf, Dart_Handle object) { | |
242 bool print_text_field = true; | |
243 if (Dart_IsNumber(object)) { | |
244 buf->Printf("\"kind\":\"number\""); | |
245 } else if (Dart_IsString(object)) { | |
246 buf->Printf("\"kind\":\"string\""); | |
247 } else if (Dart_IsBoolean(object)) { | |
248 buf->Printf("\"kind\":\"boolean\""); | |
249 } else if (Dart_IsList(object)) { | |
250 intptr_t len = 0; | |
251 Dart_Handle res = Dart_ListLength(object, &len); | |
252 ASSERT_NOT_ERROR(res); | |
253 buf->Printf("\"kind\":\"list\",\"length\":%" Pd "", len); | |
254 } else if (Dart_IsClosure(object)) { | |
255 Dart_Handle name, signature; | |
256 Dart_CodeLocation location; | |
257 Dart_Handle res = Dart_GetClosureInfo(object, &name, &signature, &location); | |
258 ASSERT_NOT_ERROR(res); | |
259 buf->Printf("\"kind\":\"function\",\"name\":\"%s\"", GetStringChars(name)); | |
260 buf->Printf(",\"signature\":\"%s\"", GetStringChars(signature)); | |
261 if (!Dart_IsNull(location.script_url)) { | |
262 ASSERT(Dart_IsString(location.script_url)); | |
263 buf->Printf(",\"location\": { \"url\":"); | |
264 FormatEncodedString(buf, location.script_url); | |
265 buf->Printf(",\"libraryId\":%d,", location.library_id); | |
266 buf->Printf("\"tokenOffset\":%d}", location.token_pos); | |
267 } | |
268 print_text_field = false; | |
269 } else { | |
270 buf->Printf("\"kind\":\"object\""); | |
271 intptr_t class_id = 0; | |
272 Dart_Handle res = Dart_GetObjClassId(object, &class_id); | |
273 if (!Dart_IsError(res)) { | |
274 buf->Printf(",\"classId\":%" Pd "", class_id); | |
275 } | |
276 } | |
277 if (print_text_field) { | |
278 buf->Printf(",\"text\":\""); | |
279 const intptr_t max_chars = 1024; | |
280 FormatTextualValue(buf, object, max_chars, true); | |
281 buf->Printf("\""); | |
282 } | |
283 } | |
284 | |
285 | |
286 static void FormatValueObj(dart::TextBuffer* buf, Dart_Handle object) { | |
287 buf->Printf("{"); | |
288 FormatValue(buf, object); | |
289 buf->Printf("}"); | |
290 } | |
291 | |
292 | |
293 static void FormatRemoteObj(dart::TextBuffer* buf, Dart_Handle object) { | |
294 intptr_t obj_id = Dart_CacheObject(object); | |
295 ASSERT(obj_id >= 0); | |
296 buf->Printf("{\"objectId\":%" Pd ",", obj_id); | |
297 FormatValue(buf, object); | |
298 buf->Printf("}"); | |
299 } | |
300 | |
301 | |
302 static void FormatNamedValue(dart::TextBuffer* buf, | |
303 Dart_Handle object_name, | |
304 Dart_Handle object) { | |
305 ASSERT(Dart_IsString(object_name)); | |
306 buf->Printf("{\"name\":\"%s\",", GetStringChars(object_name)); | |
307 buf->Printf("\"value\":"); | |
308 FormatRemoteObj(buf, object); | |
309 buf->Printf("}"); | |
310 } | |
311 | |
312 | |
313 static void FormatNamedValueList(dart::TextBuffer* buf, | |
314 Dart_Handle obj_list) { | |
315 ASSERT(Dart_IsList(obj_list)); | |
316 intptr_t list_length = 0; | |
317 Dart_Handle res = Dart_ListLength(obj_list, &list_length); | |
318 ASSERT_NOT_ERROR(res); | |
319 ASSERT(list_length % 2 == 0); | |
320 buf->Printf("["); | |
321 for (int i = 0; i + 1 < list_length; i += 2) { | |
322 Dart_Handle name_handle = Dart_ListGetAt(obj_list, i); | |
323 ASSERT_NOT_ERROR(name_handle); | |
324 Dart_Handle value_handle = Dart_ListGetAt(obj_list, i + 1); | |
325 ASSERT_NOT_ERROR(value_handle); | |
326 if (i > 0) { | |
327 buf->Printf(","); | |
328 } | |
329 FormatNamedValue(buf, name_handle, value_handle); | |
330 } | |
331 buf->Printf("]"); | |
332 } | |
333 | |
334 | |
335 static const char* FormatClassProps(dart::TextBuffer* buf, | |
336 intptr_t cls_id) { | |
337 Dart_Handle name, static_fields; | |
338 intptr_t super_id = -1; | |
339 intptr_t library_id = -1; | |
340 Dart_Handle res = | |
341 Dart_GetClassInfo(cls_id, &name, &library_id, &super_id, &static_fields); | |
342 RETURN_IF_ERROR(res); | |
343 RETURN_IF_ERROR(name); | |
344 buf->Printf("{\"name\":\"%s\",", GetStringChars(name)); | |
345 if (super_id > 0) { | |
346 buf->Printf("\"superclassId\":%" Pd ",", super_id); | |
347 } | |
348 buf->Printf("\"libraryId\":%" Pd ",", library_id); | |
349 RETURN_IF_ERROR(static_fields); | |
350 buf->Printf("\"fields\":"); | |
351 FormatNamedValueList(buf, static_fields); | |
352 buf->Printf("}"); | |
353 return NULL; | |
354 } | |
355 | |
356 | |
357 static const char* FormatLibraryProps(dart::TextBuffer* buf, | |
358 intptr_t lib_id) { | |
359 Dart_Handle url = Dart_GetLibraryURL(lib_id); | |
360 RETURN_IF_ERROR(url); | |
361 buf->Printf("{\"url\":"); | |
362 FormatEncodedString(buf, url); | |
363 | |
364 // Whether debugging is enabled. | |
365 bool is_debuggable = false; | |
366 Dart_Handle res = Dart_GetLibraryDebuggable(lib_id, &is_debuggable); | |
367 RETURN_IF_ERROR(res); | |
368 buf->Printf(",\"debuggingEnabled\":%s", | |
369 is_debuggable ? "\"true\"" : "\"false\""); | |
370 | |
371 // Imports and prefixes. | |
372 Dart_Handle import_list = Dart_GetLibraryImports(lib_id); | |
373 RETURN_IF_ERROR(import_list); | |
374 ASSERT(Dart_IsList(import_list)); | |
375 intptr_t list_length = 0; | |
376 res = Dart_ListLength(import_list, &list_length); | |
377 RETURN_IF_ERROR(res); | |
378 buf->Printf(",\"imports\":["); | |
379 for (intptr_t i = 0; i + 1 < list_length; i += 2) { | |
380 Dart_Handle lib_id = Dart_ListGetAt(import_list, i + 1); | |
381 ASSERT_NOT_ERROR(lib_id); | |
382 buf->Printf("%s{\"libraryId\":%" Pd64 ",", | |
383 (i > 0) ? ",": "", | |
384 GetIntValue(lib_id)); | |
385 | |
386 Dart_Handle name = Dart_ListGetAt(import_list, i); | |
387 ASSERT_NOT_ERROR(name); | |
388 buf->Printf("\"prefix\":\"%s\"}", | |
389 Dart_IsNull(name) ? "" : GetStringChars(name)); | |
390 } | |
391 buf->Printf("],"); | |
392 | |
393 // Global variables in the library. | |
394 Dart_Handle global_vars = Dart_GetLibraryFields(lib_id); | |
395 RETURN_IF_ERROR(global_vars); | |
396 buf->Printf("\"globals\":"); | |
397 FormatNamedValueList(buf, global_vars); | |
398 buf->Printf("}"); | |
399 return NULL; | |
400 } | |
401 | |
402 | |
403 static const char* FormatObjProps(dart::TextBuffer* buf, | |
404 Dart_Handle object) { | |
405 intptr_t class_id; | |
406 if (Dart_IsNull(object)) { | |
407 buf->Printf("{\"classId\":-1,\"fields\":[]}"); | |
408 return NULL; | |
409 } | |
410 Dart_Handle res = Dart_GetObjClassId(object, &class_id); | |
411 RETURN_IF_ERROR(res); | |
412 buf->Printf("{\"classId\": %" Pd ",", class_id); | |
413 buf->Printf("\"kind\":\"object\",\"fields\":"); | |
414 Dart_Handle fields = Dart_GetInstanceFields(object); | |
415 RETURN_IF_ERROR(fields); | |
416 FormatNamedValueList(buf, fields); | |
417 buf->Printf("}"); | |
418 return NULL; | |
419 } | |
420 | |
421 | |
422 static const char* FormatListSlice(dart::TextBuffer* buf, | |
423 Dart_Handle list, | |
424 intptr_t list_length, | |
425 intptr_t index, | |
426 intptr_t slice_length) { | |
427 intptr_t end_index = index + slice_length; | |
428 ASSERT(end_index <= list_length); | |
429 buf->Printf("{\"index\":%" Pd ",", index); | |
430 buf->Printf("\"length\":%" Pd ",", slice_length); | |
431 buf->Printf("\"elements\":["); | |
432 for (intptr_t i = index; i < end_index; i++) { | |
433 Dart_Handle value = Dart_ListGetAt(list, i); | |
434 if (i > index) { | |
435 buf->Printf(","); | |
436 } | |
437 FormatValueObj(buf, value); | |
438 } | |
439 buf->Printf("]}"); | |
440 return NULL; | |
441 } | |
442 | |
443 | |
444 static void FormatLocationFromTrace(dart::TextBuffer* msg, | |
445 Dart_StackTrace trace, | |
446 const char* prefix) { | |
447 intptr_t trace_len = 0; | |
448 Dart_Handle res = Dart_StackTraceLength(trace, &trace_len); | |
449 ASSERT_NOT_ERROR(res); | |
450 if (trace_len == 0) { | |
451 return; | |
452 } | |
453 Dart_ActivationFrame frame; | |
454 res = Dart_GetActivationFrame(trace, 0, &frame); | |
455 ASSERT_NOT_ERROR(res); | |
456 Dart_CodeLocation location; | |
457 res = Dart_ActivationFrameGetLocation(frame, NULL, NULL, &location); | |
458 ASSERT_NOT_ERROR(res); | |
459 if (!Dart_IsNull(location.script_url)) { | |
460 ASSERT(Dart_IsString(location.script_url)); | |
461 msg->Printf("%s\"location\": { \"url\":", prefix); | |
462 FormatEncodedString(msg, location.script_url); | |
463 msg->Printf(",\"libraryId\":%d,", location.library_id); | |
464 msg->Printf("\"tokenOffset\":%d}", location.token_pos); | |
465 } | |
466 } | |
467 | |
468 | |
469 static void FormatCallFrames(dart::TextBuffer* msg, Dart_StackTrace trace) { | |
470 intptr_t trace_len = 0; | |
471 Dart_Handle res = Dart_StackTraceLength(trace, &trace_len); | |
472 ASSERT_NOT_ERROR(res); | |
473 msg->Printf("\"callFrames\" : [ "); | |
474 for (int i = 0; i < trace_len; i++) { | |
475 Dart_ActivationFrame frame; | |
476 res = Dart_GetActivationFrame(trace, i, &frame); | |
477 ASSERT_NOT_ERROR(res); | |
478 Dart_Handle func_name; | |
479 Dart_Handle func; | |
480 Dart_CodeLocation location; | |
481 res = Dart_ActivationFrameGetLocation(frame, &func_name, &func, &location); | |
482 ASSERT_NOT_ERROR(res); | |
483 ASSERT(Dart_IsString(func_name)); | |
484 msg->Printf("%s{\"functionName\":", (i > 0) ? "," : ""); | |
485 FormatEncodedString(msg, func_name); | |
486 if (!Dart_IsNull(location.script_url)) { | |
487 ASSERT(Dart_IsString(location.script_url)); | |
488 msg->Printf(",\"location\": { \"url\":"); | |
489 FormatEncodedString(msg, location.script_url); | |
490 msg->Printf(",\"libraryId\":%d,", location.library_id); | |
491 msg->Printf("\"tokenOffset\":%d}", location.token_pos); | |
492 } | |
493 ASSERT_NOT_ERROR(func); | |
494 Dart_Handle origin = Dart_GetFunctionOrigin(func); | |
495 ASSERT_NOT_ERROR(origin); | |
496 if (Dart_IsInteger(origin)) { | |
497 int64_t class_id = GetIntValue(origin); | |
498 msg->Printf(",\"classId\":%" Pd64 "", class_id); | |
499 } | |
500 Dart_Handle locals = Dart_GetLocalVariables(frame); | |
501 ASSERT_NOT_ERROR(locals); | |
502 msg->Printf(",\"locals\":"); | |
503 FormatNamedValueList(msg, locals); | |
504 msg->Printf("}"); | |
505 } | |
506 msg->Printf("]"); | |
507 } | |
508 | |
509 | |
510 typedef bool (*CommandHandler)(DbgMessage* msg); | |
511 | |
512 struct JSONDebuggerCommand { | |
513 const char* cmd_string; | |
514 CommandHandler handler_function; | |
515 }; | |
516 | |
517 | |
518 static JSONDebuggerCommand debugger_commands[] = { | |
519 { "resume", DbgMessage::HandleResumeCmd }, | |
520 { "stepInto", DbgMessage::HandleStepIntoCmd }, | |
521 { "stepOut", DbgMessage::HandleStepOutCmd }, | |
522 { "stepOver", DbgMessage::HandleStepOverCmd }, | |
523 { "getLibraries", DbgMessage::HandleGetLibrariesCmd }, | |
524 { "getClassProperties", DbgMessage::HandleGetClassPropsCmd }, | |
525 { "getLibraryProperties", DbgMessage::HandleGetLibPropsCmd }, | |
526 { "setLibraryProperties", DbgMessage::HandleSetLibPropsCmd }, | |
527 { "evaluateExpr", DbgMessage::HandleEvaluateExprCmd }, | |
528 { "getObjectProperties", DbgMessage::HandleGetObjPropsCmd }, | |
529 { "getListElements", DbgMessage::HandleGetListCmd }, | |
530 { "getGlobalVariables", DbgMessage::HandleGetGlobalsCmd }, | |
531 { "getScriptURLs", DbgMessage::HandleGetScriptURLsCmd }, | |
532 { "getScriptSource", DbgMessage::HandleGetSourceCmd }, | |
533 { "getLineNumberTable", DbgMessage::HandleGetLineNumbersCmd }, | |
534 { "getStackTrace", DbgMessage::HandleGetStackTraceCmd }, | |
535 { "setBreakpoint", DbgMessage::HandleSetBpCmd }, | |
536 { "setPauseOnException", DbgMessage::HandlePauseOnExcCmd }, | |
537 { "removeBreakpoint", DbgMessage::HandleRemBpCmd }, | |
538 { NULL, NULL } | |
539 }; | |
540 | |
541 | |
542 bool DbgMessage::HandleMessage() { | |
543 // Dispatch to the appropriate handler for the command. | |
544 int max_index = (sizeof(debugger_commands) / sizeof(JSONDebuggerCommand)); | |
545 ASSERT(cmd_idx_ < max_index); | |
546 return (*debugger_commands[cmd_idx_].handler_function)(this); | |
547 } | |
548 | |
549 | |
550 void DbgMessage::SendReply(dart::TextBuffer* reply) { | |
551 DebuggerConnectionHandler::SendMsg(debug_fd(), reply); | |
552 } | |
553 | |
554 | |
555 void DbgMessage::SendErrorReply(int msg_id, const char* err_msg) { | |
556 DebuggerConnectionHandler::SendError(debug_fd(), msg_id, err_msg); | |
557 } | |
558 | |
559 | |
560 bool DbgMessage::HandleResumeCmd(DbgMessage* in_msg) { | |
561 ASSERT(in_msg != NULL); | |
562 MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len()); | |
563 int msg_id = msg_parser.MessageId(); | |
564 dart::TextBuffer msg(64); | |
565 msg.Printf("{ \"id\": %d }", msg_id); | |
566 in_msg->SendReply(&msg); | |
567 return true; | |
568 } | |
569 | |
570 | |
571 bool DbgMessage::HandleStepIntoCmd(DbgMessage* in_msg) { | |
572 Dart_Handle res = Dart_SetStepInto(); | |
573 ASSERT_NOT_ERROR(res); | |
574 return HandleResumeCmd(in_msg); | |
575 } | |
576 | |
577 | |
578 bool DbgMessage::HandleStepOutCmd(DbgMessage* in_msg) { | |
579 Dart_Handle res = Dart_SetStepOut(); | |
580 ASSERT_NOT_ERROR(res); | |
581 return HandleResumeCmd(in_msg); | |
582 } | |
583 | |
584 | |
585 bool DbgMessage::HandleStepOverCmd(DbgMessage* in_msg) { | |
586 Dart_Handle res = Dart_SetStepOver(); | |
587 ASSERT_NOT_ERROR(res); | |
588 return HandleResumeCmd(in_msg); | |
589 } | |
590 | |
591 | |
592 bool DbgMessage::HandleGetLibrariesCmd(DbgMessage* in_msg) { | |
593 ASSERT(in_msg != NULL); | |
594 MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len()); | |
595 int msg_id = msg_parser.MessageId(); | |
596 dart::TextBuffer msg(64); | |
597 msg.Printf("{ \"id\": %d, \"result\": { \"libraries\": [", msg_id); | |
598 Dart_Handle lib_ids = Dart_GetLibraryIds(); | |
599 ASSERT_NOT_ERROR(lib_ids); | |
600 intptr_t num_libs; | |
601 Dart_Handle res = Dart_ListLength(lib_ids, &num_libs); | |
602 ASSERT_NOT_ERROR(res); | |
603 for (intptr_t i = 0; i < num_libs; i++) { | |
604 Dart_Handle lib_id_handle = Dart_ListGetAt(lib_ids, i); | |
605 ASSERT(Dart_IsInteger(lib_id_handle)); | |
606 int64_t lib_id = GetIntValue(lib_id_handle); | |
607 ASSERT((lib_id >= kIntptrMin) && (lib_id <= kIntptrMax)); | |
608 Dart_Handle lib_url = Dart_GetLibraryURL(static_cast<intptr_t>(lib_id)); | |
609 ASSERT_NOT_ERROR(lib_url); | |
610 ASSERT(Dart_IsString(lib_url)); | |
611 msg.Printf("%s{\"id\":%" Pd64 ",\"url\":", (i == 0) ? "" : ", ", lib_id); | |
612 FormatEncodedString(&msg, lib_url); | |
613 msg.Printf("}"); | |
614 } | |
615 msg.Printf("]}}"); | |
616 in_msg->SendReply(&msg); | |
617 return false; | |
618 } | |
619 | |
620 | |
621 bool DbgMessage::HandleGetClassPropsCmd(DbgMessage* in_msg) { | |
622 ASSERT(in_msg != NULL); | |
623 MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len()); | |
624 int msg_id = msg_parser.MessageId(); | |
625 intptr_t cls_id = msg_parser.GetIntParam("classId"); | |
626 dart::TextBuffer msg(64); | |
627 msg.Printf("{\"id\":%d, \"result\":", msg_id); | |
628 const char* err = FormatClassProps(&msg, cls_id); | |
629 if (err != NULL) { | |
630 in_msg->SendErrorReply(msg_id, err); | |
631 return false; | |
632 } | |
633 msg.Printf("}"); | |
634 in_msg->SendReply(&msg); | |
635 return false; | |
636 } | |
637 | |
638 | |
639 bool DbgMessage::HandleGetLibPropsCmd(DbgMessage* in_msg) { | |
640 ASSERT(in_msg != NULL); | |
641 MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len()); | |
642 int msg_id = msg_parser.MessageId(); | |
643 intptr_t lib_id = msg_parser.GetIntParam("libraryId"); | |
644 dart::TextBuffer msg(64); | |
645 msg.Printf("{\"id\":%d, \"result\":", msg_id); | |
646 const char* err = FormatLibraryProps(&msg, lib_id); | |
647 if (err != NULL) { | |
648 in_msg->SendErrorReply(msg_id, err); | |
649 return false; | |
650 } | |
651 msg.Printf("}"); | |
652 in_msg->SendReply(&msg); | |
653 return false; | |
654 } | |
655 | |
656 | |
657 bool DbgMessage::HandleSetLibPropsCmd(DbgMessage* in_msg) { | |
658 ASSERT(in_msg != NULL); | |
659 MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len()); | |
660 int msg_id = msg_parser.MessageId(); | |
661 intptr_t lib_id = msg_parser.GetIntParam("libraryId"); | |
662 const char* enable_request = msg_parser.GetStringParam("debuggingEnabled"); | |
663 bool enable; | |
664 if (strcmp(enable_request, "true") == 0) { | |
665 enable = true; | |
666 } else if (strcmp(enable_request, "false") == 0) { | |
667 enable = false; | |
668 } else { | |
669 in_msg->SendErrorReply(msg_id, "illegal argument for 'debuggingEnabled'"); | |
670 return false; | |
671 } | |
672 Dart_Handle res = Dart_SetLibraryDebuggable(lib_id, enable); | |
673 if (Dart_IsError(res)) { | |
674 in_msg->SendErrorReply(msg_id, Dart_GetError(res)); | |
675 return false; | |
676 } | |
677 bool enabled = false; | |
678 res = Dart_GetLibraryDebuggable(lib_id, &enabled); | |
679 if (Dart_IsError(res)) { | |
680 in_msg->SendErrorReply(msg_id, Dart_GetError(res)); | |
681 return false; | |
682 } | |
683 dart::TextBuffer msg(64); | |
684 msg.Printf("{\"id\":%d, \"result\": {\"debuggingEnabled\": \"%s\"}}", | |
685 msg_id, | |
686 enabled ? "true" : "false"); | |
687 in_msg->SendReply(&msg); | |
688 return false; | |
689 } | |
690 | |
691 | |
692 bool DbgMessage::HandleEvaluateExprCmd(DbgMessage* in_msg) { | |
693 ASSERT(in_msg != NULL); | |
694 MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len()); | |
695 int msg_id = msg_parser.MessageId(); | |
696 Dart_Handle target = Dart_Null(); | |
697 Dart_ActivationFrame frame = NULL; | |
698 | |
699 if (msg_parser.HasParam("libraryId")) { | |
700 intptr_t lib_id = msg_parser.GetIntParam("libraryId"); | |
701 target = Dart_GetLibraryFromId(lib_id); | |
702 } else if (msg_parser.HasParam("classId")) { | |
703 intptr_t cls_id = msg_parser.GetIntParam("classId"); | |
704 target = Dart_GetClassFromId(cls_id); | |
705 } else if (msg_parser.HasParam("objectId")) { | |
706 intptr_t obj_id = msg_parser.GetIntParam("objectId"); | |
707 target = Dart_GetCachedObject(obj_id); | |
708 } else if (msg_parser.HasParam("frameId")) { | |
709 intptr_t frame_index = msg_parser.GetIntParam("frameId"); | |
710 Dart_Handle res; | |
711 Dart_StackTrace stack_trace; | |
712 res = Dart_GetStackTrace(&stack_trace); | |
713 ASSERT_NOT_ERROR(res); | |
714 intptr_t trace_length = 0; | |
715 res = Dart_StackTraceLength(stack_trace, &trace_length); | |
716 ASSERT_NOT_ERROR(res); | |
717 if (frame_index >= trace_length) { | |
718 in_msg->SendErrorReply(msg_id, "illegal frame index"); | |
719 return false; | |
720 } | |
721 res = Dart_GetActivationFrame(stack_trace, frame_index, &frame); | |
722 ASSERT_NOT_ERROR(res); | |
723 } else { | |
724 in_msg->SendErrorReply(msg_id, "illegal evaluation target"); | |
725 return false; | |
726 } | |
727 | |
728 char* expr_chars = msg_parser.GetStringParam("expression"); | |
729 Dart_Handle expr = Dart_NewStringFromCString(expr_chars); | |
730 if (Dart_IsError(expr)) { | |
731 in_msg->SendErrorReply(msg_id, Dart_GetError(expr)); | |
732 return false; | |
733 } | |
734 | |
735 Dart_Handle eval_result = Dart_Null(); | |
736 if (frame != NULL) { | |
737 eval_result = Dart_ActivationFrameEvaluate(frame, expr); | |
738 } else { | |
739 if (Dart_IsError(target)) { | |
740 in_msg->SendErrorReply(msg_id, Dart_GetError(target)); | |
741 return false; | |
742 } | |
743 eval_result = Dart_EvaluateExpr(target, expr); | |
744 } | |
745 if (Dart_IsError(eval_result)) { | |
746 in_msg->SendErrorReply(msg_id, Dart_GetError(eval_result)); | |
747 return false; | |
748 } | |
749 | |
750 dart::TextBuffer msg(64); | |
751 msg.Printf("{\"id\":%d, \"result\":", msg_id); | |
752 FormatRemoteObj(&msg, eval_result); | |
753 msg.Printf("}"); | |
754 in_msg->SendReply(&msg); | |
755 return false; | |
756 } | |
757 | |
758 | |
759 bool DbgMessage::HandleGetObjPropsCmd(DbgMessage* in_msg) { | |
760 ASSERT(in_msg != NULL); | |
761 MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len()); | |
762 int msg_id = msg_parser.MessageId(); | |
763 intptr_t obj_id = msg_parser.GetIntParam("objectId"); | |
764 Dart_Handle obj = Dart_GetCachedObject(obj_id); | |
765 if (Dart_IsError(obj)) { | |
766 in_msg->SendErrorReply(msg_id, Dart_GetError(obj)); | |
767 return false; | |
768 } | |
769 dart::TextBuffer msg(64); | |
770 msg.Printf("{\"id\":%d, \"result\":", msg_id); | |
771 const char* err = FormatObjProps(&msg, obj); | |
772 if (err != NULL) { | |
773 in_msg->SendErrorReply(msg_id, err); | |
774 return false; | |
775 } | |
776 msg.Printf("}"); | |
777 in_msg->SendReply(&msg); | |
778 return false; | |
779 } | |
780 | |
781 | |
782 bool DbgMessage::HandleGetListCmd(DbgMessage* in_msg) { | |
783 const intptr_t kDefaultSliceLength = 100; | |
784 ASSERT(in_msg != NULL); | |
785 MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len()); | |
786 int msg_id = msg_parser.MessageId(); | |
787 intptr_t obj_id = msg_parser.GetIntParam("objectId"); | |
788 Dart_Handle list = Dart_GetCachedObject(obj_id); | |
789 if (Dart_IsError(list)) { | |
790 in_msg->SendErrorReply(msg_id, Dart_GetError(list)); | |
791 return false; | |
792 } | |
793 if (!Dart_IsList(list)) { | |
794 in_msg->SendErrorReply(msg_id, "object is not a list"); | |
795 return false; | |
796 } | |
797 intptr_t list_length = 0; | |
798 Dart_Handle res = Dart_ListLength(list, &list_length); | |
799 if (Dart_IsError(res)) { | |
800 in_msg->SendErrorReply(msg_id, Dart_GetError(res)); | |
801 return false; | |
802 } | |
803 | |
804 intptr_t index = msg_parser.GetIntParam("index"); | |
805 if (index < 0) { | |
806 index = 0; | |
807 } else if (index > list_length) { | |
808 index = list_length; | |
809 } | |
810 | |
811 // If no slice length is given, get only one element. If slice length | |
812 // is given as 0, get entire list. | |
813 intptr_t slice_length = msg_parser.GetOptIntParam("length", 1); | |
814 if (slice_length == 0) { | |
815 slice_length = list_length - index; | |
816 } | |
817 if ((index + slice_length) > list_length) { | |
818 slice_length = list_length - index; | |
819 } | |
820 ASSERT(slice_length >= 0); | |
821 if (slice_length > kDefaultSliceLength) { | |
822 slice_length = kDefaultSliceLength; | |
823 } | |
824 dart::TextBuffer msg(64); | |
825 msg.Printf("{\"id\":%d, \"result\":", msg_id); | |
826 if (slice_length == 1) { | |
827 Dart_Handle value = Dart_ListGetAt(list, index); | |
828 FormatRemoteObj(&msg, value); | |
829 } else { | |
830 FormatListSlice(&msg, list, list_length, index, slice_length); | |
831 } | |
832 msg.Printf("}"); | |
833 in_msg->SendReply(&msg); | |
834 return false; | |
835 } | |
836 | |
837 | |
838 bool DbgMessage::HandleGetGlobalsCmd(DbgMessage* in_msg) { | |
839 ASSERT(in_msg != NULL); | |
840 MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len()); | |
841 int msg_id = msg_parser.MessageId(); | |
842 intptr_t lib_id = msg_parser.GetIntParam("libraryId"); | |
843 dart::TextBuffer msg(64); | |
844 msg.Printf("{\"id\":%d, \"result\": { \"globals\":", msg_id); | |
845 Dart_Handle globals = Dart_GetGlobalVariables(lib_id); | |
846 ASSERT_NOT_ERROR(globals); | |
847 FormatNamedValueList(&msg, globals); | |
848 msg.Printf("}}"); | |
849 in_msg->SendReply(&msg); | |
850 return false; | |
851 } | |
852 | |
853 | |
854 bool DbgMessage::HandleGetScriptURLsCmd(DbgMessage* in_msg) { | |
855 ASSERT(in_msg != NULL); | |
856 MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len()); | |
857 int msg_id = msg_parser.MessageId(); | |
858 dart::TextBuffer msg(64); | |
859 intptr_t lib_id = msg_parser.GetIntParam("libraryId"); | |
860 Dart_Handle lib_url = Dart_GetLibraryURL(lib_id); | |
861 ASSERT_NOT_ERROR(lib_url); | |
862 Dart_Handle urls = Dart_GetScriptURLs(lib_url); | |
863 if (Dart_IsError(urls)) { | |
864 in_msg->SendErrorReply(msg_id, Dart_GetError(urls)); | |
865 return false; | |
866 } | |
867 ASSERT(Dart_IsList(urls)); | |
868 intptr_t num_urls = 0; | |
869 Dart_ListLength(urls, &num_urls); | |
870 msg.Printf("{ \"id\": %d, ", msg_id); | |
871 msg.Printf("\"result\": { \"urls\": ["); | |
872 for (int i = 0; i < num_urls; i++) { | |
873 Dart_Handle script_url = Dart_ListGetAt(urls, i); | |
874 if (i > 0) { | |
875 msg.Printf(","); | |
876 } | |
877 FormatEncodedString(&msg, script_url); | |
878 } | |
879 msg.Printf("]}}"); | |
880 in_msg->SendReply(&msg); | |
881 return false; | |
882 } | |
883 | |
884 | |
885 bool DbgMessage::HandleGetSourceCmd(DbgMessage* in_msg) { | |
886 ASSERT(in_msg != NULL); | |
887 MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len()); | |
888 int msg_id = msg_parser.MessageId(); | |
889 dart::TextBuffer msg(64); | |
890 intptr_t lib_id = msg_parser.GetIntParam("libraryId"); | |
891 char* url_chars = msg_parser.GetStringParam("url"); | |
892 ASSERT(url_chars != NULL); | |
893 Dart_Handle url = DartUtils::NewString(url_chars); | |
894 ASSERT_NOT_ERROR(url); | |
895 free(url_chars); | |
896 url_chars = NULL; | |
897 Dart_Handle source = Dart_ScriptGetSource(lib_id, url); | |
898 if (Dart_IsError(source)) { | |
899 in_msg->SendErrorReply(msg_id, Dart_GetError(source)); | |
900 return false; | |
901 } | |
902 msg.Printf("{ \"id\": %d, ", msg_id); | |
903 msg.Printf("\"result\": { \"text\": "); | |
904 FormatEncodedString(&msg, source); | |
905 msg.Printf("}}"); | |
906 in_msg->SendReply(&msg); | |
907 return false; | |
908 } | |
909 | |
910 | |
911 bool DbgMessage::HandleGetLineNumbersCmd(DbgMessage* in_msg) { | |
912 ASSERT(in_msg != NULL); | |
913 MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len()); | |
914 int msg_id = msg_parser.MessageId(); | |
915 dart::TextBuffer msg(64); | |
916 intptr_t lib_id = msg_parser.GetIntParam("libraryId"); | |
917 char* url_chars = msg_parser.GetStringParam("url"); | |
918 ASSERT(url_chars != NULL); | |
919 Dart_Handle url = DartUtils::NewString(url_chars); | |
920 ASSERT_NOT_ERROR(url); | |
921 free(url_chars); | |
922 url_chars = NULL; | |
923 Dart_Handle info = Dart_ScriptGetTokenInfo(lib_id, url); | |
924 if (Dart_IsError(info)) { | |
925 in_msg->SendErrorReply(msg_id, Dart_GetError(info)); | |
926 return false; | |
927 } | |
928 ASSERT(Dart_IsList(info)); | |
929 intptr_t info_len = 0; | |
930 Dart_Handle res = Dart_ListLength(info, &info_len); | |
931 ASSERT_NOT_ERROR(res); | |
932 msg.Printf("{ \"id\": %d, ", msg_id); | |
933 msg.Printf("\"result\": { \"lines\": ["); | |
934 Dart_Handle elem; | |
935 intptr_t num_elems = 0; | |
936 for (intptr_t i = 0; i < info_len; i++) { | |
937 elem = Dart_ListGetAt(info, i); | |
938 if (Dart_IsNull(elem)) { | |
939 msg.Printf((i == 0) ? "[" : "], ["); | |
940 num_elems = 0; | |
941 } else { | |
942 ASSERT(Dart_IsInteger(elem)); | |
943 int64_t value = GetIntValue(elem); | |
944 if (num_elems == 0) { | |
945 msg.Printf("%" Pd64 "", value); | |
946 } else { | |
947 msg.Printf(",%" Pd64 "", value); | |
948 } | |
949 num_elems++; | |
950 } | |
951 } | |
952 msg.Printf("]]}}"); | |
953 in_msg->SendReply(&msg); | |
954 return false; | |
955 } | |
956 | |
957 | |
958 bool DbgMessage::HandleGetStackTraceCmd(DbgMessage* in_msg) { | |
959 ASSERT(in_msg != NULL); | |
960 MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len()); | |
961 int msg_id = msg_parser.MessageId(); | |
962 Dart_StackTrace trace; | |
963 Dart_Handle res = Dart_GetStackTrace(&trace); | |
964 ASSERT_NOT_ERROR(res); | |
965 dart::TextBuffer msg(128); | |
966 msg.Printf("{ \"id\": %d, \"result\": {", msg_id); | |
967 FormatCallFrames(&msg, trace); | |
968 msg.Printf("}}"); | |
969 in_msg->SendReply(&msg); | |
970 return false; | |
971 } | |
972 | |
973 | |
974 bool DbgMessage::HandleSetBpCmd(DbgMessage* in_msg) { | |
975 ASSERT(in_msg != NULL); | |
976 MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len()); | |
977 int msg_id = msg_parser.MessageId(); | |
978 char* url_chars = msg_parser.GetStringParam("url"); | |
979 ASSERT(url_chars != NULL); | |
980 Dart_Handle url = DartUtils::NewString(url_chars); | |
981 ASSERT_NOT_ERROR(url); | |
982 free(url_chars); | |
983 url_chars = NULL; | |
984 intptr_t line_number = msg_parser.GetIntParam("line"); | |
985 Dart_Handle bp_id = Dart_SetBreakpoint(url, line_number); | |
986 if (Dart_IsError(bp_id)) { | |
987 in_msg->SendErrorReply(msg_id, Dart_GetError(bp_id)); | |
988 return false; | |
989 } | |
990 ASSERT(Dart_IsInteger(bp_id)); | |
991 uint64_t bp_id_value; | |
992 Dart_Handle res = Dart_IntegerToUint64(bp_id, &bp_id_value); | |
993 ASSERT_NOT_ERROR(res); | |
994 dart::TextBuffer msg(64); | |
995 msg.Printf("{ \"id\": %d, \"result\": { \"breakpointId\": %" Pu64 " }}", | |
996 msg_id, bp_id_value); | |
997 in_msg->SendReply(&msg); | |
998 return false; | |
999 } | |
1000 | |
1001 | |
1002 bool DbgMessage::HandlePauseOnExcCmd(DbgMessage* in_msg) { | |
1003 ASSERT(in_msg != NULL); | |
1004 MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len()); | |
1005 int msg_id = msg_parser.MessageId(); | |
1006 char* exc_chars = msg_parser.GetStringParam("exceptions"); | |
1007 Dart_ExceptionPauseInfo info = kNoPauseOnExceptions; | |
1008 if (strcmp(exc_chars, "none") == 0) { | |
1009 info = kNoPauseOnExceptions; | |
1010 } else if (strcmp(exc_chars, "all") == 0) { | |
1011 info = kPauseOnAllExceptions; | |
1012 } else if (strcmp(exc_chars, "unhandled") == 0) { | |
1013 info = kPauseOnUnhandledExceptions; | |
1014 } else { | |
1015 in_msg->SendErrorReply(msg_id, "illegal value for parameter 'exceptions'"); | |
1016 return false; | |
1017 } | |
1018 Dart_Handle res = Dart_SetExceptionPauseInfo(info); | |
1019 ASSERT_NOT_ERROR(res); | |
1020 dart::TextBuffer msg(32); | |
1021 msg.Printf("{ \"id\": %d }", msg_id); | |
1022 in_msg->SendReply(&msg); | |
1023 return false; | |
1024 } | |
1025 | |
1026 | |
1027 bool DbgMessage::HandleRemBpCmd(DbgMessage* in_msg) { | |
1028 ASSERT(in_msg != NULL); | |
1029 MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len()); | |
1030 int msg_id = msg_parser.MessageId(); | |
1031 int bpt_id = msg_parser.GetIntParam("breakpointId"); | |
1032 Dart_Handle res = Dart_RemoveBreakpoint(bpt_id); | |
1033 if (Dart_IsError(res)) { | |
1034 in_msg->SendErrorReply(msg_id, Dart_GetError(res)); | |
1035 return false; | |
1036 } | |
1037 dart::TextBuffer msg(32); | |
1038 msg.Printf("{ \"id\": %d }", msg_id); | |
1039 in_msg->SendReply(&msg); | |
1040 return false; | |
1041 } | |
1042 | |
1043 | |
1044 void DbgMsgQueue::AddMessage(int32_t cmd_idx, | |
1045 const char* start, | |
1046 const char* end, | |
1047 intptr_t debug_fd) { | |
1048 if ((end > start) && ((end - start) < kMaxInt32)) { | |
1049 MonitorLocker ml(&msg_queue_lock_); | |
1050 DbgMessage* msg = new DbgMessage(cmd_idx, start, end, debug_fd); | |
1051 if (msglist_head_ == NULL) { | |
1052 ASSERT(msglist_tail_ == NULL); | |
1053 msglist_head_ = msg; | |
1054 msglist_tail_ = msg; | |
1055 ml.Notify(); | |
1056 } else { | |
1057 ASSERT(msglist_tail_ != NULL); | |
1058 msglist_tail_->set_next(msg); | |
1059 msglist_tail_ = msg; | |
1060 } | |
1061 } | |
1062 } | |
1063 | |
1064 | |
1065 void DbgMsgQueue::Notify() { | |
1066 MonitorLocker ml(&msg_queue_lock_); | |
1067 ml.Notify(); | |
1068 } | |
1069 | |
1070 | |
1071 bool DbgMsgQueue::HandlePendingMessages() { | |
1072 // Handle all available debug messages, up to a resume request. | |
1073 bool resume_requested = false; | |
1074 while (msglist_head_ != NULL && !resume_requested) { | |
1075 ASSERT(msglist_tail_ != NULL); | |
1076 DbgMessage* msg = msglist_head_; | |
1077 msglist_head_ = msglist_head_->next(); | |
1078 if (msglist_head_ == NULL) { | |
1079 msglist_tail_ = NULL; | |
1080 } | |
1081 resume_requested = msg->HandleMessage(); | |
1082 delete msg; | |
1083 } | |
1084 return resume_requested; | |
1085 } | |
1086 | |
1087 | |
1088 void DbgMsgQueue::MessageLoop() { | |
1089 MonitorLocker ml(&msg_queue_lock_); | |
1090 is_running_ = false; | |
1091 | |
1092 // Request notification on isolate messages. This allows us to | |
1093 // respond to vm service messages while at breakpoint. | |
1094 Dart_SetMessageNotifyCallback(DbgMsgQueueList::NotifyIsolate); | |
1095 | |
1096 while (true) { | |
1097 // Handle all available vm service messages, up to a resume | |
1098 // request. | |
1099 bool resume = false; | |
1100 while (!resume && Dart_HasServiceMessages()) { | |
1101 msg_queue_lock_.Exit(); | |
1102 resume = Dart_HandleServiceMessages(); | |
1103 msg_queue_lock_.Enter(); | |
1104 } | |
1105 if (resume) { | |
1106 break; | |
1107 } | |
1108 | |
1109 // Handle all available debug messages, up to a resume request. | |
1110 if (HandlePendingMessages()) { | |
1111 break; | |
1112 } | |
1113 | |
1114 // Wait for more debug or vm service messages. | |
1115 Monitor::WaitResult res = ml.Wait(); | |
1116 ASSERT(res == Monitor::kNotified); | |
1117 } | |
1118 Dart_SetMessageNotifyCallback(NULL); | |
1119 is_interrupted_ = false; | |
1120 is_running_ = true; | |
1121 } | |
1122 | |
1123 | |
1124 void DbgMsgQueue::InterruptIsolate() { | |
1125 Dart_Isolate isolate = Dart_GetIsolate(isolate_id_); | |
1126 MonitorLocker ml(&msg_queue_lock_); | |
1127 if (is_running_ && !is_interrupted_) { | |
1128 is_interrupted_ = true; | |
1129 Dart_InterruptIsolate(isolate); | |
1130 } | |
1131 } | |
1132 | |
1133 | |
1134 void DbgMsgQueue::QueueOutputMsg(dart::TextBuffer* msg) { | |
1135 queued_output_messages_.Printf("%s", msg->buf()); | |
1136 } | |
1137 | |
1138 | |
1139 void DbgMsgQueue::SendQueuedMsgs() { | |
1140 if (queued_output_messages_.length() > 0) { | |
1141 DebuggerConnectionHandler::BroadcastMsg(&queued_output_messages_); | |
1142 queued_output_messages_.Clear(); | |
1143 } | |
1144 } | |
1145 | |
1146 | |
1147 void DbgMsgQueue::SendBreakpointEvent(intptr_t bp_id, | |
1148 const Dart_CodeLocation& location) { | |
1149 dart::TextBuffer msg(128); | |
1150 msg.Printf("{ \"event\": \"paused\", \"params\": { "); | |
1151 msg.Printf("\"reason\": \"breakpoint\", "); | |
1152 msg.Printf("\"isolateId\": %" Pd64 "", isolate_id_); | |
1153 if (bp_id != ILLEGAL_BREAKPOINT_ID) { | |
1154 msg.Printf(",\"breakpointId\": %" Pd "", bp_id); | |
1155 } | |
1156 if (!Dart_IsNull(location.script_url)) { | |
1157 ASSERT(Dart_IsString(location.script_url)); | |
1158 msg.Printf(",\"location\": { \"url\":"); | |
1159 FormatEncodedString(&msg, location.script_url); | |
1160 msg.Printf(",\"libraryId\":%d,", location.library_id); | |
1161 msg.Printf("\"tokenOffset\":%d}", location.token_pos); | |
1162 } | |
1163 msg.Printf("}}"); | |
1164 DebuggerConnectionHandler::BroadcastMsg(&msg); | |
1165 } | |
1166 | |
1167 | |
1168 // TODO(hausner): Remove stack trace parameter once we remove the stack | |
1169 // trace from the paused event in the wire protocol. | |
1170 void DbgMsgQueue::SendExceptionEvent(Dart_Handle exception, | |
1171 Dart_StackTrace stack_trace) { | |
1172 intptr_t exception_id = Dart_CacheObject(exception); | |
1173 ASSERT(exception_id >= 0); | |
1174 dart::TextBuffer msg(128); | |
1175 msg.Printf("{ \"event\": \"paused\", \"params\": {"); | |
1176 msg.Printf("\"reason\": \"exception\", "); | |
1177 msg.Printf("\"isolateId\": %" Pd64 ", ", isolate_id_); | |
1178 msg.Printf("\"exception\":"); | |
1179 FormatRemoteObj(&msg, exception); | |
1180 FormatLocationFromTrace(&msg, stack_trace, ", "); | |
1181 msg.Printf("}}"); | |
1182 DebuggerConnectionHandler::BroadcastMsg(&msg); | |
1183 } | |
1184 | |
1185 | |
1186 // TODO(hausner): Remove stack trace parameter once we remove the stack | |
1187 // trace from the interrupted event in the wire protocol. | |
1188 void DbgMsgQueue::SendIsolateEvent(Dart_IsolateId isolate_id, | |
1189 Dart_IsolateEvent kind) { | |
1190 dart::TextBuffer msg(128); | |
1191 if (kind == kInterrupted) { | |
1192 Dart_StackTrace trace; | |
1193 Dart_Handle res = Dart_GetStackTrace(&trace); | |
1194 ASSERT_NOT_ERROR(res); | |
1195 msg.Printf("{ \"event\": \"paused\", \"params\": { "); | |
1196 msg.Printf("\"reason\": \"interrupted\", "); | |
1197 msg.Printf("\"isolateId\": %" Pd64 "", isolate_id); | |
1198 FormatLocationFromTrace(&msg, trace, ", "); | |
1199 msg.Printf("}}"); | |
1200 } else { | |
1201 msg.Printf("{ \"event\": \"isolate\", \"params\": { "); | |
1202 if (kind == kCreated) { | |
1203 msg.Printf("\"reason\": \"created\", "); | |
1204 } else { | |
1205 ASSERT(kind == kShutdown); | |
1206 msg.Printf("\"reason\": \"shutdown\", "); | |
1207 } | |
1208 msg.Printf("\"id\": %" Pd64 " ", isolate_id); | |
1209 msg.Printf("}}"); | |
1210 } | |
1211 DebuggerConnectionHandler::BroadcastMsg(&msg); | |
1212 } | |
1213 | |
1214 | |
1215 DbgMsgQueue* DbgMsgQueueList::list_ = NULL; | |
1216 Mutex* DbgMsgQueueList::msg_queue_list_lock_ = new Mutex(); | |
1217 | |
1218 | |
1219 void DbgMsgQueueList::Initialize() { | |
1220 // Setup handlers for isolate events, breakpoints, exceptions and | |
1221 // delayed breakpoints. | |
1222 Dart_SetIsolateEventHandler(IsolateEventHandler); | |
1223 Dart_SetPausedEventHandler(PausedEventHandler); | |
1224 Dart_SetBreakpointResolvedHandler(BptResolvedHandler); | |
1225 Dart_SetExceptionThrownHandler(ExceptionThrownHandler); | |
1226 } | |
1227 | |
1228 | |
1229 int32_t DbgMsgQueueList::LookupIsolateCommand(const char* buf, | |
1230 int32_t buflen) { | |
1231 // Check if we have a isolate specific debugger command. | |
1232 int32_t i = 0; | |
1233 while (debugger_commands[i].cmd_string != NULL) { | |
1234 if (strncmp(buf, debugger_commands[i].cmd_string, buflen) == 0) { | |
1235 return i; | |
1236 } | |
1237 i++; | |
1238 } | |
1239 return kInvalidCommand; | |
1240 } | |
1241 | |
1242 | |
1243 bool DbgMsgQueueList::AddIsolateMessage(Dart_IsolateId isolate_id, | |
1244 int32_t cmd_idx, | |
1245 const char* start, | |
1246 const char* end, | |
1247 intptr_t debug_fd) { | |
1248 MutexLocker ml(msg_queue_list_lock_); | |
1249 DbgMsgQueue* queue = DbgMsgQueueList::GetIsolateMsgQueueLocked(isolate_id); | |
1250 if (queue != NULL) { | |
1251 queue->AddMessage(cmd_idx, start, end, debug_fd); | |
1252 return true; | |
1253 } | |
1254 return false; | |
1255 } | |
1256 | |
1257 | |
1258 void DbgMsgQueueList::NotifyIsolate(Dart_Isolate isolate) { | |
1259 MutexLocker ml(msg_queue_list_lock_); | |
1260 Dart_IsolateId isolate_id = Dart_GetIsolateId(isolate); | |
1261 DbgMsgQueue* queue = DbgMsgQueueList::GetIsolateMsgQueueLocked(isolate_id); | |
1262 if (queue != NULL) { | |
1263 queue->Notify(); | |
1264 } | |
1265 } | |
1266 | |
1267 | |
1268 bool DbgMsgQueueList::InterruptIsolate(Dart_IsolateId isolate_id) { | |
1269 MutexLocker ml(msg_queue_list_lock_); | |
1270 DbgMsgQueue* queue = DbgMsgQueueList::GetIsolateMsgQueueLocked(isolate_id); | |
1271 if (queue != NULL) { | |
1272 queue->InterruptIsolate(); | |
1273 return true; | |
1274 } | |
1275 return false; | |
1276 } | |
1277 | |
1278 | |
1279 DbgMsgQueue* DbgMsgQueueList::AddIsolateMsgQueue(Dart_IsolateId isolate_id) { | |
1280 MutexLocker ml(msg_queue_list_lock_); | |
1281 | |
1282 DbgMsgQueue* queue = new DbgMsgQueue(isolate_id, list_); | |
1283 ASSERT(queue != NULL); | |
1284 list_ = queue; | |
1285 return queue; | |
1286 } | |
1287 | |
1288 | |
1289 DbgMsgQueue* DbgMsgQueueList::GetIsolateMsgQueue(Dart_IsolateId isolate_id) { | |
1290 MutexLocker ml(msg_queue_list_lock_); | |
1291 ASSERT(Dart_GetIsolate(isolate_id) == Dart_CurrentIsolate()); | |
1292 return GetIsolateMsgQueueLocked(isolate_id); | |
1293 } | |
1294 | |
1295 | |
1296 DbgMsgQueue* DbgMsgQueueList::GetIsolateMsgQueueLocked(Dart_IsolateId id) { | |
1297 if (list_ == NULL) { | |
1298 return NULL; // No items in the list. | |
1299 } | |
1300 | |
1301 // Find message queue corresponding to isolate id. | |
1302 DbgMsgQueue* iterator = list_; | |
1303 while (iterator != NULL && iterator->isolate_id() != id) { | |
1304 iterator = iterator->next(); | |
1305 } | |
1306 return iterator; | |
1307 } | |
1308 | |
1309 | |
1310 void DbgMsgQueueList::RemoveIsolateMsgQueue(Dart_IsolateId isolate_id) { | |
1311 MutexLocker ml(msg_queue_list_lock_); | |
1312 if (list_ == NULL) { | |
1313 return; // No items in the list. | |
1314 } | |
1315 DbgMsgQueue* queue = list_; | |
1316 if (queue->isolate_id() == isolate_id) { | |
1317 list_ = queue->next(); // Remove from list. | |
1318 delete queue; // Delete the message queue. | |
1319 return; | |
1320 } else { | |
1321 DbgMsgQueue* iterator = queue; | |
1322 queue = queue->next(); | |
1323 while (queue != NULL) { | |
1324 if (queue->isolate_id() == isolate_id) { | |
1325 iterator->set_next(queue->next()); // Remove from list. | |
1326 delete queue; // Delete the message queue. | |
1327 return; | |
1328 } | |
1329 iterator = queue; | |
1330 queue = queue->next(); | |
1331 } | |
1332 } | |
1333 UNREACHABLE(); | |
1334 } | |
1335 | |
1336 | |
1337 void DbgMsgQueueList::ListIsolateIds(dart::TextBuffer* msg) { | |
1338 MutexLocker ml(msg_queue_list_lock_); | |
1339 if (list_ == NULL) { | |
1340 return; // No items in the list. | |
1341 } | |
1342 DbgMsgQueue* queue = list_; | |
1343 msg->Printf("%" Pd64 "", queue->isolate_id()); | |
1344 queue = queue->next(); | |
1345 while (queue != NULL) { | |
1346 msg->Printf(",%" Pd64 "", queue->isolate_id()); | |
1347 queue = queue->next(); | |
1348 } | |
1349 } | |
1350 | |
1351 | |
1352 void DbgMsgQueueList::BptResolvedHandler(Dart_IsolateId isolate_id, | |
1353 intptr_t bp_id, | |
1354 const Dart_CodeLocation& location) { | |
1355 Dart_EnterScope(); | |
1356 dart::TextBuffer msg(128); | |
1357 msg.Printf("{ \"event\": \"breakpointResolved\", \"params\": {"); | |
1358 msg.Printf("\"breakpointId\": %" Pd "", bp_id); | |
1359 | |
1360 msg.Printf(", \"isolateId\":%" Pd64 "", isolate_id); | |
1361 ASSERT(!Dart_IsNull(location.script_url)); | |
1362 ASSERT(Dart_IsString(location.script_url)); | |
1363 msg.Printf(", \"location\":{\"url\":"); | |
1364 FormatEncodedString(&msg, location.script_url); | |
1365 msg.Printf(",\"libraryId\":%d", location.library_id); | |
1366 msg.Printf(",\"tokenOffset\":%d}}}", location.token_pos); | |
1367 | |
1368 DbgMsgQueue* msg_queue = GetIsolateMsgQueue(isolate_id); | |
1369 ASSERT(msg_queue != NULL); | |
1370 msg_queue->QueueOutputMsg(&msg); | |
1371 Dart_ExitScope(); | |
1372 } | |
1373 | |
1374 | |
1375 void DbgMsgQueueList::PausedEventHandler(Dart_IsolateId isolate_id, | |
1376 intptr_t bp_id, | |
1377 const Dart_CodeLocation& loc) { | |
1378 DebuggerConnectionHandler::WaitForConnection(); | |
1379 Dart_EnterScope(); | |
1380 DbgMsgQueue* msg_queue = GetIsolateMsgQueue(isolate_id); | |
1381 ASSERT(msg_queue != NULL); | |
1382 msg_queue->SendQueuedMsgs(); | |
1383 msg_queue->SendBreakpointEvent(bp_id, loc); | |
1384 msg_queue->MessageLoop(); | |
1385 Dart_ExitScope(); | |
1386 } | |
1387 | |
1388 | |
1389 void DbgMsgQueueList::ExceptionThrownHandler(Dart_IsolateId isolate_id, | |
1390 Dart_Handle exception, | |
1391 Dart_StackTrace stack_trace) { | |
1392 DebuggerConnectionHandler::WaitForConnection(); | |
1393 Dart_EnterScope(); | |
1394 DbgMsgQueue* msg_queue = GetIsolateMsgQueue(isolate_id); | |
1395 ASSERT(msg_queue != NULL); | |
1396 msg_queue->SendQueuedMsgs(); | |
1397 msg_queue->SendExceptionEvent(exception, stack_trace); | |
1398 msg_queue->MessageLoop(); | |
1399 Dart_ExitScope(); | |
1400 } | |
1401 | |
1402 | |
1403 void DbgMsgQueueList::IsolateEventHandler(Dart_IsolateId isolate_id, | |
1404 Dart_IsolateEvent kind) { | |
1405 if (kind == kCreated) { | |
1406 DebuggerConnectionHandler::WaitForConnection(); | |
1407 Dart_EnterScope(); | |
1408 DbgMsgQueue* msg_queue = AddIsolateMsgQueue(isolate_id); | |
1409 msg_queue->SendIsolateEvent(isolate_id, kind); | |
1410 Dart_ExitScope(); | |
1411 } else { | |
1412 DebuggerConnectionHandler::WaitForConnection(); | |
1413 DbgMsgQueue* msg_queue = GetIsolateMsgQueue(isolate_id); | |
1414 ASSERT(msg_queue != NULL); | |
1415 Dart_EnterScope(); | |
1416 msg_queue->SendQueuedMsgs(); | |
1417 msg_queue->SendIsolateEvent(isolate_id, kind); | |
1418 if (kind == kInterrupted) { | |
1419 msg_queue->MessageLoop(); | |
1420 } else { | |
1421 ASSERT(kind == kShutdown); | |
1422 RemoveIsolateMsgQueue(isolate_id); | |
1423 } | |
1424 Dart_ExitScope(); | |
1425 // If there is no receive message queue, do not wait for a connection, and | |
1426 // ignore the message. | |
1427 } | |
1428 } | |
1429 | |
1430 } // namespace bin | |
1431 } // namespace dart | |
OLD | NEW |