v8  3.14.5(node0.10.28)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
debug-agent.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 
29 #include "v8.h"
30 #include "debug.h"
31 #include "debug-agent.h"
32 
33 #ifdef ENABLE_DEBUGGER_SUPPORT
34 
35 namespace v8 {
36 namespace internal {
37 
38 // Public V8 debugger API message handler function. This function just delegates
39 // to the debugger agent through it's data parameter.
40 void DebuggerAgentMessageHandler(const v8::Debug::Message& message) {
41  DebuggerAgent* agent = Isolate::Current()->debugger_agent_instance();
42  ASSERT(agent != NULL);
43  agent->DebuggerMessage(message);
44 }
45 
46 
47 // Debugger agent main thread.
48 void DebuggerAgent::Run() {
49  const int kOneSecondInMicros = 1000000;
50 
51  // Allow this socket to reuse port even if still in TIME_WAIT.
52  server_->SetReuseAddress(true);
53 
54  // First bind the socket to the requested port.
55  bool bound = false;
56  while (!bound && !terminate_) {
57  bound = server_->Bind(port_);
58 
59  // If an error occurred wait a bit before retrying. The most common error
60  // would be that the port is already in use so this avoids a busy loop and
61  // make the agent take over the port when it becomes free.
62  if (!bound) {
63  PrintF("Failed to open socket on port %d, "
64  "waiting %d ms before retrying\n", port_, kOneSecondInMicros / 1000);
65  terminate_now_->Wait(kOneSecondInMicros);
66  }
67  }
68 
69  // Accept connections on the bound port.
70  while (!terminate_) {
71  bool ok = server_->Listen(1);
72  listening_->Signal();
73  if (ok) {
74  // Accept the new connection.
75  Socket* client = server_->Accept();
76  ok = client != NULL;
77  if (ok) {
78  // Create and start a new session.
79  CreateSession(client);
80  }
81  }
82  }
83 }
84 
85 
86 void DebuggerAgent::Shutdown() {
87  // Set the termination flag.
88  terminate_ = true;
89 
90  // Signal termination and make the server exit either its listen call or its
91  // binding loop. This makes sure that no new sessions can be established.
92  terminate_now_->Signal();
93  server_->Shutdown();
94  Join();
95 
96  // Close existing session if any.
97  CloseSession();
98 }
99 
100 
101 void DebuggerAgent::WaitUntilListening() {
102  listening_->Wait();
103 }
104 
105 static const char* kCreateSessionMessage =
106  "Remote debugging session already active\r\n";
107 
108 void DebuggerAgent::CreateSession(Socket* client) {
109  ScopedLock with(session_access_);
110 
111  // If another session is already established terminate this one.
112  if (session_ != NULL) {
113  client->Send(kCreateSessionMessage, StrLength(kCreateSessionMessage));
114  delete client;
115  return;
116  }
117 
118  // Create a new session and hook up the debug message handler.
119  session_ = new DebuggerAgentSession(this, client);
120  isolate_->debugger()->SetMessageHandler(DebuggerAgentMessageHandler);
121  session_->Start();
122 }
123 
124 
125 void DebuggerAgent::CloseSession() {
126  ScopedLock with(session_access_);
127 
128  // Terminate the session.
129  if (session_ != NULL) {
130  session_->Shutdown();
131  session_->Join();
132  delete session_;
133  session_ = NULL;
134  }
135 }
136 
137 
138 void DebuggerAgent::DebuggerMessage(const v8::Debug::Message& message) {
139  ScopedLock with(session_access_);
140 
141  // Forward the message handling to the session.
142  if (session_ != NULL) {
143  v8::String::Value val(message.GetJSON());
144  session_->DebuggerMessage(Vector<uint16_t>(const_cast<uint16_t*>(*val),
145  val.length()));
146  }
147 }
148 
149 
150 void DebuggerAgent::OnSessionClosed(DebuggerAgentSession* session) {
151  // Don't do anything during termination.
152  if (terminate_) {
153  return;
154  }
155 
156  // Terminate the session.
157  ScopedLock with(session_access_);
158  ASSERT(session == session_);
159  if (session == session_) {
160  session_->Shutdown();
161  delete session_;
162  session_ = NULL;
163  }
164 }
165 
166 
167 void DebuggerAgentSession::Run() {
168  // Send the hello message.
169  bool ok = DebuggerAgentUtil::SendConnectMessage(client_, *agent_->name_);
170  if (!ok) return;
171 
172  while (true) {
173  // Read data from the debugger front end.
174  SmartArrayPointer<char> message =
175  DebuggerAgentUtil::ReceiveMessage(client_);
176 
177  const char* msg = *message;
178  bool is_closing_session = (msg == NULL);
179 
180  if (msg == NULL) {
181  // If we lost the connection, then simulate a disconnect msg:
182  msg = "{\"seq\":1,\"type\":\"request\",\"command\":\"disconnect\"}";
183 
184  } else {
185  // Check if we're getting a disconnect request:
186  const char* disconnectRequestStr =
187  "\"type\":\"request\",\"command\":\"disconnect\"}";
188  const char* result = strstr(msg, disconnectRequestStr);
189  if (result != NULL) {
190  is_closing_session = true;
191  }
192  }
193 
194  // Convert UTF-8 to UTF-16.
195  unibrow::Utf8InputBuffer<> buf(msg, StrLength(msg));
196  int len = 0;
197  while (buf.has_more()) {
198  buf.GetNext();
199  len++;
200  }
201  ScopedVector<int16_t> temp(len + 1);
202  buf.Reset(msg, StrLength(msg));
203  for (int i = 0; i < len; i++) {
204  temp[i] = buf.GetNext();
205  }
206 
207  // Send the request received to the debugger.
208  v8::Debug::SendCommand(reinterpret_cast<const uint16_t *>(temp.start()),
209  len,
210  NULL,
211  reinterpret_cast<v8::Isolate*>(agent_->isolate()));
212 
213  if (is_closing_session) {
214  // Session is closed.
215  agent_->OnSessionClosed(this);
216  return;
217  }
218  }
219 }
220 
221 
222 void DebuggerAgentSession::DebuggerMessage(Vector<uint16_t> message) {
223  DebuggerAgentUtil::SendMessage(client_, message);
224 }
225 
226 
227 void DebuggerAgentSession::Shutdown() {
228  // Shutdown the socket to end the blocking receive.
229  client_->Shutdown();
230 }
231 
232 
233 const char* const DebuggerAgentUtil::kContentLength = "Content-Length";
234 
235 
236 SmartArrayPointer<char> DebuggerAgentUtil::ReceiveMessage(const Socket* conn) {
237  int received;
238 
239  // Read header.
240  int content_length = 0;
241  while (true) {
242  const int kHeaderBufferSize = 80;
243  char header_buffer[kHeaderBufferSize];
244  int header_buffer_position = 0;
245  char c = '\0'; // One character receive buffer.
246  char prev_c = '\0'; // Previous character.
247 
248  // Read until CRLF.
249  while (!(c == '\n' && prev_c == '\r')) {
250  prev_c = c;
251  received = conn->Receive(&c, 1);
252  if (received == 0) {
253  PrintF("Error %d\n", Socket::LastError());
254  return SmartArrayPointer<char>();
255  }
256 
257  // Add character to header buffer.
258  if (header_buffer_position < kHeaderBufferSize) {
259  header_buffer[header_buffer_position++] = c;
260  }
261  }
262 
263  // Check for end of header (empty header line).
264  if (header_buffer_position == 2) { // Receive buffer contains CRLF.
265  break;
266  }
267 
268  // Terminate header.
269  ASSERT(header_buffer_position > 1); // At least CRLF is received.
270  ASSERT(header_buffer_position <= kHeaderBufferSize);
271  header_buffer[header_buffer_position - 2] = '\0';
272 
273  // Split header.
274  char* key = header_buffer;
275  char* value = NULL;
276  for (int i = 0; header_buffer[i] != '\0'; i++) {
277  if (header_buffer[i] == ':') {
278  header_buffer[i] = '\0';
279  value = header_buffer + i + 1;
280  while (*value == ' ') {
281  value++;
282  }
283  break;
284  }
285  }
286 
287  // Check that key is Content-Length.
288  if (strcmp(key, kContentLength) == 0) {
289  // Get the content length value if present and within a sensible range.
290  if (value == NULL || strlen(value) > 7) {
291  return SmartArrayPointer<char>();
292  }
293  for (int i = 0; value[i] != '\0'; i++) {
294  // Bail out if illegal data.
295  if (value[i] < '0' || value[i] > '9') {
296  return SmartArrayPointer<char>();
297  }
298  content_length = 10 * content_length + (value[i] - '0');
299  }
300  } else {
301  // For now just print all other headers than Content-Length.
302  PrintF("%s: %s\n", key, value != NULL ? value : "(no value)");
303  }
304  }
305 
306  // Return now if no body.
307  if (content_length == 0) {
308  return SmartArrayPointer<char>();
309  }
310 
311  // Read body.
312  char* buffer = NewArray<char>(content_length + 1);
313  received = ReceiveAll(conn, buffer, content_length);
314  if (received < content_length) {
315  PrintF("Error %d\n", Socket::LastError());
316  return SmartArrayPointer<char>();
317  }
318  buffer[content_length] = '\0';
319 
320  return SmartArrayPointer<char>(buffer);
321 }
322 
323 
324 bool DebuggerAgentUtil::SendConnectMessage(const Socket* conn,
325  const char* embedding_host) {
326  static const int kBufferSize = 80;
327  char buffer[kBufferSize]; // Sending buffer.
328  bool ok;
329  int len;
330 
331  // Send the header.
332  len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
333  "Type: connect\r\n");
334  ok = conn->Send(buffer, len);
335  if (!ok) return false;
336 
337  len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
338  "V8-Version: %s\r\n", v8::V8::GetVersion());
339  ok = conn->Send(buffer, len);
340  if (!ok) return false;
341 
342  len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
343  "Protocol-Version: 1\r\n");
344  ok = conn->Send(buffer, len);
345  if (!ok) return false;
346 
347  if (embedding_host != NULL) {
348  len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
349  "Embedding-Host: %s\r\n", embedding_host);
350  ok = conn->Send(buffer, len);
351  if (!ok) return false;
352  }
353 
354  len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
355  "%s: 0\r\n", kContentLength);
356  ok = conn->Send(buffer, len);
357  if (!ok) return false;
358 
359  // Terminate header with empty line.
360  len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "\r\n");
361  ok = conn->Send(buffer, len);
362  if (!ok) return false;
363 
364  // No body for connect message.
365 
366  return true;
367 }
368 
369 
370 bool DebuggerAgentUtil::SendMessage(const Socket* conn,
371  const Vector<uint16_t> message) {
372  static const int kBufferSize = 80;
373  char buffer[kBufferSize]; // Sending buffer both for header and body.
374 
375  // Calculate the message size in UTF-8 encoding.
376  int utf8_len = 0;
378  for (int i = 0; i < message.length(); i++) {
379  uint16_t character = message[i];
380  utf8_len += unibrow::Utf8::Length(character, previous);
381  previous = character;
382  }
383 
384  // Send the header.
385  int len;
386  len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
387  "%s: %d\r\n", kContentLength, utf8_len);
388  conn->Send(buffer, len);
389 
390  // Terminate header with empty line.
391  len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "\r\n");
392  conn->Send(buffer, len);
393 
394  // Send message body as UTF-8.
395  int buffer_position = 0; // Current buffer position.
397  for (int i = 0; i < message.length(); i++) {
398  // Write next UTF-8 encoded character to buffer.
399  uint16_t character = message[i];
400  buffer_position +=
401  unibrow::Utf8::Encode(buffer + buffer_position, character, previous);
402  ASSERT(buffer_position <= kBufferSize);
403 
404  // Send buffer if full or last character is encoded.
405  if (kBufferSize - buffer_position <
407  i == message.length() - 1) {
408  if (unibrow::Utf16::IsLeadSurrogate(character)) {
409  const int kEncodedSurrogateLength =
411  ASSERT(buffer_position >= kEncodedSurrogateLength);
412  conn->Send(buffer, buffer_position - kEncodedSurrogateLength);
413  for (int i = 0; i < kEncodedSurrogateLength; i++) {
414  buffer[i] = buffer[buffer_position + i];
415  }
416  buffer_position = kEncodedSurrogateLength;
417  } else {
418  conn->Send(buffer, buffer_position);
419  buffer_position = 0;
420  }
421  }
422  previous = character;
423  }
424 
425  return true;
426 }
427 
428 
429 bool DebuggerAgentUtil::SendMessage(const Socket* conn,
430  const v8::Handle<v8::String> request) {
431  static const int kBufferSize = 80;
432  char buffer[kBufferSize]; // Sending buffer both for header and body.
433 
434  // Convert the request to UTF-8 encoding.
435  v8::String::Utf8Value utf8_request(request);
436 
437  // Send the header.
438  int len;
439  len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
440  "Content-Length: %d\r\n", utf8_request.length());
441  conn->Send(buffer, len);
442 
443  // Terminate header with empty line.
444  len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "\r\n");
445  conn->Send(buffer, len);
446 
447  // Send message body as UTF-8.
448  conn->Send(*utf8_request, utf8_request.length());
449 
450  return true;
451 }
452 
453 
454 // Receive the full buffer before returning unless an error occours.
455 int DebuggerAgentUtil::ReceiveAll(const Socket* conn, char* data, int len) {
456  int total_received = 0;
457  while (total_received < len) {
458  int received = conn->Receive(data + total_received, len - total_received);
459  if (received == 0) {
460  return total_received;
461  }
462  total_received += received;
463  }
464  return total_received;
465 }
466 
467 } } // namespace v8::internal
468 
469 #endif // ENABLE_DEBUGGER_SUPPORT
void PrintF(const char *format,...)
Definition: v8utils.cc:40
#define ASSERT(condition)
Definition: checks.h:270
unsigned short uint16_t
Definition: unicode.cc:46
static const int kMaxExtraUtf8BytesForOneUtf16CodeUnit
Definition: unicode.h:139
static const char * GetVersion()
Definition: api.cc:4394
static uchar Length(uchar chr, int previous)
Definition: unicode-inl.h:124
static const int kUtf8BytesToCodeASurrogate
Definition: unicode.h:142
virtual Handle< String > GetJSON() const =0
Definition: v8.h:105
static unsigned Encode(char *out, uchar c, int previous)
Definition: unicode-inl.h:82
int StrLength(const char *string)
Definition: utils.h:234
static int SNPrintF(Vector< char > str, const char *format,...)
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 use dead code elimination trace on stack replacement optimize closures cache optimized code for closures functions with arguments object loop weight for representation inference allow uint32 values on optimize frames if they are used only in safe operations track parallel recompilation enable all profiler experiments number of stack frames inspected by the profiler call recompile stub directly when self optimizing trigger profiler ticks based on counting instead of timing weight back edges by jump distance for interrupt triggering percentage of ICs that must have type info to allow optimization watch_ic_patching retry_self_opt interrupt_at_exit extra verbose compilation tracing generate extra 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 and VFP2 enable use of VFP2 instructions if available enable use of SDIV and UDIV instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of MIPS FPU instructions if expose natives in global object expose gc extension number of stack frames to capture disable builtin natives files print a stack trace if an assertion failure occurs use random jit cookie to mask large constants trace lazy optimization use adaptive optimizations prepare for turning on always opt minimum length for automatic enable preparsing maximum number of optimization attempts before giving up cache prototype transitions automatically set the debug break flag when debugger commands are in the queue always cause a debug break before aborting maximum length of function source code printed in a stack trace max size of the new max size of the old max size of executable always perform global GCs print one trace line following each garbage collection do not print trace line after scavenger collection print more details following each garbage collection print amount of external allocated memory after each time it is adjusted flush code that we expect not to use again before full gc do incremental marking steps track object counts and memory usage use caching Perform compaction on every full GC Never perform compaction on full GC testing only Compact code space on full incremental collections Default seed for initializing random allows verbose printing trace parsing and preparsing Check icache flushes in ARM and MIPS simulator Stack alingment in bytes in print stack trace when throwing exceptions randomize hashes to avoid predictable hash Fixed seed to use to hash property activate a timer that switches between V8 threads testing_bool_flag float flag Seed used for threading test randomness A filename with extra code to be included in the Print usage message
Definition: flags.cc:495
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 use dead code elimination trace on stack replacement optimize closures cache optimized code for closures functions with arguments object loop weight for representation inference allow uint32 values on optimize frames if they are used only in safe operations track parallel recompilation enable all profiler experiments number of stack frames inspected by the profiler call recompile stub directly when self optimizing trigger profiler ticks based on counting instead of timing weight back edges by jump distance for interrupt triggering percentage of ICs that must have type info to allow optimization watch_ic_patching retry_self_opt interrupt_at_exit extra verbose compilation tracing generate extra 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 and VFP2 enable use of VFP2 instructions if available enable use of SDIV and UDIV instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of MIPS FPU instructions if NULL
Definition: flags.cc:301
static bool IsLeadSurrogate(int code)
Definition: unicode.h:120
static void SendCommand(const uint16_t *command, int length, ClientData *client_data=NULL, Isolate *isolate=NULL)
static const int kNoPreviousCharacter
Definition: unicode.h:132