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

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

Issue 10357003: Beginnings of a debugger wire protocol (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 7 months 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 | Annotate | Revision Log
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/dartutils.h"
7 #include "bin/fdutils.h"
8 #include "bin/socket.h"
9 #include "bin/thread.h"
10 #include "bin/utils.h"
11
12 #include "platform/globals.h"
13 #include "platform/json.h"
14 #include "platform/thread.h"
15 #include "platform/utils.h"
16
17 #include "include/dart_api.h"
18
19
20 int DebuggerConnectionHandler::listener_fd_ = -1;
21 int DebuggerConnectionHandler::debugger_fd_ = -1;
22 MessageBuffer* DebuggerConnectionHandler::msgbuf_ = NULL;
23
24 bool DebuggerConnectionHandler::handler_started_ = false;
25
26
27 // TODO(hausner): Need better error handling.
28 #define ASSERT_NOT_ERROR(handle) \
29 ASSERT(!Dart_IsError(handle))
30
31
32 class MessageBuffer {
33 public:
34 explicit MessageBuffer(int fd);
35 ~MessageBuffer();
36 void ReadData();
37 bool IsValidMessage() const;
38 void PopMessage();
39 int MessageId() const;
40 char* buf() const { return buf_; }
41 bool Alive() const { return connection_is_alive_; }
42
43 private:
44 static const int kInitialBufferSize = 256;
45 char* buf_;
46 int buf_length_;
47 int fd_;
48 int data_length_;
49 bool connection_is_alive_;
siva 2012/05/03 22:52:08 The DISALLOW stuff ....
hausner 2012/05/03 23:52:00 Done.
50 };
51
52
53 MessageBuffer::MessageBuffer(int fd)
54 : buf_(NULL),
55 buf_length_(0),
56 fd_(fd),
57 data_length_(0),
58 connection_is_alive_(true) {
59 buf_ = reinterpret_cast<char*>(malloc(kInitialBufferSize));
60 if (buf_ == NULL) {
61 FATAL("Failed to allocate message buffer\n");
62 }
63 buf_length_ = kInitialBufferSize;
64 buf_[0] = '\0';
65 data_length_ = 0;
66 }
67
68
69 MessageBuffer::~MessageBuffer() {
70 free(buf_);
71 buf_ = NULL;
72 fd_ = -1;
73 }
74
75
76 bool MessageBuffer::IsValidMessage() const {
77 if (data_length_ == 0) {
78 return false;
79 }
80 dart::JSONReader msg_reader(buf_);
81 return msg_reader.EndOfObject() != NULL;
82 }
83
84
85 int MessageBuffer::MessageId() const {
86 dart::JSONReader r(buf_);
87 r.Seek("id");
88 if (r.Type() == dart::JSONReader::kInteger) {
89 return atoi(r.ValueChars());
90 } else {
91 return -1;
92 }
93 }
94
95
96 void MessageBuffer::ReadData() {
97 ASSERT(data_length_ >= 0);
98 ASSERT(data_length_ < buf_length_);
99 int max_read = buf_length_ - data_length_ - 1;
100 if (max_read == 0) {
101 // TODO(hausner):
102 // Buffer is full. What should we do if there is no valid message
103 // in the buffer? This might be possible if the client sends a message
104 // that's larger than the buffer, of if the client sends malformed
105 // messages that keep piling up.
106 ASSERT(IsValidMessage());
107 return;
108 }
109 int bytes_read = Socket::Read(fd_, buf_ + data_length_, max_read);
siva 2012/05/03 22:52:08 Socket:;Read could also return -1 on error conditi
hausner 2012/05/03 23:52:00 Done.
110 if (bytes_read == 0) {
siva 2012/05/03 22:52:08 Socket::Read seems to have some weird code in ther
hausner 2012/05/03 23:52:00 Yes I think on non-blocking sockets they treat the
111 connection_is_alive_ = false;
112 return;
113 }
114 ASSERT(bytes_read > 0);
115 data_length_ += bytes_read;
116 ASSERT(data_length_ < buf_length_);
117 buf_[data_length_] = '\0';
118 }
119
120
121 void MessageBuffer::PopMessage() {
122 dart::JSONReader msg_reader(buf_);
123 const char* end = msg_reader.EndOfObject();
124 if (end != NULL) {
125 ASSERT(*end == '}');
126 end++;
127 data_length_ = 0;
128 while (*end != '\0') {
129 buf_[data_length_] = *end++;
130 data_length_++;
131 }
132 buf_[data_length_] = '\0';
133 ASSERT(data_length_ < buf_length_);
siva 2012/05/03 22:52:08 This assert should be inside the loop where data_l
hausner 2012/05/03 23:52:00 True, but rather than slowing things down too much
134 }
135 }
136
137
138 static bool IsValidJSON(const char* msg) {
139 dart::JSONReader r(msg);
140 return r.EndOfObject() != NULL;
141 }
142
143
144 void DebuggerConnectionHandler::HandleResumeCmd() {
145 int msg_id = msgbuf_->MessageId();
146 dart::TextBuffer msg(64);
147 msg.Printf("{ \"id\": %d }", msg_id);
148 FDUtils::WriteToBlocking(debugger_fd_, msg.buf(), msg.length());
siva 2012/05/03 22:52:08 Need to check for return value from WriteToBlockin
hausner 2012/05/03 23:52:00 Added a TODO for error checking. On 2012/05/03 22
149 }
150
151
152 void DebuggerConnectionHandler::HandleMessages() {
153 for (;;) {
154 while (!msgbuf_->IsValidMessage() && msgbuf_->Alive()) {
155 msgbuf_->ReadData();
156 }
157 if (!msgbuf_->Alive()) {
158 return;
159 }
160 dart::JSONReader r(msgbuf_->buf());
161 bool found = r.Seek("command");
162 if (r.Error()) {
163 FATAL("Illegal JSON message received");
164 }
165 if (!found) {
166 printf("'command' not found in JSON message: '%s'\n", msgbuf_->buf());
167 msgbuf_->PopMessage();
168 } else if (r.IsStringLiteral("resume")) {
169 HandleResumeCmd();
170 msgbuf_->PopMessage();
171 return;
172 } else {
173 printf("unrecognized command received: '%s'\n", msgbuf_->buf());
174 msgbuf_->PopMessage();
175 }
176 }
177 }
178
179
180 void DebuggerConnectionHandler::SendBreakpointEvent(Dart_Breakpoint bpt,
181 Dart_StackTrace trace) {
182 dart::TextBuffer msg(128);
183 intptr_t trace_len = 0;
184 Dart_Handle res = Dart_StackTraceLength(trace, &trace_len);
185 ASSERT_NOT_ERROR(res);
186 msg.Printf("{ \"command\" : \"paused\", \"params\" : ");
187 msg.Printf("{ \"callFrames\" : [ ");
188 for (int i = 0; i < trace_len; i++) {
189 Dart_ActivationFrame frame;
190 res = Dart_GetActivationFrame(trace, i, &frame);
191 ASSERT_NOT_ERROR(res);
192 Dart_Handle func_name;
193 Dart_Handle script_url;
194 intptr_t line_number = 0;
195 res = Dart_ActivationFrameInfo(
196 frame, &func_name, &script_url, &line_number);
197 ASSERT_NOT_ERROR(res);
198 ASSERT(Dart_IsString(func_name));
199 const char* func_name_chars;
200 Dart_StringToCString(func_name, &func_name_chars);
201 msg.Printf("%s { \"functionName\" : \"%s\" , ",
202 i > 0 ? "," : "",
203 func_name_chars);
204 ASSERT(Dart_IsString(script_url));
205 const char* script_url_chars;
206 Dart_StringToCString(script_url, &script_url_chars);
207 msg.Printf("\"location\": { \"scriptId\": \"%s\", \"lineNumber\": %d }}",
208 script_url_chars, line_number);
209 }
210 msg.Printf("]}}");
211 printf("Breakpoint event message: '%s'\n", msg.buf());
212 ASSERT(IsValidJSON(msg.buf()));
213 }
214
215
216 void DebuggerConnectionHandler::BreakpointHandler(Dart_Breakpoint bpt,
217 Dart_StackTrace trace) {
218 while (!IsConnected()) {
219 printf("Waiting for debugger connection\n");
220 sleep(1);
221 }
siva 2012/05/03 22:52:08 I am wondering if this loop instead of sitting her
hausner 2012/05/03 23:52:00 True, but fairly soon I plan to support the "pause
222 SendBreakpointEvent(bpt, trace);
223 HandleMessages();
224 if (!msgbuf_->Alive()) {
225 CloseDbgConnection();
226 }
227 }
228
229
230 void DebuggerConnectionHandler::AcceptDbgConnection(int debugger_fd) {
231 debugger_fd_ = debugger_fd;
232 ASSERT(msgbuf_ == NULL);
233 msgbuf_ = new MessageBuffer(debugger_fd_);
234 }
235
236 void DebuggerConnectionHandler::CloseDbgConnection() {
237 if (debugger_fd_ >= 0) {
238 // TODO(hausner): need a Socket::Close() function.
239 }
240 if (msgbuf_ != NULL) {
241 delete msgbuf_;
242 msgbuf_ = NULL;
243 }
siva 2012/05/03 22:52:08 What about the debugger state (breakpoints set etc
hausner 2012/05/03 23:52:00 Good point. I was thinking of removing all breakpo
244 }
245
246 void DebuggerConnectionHandler::StartHandler(int port_number) {
247 if (handler_started_) {
248 return;
249 }
250 ASSERT(listener_fd_ == -1);
251 listener_fd_ = ServerSocket::CreateBindListen("127.0.0.1", port_number, 1);
siva 2012/05/03 22:52:08 instead of hard coding the ip address why not acce
hausner 2012/05/03 23:52:00 I moved this default IP address to main.cc and add
252
253 handler_started_ = true;
254 DebuggerConnectionImpl::StartHandler(port_number);
255 Dart_SetBreakpointHandler(BreakpointHandler);
256 }
257
258
259 DebuggerConnectionHandler::~DebuggerConnectionHandler() {
260 CloseDbgConnection();
261 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698