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