Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5)

Side by Side Diff: runtime/bin/dbg_connection.cc

Issue 1497033003: - Remove the legacy debug protocol. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 #include "bin/dbg_connection.h"
6 #include "bin/dbg_message.h"
7 #include "bin/dartutils.h"
8 #include "bin/lockers.h"
9 #include "bin/log.h"
10 #include "bin/socket.h"
11 #include "bin/thread.h"
12 #include "bin/utils.h"
13
14 #include "platform/globals.h"
15 #include "platform/json.h"
16 #include "platform/utils.h"
17
18 #include "include/dart_api.h"
19
20
21 namespace dart {
22 namespace bin {
23
24 bool trace_debug_protocol = false;
25
26 intptr_t DebuggerConnectionHandler::listener_fd_ = -1;
27 Monitor* DebuggerConnectionHandler::handler_lock_ = new Monitor();
28
29 // TODO(asiva): Remove this once we have support for multiple debugger
30 // connections. For now we just store the single debugger connection
31 // handler in a static variable.
32 static DebuggerConnectionHandler* singleton_handler = NULL;
33
34 // The maximum message length to print when --trace_debug_protocol is
35 // specified.
36 static const int kMaxPrintMessageLen = 1024;
37
38 class MessageBuffer {
39 public:
40 explicit MessageBuffer(intptr_t fd);
41 ~MessageBuffer();
42 void ReadData();
43 bool IsValidMessage() const;
44 void PopMessage();
45 int MessageId() const;
46 char* buf() const { return buf_; }
47 bool Alive() const { return connection_is_alive_; }
48
49 private:
50 static const int kInitialBufferSize = 256;
51 char* buf_;
52 int buf_length_;
53 intptr_t fd_;
54 int data_length_;
55 bool connection_is_alive_;
56
57 DISALLOW_COPY_AND_ASSIGN(MessageBuffer);
58 };
59
60
61 MessageBuffer::MessageBuffer(intptr_t fd)
62 : buf_(NULL),
63 buf_length_(0),
64 fd_(fd),
65 data_length_(0),
66 connection_is_alive_(true) {
67 buf_ = reinterpret_cast<char*>(malloc(kInitialBufferSize));
68 if (buf_ == NULL) {
69 FATAL("Failed to allocate message buffer\n");
70 }
71 buf_length_ = kInitialBufferSize;
72 buf_[0] = '\0';
73 data_length_ = 0;
74 }
75
76
77 MessageBuffer::~MessageBuffer() {
78 free(buf_);
79 buf_ = NULL;
80 fd_ = -1;
81 }
82
83
84 bool MessageBuffer::IsValidMessage() const {
85 if (data_length_ == 0) {
86 return false;
87 }
88 dart::JSONReader msg_reader(buf_);
89 return msg_reader.EndOfObject() != NULL;
90 }
91
92
93 int MessageBuffer::MessageId() const {
94 dart::JSONReader r(buf_);
95 r.Seek("id");
96 if (r.Type() == dart::JSONReader::kInteger) {
97 return atoi(r.ValueChars());
98 } else {
99 return -1;
100 }
101 }
102
103
104 void MessageBuffer::ReadData() {
105 ASSERT(data_length_ >= 0);
106 ASSERT(data_length_ < buf_length_);
107 int max_read = buf_length_ - data_length_ - 1;
108 if (max_read == 0) {
109 // TODO(hausner):
110 // Buffer is full. What should we do if there is no valid message
111 // in the buffer? This might be possible if the client sends a message
112 // that's larger than the buffer, of if the client sends malformed
113 // messages that keep piling up.
114 ASSERT(IsValidMessage());
115 return;
116 }
117 // TODO(hausner): Handle error conditions returned by Read. We may
118 // want to close the debugger connection if we get any errors.
119 int bytes_read =
120 DebuggerConnectionImpl::Receive(fd_, buf_ + data_length_, max_read);
121 if (bytes_read == 0) {
122 connection_is_alive_ = false;
123 return;
124 }
125 ASSERT(bytes_read > 0);
126 data_length_ += bytes_read;
127 ASSERT(data_length_ < buf_length_);
128 buf_[data_length_] = '\0';
129 }
130
131
132 void MessageBuffer::PopMessage() {
133 dart::JSONReader msg_reader(buf_);
134 const char* end = msg_reader.EndOfObject();
135 if (end != NULL) {
136 ASSERT(*end == '}');
137 end++;
138 data_length_ = 0;
139 while (*end != '\0') {
140 buf_[data_length_] = *end++;
141 data_length_++;
142 }
143 buf_[data_length_] = '\0';
144 ASSERT(data_length_ < buf_length_);
145 }
146 }
147
148
149 static bool IsValidJSON(const char* msg) {
150 dart::JSONReader r(msg);
151 return r.CheckMessage();
152 }
153
154
155 DebuggerConnectionHandler::DebuggerConnectionHandler(intptr_t debug_fd)
156 : debug_fd_(debug_fd), msgbuf_(NULL) {
157 msgbuf_ = new MessageBuffer(debug_fd_);
158 }
159
160
161 DebuggerConnectionHandler::~DebuggerConnectionHandler() {
162 CloseDbgConnection();
163 DebuggerConnectionHandler::RemoveDebuggerConnection(debug_fd_);
164 }
165
166
167 int DebuggerConnectionHandler::MessageId() {
168 ASSERT(msgbuf_ != NULL);
169 return msgbuf_->MessageId();
170 }
171
172
173 void DebuggerConnectionHandler::HandleUnknownMsg() {
174 int msg_id = msgbuf_->MessageId();
175 ASSERT(msg_id >= 0);
176 SendError(debug_fd_, msg_id, "unknown debugger command");
177 }
178
179
180 typedef void (*CommandHandler)(DbgMessage* msg);
181
182 struct JSONDebuggerCommand {
183 const char* cmd_string;
184 CommandHandler handler_function;
185 };
186
187
188 void DebuggerConnectionHandler::HandleMessages() {
189 static JSONDebuggerCommand generic_debugger_commands[] = {
190 { "interrupt", HandleInterruptCmd },
191 { "getIsolateIds", HandleIsolatesListCmd },
192 { NULL, NULL }
193 };
194
195 for (;;) {
196 // Read a message.
197 while (!msgbuf_->IsValidMessage() && msgbuf_->Alive()) {
198 msgbuf_->ReadData();
199 }
200 if (!msgbuf_->Alive()) {
201 if (trace_debug_protocol) {
202 Log::Print("Debugger is exiting HandleMessages loop.\n");
203 }
204 return;
205 }
206
207 if (trace_debug_protocol) {
208 dart::JSONReader r(msgbuf_->buf());
209 const char* msg_end = r.EndOfObject();
210 if (msg_end != NULL) {
211 intptr_t msg_len = msg_end - msgbuf_->buf();
212 int print_len = ((msg_len > kMaxPrintMessageLen)
213 ? kMaxPrintMessageLen : msg_len);
214 Log::Print("[<<<] Receiving message from debug fd %" Pd ":\n%.*s%s\n",
215 debug_fd_, print_len, msgbuf_->buf(),
216 ((msg_len > print_len) ? "..." : ""));
217 }
218 }
219
220 // Parse out the command portion from the message.
221 dart::JSONReader r(msgbuf_->buf());
222 bool found = r.Seek("command");
223 if (r.Error()) {
224 FATAL("Illegal JSON message received");
225 }
226 if (!found) {
227 Log::Print("'command' not found in JSON message: '%s'\n",
228 msgbuf_->buf());
229 msgbuf_->PopMessage();
230 }
231
232 // Check if this is a generic command (not isolate specific).
233 int i = 0;
234 bool is_handled = false;
235 while (generic_debugger_commands[i].cmd_string != NULL) {
236 if (r.IsStringLiteral(generic_debugger_commands[i].cmd_string)) {
237 DbgMessage* msg = new DbgMessage(i,
238 msgbuf_->buf(),
239 r.EndOfObject(),
240 debug_fd_);
241 (*generic_debugger_commands[i].handler_function)(msg);
242 is_handled = true;
243 msgbuf_->PopMessage();
244 delete msg;
245 break;
246 }
247 i++;
248 }
249 if (!is_handled) {
250 // Check if this is an isolate specific command.
251 int32_t cmd_idx = DbgMsgQueueList::LookupIsolateCommand(r.ValueChars(),
252 r.ValueLen());
253 if (cmd_idx != DbgMsgQueueList::kInvalidCommand) {
254 const char* start = msgbuf_->buf();
255 const char* end = r.EndOfObject();
256 // Get debug message queue corresponding to isolate.
257 MessageParser msg_parser(start, (end - start));
258 Dart_IsolateId isolate_id = msg_parser.GetInt64Param("isolateId");
259 if (!DbgMsgQueueList::AddIsolateMessage(isolate_id,
260 cmd_idx,
261 msgbuf_->buf(),
262 r.EndOfObject(),
263 debug_fd_)) {
264 SendError(debug_fd_, MessageId(), "Invalid isolate specified");
265 }
266 msgbuf_->PopMessage();
267 continue;
268 }
269
270 // This is an unrecognized command, report error and move on to next.
271 Log::Print("unrecognized command received: '%s'\n", msgbuf_->buf());
272 HandleUnknownMsg();
273 msgbuf_->PopMessage();
274 }
275 }
276 }
277
278
279 void DebuggerConnectionHandler::SendError(intptr_t debug_fd,
280 int msg_id,
281 const char* err_msg) {
282 dart::TextBuffer msg(64);
283 msg.Printf("{\"id\": %d, \"error\": \"Error: ", msg_id);
284 msg.AddEscapedString(err_msg);
285 msg.Printf("\"}");
286 SendMsg(debug_fd, &msg);
287 }
288
289
290 void DebuggerConnectionHandler::CloseDbgConnection() {
291 if (debug_fd_ >= 0) {
292 Socket::Close(debug_fd_);
293 }
294 if (msgbuf_ != NULL) {
295 delete msgbuf_;
296 msgbuf_ = NULL;
297 }
298 // TODO(hausner): Need to tell the VM debugger object to remove all
299 // breakpoints.
300 }
301
302
303 // The vm service relies on certain debugger functionality.
304 void DebuggerConnectionHandler::InitForVmService() {
305 MonitorLocker ml(handler_lock_);
306 DbgMsgQueueList::Initialize();
307 }
308
309
310 int DebuggerConnectionHandler::StartHandler(const char* address,
311 int port_number) {
312 ASSERT(handler_lock_ != NULL);
313 MonitorLocker ml(handler_lock_);
314 if (IsListening()) {
315 // The debugger connection handler was already started.
316 return Socket::GetPort(listener_fd_);
317 }
318
319 // First setup breakpoint, exception and delayed breakpoint handlers.
320 DbgMsgQueueList::Initialize();
321
322 // Initialize the socket implementation.
323 if (!Socket::Initialize()) {
324 FATAL("Failed initializing socket implementation.");
325 }
326
327 // Now setup a listener socket and start a thread which will
328 // listen, accept connections from debuggers, read and handle/dispatch
329 // debugger commands received on these connections.
330 ASSERT(listener_fd_ == -1);
331 OSError *os_error;
332 AddressList<SocketAddress>* addresses =
333 Socket::LookupAddress(address, -1, &os_error);
334 RawAddr addr = addresses->GetAt(0)->addr();
335 SocketAddress::SetAddrPort(&addr, port_number);
336 listener_fd_ = ServerSocket::CreateBindListen(addr, 1);
337 delete addresses;
338 if (listener_fd_ < 0) {
339 fprintf(stderr, "%s", "Could not initialize debug socket\n");
340 fflush(stderr);
341 exit(255);
342 }
343
344 port_number = Socket::GetPort(listener_fd_);
345 DebuggerConnectionImpl::StartHandler(port_number);
346 return port_number;
347 }
348
349
350 void DebuggerConnectionHandler::StopHandler() {
351 if (IsConnected()) {
352 DebuggerConnectionImpl::StopHandler(singleton_handler->debug_fd());
353 }
354 }
355
356
357 void DebuggerConnectionHandler::WaitForConnection() {
358 ASSERT(handler_lock_ != NULL);
359 MonitorLocker ml(handler_lock_);
360 if (!IsListening()) {
361 // If we are only running the vm service, don't wait for
362 // connections.
363 return;
364 }
365 while (!IsConnected()) {
366 Monitor::WaitResult res = ml.Wait();
367 ASSERT(res == Monitor::kNotified);
368 }
369 }
370
371
372 void DebuggerConnectionHandler::SendMsg(intptr_t debug_fd,
373 dart::TextBuffer* msg) {
374 ASSERT(handler_lock_ != NULL);
375 MonitorLocker ml(handler_lock_);
376 SendMsgHelper(debug_fd, msg);
377 }
378
379
380 void DebuggerConnectionHandler::BroadcastMsg(dart::TextBuffer* msg) {
381 ASSERT(handler_lock_ != NULL);
382 MonitorLocker ml(handler_lock_);
383 if (!IsListening()) {
384 // If we are only running the vm service, don't try to broadcast
385 // to debugger clients.
386 return;
387 }
388 // TODO(asiva): Once we support connection to multiple debuggers
389 // we need to send the message to all of them.
390 ASSERT(singleton_handler != NULL);
391 SendMsgHelper(singleton_handler->debug_fd(), msg);
392 }
393
394
395 void DebuggerConnectionHandler::SendMsgHelper(intptr_t debug_fd,
396 dart::TextBuffer* msg) {
397 ASSERT(debug_fd >= 0);
398 ASSERT(IsValidJSON(msg->buf()));
399
400 if (trace_debug_protocol) {
401 int print_len = ((msg->length() > kMaxPrintMessageLen)
402 ? kMaxPrintMessageLen : msg->length());
403 Log::Print("[>>>] Sending message to debug fd %" Pd ":\n%.*s%s\n",
404 debug_fd, print_len, msg->buf(),
405 ((msg->length() > print_len) ? "..." : ""));
406 }
407
408 // Sending messages in short pieces can be used to stress test the
409 // debugger front-end's message handling code.
410 const bool send_in_pieces = false;
411 if (send_in_pieces) {
412 intptr_t remaining = msg->length();
413 intptr_t sent = 0;
414 const intptr_t max_piece_len = 122; // Pretty arbitrary, not a power of 2.
415 Monitor sleep;
416 while (remaining > 0) {
417 intptr_t piece_len = remaining;
418 if (piece_len > max_piece_len) {
419 piece_len = max_piece_len;
420 }
421 intptr_t written =
422 DebuggerConnectionImpl::Send(debug_fd, msg->buf() + sent, piece_len);
423 ASSERT(written == piece_len);
424 sent += written;
425 remaining -= written;
426 // Wait briefly so the OS does not coalesce message fragments.
427 {
428 MonitorLocker ml(&sleep);
429 ml.Wait(10);
430 }
431 }
432 return;
433 }
434 intptr_t bytes_written =
435 DebuggerConnectionImpl::Send(debug_fd, msg->buf(), msg->length());
436 ASSERT(msg->length() == bytes_written);
437 // TODO(hausner): Error checking. Probably just shut down the debugger
438 // session if we there is an error while writing.
439 }
440
441
442 void DebuggerConnectionHandler::AcceptDbgConnection(intptr_t debug_fd) {
443 Socket::SetNoDelay(debug_fd, true);
444 AddNewDebuggerConnection(debug_fd);
445 {
446 ASSERT(handler_lock_ != NULL);
447 MonitorLocker ml(handler_lock_);
448 ml.NotifyAll();
449 }
450 // TODO(asiva): Once we implement support for multiple connections
451 // we should have a different callback for wakeups on fds which
452 // are not the listener_fd_.
453 // In that callback we would lookup the handler object
454 // corresponding to that fd and invoke HandleMessages on it.
455 // For now we run that code here.
456 DebuggerConnectionHandler* handler = GetDebuggerConnectionHandler(debug_fd);
457 if (handler != NULL) {
458 handler->HandleMessages();
459 delete handler;
460 }
461 }
462
463
464 void DebuggerConnectionHandler::HandleInterruptCmd(DbgMessage* in_msg) {
465 MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
466 int msg_id = msg_parser.MessageId();
467 Dart_IsolateId isolate_id = msg_parser.GetInt64Param("isolateId");
468 if (isolate_id == ILLEGAL_ISOLATE_ID || Dart_GetIsolate(isolate_id) == NULL) {
469 in_msg->SendErrorReply(msg_id, "Invalid isolate specified");
470 return;
471 }
472 if (!DbgMsgQueueList::InterruptIsolate(isolate_id)) {
473 in_msg->SendErrorReply(msg_id, "Invalid isolate specified");
474 return;
475 }
476 dart::TextBuffer msg(64);
477 msg.Printf("{ \"id\": %d }", msg_id);
478 in_msg->SendReply(&msg);
479 }
480
481
482 void DebuggerConnectionHandler::HandleIsolatesListCmd(DbgMessage* in_msg) {
483 MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
484 int msg_id = msg_parser.MessageId();
485 ASSERT(msg_id >= 0);
486 dart::TextBuffer msg(64);
487 msg.Printf("{ \"id\": %d, \"result\": { \"isolateIds\": [", msg_id);
488 DbgMsgQueueList::ListIsolateIds(&msg);
489 msg.Printf("]}}");
490 in_msg->SendReply(&msg);
491 }
492
493
494 void DebuggerConnectionHandler::AddNewDebuggerConnection(intptr_t debug_fd) {
495 // TODO(asiva): Support multiple debugger connections, for now we just
496 // create one handler, store it in a static variable and use it.
497 ASSERT(singleton_handler == NULL);
498 singleton_handler = new DebuggerConnectionHandler(debug_fd);
499 }
500
501
502 void DebuggerConnectionHandler::RemoveDebuggerConnection(intptr_t debug_fd) {
503 // TODO(asiva): Support multiple debugger connections, for now we just
504 // set the static handler back to NULL.
505 ASSERT(singleton_handler != NULL);
506 singleton_handler = NULL;
507 }
508
509
510 DebuggerConnectionHandler*
511 DebuggerConnectionHandler::GetDebuggerConnectionHandler(intptr_t debug_fd) {
512 // TODO(asiva): Support multiple debugger connections, for now we just
513 // return the one static handler that was created.
514 ASSERT(singleton_handler != NULL);
515 return singleton_handler;
516 }
517
518
519 bool DebuggerConnectionHandler::IsConnected() {
520 // TODO(asiva): Support multiple debugger connections.
521 // Return true if a connection has been established.
522 return singleton_handler != NULL;
523 }
524
525 } // namespace bin
526 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698