[V8] Introduce a QML compilation mode
[profile/ivi/qtjsbackend.git] / src / 3rdparty / v8 / src / debug-agent.cc
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     CloseSession();
161   }
162 }
163
164
165 void DebuggerAgentSession::Run() {
166   // Send the hello message.
167   bool ok = DebuggerAgentUtil::SendConnectMessage(client_, *agent_->name_);
168   if (!ok) return;
169
170   while (true) {
171     // Read data from the debugger front end.
172     SmartArrayPointer<char> message =
173         DebuggerAgentUtil::ReceiveMessage(client_);
174
175     const char* msg = *message;
176     bool is_closing_session = (msg == NULL);
177
178     if (msg == NULL) {
179       // If we lost the connection, then simulate a disconnect msg:
180       msg = "{\"seq\":1,\"type\":\"request\",\"command\":\"disconnect\"}";
181
182     } else {
183       // Check if we're getting a disconnect request:
184       const char* disconnectRequestStr =
185           "\"type\":\"request\",\"command\":\"disconnect\"}";
186       const char* result = strstr(msg, disconnectRequestStr);
187       if (result != NULL) {
188         is_closing_session = true;
189       }
190     }
191
192     // Convert UTF-8 to UTF-16.
193     unibrow::Utf8InputBuffer<> buf(msg, StrLength(msg));
194     int len = 0;
195     while (buf.has_more()) {
196       buf.GetNext();
197       len++;
198     }
199     ScopedVector<int16_t> temp(len + 1);
200     buf.Reset(msg, StrLength(msg));
201     for (int i = 0; i < len; i++) {
202       temp[i] = buf.GetNext();
203     }
204
205     // Send the request received to the debugger.
206     v8::Debug::SendCommand(reinterpret_cast<const uint16_t *>(temp.start()),
207                            len,
208                            NULL,
209                            reinterpret_cast<v8::Isolate*>(agent_->isolate()));
210
211     if (is_closing_session) {
212       // Session is closed.
213       agent_->OnSessionClosed(this);
214       return;
215     }
216   }
217 }
218
219
220 void DebuggerAgentSession::DebuggerMessage(Vector<uint16_t> message) {
221   DebuggerAgentUtil::SendMessage(client_, message);
222 }
223
224
225 void DebuggerAgentSession::Shutdown() {
226   // Shutdown the socket to end the blocking receive.
227   client_->Shutdown();
228 }
229
230
231 const char* const DebuggerAgentUtil::kContentLength = "Content-Length";
232
233
234 SmartArrayPointer<char> DebuggerAgentUtil::ReceiveMessage(const Socket* conn) {
235   int received;
236
237   // Read header.
238   int content_length = 0;
239   while (true) {
240     const int kHeaderBufferSize = 80;
241     char header_buffer[kHeaderBufferSize];
242     int header_buffer_position = 0;
243     char c = '\0';  // One character receive buffer.
244     char prev_c = '\0';  // Previous character.
245
246     // Read until CRLF.
247     while (!(c == '\n' && prev_c == '\r')) {
248       prev_c = c;
249       received = conn->Receive(&c, 1);
250       if (received == 0) {
251         PrintF("Error %d\n", Socket::LastError());
252         return SmartArrayPointer<char>();
253       }
254
255       // Add character to header buffer.
256       if (header_buffer_position < kHeaderBufferSize) {
257         header_buffer[header_buffer_position++] = c;
258       }
259     }
260
261     // Check for end of header (empty header line).
262     if (header_buffer_position == 2) {  // Receive buffer contains CRLF.
263       break;
264     }
265
266     // Terminate header.
267     ASSERT(header_buffer_position > 1);  // At least CRLF is received.
268     ASSERT(header_buffer_position <= kHeaderBufferSize);
269     header_buffer[header_buffer_position - 2] = '\0';
270
271     // Split header.
272     char* key = header_buffer;
273     char* value = NULL;
274     for (int i = 0; header_buffer[i] != '\0'; i++) {
275       if (header_buffer[i] == ':') {
276         header_buffer[i] = '\0';
277         value = header_buffer + i + 1;
278         while (*value == ' ') {
279           value++;
280         }
281         break;
282       }
283     }
284
285     // Check that key is Content-Length.
286     if (strcmp(key, kContentLength) == 0) {
287       // Get the content length value if present and within a sensible range.
288       if (value == NULL || strlen(value) > 7) {
289         return SmartArrayPointer<char>();
290       }
291       for (int i = 0; value[i] != '\0'; i++) {
292         // Bail out if illegal data.
293         if (value[i] < '0' || value[i] > '9') {
294           return SmartArrayPointer<char>();
295         }
296         content_length = 10 * content_length + (value[i] - '0');
297       }
298     } else {
299       // For now just print all other headers than Content-Length.
300       PrintF("%s: %s\n", key, value != NULL ? value : "(no value)");
301     }
302   }
303
304   // Return now if no body.
305   if (content_length == 0) {
306     return SmartArrayPointer<char>();
307   }
308
309   // Read body.
310   char* buffer = NewArray<char>(content_length + 1);
311   received = ReceiveAll(conn, buffer, content_length);
312   if (received < content_length) {
313     PrintF("Error %d\n", Socket::LastError());
314     return SmartArrayPointer<char>();
315   }
316   buffer[content_length] = '\0';
317
318   return SmartArrayPointer<char>(buffer);
319 }
320
321
322 bool DebuggerAgentUtil::SendConnectMessage(const Socket* conn,
323                                            const char* embedding_host) {
324   static const int kBufferSize = 80;
325   char buffer[kBufferSize];  // Sending buffer.
326   bool ok;
327   int len;
328
329   // Send the header.
330   len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
331                      "Type: connect\r\n");
332   ok = conn->Send(buffer, len);
333   if (!ok) return false;
334
335   len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
336                      "V8-Version: %s\r\n", v8::V8::GetVersion());
337   ok = conn->Send(buffer, len);
338   if (!ok) return false;
339
340   len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
341                      "Protocol-Version: 1\r\n");
342   ok = conn->Send(buffer, len);
343   if (!ok) return false;
344
345   if (embedding_host != NULL) {
346     len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
347                        "Embedding-Host: %s\r\n", embedding_host);
348     ok = conn->Send(buffer, len);
349     if (!ok) return false;
350   }
351
352   len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
353                      "%s: 0\r\n", kContentLength);
354   ok = conn->Send(buffer, len);
355   if (!ok) return false;
356
357   // Terminate header with empty line.
358   len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "\r\n");
359   ok = conn->Send(buffer, len);
360   if (!ok) return false;
361
362   // No body for connect message.
363
364   return true;
365 }
366
367
368 bool DebuggerAgentUtil::SendMessage(const Socket* conn,
369                                     const Vector<uint16_t> message) {
370   static const int kBufferSize = 80;
371   char buffer[kBufferSize];  // Sending buffer both for header and body.
372
373   // Calculate the message size in UTF-8 encoding.
374   int utf8_len = 0;
375   int previous = unibrow::Utf16::kNoPreviousCharacter;
376   for (int i = 0; i < message.length(); i++) {
377     uint16_t character = message[i];
378     utf8_len += unibrow::Utf8::Length(character, previous);
379     previous = character;
380   }
381
382   // Send the header.
383   int len;
384   len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
385                      "%s: %d\r\n", kContentLength, utf8_len);
386   conn->Send(buffer, len);
387
388   // Terminate header with empty line.
389   len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "\r\n");
390   conn->Send(buffer, len);
391
392   // Send message body as UTF-8.
393   int buffer_position = 0;  // Current buffer position.
394   previous = unibrow::Utf16::kNoPreviousCharacter;
395   for (int i = 0; i < message.length(); i++) {
396     // Write next UTF-8 encoded character to buffer.
397     uint16_t character = message[i];
398     buffer_position +=
399         unibrow::Utf8::Encode(buffer + buffer_position, character, previous);
400     ASSERT(buffer_position < kBufferSize);
401
402     // Send buffer if full or last character is encoded.
403     if (kBufferSize - buffer_position <
404           unibrow::Utf16::kMaxExtraUtf8BytesForOneUtf16CodeUnit ||
405         i == message.length() - 1) {
406       if (unibrow::Utf16::IsLeadSurrogate(character)) {
407         const int kEncodedSurrogateLength =
408             unibrow::Utf16::kUtf8BytesToCodeASurrogate;
409         ASSERT(buffer_position >= kEncodedSurrogateLength);
410         conn->Send(buffer, buffer_position - kEncodedSurrogateLength);
411         for (int i = 0; i < kEncodedSurrogateLength; i++) {
412           buffer[i] = buffer[buffer_position + i];
413         }
414         buffer_position = kEncodedSurrogateLength;
415       } else {
416         conn->Send(buffer, buffer_position);
417         buffer_position = 0;
418       }
419     }
420     previous = character;
421   }
422
423   return true;
424 }
425
426
427 bool DebuggerAgentUtil::SendMessage(const Socket* conn,
428                                     const v8::Handle<v8::String> request) {
429   static const int kBufferSize = 80;
430   char buffer[kBufferSize];  // Sending buffer both for header and body.
431
432   // Convert the request to UTF-8 encoding.
433   v8::String::Utf8Value utf8_request(request);
434
435   // Send the header.
436   int len;
437   len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
438                      "Content-Length: %d\r\n", utf8_request.length());
439   conn->Send(buffer, len);
440
441   // Terminate header with empty line.
442   len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "\r\n");
443   conn->Send(buffer, len);
444
445   // Send message body as UTF-8.
446   conn->Send(*utf8_request, utf8_request.length());
447
448   return true;
449 }
450
451
452 // Receive the full buffer before returning unless an error occours.
453 int DebuggerAgentUtil::ReceiveAll(const Socket* conn, char* data, int len) {
454   int total_received = 0;
455   while (total_received < len) {
456     int received = conn->Receive(data + total_received, len - total_received);
457     if (received == 0) {
458       return total_received;
459     }
460     total_received += received;
461   }
462   return total_received;
463 }
464
465 } }  // namespace v8::internal
466
467 #endif  // ENABLE_DEBUGGER_SUPPORT