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) { | |
184 int msg_id = msgbuf_->MessageId(); | |
185 dart::JSONReader r(json_msg); | |
siva
2012/05/10 20:08:36
This r object appears to be unused.
hausner
2012/05/10 22:36:28
Done.
| |
186 dart::TextBuffer msg(64); | |
187 msg.Printf("{ \"id\": %d }", msg_id); | |
188 Socket::Write(debugger_fd_, msg.buf(), msg.length()); | |
189 // TODO(hausner): Error checking. Probably just shut down the debugger | |
190 // session if we there is an error while writing. | |
191 request_resume_ = true; | |
192 } | |
193 | |
194 | |
195 void DebuggerConnectionHandler::HandleStepIntoCmd(const char* json_msg) { | |
196 Dart_Handle res = Dart_SetStepInto(); | |
197 ASSERT_NOT_ERROR(res); | |
198 HandleResumeCmd(json_msg); | |
199 } | |
200 | |
201 | |
202 void DebuggerConnectionHandler::HandleStepOutCmd(const char* json_msg) { | |
203 Dart_Handle res = Dart_SetStepOut(); | |
204 ASSERT_NOT_ERROR(res); | |
205 HandleResumeCmd(json_msg); | |
206 } | |
207 | |
208 | |
209 void DebuggerConnectionHandler::HandleStepOverCmd(const char* json_msg) { | |
210 Dart_Handle res = Dart_SetStepOver(); | |
211 ASSERT_NOT_ERROR(res); | |
212 HandleResumeCmd(json_msg); | |
213 } | |
214 | |
215 | |
216 void DebuggerConnectionHandler::HandleGetScriptURLsCmd(const char* json_msg) { | |
149 int msg_id = msgbuf_->MessageId(); | 217 int msg_id = msgbuf_->MessageId(); |
150 dart::TextBuffer msg(64); | 218 dart::TextBuffer msg(64); |
151 msg.Printf("{ \"id\": %d }", msg_id); | 219 const char* params = msgbuf_->Params(); |
220 ASSERT(params != NULL); | |
221 dart::JSONReader pr(params); | |
222 pr.Seek("library"); | |
223 ASSERT(pr.Type() == dart::JSONReader::kString); | |
224 char lib_url_chars[128]; | |
225 pr.GetValueChars(lib_url_chars, sizeof(lib_url_chars)); | |
226 Dart_Handle lib_url = Dart_NewString(lib_url_chars); | |
siva
2012/05/10 20:08:36
ASSERT(!Dart_IsError(lib_url));
hausner
2012/05/10 22:36:28
Done.
| |
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); | |
siva
2012/05/10 20:08:36
See comments below about allocation of chars.
hausner
2012/05/10 22:36:28
Done.
| |
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); | |
siva
2012/05/10 20:08:36
Does msg.Printf handle buffer overruns?
hausner
2012/05/10 22:36:28
Yes, it dynamically reallocs buffer space.
| |
255 Dart_Handle urls = Dart_GetLibraryURLs(); | |
siva
2012/05/10 20:08:36
ASSERT(!Dart_IsError(urls));
hausner
2012/05/10 22:36:28
Done.
| |
256 intptr_t num_libs; | |
257 Dart_ListLength(urls, &num_libs); | |
258 for (int i = 0; i < num_libs; i++) { | |
259 Dart_Handle lib_url = Dart_ListGetAt(urls, i); | |
260 ASSERT(Dart_IsString(lib_url)); | |
261 char const* chars; | |
262 Dart_StringToCString(lib_url, &chars); | |
siva
2012/05/10 20:08:36
chars is allocated in the ApiScope, do you create
hausner
2012/05/10 22:36:28
Thanks for this tip. Added a scope around the call
| |
263 msg.Printf("%s\"%s\"", (i == 0) ? "" : ", ", chars); | |
264 } | |
265 msg.Printf("] }}"); | |
152 Socket::Write(debugger_fd_, msg.buf(), msg.length()); | 266 Socket::Write(debugger_fd_, msg.buf(), msg.length()); |
153 // TODO(hausner): Error checking. Probably just shut down the debugger | 267 // TODO(hausner): Error checking. Probably just shut down the debugger |
154 // session if we there is an error while writing. | 268 // session if we there is an error while writing. |
155 } | 269 } |
156 | 270 |
157 | 271 |
158 void DebuggerConnectionHandler::HandleMessages() { | 272 void DebuggerConnectionHandler::HandleMessages() { |
273 static JSONDebuggerCommand debugger_commands[] = { | |
274 { "resume", HandleResumeCmd }, | |
275 { "getLibraryURLs", HandleGetLibraryURLsCmd}, | |
276 { "getScriptURLs", HandleGetScriptURLsCmd }, | |
277 { "stepInto", HandleStepIntoCmd }, | |
278 { "stepOut", HandleStepOutCmd }, | |
279 { "stepOver", HandleStepOverCmd }, | |
280 { NULL, NULL } | |
281 }; | |
282 | |
159 for (;;) { | 283 for (;;) { |
160 while (!msgbuf_->IsValidMessage() && msgbuf_->Alive()) { | 284 while (!msgbuf_->IsValidMessage() && msgbuf_->Alive()) { |
161 msgbuf_->ReadData(); | 285 msgbuf_->ReadData(); |
162 } | 286 } |
163 if (!msgbuf_->Alive()) { | 287 if (!msgbuf_->Alive()) { |
164 return; | 288 return; |
165 } | 289 } |
166 dart::JSONReader r(msgbuf_->buf()); | 290 dart::JSONReader r(msgbuf_->buf()); |
167 bool found = r.Seek("command"); | 291 bool found = r.Seek("command"); |
168 if (r.Error()) { | 292 if (r.Error()) { |
169 FATAL("Illegal JSON message received"); | 293 FATAL("Illegal JSON message received"); |
170 } | 294 } |
171 if (!found) { | 295 if (!found) { |
172 printf("'command' not found in JSON message: '%s'\n", msgbuf_->buf()); | 296 printf("'command' not found in JSON message: '%s'\n", msgbuf_->buf()); |
173 msgbuf_->PopMessage(); | 297 msgbuf_->PopMessage(); |
174 } else if (r.IsStringLiteral("resume")) { | 298 } |
175 HandleResumeCmd(); | 299 int i = 0; |
176 msgbuf_->PopMessage(); | 300 bool is_handled = false; |
177 return; | 301 request_resume_ = false; |
178 } else { | 302 while (debugger_commands[i].cmd_string != NULL) { |
303 if (r.IsStringLiteral(debugger_commands[i].cmd_string)) { | |
304 is_handled = true; | |
305 (*debugger_commands[i].handler_function)(msgbuf_->buf()); | |
306 msgbuf_->PopMessage(); | |
307 if (request_resume_) { | |
308 return; | |
309 } | |
310 break; | |
311 } | |
312 i++; | |
313 } | |
314 if (!is_handled) { | |
siva
2012/05/10 20:08:36
It appears that the loop above could handle multip
hausner
2012/05/10 22:36:28
If a message is handled, the break statement in li
| |
179 printf("unrecognized command received: '%s'\n", msgbuf_->buf()); | 315 printf("unrecognized command received: '%s'\n", msgbuf_->buf()); |
180 msgbuf_->PopMessage(); | 316 msgbuf_->PopMessage(); |
181 } | 317 } |
182 } | 318 } |
183 } | 319 } |
184 | 320 |
185 | 321 |
186 void DebuggerConnectionHandler::SendBreakpointEvent(Dart_Breakpoint bpt, | 322 void DebuggerConnectionHandler::SendBreakpointEvent(Dart_Breakpoint bpt, |
187 Dart_StackTrace trace) { | 323 Dart_StackTrace trace) { |
188 dart::TextBuffer msg(128); | 324 dart::TextBuffer msg(128); |
189 intptr_t trace_len = 0; | 325 intptr_t trace_len = 0; |
190 Dart_Handle res = Dart_StackTraceLength(trace, &trace_len); | 326 Dart_Handle res = Dart_StackTraceLength(trace, &trace_len); |
191 ASSERT_NOT_ERROR(res); | 327 ASSERT_NOT_ERROR(res); |
192 msg.Printf("{ \"command\" : \"paused\", \"params\" : "); | 328 msg.Printf("{ \"event\": \"paused\", \"params\": "); |
193 msg.Printf("{ \"callFrames\" : [ "); | 329 msg.Printf("{ \"callFrames\" : [ "); |
194 for (int i = 0; i < trace_len; i++) { | 330 for (int i = 0; i < trace_len; i++) { |
195 Dart_ActivationFrame frame; | 331 Dart_ActivationFrame frame; |
196 res = Dart_GetActivationFrame(trace, i, &frame); | 332 res = Dart_GetActivationFrame(trace, i, &frame); |
197 ASSERT_NOT_ERROR(res); | 333 ASSERT_NOT_ERROR(res); |
198 Dart_Handle func_name; | 334 Dart_Handle func_name; |
199 Dart_Handle script_url; | 335 Dart_Handle script_url; |
200 intptr_t line_number = 0; | 336 intptr_t line_number = 0; |
201 res = Dart_ActivationFrameInfo( | 337 res = Dart_ActivationFrameInfo( |
202 frame, &func_name, &script_url, &line_number); | 338 frame, &func_name, &script_url, &line_number); |
203 ASSERT_NOT_ERROR(res); | 339 ASSERT_NOT_ERROR(res); |
204 ASSERT(Dart_IsString(func_name)); | 340 ASSERT(Dart_IsString(func_name)); |
205 const char* func_name_chars; | 341 const char* func_name_chars; |
206 Dart_StringToCString(func_name, &func_name_chars); | 342 Dart_StringToCString(func_name, &func_name_chars); |
207 msg.Printf("%s { \"functionName\" : \"%s\" , ", | 343 msg.Printf("%s { \"functionName\": \"%s\" , ", |
208 i > 0 ? "," : "", | 344 i > 0 ? "," : "", |
209 func_name_chars); | 345 func_name_chars); |
210 ASSERT(Dart_IsString(script_url)); | 346 ASSERT(Dart_IsString(script_url)); |
211 const char* script_url_chars; | 347 const char* script_url_chars; |
212 Dart_StringToCString(script_url, &script_url_chars); | 348 Dart_StringToCString(script_url, &script_url_chars); |
213 msg.Printf("\"location\": { \"url\": \"%s\", \"lineNumber\": %d }}", | 349 msg.Printf("\"location\": { \"url\": \"%s\", \"lineNumber\": %d }}", |
214 script_url_chars, line_number); | 350 script_url_chars, line_number); |
215 } | 351 } |
216 msg.Printf("]}}"); | 352 msg.Printf("]}}"); |
217 Socket::Write(debugger_fd_, msg.buf(), msg.length()); | 353 Socket::Write(debugger_fd_, msg.buf(), msg.length()); |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
269 | 405 |
270 handler_started_ = true; | 406 handler_started_ = true; |
271 DebuggerConnectionImpl::StartHandler(port_number); | 407 DebuggerConnectionImpl::StartHandler(port_number); |
272 Dart_SetBreakpointHandler(BreakpointHandler); | 408 Dart_SetBreakpointHandler(BreakpointHandler); |
273 } | 409 } |
274 | 410 |
275 | 411 |
276 DebuggerConnectionHandler::~DebuggerConnectionHandler() { | 412 DebuggerConnectionHandler::~DebuggerConnectionHandler() { |
277 CloseDbgConnection(); | 413 CloseDbgConnection(); |
278 } | 414 } |
OLD | NEW |