dff049ab71
Debugger no longer calls toString on objects. It continues to do so on known basic types like numbers, booleans, strings. This is necessary because toString() may have side effects. See issue 16229 for example. R=johnmccutchan@google.com Review URL: https://codereview.chromium.org//146833007 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@32003 260f80e4-7a28-3924-810f-c04153c831b5
1379 lines
42 KiB
C++
1379 lines
42 KiB
C++
// 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/thread.h"
|
|
#include "bin/utils.h"
|
|
|
|
#include "platform/globals.h"
|
|
#include "platform/json.h"
|
|
#include "platform/thread.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);
|
|
}
|
|
|
|
|
|
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 int 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);
|
|
// TODO(hausner): Range check.
|
|
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* codepoints =
|
|
reinterpret_cast<uint16_t*>(malloc(num_chars * sizeof(uint16_t)));
|
|
ASSERT(codepoints != NULL);
|
|
intptr_t actual_len = num_chars;
|
|
res = Dart_StringToUTF16(str, codepoints, &actual_len);
|
|
ASSERT_NOT_ERROR(res);
|
|
ASSERT(num_chars == actual_len);
|
|
for (int i = 0; i < num_chars; i++) {
|
|
buf->AddEscapedChar(codepoints[i]);
|
|
}
|
|
if (str_len > max_chars) {
|
|
buf->Printf("...");
|
|
}
|
|
free(codepoints);
|
|
}
|
|
|
|
|
|
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* codepoints =
|
|
reinterpret_cast<uint16_t*>(malloc(str_len * sizeof(uint16_t)));
|
|
ASSERT(codepoints != NULL);
|
|
intptr_t actual_len = str_len;
|
|
res = Dart_StringToUTF16(str, codepoints, &actual_len);
|
|
ASSERT_NOT_ERROR(res);
|
|
ASSERT(str_len == actual_len);
|
|
for (int i = 0; i < str_len; i++) {
|
|
buf->AddEscapedChar(codepoints[i]);
|
|
}
|
|
free(codepoints);
|
|
}
|
|
|
|
|
|
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 (int 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\":%d,",
|
|
(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);
|
|
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_CodeLocation location;
|
|
res = Dart_ActivationFrameGetLocation(frame, &func_name, NULL, &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);
|
|
}
|
|
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 (int i = 0; i < num_libs; i++) {
|
|
Dart_Handle lib_id_handle = Dart_ListGetAt(lib_ids, i);
|
|
ASSERT(Dart_IsInteger(lib_id_handle));
|
|
int lib_id = GetIntValue(lib_id_handle);
|
|
Dart_Handle lib_url = Dart_GetLibraryURL(lib_id);
|
|
ASSERT_NOT_ERROR(lib_url);
|
|
ASSERT(Dart_IsString(lib_url));
|
|
msg.Printf("%s{\"id\":%d,\"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;
|
|
|
|
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 {
|
|
in_msg->SendErrorReply(msg_id, "illegal evaluation target");
|
|
return false;
|
|
}
|
|
|
|
if (Dart_IsError(target)) {
|
|
in_msg->SendErrorReply(msg_id, Dart_GetError(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 value = Dart_EvaluateExpr(target, expr);
|
|
if (Dart_IsError(value)) {
|
|
in_msg->SendErrorReply(msg_id, Dart_GetError(value));
|
|
return false;
|
|
}
|
|
|
|
dart::TextBuffer msg(64);
|
|
msg.Printf("{\"id\":%d, \"result\":", msg_id);
|
|
FormatRemoteObj(&msg, value);
|
|
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));
|
|
int value = GetIntValue(elem);
|
|
if (num_elems == 0) {
|
|
msg.Printf("%d", value);
|
|
} else {
|
|
msg.Printf(",%d", 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,
|
|
int 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.
|
|
if (Dart_HandleServiceMessages()) {
|
|
break;
|
|
}
|
|
|
|
// Handle all available debug messages, up to a resume request.
|
|
if (HandlePendingMessages()) {
|
|
break;
|
|
}
|
|
|
|
// Wait for more debug or vm service messages.
|
|
dart::Monitor::WaitResult res = ml.Wait();
|
|
ASSERT(res == dart::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;
|
|
dart::Mutex* DbgMsgQueueList::msg_queue_list_lock_ = new dart::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,
|
|
int 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) {
|
|
DebuggerConnectionHandler::WaitForConnection();
|
|
Dart_EnterScope();
|
|
if (kind == kCreated) {
|
|
DbgMsgQueue* msg_queue = AddIsolateMsgQueue(isolate_id);
|
|
msg_queue->SendIsolateEvent(isolate_id, kind);
|
|
} else {
|
|
DbgMsgQueue* msg_queue = GetIsolateMsgQueue(isolate_id);
|
|
ASSERT(msg_queue != NULL);
|
|
msg_queue->SendQueuedMsgs();
|
|
msg_queue->SendIsolateEvent(isolate_id, kind);
|
|
if (kind == kInterrupted) {
|
|
msg_queue->MessageLoop();
|
|
} else {
|
|
ASSERT(kind == kShutdown);
|
|
RemoveIsolateMsgQueue(isolate_id);
|
|
}
|
|
}
|
|
Dart_ExitScope();
|
|
}
|
|
|
|
} // namespace bin
|
|
} // namespace dart
|