The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / debug-agent.cc @ 40c0f755

History | View | Annotate | Download (12.1 KB)

1
// Copyright 2009 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-agent.h"
31

    
32
namespace v8 { namespace internal {
33

    
34

    
35
// Public V8 debugger API message handler function. This function just delegates
36
// to the debugger agent through it's data parameter.
37
void DebuggerAgentMessageHandler(const uint16_t* message, int length,
38
                                 void *data) {
39
  reinterpret_cast<DebuggerAgent*>(data)->DebuggerMessage(message, length);
40
}
41

    
42

    
43
// Debugger agent main thread.
44
void DebuggerAgent::Run() {
45
  const int kOneSecondInMicros = 1000000;
46

    
47
  // Allow this socket to reuse port even if still in TIME_WAIT.
48
  server_->SetReuseAddress(true);
49

    
50
  // First bind the socket to the requested port.
51
  bool bound = false;
52
  while (!bound && !terminate_) {
53
    bound = server_->Bind(port_);
54

    
55
    // If an error occoured wait a bit before retrying. The most common error
56
    // would be that the port is already in use so this avoids a busy loop and
57
    // make the agent take over the port when it becomes free.
58
    if (!bound) {
59
      terminate_now_->Wait(kOneSecondInMicros);
60
    }
61
  }
62

    
63
  // Accept connections on the bound port.
64
  while (!terminate_) {
65
    bool ok = server_->Listen(1);
66
    if (ok) {
67
      // Accept the new connection.
68
      Socket* client = server_->Accept();
69
      ok = client != NULL;
70
      if (ok) {
71
        // Create and start a new session.
72
        CreateSession(client);
73
      }
74
    }
75
  }
76
}
77

    
78

    
79
void DebuggerAgent::Shutdown() {
80
  // Set the termination flag.
81
  terminate_ = true;
82

    
83
  // Signal termination and make the server exit either its listen call or its
84
  // binding loop. This makes sure that no new sessions can be established.
85
  terminate_now_->Signal();
86
  server_->Shutdown();
87
  Join();
88

    
89
  // Close existing session if any.
90
  CloseSession();
91
}
92

    
93

    
94
void DebuggerAgent::CreateSession(Socket* client) {
95
  ScopedLock with(session_access_);
96

    
97
  // If another session is already established terminate this one.
98
  if (session_ != NULL) {
99
    static const char* message = "Remote debugging session already active\r\n";
100

    
101
    client->Send(message, strlen(message));
102
    delete client;
103
    return;
104
  }
105

    
106
  // Create a new session and hook up the debug message handler.
107
  session_ = new DebuggerAgentSession(this, client);
108
  v8::Debug::SetMessageHandler(DebuggerAgentMessageHandler, this);
109
  session_->Start();
110
}
111

    
112

    
113
void DebuggerAgent::CloseSession() {
114
  ScopedLock with(session_access_);
115

    
116
  // Terminate the session.
117
  if (session_ != NULL) {
118
    session_->Shutdown();
119
    session_->Join();
120
    delete session_;
121
    session_ = NULL;
122
  }
123
}
124

    
125

    
126
void DebuggerAgent::DebuggerMessage(const uint16_t* message, int length) {
127
  ScopedLock with(session_access_);
128

    
129
  // Forward the message handling to the session.
130
  if (session_ != NULL) {
131
    session_->DebuggerMessage(Vector<uint16_t>(const_cast<uint16_t*>(message),
132
                              length));
133
  }
134
}
135

    
136

    
137
void DebuggerAgent::OnSessionClosed(DebuggerAgentSession* session) {
138
  // Don't do anything during termination.
139
  if (terminate_) {
140
    return;
141
  }
142

    
143
  // Terminate the session.
144
  ScopedLock with(session_access_);
145
  ASSERT(session == session_);
146
  if (session == session_) {
147
    CloseSession();
148
  }
149
}
150

    
151

    
152
void DebuggerAgentSession::Run() {
153
  // Send the hello message.
154
  bool ok = DebuggerAgentUtil::SendConnectMessage(client_, *agent_->name_);
155
  if (!ok) return;
156

    
157
  while (true) {
158
    // Read data from the debugger front end.
159
    SmartPointer<char> message = DebuggerAgentUtil::ReceiveMessage(client_);
160
    if (*message == NULL) {
161
      // Session is closed.
162
      agent_->OnSessionClosed(this);
163
      return;
164
    }
165

    
166
    // Convert UTF-8 to UTF-16.
167
    unibrow::Utf8InputBuffer<> buf(*message, strlen(*message));
168
    int len = 0;
169
    while (buf.has_more()) {
170
      buf.GetNext();
171
      len++;
172
    }
173
    int16_t* temp = NewArray<int16_t>(len + 1);
174
    buf.Reset(*message, strlen(*message));
175
    for (int i = 0; i < len; i++) {
176
      temp[i] = buf.GetNext();
177
    }
178

    
179
    // Send the request received to the debugger.
180
    v8::Debug::SendCommand(reinterpret_cast<const uint16_t *>(temp), len);
181
    DeleteArray(temp);
182
  }
183
}
184

    
185

    
186
void DebuggerAgentSession::DebuggerMessage(Vector<uint16_t> message) {
187
  DebuggerAgentUtil::SendMessage(client_, message);
188
}
189

    
190

    
191
void DebuggerAgentSession::Shutdown() {
192
  // Shutdown the socket to end the blocking receive.
193
  client_->Shutdown();
194
}
195

    
196

    
197
const char* DebuggerAgentUtil::kContentLength = "Content-Length";
198
int DebuggerAgentUtil::kContentLengthSize = strlen(kContentLength);
199

    
200

    
201
SmartPointer<char> DebuggerAgentUtil::ReceiveMessage(const Socket* conn) {
202
  int received;
203

    
204
  // Read header.
205
  int content_length = 0;
206
  while (true) {
207
    const int kHeaderBufferSize = 80;
208
    char header_buffer[kHeaderBufferSize];
209
    int header_buffer_position = 0;
210
    char c = '\0';  // One character receive buffer.
211
    char prev_c = '\0';  // Previous character.
212

    
213
    // Read until CRLF.
214
    while (!(c == '\n' && prev_c == '\r')) {
215
      prev_c = c;
216
      received = conn->Receive(&c, 1);
217
      if (received <= 0) {
218
        PrintF("Error %d\n", Socket::LastError());
219
        return SmartPointer<char>();
220
      }
221

    
222
      // Add character to header buffer.
223
      if (header_buffer_position < kHeaderBufferSize) {
224
        header_buffer[header_buffer_position++] = c;
225
      }
226
    }
227

    
228
    // Check for end of header (empty header line).
229
    if (header_buffer_position == 2) {  // Receive buffer contains CRLF.
230
      break;
231
    }
232

    
233
    // Terminate header.
234
    ASSERT(header_buffer_position > 1);  // At least CRLF is received.
235
    ASSERT(header_buffer_position <= kHeaderBufferSize);
236
    header_buffer[header_buffer_position - 2] = '\0';
237

    
238
    // Split header.
239
    char* key = header_buffer;
240
    char* value = NULL;
241
    for (int i = 0; header_buffer[i] != '\0'; i++) {
242
      if (header_buffer[i] == ':') {
243
        header_buffer[i] = '\0';
244
        value = header_buffer + i + 1;
245
        while (*value == ' ') {
246
          value++;
247
        }
248
        break;
249
      }
250
    }
251

    
252
    // Check that key is Content-Length.
253
    if (strcmp(key, kContentLength) == 0) {
254
      // Get the content length value if within a sensible range.
255
      if (strlen(value) > 7) {
256
        return SmartPointer<char>();
257
      }
258
      for (int i = 0; value[i] != '\0'; i++) {
259
        // Bail out if illegal data.
260
        if (value[i] < '0' || value[i] > '9') {
261
          return SmartPointer<char>();
262
        }
263
        content_length = 10 * content_length + (value[i] - '0');
264
      }
265
    } else {
266
      // For now just print all other headers than Content-Length.
267
      PrintF("%s: %s\n", key, value != NULL ? value : "(no value)");
268
    }
269
  }
270

    
271
  // Return now if no body.
272
  if (content_length == 0) {
273
    return SmartPointer<char>();
274
  }
275

    
276
  // Read body.
277
  char* buffer = NewArray<char>(content_length + 1);
278
  received = ReceiveAll(conn, buffer, content_length);
279
  if (received < content_length) {
280
    PrintF("Error %d\n", Socket::LastError());
281
    return SmartPointer<char>();
282
  }
283
  buffer[content_length] = '\0';
284

    
285
  return SmartPointer<char>(buffer);
286
}
287

    
288

    
289
bool DebuggerAgentUtil::SendConnectMessage(const Socket* conn,
290
                                           const char* embedding_host) {
291
  static const int kBufferSize = 80;
292
  char buffer[kBufferSize];  // Sending buffer.
293
  bool ok;
294
  int len;
295

    
296
  // Send the header.
297
  len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
298
                     "Type: connect\r\n");
299
  ok = conn->Send(buffer, len);
300
  if (!ok) return false;
301

    
302
  len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
303
                     "V8-Version: %s\r\n", v8::V8::GetVersion());
304
  ok = conn->Send(buffer, len);
305
  if (!ok) return false;
306

    
307
  len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
308
                     "Protocol-Version: 1\r\n");
309
  ok = conn->Send(buffer, len);
310
  if (!ok) return false;
311

    
312
  if (embedding_host != NULL) {
313
    len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
314
                       "Embedding-Host: %s\r\n", embedding_host);
315
    ok = conn->Send(buffer, len);
316
    if (!ok) return false;
317
  }
318

    
319
  len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
320
                     "%s: 0\r\n", kContentLength);
321
  ok = conn->Send(buffer, len);
322
  if (!ok) return false;
323

    
324
  // Terminate header with empty line.
325
  len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "\r\n");
326
  ok = conn->Send(buffer, len);
327
  if (!ok) return false;
328

    
329
  // No body for connect message.
330

    
331
  return true;
332
}
333

    
334

    
335
bool DebuggerAgentUtil::SendMessage(const Socket* conn,
336
                                    const Vector<uint16_t> message) {
337
  static const int kBufferSize = 80;
338
  char buffer[kBufferSize];  // Sending buffer both for header and body.
339

    
340
  // Calculate the message size in UTF-8 encoding.
341
  int utf8_len = 0;
342
  for (int i = 0; i < message.length(); i++) {
343
    utf8_len += unibrow::Utf8::Length(message[i]);
344
  }
345

    
346
  // Send the header.
347
  int len;
348
  len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
349
                     "%s: %d\r\n", kContentLength, utf8_len);
350
  conn->Send(buffer, len);
351

    
352
  // Terminate header with empty line.
353
  len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "\r\n");
354
  conn->Send(buffer, len);
355

    
356
  // Send message body as UTF-8.
357
  int buffer_position = 0;  // Current buffer position.
358
  for (int i = 0; i < message.length(); i++) {
359
    // Write next UTF-8 encoded character to buffer.
360
    buffer_position +=
361
        unibrow::Utf8::Encode(buffer + buffer_position, message[i]);
362
    ASSERT(buffer_position < kBufferSize);
363

    
364
    // Send buffer if full or last character is encoded.
365
    if (kBufferSize - buffer_position < 3 || i == message.length() - 1) {
366
      conn->Send(buffer, buffer_position);
367
      buffer_position = 0;
368
    }
369
  }
370

    
371
  return true;
372
}
373

    
374

    
375
bool DebuggerAgentUtil::SendMessage(const Socket* conn,
376
                                    const v8::Handle<v8::String> request) {
377
  static const int kBufferSize = 80;
378
  char buffer[kBufferSize];  // Sending buffer both for header and body.
379

    
380
  // Convert the request to UTF-8 encoding.
381
  v8::String::Utf8Value utf8_request(request);
382

    
383
  // Send the header.
384
  int len;
385
  len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
386
                     "Content-Length: %d\r\n", utf8_request.length());
387
  conn->Send(buffer, len);
388

    
389
  // Terminate header with empty line.
390
  len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "\r\n");
391
  conn->Send(buffer, len);
392

    
393
  // Send message body as UTF-8.
394
  conn->Send(*utf8_request, utf8_request.length());
395

    
396
  return true;
397
}
398

    
399

    
400
// Receive the full buffer before returning unless an error occours.
401
int DebuggerAgentUtil::ReceiveAll(const Socket* conn, char* data, int len) {
402
  int total_received = 0;
403
  while (total_received < len) {
404
    int received = conn->Receive(data + total_received, len - total_received);
405
    if (received <= 0) {
406
      return total_received;
407
    }
408
    total_received += received;
409
  }
410
  return total_received;
411
}
412

    
413

    
414
} }  // namespace v8::internal