OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "d8.h" | 5 #include "d8.h" |
6 #include "d8-debug.h" | 6 #include "d8-debug.h" |
7 #include "debug-agent.h" | |
8 #include "platform/socket.h" | |
9 | |
10 | 7 |
11 namespace v8 { | 8 namespace v8 { |
12 | 9 |
13 static bool was_running = true; | |
14 | |
15 void PrintPrompt(bool is_running) { | 10 void PrintPrompt(bool is_running) { |
16 const char* prompt = is_running? "> " : "dbg> "; | 11 const char* prompt = is_running? "> " : "dbg> "; |
17 was_running = is_running; | |
18 printf("%s", prompt); | 12 printf("%s", prompt); |
19 fflush(stdout); | 13 fflush(stdout); |
20 } | 14 } |
21 | 15 |
22 | 16 |
23 void PrintPrompt() { | |
24 PrintPrompt(was_running); | |
25 } | |
26 | |
27 | |
28 void HandleDebugEvent(const Debug::EventDetails& event_details) { | 17 void HandleDebugEvent(const Debug::EventDetails& event_details) { |
29 // TODO(svenpanne) There should be a way to retrieve this in the callback. | 18 // TODO(svenpanne) There should be a way to retrieve this in the callback. |
30 Isolate* isolate = Isolate::GetCurrent(); | 19 Isolate* isolate = Isolate::GetCurrent(); |
31 HandleScope scope(isolate); | 20 HandleScope scope(isolate); |
32 | 21 |
33 DebugEvent event = event_details.GetEvent(); | 22 DebugEvent event = event_details.GetEvent(); |
34 // Check for handled event. | 23 // Check for handled event. |
35 if (event != Break && event != Exception && event != AfterCompile) { | 24 if (event != Break && event != Exception && event != AfterCompile) { |
36 return; | 25 return; |
37 } | 26 } |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
133 response_details->Get(String::NewFromUtf8(isolate, "text"))); | 122 response_details->Get(String::NewFromUtf8(isolate, "text"))); |
134 if (text_str.length() > 0) { | 123 if (text_str.length() > 0) { |
135 printf("%s\n", *text_str); | 124 printf("%s\n", *text_str); |
136 } | 125 } |
137 running = response_details->Get(String::NewFromUtf8(isolate, "running")) | 126 running = response_details->Get(String::NewFromUtf8(isolate, "running")) |
138 ->ToBoolean() | 127 ->ToBoolean() |
139 ->Value(); | 128 ->Value(); |
140 } | 129 } |
141 } | 130 } |
142 | 131 |
143 | |
144 void RunRemoteDebugger(Isolate* isolate, int port) { | |
145 RemoteDebugger debugger(isolate, port); | |
146 debugger.Run(); | |
147 } | |
148 | |
149 | |
150 void RemoteDebugger::Run() { | |
151 bool ok; | |
152 | |
153 // Connect to the debugger agent. | |
154 conn_ = new i::Socket; | |
155 static const int kPortStrSize = 6; | |
156 char port_str[kPortStrSize]; | |
157 i::OS::SNPrintF(i::Vector<char>(port_str, kPortStrSize), "%d", port_); | |
158 ok = conn_->Connect("localhost", port_str); | |
159 if (!ok) { | |
160 printf("Unable to connect to debug agent %d\n", i::Socket::GetLastError()); | |
161 return; | |
162 } | |
163 | |
164 // Start the receiver thread. | |
165 ReceiverThread receiver(this); | |
166 receiver.Start(); | |
167 | |
168 // Start the keyboard thread. | |
169 KeyboardThread keyboard(this); | |
170 keyboard.Start(); | |
171 PrintPrompt(); | |
172 | |
173 // Process events received from debugged VM and from the keyboard. | |
174 bool terminate = false; | |
175 while (!terminate) { | |
176 event_available_.Wait(); | |
177 RemoteDebuggerEvent* event = GetEvent(); | |
178 switch (event->type()) { | |
179 case RemoteDebuggerEvent::kMessage: | |
180 HandleMessageReceived(event->data()); | |
181 break; | |
182 case RemoteDebuggerEvent::kKeyboard: | |
183 HandleKeyboardCommand(event->data()); | |
184 break; | |
185 case RemoteDebuggerEvent::kDisconnect: | |
186 terminate = true; | |
187 break; | |
188 | |
189 default: | |
190 UNREACHABLE(); | |
191 } | |
192 delete event; | |
193 } | |
194 | |
195 delete conn_; | |
196 conn_ = NULL; | |
197 // Wait for the receiver thread to end. | |
198 receiver.Join(); | |
199 } | |
200 | |
201 | |
202 void RemoteDebugger::MessageReceived(i::SmartArrayPointer<char> message) { | |
203 RemoteDebuggerEvent* event = | |
204 new RemoteDebuggerEvent(RemoteDebuggerEvent::kMessage, message); | |
205 AddEvent(event); | |
206 } | |
207 | |
208 | |
209 void RemoteDebugger::KeyboardCommand(i::SmartArrayPointer<char> command) { | |
210 RemoteDebuggerEvent* event = | |
211 new RemoteDebuggerEvent(RemoteDebuggerEvent::kKeyboard, command); | |
212 AddEvent(event); | |
213 } | |
214 | |
215 | |
216 void RemoteDebugger::ConnectionClosed() { | |
217 RemoteDebuggerEvent* event = | |
218 new RemoteDebuggerEvent(RemoteDebuggerEvent::kDisconnect, | |
219 i::SmartArrayPointer<char>()); | |
220 AddEvent(event); | |
221 } | |
222 | |
223 | |
224 void RemoteDebugger::AddEvent(RemoteDebuggerEvent* event) { | |
225 i::LockGuard<i::Mutex> lock_guard(&event_access_); | |
226 if (head_ == NULL) { | |
227 ASSERT(tail_ == NULL); | |
228 head_ = event; | |
229 tail_ = event; | |
230 } else { | |
231 ASSERT(tail_ != NULL); | |
232 tail_->set_next(event); | |
233 tail_ = event; | |
234 } | |
235 event_available_.Signal(); | |
236 } | |
237 | |
238 | |
239 RemoteDebuggerEvent* RemoteDebugger::GetEvent() { | |
240 i::LockGuard<i::Mutex> lock_guard(&event_access_); | |
241 ASSERT(head_ != NULL); | |
242 RemoteDebuggerEvent* result = head_; | |
243 head_ = head_->next(); | |
244 if (head_ == NULL) { | |
245 ASSERT(tail_ == result); | |
246 tail_ = NULL; | |
247 } | |
248 return result; | |
249 } | |
250 | |
251 | |
252 void RemoteDebugger::HandleMessageReceived(char* message) { | |
253 Locker lock(isolate_); | |
254 HandleScope scope(isolate_); | |
255 | |
256 // Print the event details. | |
257 TryCatch try_catch; | |
258 Handle<Object> details = Shell::DebugMessageDetails( | |
259 isolate_, Handle<String>::Cast(String::NewFromUtf8(isolate_, message))); | |
260 if (try_catch.HasCaught()) { | |
261 Shell::ReportException(isolate_, &try_catch); | |
262 PrintPrompt(); | |
263 return; | |
264 } | |
265 String::Utf8Value str(details->Get(String::NewFromUtf8(isolate_, "text"))); | |
266 if (str.length() == 0) { | |
267 // Empty string is used to signal not to process this event. | |
268 return; | |
269 } | |
270 if (*str != NULL) { | |
271 printf("%s\n", *str); | |
272 } else { | |
273 printf("???\n"); | |
274 } | |
275 | |
276 bool is_running = details->Get(String::NewFromUtf8(isolate_, "running")) | |
277 ->ToBoolean() | |
278 ->Value(); | |
279 PrintPrompt(is_running); | |
280 } | |
281 | |
282 | |
283 void RemoteDebugger::HandleKeyboardCommand(char* command) { | |
284 Locker lock(isolate_); | |
285 HandleScope scope(isolate_); | |
286 | |
287 // Convert the debugger command to a JSON debugger request. | |
288 TryCatch try_catch; | |
289 Handle<Value> request = Shell::DebugCommandToJSONRequest( | |
290 isolate_, String::NewFromUtf8(isolate_, command)); | |
291 if (try_catch.HasCaught()) { | |
292 Shell::ReportException(isolate_, &try_catch); | |
293 PrintPrompt(); | |
294 return; | |
295 } | |
296 | |
297 // If undefined is returned the command was handled internally and there is | |
298 // no JSON to send. | |
299 if (request->IsUndefined()) { | |
300 PrintPrompt(); | |
301 return; | |
302 } | |
303 | |
304 // Send the JSON debugger request. | |
305 i::DebuggerAgentUtil::SendMessage(conn_, Handle<String>::Cast(request)); | |
306 } | |
307 | |
308 | |
309 void ReceiverThread::Run() { | |
310 // Receive the connect message (with empty body). | |
311 i::SmartArrayPointer<char> message = | |
312 i::DebuggerAgentUtil::ReceiveMessage(remote_debugger_->conn()); | |
313 ASSERT(message.get() == NULL); | |
314 | |
315 while (true) { | |
316 // Receive a message. | |
317 i::SmartArrayPointer<char> message = | |
318 i::DebuggerAgentUtil::ReceiveMessage(remote_debugger_->conn()); | |
319 if (message.get() == NULL) { | |
320 remote_debugger_->ConnectionClosed(); | |
321 return; | |
322 } | |
323 | |
324 // Pass the message to the main thread. | |
325 remote_debugger_->MessageReceived(message); | |
326 } | |
327 } | |
328 | |
329 | |
330 void KeyboardThread::Run() { | |
331 static const int kBufferSize = 256; | |
332 while (true) { | |
333 // read keyboard input. | |
334 char command[kBufferSize]; | |
335 char* str = fgets(command, kBufferSize, stdin); | |
336 if (str == NULL) { | |
337 break; | |
338 } | |
339 | |
340 // Pass the keyboard command to the main thread. | |
341 remote_debugger_->KeyboardCommand( | |
342 i::SmartArrayPointer<char>(i::StrDup(command))); | |
343 } | |
344 } | |
345 | |
346 | |
347 } // namespace v8 | 132 } // namespace v8 |
OLD | NEW |