| 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 |