v8  3.11.10(node0.8.26)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
d8-debug.cc
Go to the documentation of this file.
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #ifdef ENABLE_DEBUGGER_SUPPORT
29 
30 #include "d8.h"
31 #include "d8-debug.h"
32 #include "platform.h"
33 #include "debug-agent.h"
34 
35 
36 namespace v8 {
37 
38 static bool was_running = true;
39 
40 void PrintPrompt(bool is_running) {
41  const char* prompt = is_running? "> " : "dbg> ";
42  was_running = is_running;
43  printf("%s", prompt);
44  fflush(stdout);
45 }
46 
47 
48 void PrintPrompt() {
49  PrintPrompt(was_running);
50 }
51 
52 
53 void HandleDebugEvent(DebugEvent event,
54  Handle<Object> exec_state,
55  Handle<Object> event_data,
56  Handle<Value> data) {
57  HandleScope scope;
58 
59  // Check for handled event.
60  if (event != Break && event != Exception && event != AfterCompile) {
61  return;
62  }
63 
64  TryCatch try_catch;
65 
66  // Get the toJSONProtocol function on the event and get the JSON format.
67  Local<String> to_json_fun_name = String::New("toJSONProtocol");
68  Local<Function> to_json_fun =
69  Function::Cast(*event_data->Get(to_json_fun_name));
70  Local<Value> event_json = to_json_fun->Call(event_data, 0, NULL);
71  if (try_catch.HasCaught()) {
72  Shell::ReportException(&try_catch);
73  return;
74  }
75 
76  // Print the event details.
77  Handle<Object> details =
78  Shell::DebugMessageDetails(Handle<String>::Cast(event_json));
79  if (try_catch.HasCaught()) {
80  Shell::ReportException(&try_catch);
81  return;
82  }
83  String::Utf8Value str(details->Get(String::New("text")));
84  if (str.length() == 0) {
85  // Empty string is used to signal not to process this event.
86  return;
87  }
88  printf("%s\n", *str);
89 
90  // Get the debug command processor.
91  Local<String> fun_name = String::New("debugCommandProcessor");
92  Local<Function> fun = Function::Cast(*exec_state->Get(fun_name));
93  Local<Object> cmd_processor =
94  Object::Cast(*fun->Call(exec_state, 0, NULL));
95  if (try_catch.HasCaught()) {
96  Shell::ReportException(&try_catch);
97  return;
98  }
99 
100  static const int kBufferSize = 256;
101  bool running = false;
102  while (!running) {
103  char command[kBufferSize];
104  PrintPrompt(running);
105  char* str = fgets(command, kBufferSize, stdin);
106  if (str == NULL) break;
107 
108  // Ignore empty commands.
109  if (strlen(command) == 0) continue;
110 
111  TryCatch try_catch;
112 
113  // Convert the debugger command to a JSON debugger request.
114  Handle<Value> request =
115  Shell::DebugCommandToJSONRequest(String::New(command));
116  if (try_catch.HasCaught()) {
117  Shell::ReportException(&try_catch);
118  continue;
119  }
120 
121  // If undefined is returned the command was handled internally and there is
122  // no JSON to send.
123  if (request->IsUndefined()) {
124  continue;
125  }
126 
127  Handle<String> fun_name;
128  Handle<Function> fun;
129  // All the functions used below take one argument.
130  static const int kArgc = 1;
131  Handle<Value> args[kArgc];
132 
133  // Invoke the JavaScript to convert the debug command line to a JSON
134  // request, invoke the JSON request and convert the JSON respose to a text
135  // representation.
136  fun_name = String::New("processDebugRequest");
137  fun = Handle<Function>::Cast(cmd_processor->Get(fun_name));
138  args[0] = request;
139  Handle<Value> response_val = fun->Call(cmd_processor, kArgc, args);
140  if (try_catch.HasCaught()) {
141  Shell::ReportException(&try_catch);
142  continue;
143  }
144  Handle<String> response = Handle<String>::Cast(response_val);
145 
146  // Convert the debugger response into text details and the running state.
147  Handle<Object> response_details = Shell::DebugMessageDetails(response);
148  if (try_catch.HasCaught()) {
149  Shell::ReportException(&try_catch);
150  continue;
151  }
152  String::Utf8Value text_str(response_details->Get(String::New("text")));
153  if (text_str.length() > 0) {
154  printf("%s\n", *text_str);
155  }
156  running =
157  response_details->Get(String::New("running"))->ToBoolean()->Value();
158  }
159 }
160 
161 
162 void RunRemoteDebugger(int port) {
163  RemoteDebugger debugger(port);
164  debugger.Run();
165 }
166 
167 
168 void RemoteDebugger::Run() {
169  bool ok;
170 
171  // Make sure that socket support is initialized.
172  ok = i::Socket::SetUp();
173  if (!ok) {
174  printf("Unable to initialize socket support %d\n", i::Socket::LastError());
175  return;
176  }
177 
178  // Connect to the debugger agent.
179  conn_ = i::OS::CreateSocket();
180  static const int kPortStrSize = 6;
181  char port_str[kPortStrSize];
182  i::OS::SNPrintF(i::Vector<char>(port_str, kPortStrSize), "%d", port_);
183  ok = conn_->Connect("localhost", port_str);
184  if (!ok) {
185  printf("Unable to connect to debug agent %d\n", i::Socket::LastError());
186  return;
187  }
188 
189  // Start the receiver thread.
190  ReceiverThread receiver(this);
191  receiver.Start();
192 
193  // Start the keyboard thread.
194  KeyboardThread keyboard(this);
195  keyboard.Start();
196  PrintPrompt();
197 
198  // Process events received from debugged VM and from the keyboard.
199  bool terminate = false;
200  while (!terminate) {
201  event_available_->Wait();
202  RemoteDebuggerEvent* event = GetEvent();
203  switch (event->type()) {
205  HandleMessageReceived(event->data());
206  break;
208  HandleKeyboardCommand(event->data());
209  break;
211  terminate = true;
212  break;
213 
214  default:
215  UNREACHABLE();
216  }
217  delete event;
218  }
219 
220  // Wait for the receiver thread to end.
221  receiver.Join();
222 }
223 
224 
226  RemoteDebuggerEvent* event =
227  new RemoteDebuggerEvent(RemoteDebuggerEvent::kMessage, message);
228  AddEvent(event);
229 }
230 
231 
233  RemoteDebuggerEvent* event =
234  new RemoteDebuggerEvent(RemoteDebuggerEvent::kKeyboard, command);
235  AddEvent(event);
236 }
237 
238 
240  RemoteDebuggerEvent* event =
241  new RemoteDebuggerEvent(RemoteDebuggerEvent::kDisconnect,
243  AddEvent(event);
244 }
245 
246 
247 void RemoteDebugger::AddEvent(RemoteDebuggerEvent* event) {
248  i::ScopedLock lock(event_access_);
249  if (head_ == NULL) {
250  ASSERT(tail_ == NULL);
251  head_ = event;
252  tail_ = event;
253  } else {
254  ASSERT(tail_ != NULL);
255  tail_->set_next(event);
256  tail_ = event;
257  }
258  event_available_->Signal();
259 }
260 
261 
262 RemoteDebuggerEvent* RemoteDebugger::GetEvent() {
263  i::ScopedLock lock(event_access_);
264  ASSERT(head_ != NULL);
265  RemoteDebuggerEvent* result = head_;
266  head_ = head_->next();
267  if (head_ == NULL) {
268  ASSERT(tail_ == result);
269  tail_ = NULL;
270  }
271  return result;
272 }
273 
274 
275 void RemoteDebugger::HandleMessageReceived(char* message) {
276  Locker lock;
277  HandleScope scope;
278 
279  // Print the event details.
280  TryCatch try_catch;
281  Handle<Object> details =
282  Shell::DebugMessageDetails(Handle<String>::Cast(String::New(message)));
283  if (try_catch.HasCaught()) {
284  Shell::ReportException(&try_catch);
285  PrintPrompt();
286  return;
287  }
288  String::Utf8Value str(details->Get(String::New("text")));
289  if (str.length() == 0) {
290  // Empty string is used to signal not to process this event.
291  return;
292  }
293  if (*str != NULL) {
294  printf("%s\n", *str);
295  } else {
296  printf("???\n");
297  }
298 
299  bool is_running = details->Get(String::New("running"))->ToBoolean()->Value();
300  PrintPrompt(is_running);
301 }
302 
303 
304 void RemoteDebugger::HandleKeyboardCommand(char* command) {
305  Locker lock;
306  HandleScope scope;
307 
308  // Convert the debugger command to a JSON debugger request.
309  TryCatch try_catch;
310  Handle<Value> request =
311  Shell::DebugCommandToJSONRequest(String::New(command));
312  if (try_catch.HasCaught()) {
313  Shell::ReportException(&try_catch);
314  PrintPrompt();
315  return;
316  }
317 
318  // If undefined is returned the command was handled internally and there is
319  // no JSON to send.
320  if (request->IsUndefined()) {
321  PrintPrompt();
322  return;
323  }
324 
325  // Send the JSON debugger request.
326  i::DebuggerAgentUtil::SendMessage(conn_, Handle<String>::Cast(request));
327 }
328 
329 
330 void ReceiverThread::Run() {
331  // Receive the connect message (with empty body).
333  i::DebuggerAgentUtil::ReceiveMessage(remote_debugger_->conn());
334  ASSERT(*message == NULL);
335 
336  while (true) {
337  // Receive a message.
339  i::DebuggerAgentUtil::ReceiveMessage(remote_debugger_->conn());
340  if (*message == NULL) {
341  remote_debugger_->ConnectionClosed();
342  return;
343  }
344 
345  // Pass the message to the main thread.
346  remote_debugger_->MessageReceived(message);
347  }
348 }
349 
350 
351 void KeyboardThread::Run() {
352  static const int kBufferSize = 256;
353  while (true) {
354  // read keyboard input.
355  char command[kBufferSize];
356  char* str = fgets(command, kBufferSize, stdin);
357  if (str == NULL) {
358  break;
359  }
360 
361  // Pass the keyboard command to the main thread.
362  remote_debugger_->KeyboardCommand(
364  }
365 }
366 
367 
368 } // namespace v8
369 
370 #endif // ENABLE_DEBUGGER_SUPPORT
static Object * Cast(Value *obj)
Definition: v8.h:4386
void RunRemoteDebugger(int port)
friend class ReceiverThread
Definition: d8-debug.h:93
static const int kDisconnect
Definition: d8-debug.h:137
static V8EXPORT Local< String > New(const char *data, int length=-1)
Definition: api.cc:4655
DebugEvent
Definition: v8-debug.h:73
static Handle< String > Cast(Handle< S > that)
Definition: v8.h:243
V8EXPORT Local< Value > Call(Handle< Object > recv, int argc, Handle< Value > argv[])
Definition: api.cc:3629
#define ASSERT(condition)
Definition: checks.h:270
static const int kMessage
Definition: d8-debug.h:135
static Function * Cast(Value *obj)
Definition: v8.h:4402
#define UNREACHABLE()
Definition: checks.h:50
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination trace on stack replacement optimize closures functions with arguments object optimize functions containing for in loops profiler considers IC stability primitive functions trigger their own optimization re try self optimization if it failed insert an interrupt check at function exit execution budget before interrupt is triggered call count before self optimization self_optimization count_based_interrupts weighted_back_edges trace_opt emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of SAHF instruction if enable use of VFP3 instructions if available this implies enabling ARMv7 enable use of ARMv7 instructions if enable use of MIPS FPU instructions if NULL
void KeyboardCommand(i::SmartArrayPointer< char > command)
static const int kKeyboard
Definition: d8-debug.h:136
virtual bool Connect(const char *host, const char *port)=0
static int SNPrintF(Vector< char > str, const char *format,...)
virtual void Signal()=0
static void ReportException(TryCatch *try_catch)
Definition: d8.cc:528
virtual void Wait()=0
char * StrDup(const char *str)
Definition: allocation.cc:85
void MessageReceived(i::SmartArrayPointer< char > message)
void HandleDebugEvent(DebugEvent event, Handle< Object > exec_state, Handle< Object > event_data, Handle< Value > data)
static Socket * CreateSocket()