| // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| #include "bin/dbg_connection.h" |
| #include "bin/dbg_message.h" |
| #include "bin/dartutils.h" |
| #include "bin/lockers.h" |
| #include "bin/thread.h" |
| #include "bin/utils.h" |
| |
| #include "platform/globals.h" |
| #include "platform/json.h" |
| #include "platform/utils.h" |
| |
| #include "include/dart_api.h" |
| |
| |
| namespace dart { |
| namespace bin { |
| |
| bool MessageParser::IsValidMessage() const { |
| if (buf_length_ == 0) { |
| return false; |
| } |
| dart::JSONReader msg_reader(buf_); |
| return msg_reader.EndOfObject() != NULL; |
| } |
| |
| |
| int MessageParser::MessageId() const { |
| dart::JSONReader r(buf_); |
| r.Seek("id"); |
| if (r.Type() == dart::JSONReader::kInteger) { |
| return atoi(r.ValueChars()); |
| } else { |
| return -1; |
| } |
| } |
| |
| |
| const char* MessageParser::Params() const { |
| dart::JSONReader r(buf_); |
| r.Seek("params"); |
| if (r.Type() == dart::JSONReader::kObject) { |
| return r.ValueChars(); |
| } else { |
| return NULL; |
| } |
| } |
| |
| |
| bool MessageParser::HasParam(const char* name) const { |
| const char* params = Params(); |
| ASSERT(params != NULL); |
| dart::JSONReader r(params); |
| return r.Seek(name); |
| } |
| |
| |
| intptr_t MessageParser::GetIntParam(const char* name) const { |
| const char* params = Params(); |
| ASSERT(params != NULL); |
| dart::JSONReader r(params); |
| r.Seek(name); |
| ASSERT(r.Type() == dart::JSONReader::kInteger); |
| return strtol(r.ValueChars(), NULL, 10); |
| } |
| |
| |
| int64_t MessageParser::GetInt64Param(const char* name) const { |
| const char* params = Params(); |
| ASSERT(params != NULL); |
| dart::JSONReader r(params); |
| r.Seek(name); |
| ASSERT(r.Type() == dart::JSONReader::kInteger); |
| return strtoll(r.ValueChars(), NULL, 10); |
| } |
| |
| |
| intptr_t MessageParser::GetOptIntParam(const char* name, |
| intptr_t default_val) const { |
| const char* params = Params(); |
| ASSERT(params != NULL); |
| dart::JSONReader r(params); |
| r.Seek(name); |
| if (r.Type() == dart::JSONReader::kInteger) { |
| return strtol(r.ValueChars(), NULL, 10); |
| } else { |
| return default_val; |
| } |
| } |
| |
| |
| static const char* GetStringChars(Dart_Handle str) { |
| ASSERT(Dart_IsString(str)); |
| const char* chars; |
| Dart_Handle res = Dart_StringToCString(str, &chars); |
| ASSERT(!Dart_IsError(res)); |
| return chars; |
| } |
| |
| |
| static int64_t GetIntValue(Dart_Handle int_handle) { |
| int64_t int64_val = -1; |
| ASSERT(Dart_IsInteger(int_handle)); |
| Dart_Handle res = Dart_IntegerToInt64(int_handle, &int64_val); |
| ASSERT_NOT_ERROR(res); |
| return int64_val; |
| } |
| |
| |
| char* MessageParser::GetStringParam(const char* name) const { |
| const char* params = Params(); |
| ASSERT(params != NULL); |
| dart::JSONReader pr(params); |
| pr.Seek(name); |
| if (pr.Type() != dart::JSONReader::kString) { |
| return NULL; |
| } |
| intptr_t buflen = pr.ValueLen() + 1; |
| char* param_chars = reinterpret_cast<char*>(malloc(buflen)); |
| pr.GetDecodedValueChars(param_chars, buflen); |
| return param_chars; |
| } |
| |
| |
| static void FormatEncodedCharsTrunc(dart::TextBuffer* buf, |
| Dart_Handle str, |
| intptr_t max_chars) { |
| intptr_t str_len = 0; |
| Dart_Handle res = Dart_StringLength(str, &str_len); |
| ASSERT_NOT_ERROR(res); |
| intptr_t num_chars = (str_len > max_chars) ? max_chars : str_len; |
| uint16_t* codeunits = |
| reinterpret_cast<uint16_t*>(malloc(num_chars * sizeof(uint16_t))); |
| ASSERT(codeunits != NULL); |
| intptr_t actual_len = num_chars; |
| res = Dart_StringToUTF16(str, codeunits, &actual_len); |
| ASSERT_NOT_ERROR(res); |
| ASSERT(num_chars == actual_len); |
| for (int i = 0; i < num_chars; i++) { |
| buf->EscapeAndAddCodeUnit(codeunits[i]); |
| } |
| if (str_len > max_chars) { |
| buf->Printf("..."); |
| } |
| free(codeunits); |
| } |
| |
| |
| static void FormatEncodedChars(dart::TextBuffer* buf, Dart_Handle str) { |
| intptr_t str_len = 0; |
| Dart_Handle res = Dart_StringLength(str, &str_len); |
| ASSERT_NOT_ERROR(res); |
| uint16_t* codeunits = |
| reinterpret_cast<uint16_t*>(malloc(str_len * sizeof(uint16_t))); |
| ASSERT(codeunits != NULL); |
| intptr_t actual_len = str_len; |
| res = Dart_StringToUTF16(str, codeunits, &actual_len); |
| ASSERT_NOT_ERROR(res); |
| ASSERT(str_len == actual_len); |
| for (int i = 0; i < str_len; i++) { |
| buf->EscapeAndAddCodeUnit(codeunits[i]); |
| } |
| free(codeunits); |
| } |
| |
| |
| static void FormatEncodedString(dart::TextBuffer* buf, Dart_Handle str) { |
| buf->AddChar('\"'); |
| FormatEncodedChars(buf, str); |
| buf->AddChar('\"'); |
| } |
| |
| |
| static void FormatTextualValue(dart::TextBuffer* buf, |
| Dart_Handle object, |
| intptr_t max_chars, |
| bool expand_list); |
| |
| |
| static void FormatTextualListValue(dart::TextBuffer* buf, |
| Dart_Handle list, |
| intptr_t max_chars) { |
| intptr_t len = 0; |
| Dart_Handle res = Dart_ListLength(list, &len); |
| ASSERT_NOT_ERROR(res); |
| const intptr_t initial_buffer_length = buf->length(); |
| // Maximum number of characters we print for array elements. |
| const intptr_t max_buffer_length = initial_buffer_length + max_chars; |
| buf->Printf("["); |
| for (int i = 0; i < len; i++) { |
| if (i > 0) { |
| buf->Printf(", "); |
| } |
| Dart_Handle elem = Dart_ListGetAt(list, i); |
| const intptr_t max_element_chars = 50; |
| FormatTextualValue(buf, elem, max_element_chars, false); |
| if (buf->length() > max_buffer_length) { |
| buf->Printf(", ..."); |
| break; |
| } |
| } |
| buf->Printf("]"); |
| } |
| |
| |
| static void FormatTextualValue(dart::TextBuffer* buf, |
| Dart_Handle object, |
| intptr_t max_chars, |
| bool expand_list) { |
| ASSERT(!Dart_IsError(object)); |
| if (Dart_IsList(object)) { |
| if (expand_list) { |
| FormatTextualListValue(buf, object, max_chars); |
| } else { |
| buf->Printf("[...]"); |
| } |
| } else if (Dart_IsNull(object)) { |
| buf->Printf("null"); |
| } else if (Dart_IsString(object)) { |
| buf->Printf("\\\""); |
| FormatEncodedCharsTrunc(buf, object, max_chars); |
| buf->Printf("\\\""); |
| } else if (Dart_IsNumber(object) || Dart_IsBoolean(object)) { |
| Dart_Handle text = Dart_ToString(object); |
| ASSERT(!Dart_IsNull(text) && !Dart_IsError(text)); |
| FormatEncodedCharsTrunc(buf, text, max_chars); |
| } else { |
| Dart_Handle type = Dart_InstanceGetType(object); |
| ASSERT_NOT_ERROR(type); |
| type = Dart_ToString(type); |
| ASSERT_NOT_ERROR(type); |
| buf->Printf("object of type "); |
| FormatEncodedCharsTrunc(buf, type, max_chars); |
| } |
| } |
| |
| |
| static void FormatValue(dart::TextBuffer* buf, Dart_Handle object) { |
| bool print_text_field = true; |
| if (Dart_IsNumber(object)) { |
| buf->Printf("\"kind\":\"number\""); |
| } else if (Dart_IsString(object)) { |
| buf->Printf("\"kind\":\"string\""); |
| } else if (Dart_IsBoolean(object)) { |
| buf->Printf("\"kind\":\"boolean\""); |
| } else if (Dart_IsList(object)) { |
| intptr_t len = 0; |
| Dart_Handle res = Dart_ListLength(object, &len); |
| ASSERT_NOT_ERROR(res); |
| buf->Printf("\"kind\":\"list\",\"length\":%" Pd "", len); |
| } else if (Dart_IsClosure(object)) { |
| Dart_Handle name, signature; |
| Dart_CodeLocation location; |
| Dart_Handle res = Dart_GetClosureInfo(object, &name, &signature, &location); |
| ASSERT_NOT_ERROR(res); |
| buf->Printf("\"kind\":\"function\",\"name\":\"%s\"", GetStringChars(name)); |
| buf->Printf(",\"signature\":\"%s\"", GetStringChars(signature)); |
| if (!Dart_IsNull(location.script_url)) { |
| ASSERT(Dart_IsString(location.script_url)); |
| buf->Printf(",\"location\": { \"url\":"); |
| FormatEncodedString(buf, location.script_url); |
| buf->Printf(",\"libraryId\":%d,", location.library_id); |
| buf->Printf("\"tokenOffset\":%d}", location.token_pos); |
| } |
| print_text_field = false; |
| } else { |
| buf->Printf("\"kind\":\"object\""); |
| intptr_t class_id = 0; |
| Dart_Handle res = Dart_GetObjClassId(object, &class_id); |
| if (!Dart_IsError(res)) { |
| buf->Printf(",\"classId\":%" Pd "", class_id); |
| } |
| } |
| if (print_text_field) { |
| buf->Printf(",\"text\":\""); |
| const intptr_t max_chars = 1024; |
| FormatTextualValue(buf, object, max_chars, true); |
| buf->Printf("\""); |
| } |
| } |
| |
| |
| static void FormatValueObj(dart::TextBuffer* buf, Dart_Handle object) { |
| buf->Printf("{"); |
| FormatValue(buf, object); |
| buf->Printf("}"); |
| } |
| |
| |
| static void FormatRemoteObj(dart::TextBuffer* buf, Dart_Handle object) { |
| intptr_t obj_id = Dart_CacheObject(object); |
| ASSERT(obj_id >= 0); |
| buf->Printf("{\"objectId\":%" Pd ",", obj_id); |
| FormatValue(buf, object); |
| buf->Printf("}"); |
| } |
| |
| |
| static void FormatNamedValue(dart::TextBuffer* buf, |
| Dart_Handle object_name, |
| Dart_Handle object) { |
| ASSERT(Dart_IsString(object_name)); |
| buf->Printf("{\"name\":\"%s\",", GetStringChars(object_name)); |
| buf->Printf("\"value\":"); |
| FormatRemoteObj(buf, object); |
| buf->Printf("}"); |
| } |
| |
| |
| static void FormatNamedValueList(dart::TextBuffer* buf, |
| Dart_Handle obj_list) { |
| ASSERT(Dart_IsList(obj_list)); |
| intptr_t list_length = 0; |
| Dart_Handle res = Dart_ListLength(obj_list, &list_length); |
| ASSERT_NOT_ERROR(res); |
| ASSERT(list_length % 2 == 0); |
| buf->Printf("["); |
| for (int i = 0; i + 1 < list_length; i += 2) { |
| Dart_Handle name_handle = Dart_ListGetAt(obj_list, i); |
| ASSERT_NOT_ERROR(name_handle); |
| Dart_Handle value_handle = Dart_ListGetAt(obj_list, i + 1); |
| ASSERT_NOT_ERROR(value_handle); |
| if (i > 0) { |
| buf->Printf(","); |
| } |
| FormatNamedValue(buf, name_handle, value_handle); |
| } |
| buf->Printf("]"); |
| } |
| |
| |
| static const char* FormatClassProps(dart::TextBuffer* buf, |
| intptr_t cls_id) { |
| Dart_Handle name, static_fields; |
| intptr_t super_id = -1; |
| intptr_t library_id = -1; |
| Dart_Handle res = |
| Dart_GetClassInfo(cls_id, &name, &library_id, &super_id, &static_fields); |
| RETURN_IF_ERROR(res); |
| RETURN_IF_ERROR(name); |
| buf->Printf("{\"name\":\"%s\",", GetStringChars(name)); |
| if (super_id > 0) { |
| buf->Printf("\"superclassId\":%" Pd ",", super_id); |
| } |
| buf->Printf("\"libraryId\":%" Pd ",", library_id); |
| RETURN_IF_ERROR(static_fields); |
| buf->Printf("\"fields\":"); |
| FormatNamedValueList(buf, static_fields); |
| buf->Printf("}"); |
| return NULL; |
| } |
| |
| |
| static const char* FormatLibraryProps(dart::TextBuffer* buf, |
| intptr_t lib_id) { |
| Dart_Handle url = Dart_GetLibraryURL(lib_id); |
| RETURN_IF_ERROR(url); |
| buf->Printf("{\"url\":"); |
| FormatEncodedString(buf, url); |
| |
| // Whether debugging is enabled. |
| bool is_debuggable = false; |
| Dart_Handle res = Dart_GetLibraryDebuggable(lib_id, &is_debuggable); |
| RETURN_IF_ERROR(res); |
| buf->Printf(",\"debuggingEnabled\":%s", |
| is_debuggable ? "\"true\"" : "\"false\""); |
| |
| // Imports and prefixes. |
| Dart_Handle import_list = Dart_GetLibraryImports(lib_id); |
| RETURN_IF_ERROR(import_list); |
| ASSERT(Dart_IsList(import_list)); |
| intptr_t list_length = 0; |
| res = Dart_ListLength(import_list, &list_length); |
| RETURN_IF_ERROR(res); |
| buf->Printf(",\"imports\":["); |
| for (intptr_t i = 0; i + 1 < list_length; i += 2) { |
| Dart_Handle lib_id = Dart_ListGetAt(import_list, i + 1); |
| ASSERT_NOT_ERROR(lib_id); |
| buf->Printf("%s{\"libraryId\":%" Pd64 ",", |
| (i > 0) ? ",": "", |
| GetIntValue(lib_id)); |
| |
| Dart_Handle name = Dart_ListGetAt(import_list, i); |
| ASSERT_NOT_ERROR(name); |
| buf->Printf("\"prefix\":\"%s\"}", |
| Dart_IsNull(name) ? "" : GetStringChars(name)); |
| } |
| buf->Printf("],"); |
| |
| // Global variables in the library. |
| Dart_Handle global_vars = Dart_GetLibraryFields(lib_id); |
| RETURN_IF_ERROR(global_vars); |
| buf->Printf("\"globals\":"); |
| FormatNamedValueList(buf, global_vars); |
| buf->Printf("}"); |
| return NULL; |
| } |
| |
| |
| static const char* FormatObjProps(dart::TextBuffer* buf, |
| Dart_Handle object) { |
| intptr_t class_id; |
| if (Dart_IsNull(object)) { |
| buf->Printf("{\"classId\":-1,\"fields\":[]}"); |
| return NULL; |
| } |
| Dart_Handle res = Dart_GetObjClassId(object, &class_id); |
| RETURN_IF_ERROR(res); |
| buf->Printf("{\"classId\": %" Pd ",", class_id); |
| buf->Printf("\"kind\":\"object\",\"fields\":"); |
| Dart_Handle fields = Dart_GetInstanceFields(object); |
| RETURN_IF_ERROR(fields); |
| FormatNamedValueList(buf, fields); |
| buf->Printf("}"); |
| return NULL; |
| } |
| |
| |
| static const char* FormatListSlice(dart::TextBuffer* buf, |
| Dart_Handle list, |
| intptr_t list_length, |
| intptr_t index, |
| intptr_t slice_length) { |
| intptr_t end_index = index + slice_length; |
| ASSERT(end_index <= list_length); |
| buf->Printf("{\"index\":%" Pd ",", index); |
| buf->Printf("\"length\":%" Pd ",", slice_length); |
| buf->Printf("\"elements\":["); |
| for (intptr_t i = index; i < end_index; i++) { |
| Dart_Handle value = Dart_ListGetAt(list, i); |
| if (i > index) { |
| buf->Printf(","); |
| } |
| FormatValueObj(buf, value); |
| } |
| buf->Printf("]}"); |
| return NULL; |
| } |
| |
| |
| static void FormatLocationFromTrace(dart::TextBuffer* msg, |
| Dart_StackTrace trace, |
| const char* prefix) { |
| intptr_t trace_len = 0; |
| Dart_Handle res = Dart_StackTraceLength(trace, &trace_len); |
| ASSERT_NOT_ERROR(res); |
| if (trace_len == 0) { |
| return; |
| } |
| Dart_ActivationFrame frame; |
| res = Dart_GetActivationFrame(trace, 0, &frame); |
| ASSERT_NOT_ERROR(res); |
| Dart_CodeLocation location; |
| res = Dart_ActivationFrameGetLocation(frame, NULL, NULL, &location); |
| ASSERT_NOT_ERROR(res); |
| if (!Dart_IsNull(location.script_url)) { |
| ASSERT(Dart_IsString(location.script_url)); |
| msg->Printf("%s\"location\": { \"url\":", prefix); |
| FormatEncodedString(msg, location.script_url); |
| msg->Printf(",\"libraryId\":%d,", location.library_id); |
| msg->Printf("\"tokenOffset\":%d}", location.token_pos); |
| } |
| } |
| |
| |
| static void FormatCallFrames(dart::TextBuffer* msg, Dart_StackTrace trace) { |
| intptr_t trace_len = 0; |
| Dart_Handle res = Dart_StackTraceLength(trace, &trace_len); |
| ASSERT_NOT_ERROR(res); |
| msg->Printf("\"callFrames\" : [ "); |
| for (int i = 0; i < trace_len; i++) { |
| Dart_ActivationFrame frame; |
| res = Dart_GetActivationFrame(trace, i, &frame); |
| ASSERT_NOT_ERROR(res); |
| Dart_Handle func_name; |
| Dart_Handle func; |
| Dart_CodeLocation location; |
| res = Dart_ActivationFrameGetLocation(frame, &func_name, &func, &location); |
| ASSERT_NOT_ERROR(res); |
| ASSERT(Dart_IsString(func_name)); |
| msg->Printf("%s{\"functionName\":", (i > 0) ? "," : ""); |
| FormatEncodedString(msg, func_name); |
| if (!Dart_IsNull(location.script_url)) { |
| ASSERT(Dart_IsString(location.script_url)); |
| msg->Printf(",\"location\": { \"url\":"); |
| FormatEncodedString(msg, location.script_url); |
| msg->Printf(",\"libraryId\":%d,", location.library_id); |
| msg->Printf("\"tokenOffset\":%d}", location.token_pos); |
| } |
| ASSERT_NOT_ERROR(func); |
| Dart_Handle origin = Dart_GetFunctionOrigin(func); |
| ASSERT_NOT_ERROR(origin); |
| if (Dart_IsInteger(origin)) { |
| int64_t class_id = GetIntValue(origin); |
| msg->Printf(",\"classId\":%" Pd64 "", class_id); |
| } |
| Dart_Handle locals = Dart_GetLocalVariables(frame); |
| ASSERT_NOT_ERROR(locals); |
| msg->Printf(",\"locals\":"); |
| FormatNamedValueList(msg, locals); |
| msg->Printf("}"); |
| } |
| msg->Printf("]"); |
| } |
| |
| |
| typedef bool (*CommandHandler)(DbgMessage* msg); |
| |
| struct JSONDebuggerCommand { |
| const char* cmd_string; |
| CommandHandler handler_function; |
| }; |
| |
| |
| static JSONDebuggerCommand debugger_commands[] = { |
| { "resume", DbgMessage::HandleResumeCmd }, |
| { "stepInto", DbgMessage::HandleStepIntoCmd }, |
| { "stepOut", DbgMessage::HandleStepOutCmd }, |
| { "stepOver", DbgMessage::HandleStepOverCmd }, |
| { "getLibraries", DbgMessage::HandleGetLibrariesCmd }, |
| { "getClassProperties", DbgMessage::HandleGetClassPropsCmd }, |
| { "getLibraryProperties", DbgMessage::HandleGetLibPropsCmd }, |
| { "setLibraryProperties", DbgMessage::HandleSetLibPropsCmd }, |
| { "evaluateExpr", DbgMessage::HandleEvaluateExprCmd }, |
| { "getObjectProperties", DbgMessage::HandleGetObjPropsCmd }, |
| { "getListElements", DbgMessage::HandleGetListCmd }, |
| { "getGlobalVariables", DbgMessage::HandleGetGlobalsCmd }, |
| { "getScriptURLs", DbgMessage::HandleGetScriptURLsCmd }, |
| { "getScriptSource", DbgMessage::HandleGetSourceCmd }, |
| { "getLineNumberTable", DbgMessage::HandleGetLineNumbersCmd }, |
| { "getStackTrace", DbgMessage::HandleGetStackTraceCmd }, |
| { "setBreakpoint", DbgMessage::HandleSetBpCmd }, |
| { "setPauseOnException", DbgMessage::HandlePauseOnExcCmd }, |
| { "removeBreakpoint", DbgMessage::HandleRemBpCmd }, |
| { NULL, NULL } |
| }; |
| |
| |
| bool DbgMessage::HandleMessage() { |
| // Dispatch to the appropriate handler for the command. |
| int max_index = (sizeof(debugger_commands) / sizeof(JSONDebuggerCommand)); |
| ASSERT(cmd_idx_ < max_index); |
| return (*debugger_commands[cmd_idx_].handler_function)(this); |
| } |
| |
| |
| void DbgMessage::SendReply(dart::TextBuffer* reply) { |
| DebuggerConnectionHandler::SendMsg(debug_fd(), reply); |
| } |
| |
| |
| void DbgMessage::SendErrorReply(int msg_id, const char* err_msg) { |
| DebuggerConnectionHandler::SendError(debug_fd(), msg_id, err_msg); |
| } |
| |
| |
| bool DbgMessage::HandleResumeCmd(DbgMessage* in_msg) { |
| ASSERT(in_msg != NULL); |
| MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len()); |
| int msg_id = msg_parser.MessageId(); |
| dart::TextBuffer msg(64); |
| msg.Printf("{ \"id\": %d }", msg_id); |
| in_msg->SendReply(&msg); |
| return true; |
| } |
| |
| |
| bool DbgMessage::HandleStepIntoCmd(DbgMessage* in_msg) { |
| Dart_Handle res = Dart_SetStepInto(); |
| ASSERT_NOT_ERROR(res); |
| return HandleResumeCmd(in_msg); |
| } |
| |
| |
| bool DbgMessage::HandleStepOutCmd(DbgMessage* in_msg) { |
| Dart_Handle res = Dart_SetStepOut(); |
| ASSERT_NOT_ERROR(res); |
| return HandleResumeCmd(in_msg); |
| } |
| |
| |
| bool DbgMessage::HandleStepOverCmd(DbgMessage* in_msg) { |
| Dart_Handle res = Dart_SetStepOver(); |
| ASSERT_NOT_ERROR(res); |
| return HandleResumeCmd(in_msg); |
| } |
| |
| |
| bool DbgMessage::HandleGetLibrariesCmd(DbgMessage* in_msg) { |
| ASSERT(in_msg != NULL); |
| MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len()); |
| int msg_id = msg_parser.MessageId(); |
| dart::TextBuffer msg(64); |
| msg.Printf("{ \"id\": %d, \"result\": { \"libraries\": [", msg_id); |
| Dart_Handle lib_ids = Dart_GetLibraryIds(); |
| ASSERT_NOT_ERROR(lib_ids); |
| intptr_t num_libs; |
| Dart_Handle res = Dart_ListLength(lib_ids, &num_libs); |
| ASSERT_NOT_ERROR(res); |
| for (intptr_t i = 0; i < num_libs; i++) { |
| Dart_Handle lib_id_handle = Dart_ListGetAt(lib_ids, i); |
| ASSERT(Dart_IsInteger(lib_id_handle)); |
| int64_t lib_id = GetIntValue(lib_id_handle); |
| ASSERT((lib_id >= kIntptrMin) && (lib_id <= kIntptrMax)); |
| Dart_Handle lib_url = Dart_GetLibraryURL(static_cast<intptr_t>(lib_id)); |
| ASSERT_NOT_ERROR(lib_url); |
| ASSERT(Dart_IsString(lib_url)); |
| msg.Printf("%s{\"id\":%" Pd64 ",\"url\":", (i == 0) ? "" : ", ", lib_id); |
| FormatEncodedString(&msg, lib_url); |
| msg.Printf("}"); |
| } |
| msg.Printf("]}}"); |
| in_msg->SendReply(&msg); |
| return false; |
| } |
| |
| |
| bool DbgMessage::HandleGetClassPropsCmd(DbgMessage* in_msg) { |
| ASSERT(in_msg != NULL); |
| MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len()); |
| int msg_id = msg_parser.MessageId(); |
| intptr_t cls_id = msg_parser.GetIntParam("classId"); |
| dart::TextBuffer msg(64); |
| msg.Printf("{\"id\":%d, \"result\":", msg_id); |
| const char* err = FormatClassProps(&msg, cls_id); |
| if (err != NULL) { |
| in_msg->SendErrorReply(msg_id, err); |
| return false; |
| } |
| msg.Printf("}"); |
| in_msg->SendReply(&msg); |
| return false; |
| } |
| |
| |
| bool DbgMessage::HandleGetLibPropsCmd(DbgMessage* in_msg) { |
| ASSERT(in_msg != NULL); |
| MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len()); |
| int msg_id = msg_parser.MessageId(); |
| intptr_t lib_id = msg_parser.GetIntParam("libraryId"); |
| dart::TextBuffer msg(64); |
| msg.Printf("{\"id\":%d, \"result\":", msg_id); |
| const char* err = FormatLibraryProps(&msg, lib_id); |
| if (err != NULL) { |
| in_msg->SendErrorReply(msg_id, err); |
| return false; |
| } |
| msg.Printf("}"); |
| in_msg->SendReply(&msg); |
| return false; |
| } |
| |
| |
| bool DbgMessage::HandleSetLibPropsCmd(DbgMessage* in_msg) { |
| ASSERT(in_msg != NULL); |
| MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len()); |
| int msg_id = msg_parser.MessageId(); |
| intptr_t lib_id = msg_parser.GetIntParam("libraryId"); |
| const char* enable_request = msg_parser.GetStringParam("debuggingEnabled"); |
| bool enable; |
| if (strcmp(enable_request, "true") == 0) { |
| enable = true; |
| } else if (strcmp(enable_request, "false") == 0) { |
| enable = false; |
| } else { |
| in_msg->SendErrorReply(msg_id, "illegal argument for 'debuggingEnabled'"); |
| return false; |
| } |
| Dart_Handle res = Dart_SetLibraryDebuggable(lib_id, enable); |
| if (Dart_IsError(res)) { |
| in_msg->SendErrorReply(msg_id, Dart_GetError(res)); |
| return false; |
| } |
| bool enabled = false; |
| res = Dart_GetLibraryDebuggable(lib_id, &enabled); |
| if (Dart_IsError(res)) { |
| in_msg->SendErrorReply(msg_id, Dart_GetError(res)); |
| return false; |
| } |
| dart::TextBuffer msg(64); |
| msg.Printf("{\"id\":%d, \"result\": {\"debuggingEnabled\": \"%s\"}}", |
| msg_id, |
| enabled ? "true" : "false"); |
| in_msg->SendReply(&msg); |
| return false; |
| } |
| |
| |
| bool DbgMessage::HandleEvaluateExprCmd(DbgMessage* in_msg) { |
| ASSERT(in_msg != NULL); |
| MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len()); |
| int msg_id = msg_parser.MessageId(); |
| Dart_Handle target = Dart_Null(); |
| Dart_ActivationFrame frame = NULL; |
| |
| if (msg_parser.HasParam("libraryId")) { |
| intptr_t lib_id = msg_parser.GetIntParam("libraryId"); |
| target = Dart_GetLibraryFromId(lib_id); |
| } else if (msg_parser.HasParam("classId")) { |
| intptr_t cls_id = msg_parser.GetIntParam("classId"); |
| target = Dart_GetClassFromId(cls_id); |
| } else if (msg_parser.HasParam("objectId")) { |
| intptr_t obj_id = msg_parser.GetIntParam("objectId"); |
| target = Dart_GetCachedObject(obj_id); |
| } else if (msg_parser.HasParam("frameId")) { |
| intptr_t frame_index = msg_parser.GetIntParam("frameId"); |
| Dart_Handle res; |
| Dart_StackTrace stack_trace; |
| res = Dart_GetStackTrace(&stack_trace); |
| ASSERT_NOT_ERROR(res); |
| intptr_t trace_length = 0; |
| res = Dart_StackTraceLength(stack_trace, &trace_length); |
| ASSERT_NOT_ERROR(res); |
| if (frame_index >= trace_length) { |
| in_msg->SendErrorReply(msg_id, "illegal frame index"); |
| return false; |
| } |
| res = Dart_GetActivationFrame(stack_trace, frame_index, &frame); |
| ASSERT_NOT_ERROR(res); |
| } else { |
| in_msg->SendErrorReply(msg_id, "illegal evaluation target"); |
| return false; |
| } |
| |
| char* expr_chars = msg_parser.GetStringParam("expression"); |
| Dart_Handle expr = Dart_NewStringFromCString(expr_chars); |
| if (Dart_IsError(expr)) { |
| in_msg->SendErrorReply(msg_id, Dart_GetError(expr)); |
| return false; |
| } |
| |
| Dart_Handle eval_result = Dart_Null(); |
| if (frame != NULL) { |
| eval_result = Dart_ActivationFrameEvaluate(frame, expr); |
| } else { |
| if (Dart_IsError(target)) { |
| in_msg->SendErrorReply(msg_id, Dart_GetError(target)); |
| return false; |
| } |
| eval_result = Dart_EvaluateExpr(target, expr); |
| } |
| if (Dart_IsError(eval_result)) { |
| in_msg->SendErrorReply(msg_id, Dart_GetError(eval_result)); |
| return false; |
| } |
| |
| dart::TextBuffer msg(64); |
| msg.Printf("{\"id\":%d, \"result\":", msg_id); |
| FormatRemoteObj(&msg, eval_result); |
| msg.Printf("}"); |
| in_msg->SendReply(&msg); |
| return false; |
| } |
| |
| |
| bool DbgMessage::HandleGetObjPropsCmd(DbgMessage* in_msg) { |
| ASSERT(in_msg != NULL); |
| MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len()); |
| int msg_id = msg_parser.MessageId(); |
| intptr_t obj_id = msg_parser.GetIntParam("objectId"); |
| Dart_Handle obj = Dart_GetCachedObject(obj_id); |
| if (Dart_IsError(obj)) { |
| in_msg->SendErrorReply(msg_id, Dart_GetError(obj)); |
| return false; |
| } |
| dart::TextBuffer msg(64); |
| msg.Printf("{\"id\":%d, \"result\":", msg_id); |
| const char* err = FormatObjProps(&msg, obj); |
| if (err != NULL) { |
| in_msg->SendErrorReply(msg_id, err); |
| return false; |
| } |
| msg.Printf("}"); |
| in_msg->SendReply(&msg); |
| return false; |
| } |
| |
| |
| bool DbgMessage::HandleGetListCmd(DbgMessage* in_msg) { |
| const intptr_t kDefaultSliceLength = 100; |
| ASSERT(in_msg != NULL); |
| MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len()); |
| int msg_id = msg_parser.MessageId(); |
| intptr_t obj_id = msg_parser.GetIntParam("objectId"); |
| Dart_Handle list = Dart_GetCachedObject(obj_id); |
| if (Dart_IsError(list)) { |
| in_msg->SendErrorReply(msg_id, Dart_GetError(list)); |
| return false; |
| } |
| if (!Dart_IsList(list)) { |
| in_msg->SendErrorReply(msg_id, "object is not a list"); |
| return false; |
| } |
| intptr_t list_length = 0; |
| Dart_Handle res = Dart_ListLength(list, &list_length); |
| if (Dart_IsError(res)) { |
| in_msg->SendErrorReply(msg_id, Dart_GetError(res)); |
| return false; |
| } |
| |
| intptr_t index = msg_parser.GetIntParam("index"); |
| if (index < 0) { |
| index = 0; |
| } else if (index > list_length) { |
| index = list_length; |
| } |
| |
| // If no slice length is given, get only one element. If slice length |
| // is given as 0, get entire list. |
| intptr_t slice_length = msg_parser.GetOptIntParam("length", 1); |
| if (slice_length == 0) { |
| slice_length = list_length - index; |
| } |
| if ((index + slice_length) > list_length) { |
| slice_length = list_length - index; |
| } |
| ASSERT(slice_length >= 0); |
| if (slice_length > kDefaultSliceLength) { |
| slice_length = kDefaultSliceLength; |
| } |
| dart::TextBuffer msg(64); |
| msg.Printf("{\"id\":%d, \"result\":", msg_id); |
| if (slice_length == 1) { |
| Dart_Handle value = Dart_ListGetAt(list, index); |
| FormatRemoteObj(&msg, value); |
| } else { |
| FormatListSlice(&msg, list, list_length, index, slice_length); |
| } |
| msg.Printf("}"); |
| in_msg->SendReply(&msg); |
| return false; |
| } |
| |
| |
| bool DbgMessage::HandleGetGlobalsCmd(DbgMessage* in_msg) { |
| ASSERT(in_msg != NULL); |
| MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len()); |
| int msg_id = msg_parser.MessageId(); |
| intptr_t lib_id = msg_parser.GetIntParam("libraryId"); |
| dart::TextBuffer msg(64); |
| msg.Printf("{\"id\":%d, \"result\": { \"globals\":", msg_id); |
| Dart_Handle globals = Dart_GetGlobalVariables(lib_id); |
| ASSERT_NOT_ERROR(globals); |
| FormatNamedValueList(&msg, globals); |
| msg.Printf("}}"); |
| in_msg->SendReply(&msg); |
| return false; |
| } |
| |
| |
| bool DbgMessage::HandleGetScriptURLsCmd(DbgMessage* in_msg) { |
| ASSERT(in_msg != NULL); |
| MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len()); |
| int msg_id = msg_parser.MessageId(); |
| dart::TextBuffer msg(64); |
| intptr_t lib_id = msg_parser.GetIntParam("libraryId"); |
| Dart_Handle lib_url = Dart_GetLibraryURL(lib_id); |
| ASSERT_NOT_ERROR(lib_url); |
| Dart_Handle urls = Dart_GetScriptURLs(lib_url); |
| if (Dart_IsError(urls)) { |
| in_msg->SendErrorReply(msg_id, Dart_GetError(urls)); |
| return false; |
| } |
| ASSERT(Dart_IsList(urls)); |
| intptr_t num_urls = 0; |
| Dart_ListLength(urls, &num_urls); |
| msg.Printf("{ \"id\": %d, ", msg_id); |
| msg.Printf("\"result\": { \"urls\": ["); |
| for (int i = 0; i < num_urls; i++) { |
| Dart_Handle script_url = Dart_ListGetAt(urls, i); |
| if (i > 0) { |
| msg.Printf(","); |
| } |
| FormatEncodedString(&msg, script_url); |
| } |
| msg.Printf("]}}"); |
| in_msg->SendReply(&msg); |
| return false; |
| } |
| |
| |
| bool DbgMessage::HandleGetSourceCmd(DbgMessage* in_msg) { |
| ASSERT(in_msg != NULL); |
| MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len()); |
| int msg_id = msg_parser.MessageId(); |
| dart::TextBuffer msg(64); |
| intptr_t lib_id = msg_parser.GetIntParam("libraryId"); |
| char* url_chars = msg_parser.GetStringParam("url"); |
| ASSERT(url_chars != NULL); |
| Dart_Handle url = DartUtils::NewString(url_chars); |
| ASSERT_NOT_ERROR(url); |
| free(url_chars); |
| url_chars = NULL; |
| Dart_Handle source = Dart_ScriptGetSource(lib_id, url); |
| if (Dart_IsError(source)) { |
| in_msg->SendErrorReply(msg_id, Dart_GetError(source)); |
| return false; |
| } |
| msg.Printf("{ \"id\": %d, ", msg_id); |
| msg.Printf("\"result\": { \"text\": "); |
| FormatEncodedString(&msg, source); |
| msg.Printf("}}"); |
| in_msg->SendReply(&msg); |
| return false; |
| } |
| |
| |
| bool DbgMessage::HandleGetLineNumbersCmd(DbgMessage* in_msg) { |
| ASSERT(in_msg != NULL); |
| MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len()); |
| int msg_id = msg_parser.MessageId(); |
| dart::TextBuffer msg(64); |
| intptr_t lib_id = msg_parser.GetIntParam("libraryId"); |
| char* url_chars = msg_parser.GetStringParam("url"); |
| ASSERT(url_chars != NULL); |
| Dart_Handle url = DartUtils::NewString(url_chars); |
| ASSERT_NOT_ERROR(url); |
| free(url_chars); |
| url_chars = NULL; |
| Dart_Handle info = Dart_ScriptGetTokenInfo(lib_id, url); |
| if (Dart_IsError(info)) { |
| in_msg->SendErrorReply(msg_id, Dart_GetError(info)); |
| return false; |
| } |
| ASSERT(Dart_IsList(info)); |
| intptr_t info_len = 0; |
| Dart_Handle res = Dart_ListLength(info, &info_len); |
| ASSERT_NOT_ERROR(res); |
| msg.Printf("{ \"id\": %d, ", msg_id); |
| msg.Printf("\"result\": { \"lines\": ["); |
| Dart_Handle elem; |
| intptr_t num_elems = 0; |
| for (intptr_t i = 0; i < info_len; i++) { |
| elem = Dart_ListGetAt(info, i); |
| if (Dart_IsNull(elem)) { |
| msg.Printf((i == 0) ? "[" : "], ["); |
| num_elems = 0; |
| } else { |
| ASSERT(Dart_IsInteger(elem)); |
| int64_t value = GetIntValue(elem); |
| if (num_elems == 0) { |
| msg.Printf("%" Pd64 "", value); |
| } else { |
| msg.Printf(",%" Pd64 "", value); |
| } |
| num_elems++; |
| } |
| } |
| msg.Printf("]]}}"); |
| in_msg->SendReply(&msg); |
| return false; |
| } |
| |
| |
| bool DbgMessage::HandleGetStackTraceCmd(DbgMessage* in_msg) { |
| ASSERT(in_msg != NULL); |
| MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len()); |
| int msg_id = msg_parser.MessageId(); |
| Dart_StackTrace trace; |
| Dart_Handle res = Dart_GetStackTrace(&trace); |
| ASSERT_NOT_ERROR(res); |
| dart::TextBuffer msg(128); |
| msg.Printf("{ \"id\": %d, \"result\": {", msg_id); |
| FormatCallFrames(&msg, trace); |
| msg.Printf("}}"); |
| in_msg->SendReply(&msg); |
| return false; |
| } |
| |
| |
| bool DbgMessage::HandleSetBpCmd(DbgMessage* in_msg) { |
| ASSERT(in_msg != NULL); |
| MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len()); |
| int msg_id = msg_parser.MessageId(); |
| char* url_chars = msg_parser.GetStringParam("url"); |
| ASSERT(url_chars != NULL); |
| Dart_Handle url = DartUtils::NewString(url_chars); |
| ASSERT_NOT_ERROR(url); |
| free(url_chars); |
| url_chars = NULL; |
| intptr_t line_number = msg_parser.GetIntParam("line"); |
| Dart_Handle bp_id = Dart_SetBreakpoint(url, line_number); |
| if (Dart_IsError(bp_id)) { |
| in_msg->SendErrorReply(msg_id, Dart_GetError(bp_id)); |
| return false; |
| } |
| ASSERT(Dart_IsInteger(bp_id)); |
| uint64_t bp_id_value; |
| Dart_Handle res = Dart_IntegerToUint64(bp_id, &bp_id_value); |
| ASSERT_NOT_ERROR(res); |
| dart::TextBuffer msg(64); |
| msg.Printf("{ \"id\": %d, \"result\": { \"breakpointId\": %" Pu64 " }}", |
| msg_id, bp_id_value); |
| in_msg->SendReply(&msg); |
| return false; |
| } |
| |
| |
| bool DbgMessage::HandlePauseOnExcCmd(DbgMessage* in_msg) { |
| ASSERT(in_msg != NULL); |
| MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len()); |
| int msg_id = msg_parser.MessageId(); |
| char* exc_chars = msg_parser.GetStringParam("exceptions"); |
| Dart_ExceptionPauseInfo info = kNoPauseOnExceptions; |
| if (strcmp(exc_chars, "none") == 0) { |
| info = kNoPauseOnExceptions; |
| } else if (strcmp(exc_chars, "all") == 0) { |
| info = kPauseOnAllExceptions; |
| } else if (strcmp(exc_chars, "unhandled") == 0) { |
| info = kPauseOnUnhandledExceptions; |
| } else { |
| in_msg->SendErrorReply(msg_id, "illegal value for parameter 'exceptions'"); |
| return false; |
| } |
| Dart_Handle res = Dart_SetExceptionPauseInfo(info); |
| ASSERT_NOT_ERROR(res); |
| dart::TextBuffer msg(32); |
| msg.Printf("{ \"id\": %d }", msg_id); |
| in_msg->SendReply(&msg); |
| return false; |
| } |
| |
| |
| bool DbgMessage::HandleRemBpCmd(DbgMessage* in_msg) { |
| ASSERT(in_msg != NULL); |
| MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len()); |
| int msg_id = msg_parser.MessageId(); |
| int bpt_id = msg_parser.GetIntParam("breakpointId"); |
| Dart_Handle res = Dart_RemoveBreakpoint(bpt_id); |
| if (Dart_IsError(res)) { |
| in_msg->SendErrorReply(msg_id, Dart_GetError(res)); |
| return false; |
| } |
| dart::TextBuffer msg(32); |
| msg.Printf("{ \"id\": %d }", msg_id); |
| in_msg->SendReply(&msg); |
| return false; |
| } |
| |
| |
| void DbgMsgQueue::AddMessage(int32_t cmd_idx, |
| const char* start, |
| const char* end, |
| intptr_t debug_fd) { |
| if ((end > start) && ((end - start) < kMaxInt32)) { |
| MonitorLocker ml(&msg_queue_lock_); |
| DbgMessage* msg = new DbgMessage(cmd_idx, start, end, debug_fd); |
| if (msglist_head_ == NULL) { |
| ASSERT(msglist_tail_ == NULL); |
| msglist_head_ = msg; |
| msglist_tail_ = msg; |
| ml.Notify(); |
| } else { |
| ASSERT(msglist_tail_ != NULL); |
| msglist_tail_->set_next(msg); |
| msglist_tail_ = msg; |
| } |
| } |
| } |
| |
| |
| void DbgMsgQueue::Notify() { |
| MonitorLocker ml(&msg_queue_lock_); |
| ml.Notify(); |
| } |
| |
| |
| bool DbgMsgQueue::HandlePendingMessages() { |
| // Handle all available debug messages, up to a resume request. |
| bool resume_requested = false; |
| while (msglist_head_ != NULL && !resume_requested) { |
| ASSERT(msglist_tail_ != NULL); |
| DbgMessage* msg = msglist_head_; |
| msglist_head_ = msglist_head_->next(); |
| if (msglist_head_ == NULL) { |
| msglist_tail_ = NULL; |
| } |
| resume_requested = msg->HandleMessage(); |
| delete msg; |
| } |
| return resume_requested; |
| } |
| |
| |
| void DbgMsgQueue::MessageLoop() { |
| MonitorLocker ml(&msg_queue_lock_); |
| is_running_ = false; |
| |
| // Request notification on isolate messages. This allows us to |
| // respond to vm service messages while at breakpoint. |
| Dart_SetMessageNotifyCallback(DbgMsgQueueList::NotifyIsolate); |
| |
| while (true) { |
| // Handle all available vm service messages, up to a resume |
| // request. |
| bool resume = false; |
| while (!resume && Dart_HasServiceMessages()) { |
| msg_queue_lock_.Exit(); |
| resume = Dart_HandleServiceMessages(); |
| msg_queue_lock_.Enter(); |
| } |
| if (resume) { |
| break; |
| } |
| |
| // Handle all available debug messages, up to a resume request. |
| if (HandlePendingMessages()) { |
| break; |
| } |
| |
| // Wait for more debug or vm service messages. |
| Monitor::WaitResult res = ml.Wait(); |
| ASSERT(res == Monitor::kNotified); |
| } |
| Dart_SetMessageNotifyCallback(NULL); |
| is_interrupted_ = false; |
| is_running_ = true; |
| } |
| |
| |
| void DbgMsgQueue::InterruptIsolate() { |
| Dart_Isolate isolate = Dart_GetIsolate(isolate_id_); |
| MonitorLocker ml(&msg_queue_lock_); |
| if (is_running_ && !is_interrupted_) { |
| is_interrupted_ = true; |
| Dart_InterruptIsolate(isolate); |
| } |
| } |
| |
| |
| void DbgMsgQueue::QueueOutputMsg(dart::TextBuffer* msg) { |
| queued_output_messages_.Printf("%s", msg->buf()); |
| } |
| |
| |
| void DbgMsgQueue::SendQueuedMsgs() { |
| if (queued_output_messages_.length() > 0) { |
| DebuggerConnectionHandler::BroadcastMsg(&queued_output_messages_); |
| queued_output_messages_.Clear(); |
| } |
| } |
| |
| |
| void DbgMsgQueue::SendBreakpointEvent(intptr_t bp_id, |
| const Dart_CodeLocation& location) { |
| dart::TextBuffer msg(128); |
| msg.Printf("{ \"event\": \"paused\", \"params\": { "); |
| msg.Printf("\"reason\": \"breakpoint\", "); |
| msg.Printf("\"isolateId\": %" Pd64 "", isolate_id_); |
| if (bp_id != ILLEGAL_BREAKPOINT_ID) { |
| msg.Printf(",\"breakpointId\": %" Pd "", bp_id); |
| } |
| if (!Dart_IsNull(location.script_url)) { |
| ASSERT(Dart_IsString(location.script_url)); |
| msg.Printf(",\"location\": { \"url\":"); |
| FormatEncodedString(&msg, location.script_url); |
| msg.Printf(",\"libraryId\":%d,", location.library_id); |
| msg.Printf("\"tokenOffset\":%d}", location.token_pos); |
| } |
| msg.Printf("}}"); |
| DebuggerConnectionHandler::BroadcastMsg(&msg); |
| } |
| |
| |
| // TODO(hausner): Remove stack trace parameter once we remove the stack |
| // trace from the paused event in the wire protocol. |
| void DbgMsgQueue::SendExceptionEvent(Dart_Handle exception, |
| Dart_StackTrace stack_trace) { |
| intptr_t exception_id = Dart_CacheObject(exception); |
| ASSERT(exception_id >= 0); |
| dart::TextBuffer msg(128); |
| msg.Printf("{ \"event\": \"paused\", \"params\": {"); |
| msg.Printf("\"reason\": \"exception\", "); |
| msg.Printf("\"isolateId\": %" Pd64 ", ", isolate_id_); |
| msg.Printf("\"exception\":"); |
| FormatRemoteObj(&msg, exception); |
| FormatLocationFromTrace(&msg, stack_trace, ", "); |
| msg.Printf("}}"); |
| DebuggerConnectionHandler::BroadcastMsg(&msg); |
| } |
| |
| |
| // TODO(hausner): Remove stack trace parameter once we remove the stack |
| // trace from the interrupted event in the wire protocol. |
| void DbgMsgQueue::SendIsolateEvent(Dart_IsolateId isolate_id, |
| Dart_IsolateEvent kind) { |
| dart::TextBuffer msg(128); |
| if (kind == kInterrupted) { |
| Dart_StackTrace trace; |
| Dart_Handle res = Dart_GetStackTrace(&trace); |
| ASSERT_NOT_ERROR(res); |
| msg.Printf("{ \"event\": \"paused\", \"params\": { "); |
| msg.Printf("\"reason\": \"interrupted\", "); |
| msg.Printf("\"isolateId\": %" Pd64 "", isolate_id); |
| FormatLocationFromTrace(&msg, trace, ", "); |
| msg.Printf("}}"); |
| } else { |
| msg.Printf("{ \"event\": \"isolate\", \"params\": { "); |
| if (kind == kCreated) { |
| msg.Printf("\"reason\": \"created\", "); |
| } else { |
| ASSERT(kind == kShutdown); |
| msg.Printf("\"reason\": \"shutdown\", "); |
| } |
| msg.Printf("\"id\": %" Pd64 " ", isolate_id); |
| msg.Printf("}}"); |
| } |
| DebuggerConnectionHandler::BroadcastMsg(&msg); |
| } |
| |
| |
| DbgMsgQueue* DbgMsgQueueList::list_ = NULL; |
| Mutex* DbgMsgQueueList::msg_queue_list_lock_ = new Mutex(); |
| |
| |
| void DbgMsgQueueList::Initialize() { |
| // Setup handlers for isolate events, breakpoints, exceptions and |
| // delayed breakpoints. |
| Dart_SetIsolateEventHandler(IsolateEventHandler); |
| Dart_SetPausedEventHandler(PausedEventHandler); |
| Dart_SetBreakpointResolvedHandler(BptResolvedHandler); |
| Dart_SetExceptionThrownHandler(ExceptionThrownHandler); |
| } |
| |
| |
| int32_t DbgMsgQueueList::LookupIsolateCommand(const char* buf, |
| int32_t buflen) { |
| // Check if we have a isolate specific debugger command. |
| int32_t i = 0; |
| while (debugger_commands[i].cmd_string != NULL) { |
| if (strncmp(buf, debugger_commands[i].cmd_string, buflen) == 0) { |
| return i; |
| } |
| i++; |
| } |
| return kInvalidCommand; |
| } |
| |
| |
| bool DbgMsgQueueList::AddIsolateMessage(Dart_IsolateId isolate_id, |
| int32_t cmd_idx, |
| const char* start, |
| const char* end, |
| intptr_t debug_fd) { |
| MutexLocker ml(msg_queue_list_lock_); |
| DbgMsgQueue* queue = DbgMsgQueueList::GetIsolateMsgQueueLocked(isolate_id); |
| if (queue != NULL) { |
| queue->AddMessage(cmd_idx, start, end, debug_fd); |
| return true; |
| } |
| return false; |
| } |
| |
| |
| void DbgMsgQueueList::NotifyIsolate(Dart_Isolate isolate) { |
| MutexLocker ml(msg_queue_list_lock_); |
| Dart_IsolateId isolate_id = Dart_GetIsolateId(isolate); |
| DbgMsgQueue* queue = DbgMsgQueueList::GetIsolateMsgQueueLocked(isolate_id); |
| if (queue != NULL) { |
| queue->Notify(); |
| } |
| } |
| |
| |
| bool DbgMsgQueueList::InterruptIsolate(Dart_IsolateId isolate_id) { |
| MutexLocker ml(msg_queue_list_lock_); |
| DbgMsgQueue* queue = DbgMsgQueueList::GetIsolateMsgQueueLocked(isolate_id); |
| if (queue != NULL) { |
| queue->InterruptIsolate(); |
| return true; |
| } |
| return false; |
| } |
| |
| |
| DbgMsgQueue* DbgMsgQueueList::AddIsolateMsgQueue(Dart_IsolateId isolate_id) { |
| MutexLocker ml(msg_queue_list_lock_); |
| |
| DbgMsgQueue* queue = new DbgMsgQueue(isolate_id, list_); |
| ASSERT(queue != NULL); |
| list_ = queue; |
| return queue; |
| } |
| |
| |
| DbgMsgQueue* DbgMsgQueueList::GetIsolateMsgQueue(Dart_IsolateId isolate_id) { |
| MutexLocker ml(msg_queue_list_lock_); |
| ASSERT(Dart_GetIsolate(isolate_id) == Dart_CurrentIsolate()); |
| return GetIsolateMsgQueueLocked(isolate_id); |
| } |
| |
| |
| DbgMsgQueue* DbgMsgQueueList::GetIsolateMsgQueueLocked(Dart_IsolateId id) { |
| if (list_ == NULL) { |
| return NULL; // No items in the list. |
| } |
| |
| // Find message queue corresponding to isolate id. |
| DbgMsgQueue* iterator = list_; |
| while (iterator != NULL && iterator->isolate_id() != id) { |
| iterator = iterator->next(); |
| } |
| return iterator; |
| } |
| |
| |
| void DbgMsgQueueList::RemoveIsolateMsgQueue(Dart_IsolateId isolate_id) { |
| MutexLocker ml(msg_queue_list_lock_); |
| if (list_ == NULL) { |
| return; // No items in the list. |
| } |
| DbgMsgQueue* queue = list_; |
| if (queue->isolate_id() == isolate_id) { |
| list_ = queue->next(); // Remove from list. |
| delete queue; // Delete the message queue. |
| return; |
| } else { |
| DbgMsgQueue* iterator = queue; |
| queue = queue->next(); |
| while (queue != NULL) { |
| if (queue->isolate_id() == isolate_id) { |
| iterator->set_next(queue->next()); // Remove from list. |
| delete queue; // Delete the message queue. |
| return; |
| } |
| iterator = queue; |
| queue = queue->next(); |
| } |
| } |
| UNREACHABLE(); |
| } |
| |
| |
| void DbgMsgQueueList::ListIsolateIds(dart::TextBuffer* msg) { |
| MutexLocker ml(msg_queue_list_lock_); |
| if (list_ == NULL) { |
| return; // No items in the list. |
| } |
| DbgMsgQueue* queue = list_; |
| msg->Printf("%" Pd64 "", queue->isolate_id()); |
| queue = queue->next(); |
| while (queue != NULL) { |
| msg->Printf(",%" Pd64 "", queue->isolate_id()); |
| queue = queue->next(); |
| } |
| } |
| |
| |
| void DbgMsgQueueList::BptResolvedHandler(Dart_IsolateId isolate_id, |
| intptr_t bp_id, |
| const Dart_CodeLocation& location) { |
| Dart_EnterScope(); |
| dart::TextBuffer msg(128); |
| msg.Printf("{ \"event\": \"breakpointResolved\", \"params\": {"); |
| msg.Printf("\"breakpointId\": %" Pd "", bp_id); |
| |
| msg.Printf(", \"isolateId\":%" Pd64 "", isolate_id); |
| ASSERT(!Dart_IsNull(location.script_url)); |
| ASSERT(Dart_IsString(location.script_url)); |
| msg.Printf(", \"location\":{\"url\":"); |
| FormatEncodedString(&msg, location.script_url); |
| msg.Printf(",\"libraryId\":%d", location.library_id); |
| msg.Printf(",\"tokenOffset\":%d}}}", location.token_pos); |
| |
| DbgMsgQueue* msg_queue = GetIsolateMsgQueue(isolate_id); |
| ASSERT(msg_queue != NULL); |
| msg_queue->QueueOutputMsg(&msg); |
| Dart_ExitScope(); |
| } |
| |
| |
| void DbgMsgQueueList::PausedEventHandler(Dart_IsolateId isolate_id, |
| intptr_t bp_id, |
| const Dart_CodeLocation& loc) { |
| DebuggerConnectionHandler::WaitForConnection(); |
| Dart_EnterScope(); |
| DbgMsgQueue* msg_queue = GetIsolateMsgQueue(isolate_id); |
| ASSERT(msg_queue != NULL); |
| msg_queue->SendQueuedMsgs(); |
| msg_queue->SendBreakpointEvent(bp_id, loc); |
| msg_queue->MessageLoop(); |
| Dart_ExitScope(); |
| } |
| |
| |
| void DbgMsgQueueList::ExceptionThrownHandler(Dart_IsolateId isolate_id, |
| Dart_Handle exception, |
| Dart_StackTrace stack_trace) { |
| DebuggerConnectionHandler::WaitForConnection(); |
| Dart_EnterScope(); |
| DbgMsgQueue* msg_queue = GetIsolateMsgQueue(isolate_id); |
| ASSERT(msg_queue != NULL); |
| msg_queue->SendQueuedMsgs(); |
| msg_queue->SendExceptionEvent(exception, stack_trace); |
| msg_queue->MessageLoop(); |
| Dart_ExitScope(); |
| } |
| |
| |
| void DbgMsgQueueList::IsolateEventHandler(Dart_IsolateId isolate_id, |
| Dart_IsolateEvent kind) { |
| if (kind == kCreated) { |
| DebuggerConnectionHandler::WaitForConnection(); |
| Dart_EnterScope(); |
| DbgMsgQueue* msg_queue = AddIsolateMsgQueue(isolate_id); |
| msg_queue->SendIsolateEvent(isolate_id, kind); |
| Dart_ExitScope(); |
| } else { |
| DebuggerConnectionHandler::WaitForConnection(); |
| DbgMsgQueue* msg_queue = GetIsolateMsgQueue(isolate_id); |
| ASSERT(msg_queue != NULL); |
| Dart_EnterScope(); |
| msg_queue->SendQueuedMsgs(); |
| msg_queue->SendIsolateEvent(isolate_id, kind); |
| if (kind == kInterrupted) { |
| msg_queue->MessageLoop(); |
| } else { |
| ASSERT(kind == kShutdown); |
| RemoveIsolateMsgQueue(isolate_id); |
| } |
| Dart_ExitScope(); |
| // If there is no receive message queue, do not wait for a connection, and |
| // ignore the message. |
| } |
| } |
| |
| } // namespace bin |
| } // namespace dart |