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 / d8-debug.cc @ f230a1cf

History | View | Annotate | Download (10.5 KB)

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 "debug-agent.h"
33

    
34

    
35
namespace v8 {
36

    
37
static bool was_running = true;
38

    
39
void PrintPrompt(bool is_running) {
40
  const char* prompt = is_running? "> " : "dbg> ";
41
  was_running = is_running;
42
  printf("%s", prompt);
43
  fflush(stdout);
44
}
45

    
46

    
47
void PrintPrompt() {
48
  PrintPrompt(was_running);
49
}
50

    
51

    
52
void HandleDebugEvent(const Debug::EventDetails& event_details) {
53
  // TODO(svenpanne) There should be a way to retrieve this in the callback.
54
  Isolate* isolate = Isolate::GetCurrent();
55
  HandleScope scope(isolate);
56

    
57
  DebugEvent event = event_details.GetEvent();
58
  // Check for handled event.
59
  if (event != Break && event != Exception && event != AfterCompile) {
60
    return;
61
  }
62

    
63
  TryCatch try_catch;
64

    
65
  // Get the toJSONProtocol function on the event and get the JSON format.
66
  Local<String> to_json_fun_name = String::New("toJSONProtocol");
67
  Handle<Object> event_data = event_details.GetEventData();
68
  Local<Function> to_json_fun =
69
      Local<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(isolate, &try_catch);
73
    return;
74
  }
75

    
76
  // Print the event details.
77
  Handle<Object> details =
78
      Shell::DebugMessageDetails(isolate, Handle<String>::Cast(event_json));
79
  if (try_catch.HasCaught()) {
80
    Shell::ReportException(isolate, &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
  Handle<Object> exec_state = event_details.GetExecutionState();
93
  Local<Function> fun = Local<Function>::Cast(exec_state->Get(fun_name));
94
  Local<Object> cmd_processor =
95
      Local<Object>::Cast(fun->Call(exec_state, 0, NULL));
96
  if (try_catch.HasCaught()) {
97
    Shell::ReportException(isolate, &try_catch);
98
    return;
99
  }
100

    
101
  static const int kBufferSize = 256;
102
  bool running = false;
103
  while (!running) {
104
    char command[kBufferSize];
105
    PrintPrompt(running);
106
    char* str = fgets(command, kBufferSize, stdin);
107
    if (str == NULL) break;
108

    
109
    // Ignore empty commands.
110
    if (strlen(command) == 0) continue;
111

    
112
    TryCatch try_catch;
113

    
114
    // Convert the debugger command to a JSON debugger request.
115
    Handle<Value> request =
116
        Shell::DebugCommandToJSONRequest(isolate, String::New(command));
117
    if (try_catch.HasCaught()) {
118
      Shell::ReportException(isolate, &try_catch);
119
      continue;
120
    }
121

    
122
    // If undefined is returned the command was handled internally and there is
123
    // no JSON to send.
124
    if (request->IsUndefined()) {
125
      continue;
126
    }
127

    
128
    Handle<String> fun_name;
129
    Handle<Function> fun;
130
    // All the functions used below take one argument.
131
    static const int kArgc = 1;
132
    Handle<Value> args[kArgc];
133

    
134
    // Invoke the JavaScript to convert the debug command line to a JSON
135
    // request, invoke the JSON request and convert the JSON respose to a text
136
    // representation.
137
    fun_name = String::New("processDebugRequest");
138
    fun = Handle<Function>::Cast(cmd_processor->Get(fun_name));
139
    args[0] = request;
140
    Handle<Value> response_val = fun->Call(cmd_processor, kArgc, args);
141
    if (try_catch.HasCaught()) {
142
      Shell::ReportException(isolate, &try_catch);
143
      continue;
144
    }
145
    Handle<String> response = Handle<String>::Cast(response_val);
146

    
147
    // Convert the debugger response into text details and the running state.
148
    Handle<Object> response_details =
149
        Shell::DebugMessageDetails(isolate, response);
150
    if (try_catch.HasCaught()) {
151
      Shell::ReportException(isolate, &try_catch);
152
      continue;
153
    }
154
    String::Utf8Value text_str(response_details->Get(String::New("text")));
155
    if (text_str.length() > 0) {
156
      printf("%s\n", *text_str);
157
    }
158
    running =
159
        response_details->Get(String::New("running"))->ToBoolean()->Value();
160
  }
161
}
162

    
163

    
164
void RunRemoteDebugger(Isolate* isolate, int port) {
165
  RemoteDebugger debugger(isolate, port);
166
  debugger.Run();
167
}
168

    
169

    
170
void RemoteDebugger::Run() {
171
  bool ok;
172

    
173
  // Connect to the debugger agent.
174
  conn_ = new i::Socket;
175
  static const int kPortStrSize = 6;
176
  char port_str[kPortStrSize];
177
  i::OS::SNPrintF(i::Vector<char>(port_str, kPortStrSize), "%d", port_);
178
  ok = conn_->Connect("localhost", port_str);
179
  if (!ok) {
180
    printf("Unable to connect to debug agent %d\n", i::Socket::GetLastError());
181
    return;
182
  }
183

    
184
  // Start the receiver thread.
185
  ReceiverThread receiver(this);
186
  receiver.Start();
187

    
188
  // Start the keyboard thread.
189
  KeyboardThread keyboard(this);
190
  keyboard.Start();
191
  PrintPrompt();
192

    
193
  // Process events received from debugged VM and from the keyboard.
194
  bool terminate = false;
195
  while (!terminate) {
196
    event_available_.Wait();
197
    RemoteDebuggerEvent* event = GetEvent();
198
    switch (event->type()) {
199
      case RemoteDebuggerEvent::kMessage:
200
        HandleMessageReceived(event->data());
201
        break;
202
      case RemoteDebuggerEvent::kKeyboard:
203
        HandleKeyboardCommand(event->data());
204
        break;
205
      case RemoteDebuggerEvent::kDisconnect:
206
        terminate = true;
207
        break;
208

    
209
      default:
210
        UNREACHABLE();
211
    }
212
    delete event;
213
  }
214

    
215
  // Wait for the receiver thread to end.
216
  receiver.Join();
217
}
218

    
219

    
220
void RemoteDebugger::MessageReceived(i::SmartArrayPointer<char> message) {
221
  RemoteDebuggerEvent* event =
222
      new RemoteDebuggerEvent(RemoteDebuggerEvent::kMessage, message);
223
  AddEvent(event);
224
}
225

    
226

    
227
void RemoteDebugger::KeyboardCommand(i::SmartArrayPointer<char> command) {
228
  RemoteDebuggerEvent* event =
229
      new RemoteDebuggerEvent(RemoteDebuggerEvent::kKeyboard, command);
230
  AddEvent(event);
231
}
232

    
233

    
234
void RemoteDebugger::ConnectionClosed() {
235
  RemoteDebuggerEvent* event =
236
      new RemoteDebuggerEvent(RemoteDebuggerEvent::kDisconnect,
237
                              i::SmartArrayPointer<char>());
238
  AddEvent(event);
239
}
240

    
241

    
242
void RemoteDebugger::AddEvent(RemoteDebuggerEvent* event) {
243
  i::LockGuard<i::Mutex> lock_guard(&event_access_);
244
  if (head_ == NULL) {
245
    ASSERT(tail_ == NULL);
246
    head_ = event;
247
    tail_ = event;
248
  } else {
249
    ASSERT(tail_ != NULL);
250
    tail_->set_next(event);
251
    tail_ = event;
252
  }
253
  event_available_.Signal();
254
}
255

    
256

    
257
RemoteDebuggerEvent* RemoteDebugger::GetEvent() {
258
  i::LockGuard<i::Mutex> lock_guard(&event_access_);
259
  ASSERT(head_ != NULL);
260
  RemoteDebuggerEvent* result = head_;
261
  head_ = head_->next();
262
  if (head_ == NULL) {
263
    ASSERT(tail_ == result);
264
    tail_ = NULL;
265
  }
266
  return result;
267
}
268

    
269

    
270
void RemoteDebugger::HandleMessageReceived(char* message) {
271
  Locker lock(isolate_);
272
  HandleScope scope(isolate_);
273

    
274
  // Print the event details.
275
  TryCatch try_catch;
276
  Handle<Object> details =
277
      Shell::DebugMessageDetails(isolate_,
278
                                 Handle<String>::Cast(String::New(message)));
279
  if (try_catch.HasCaught()) {
280
    Shell::ReportException(isolate_, &try_catch);
281
    PrintPrompt();
282
    return;
283
  }
284
  String::Utf8Value str(details->Get(String::New("text")));
285
  if (str.length() == 0) {
286
    // Empty string is used to signal not to process this event.
287
    return;
288
  }
289
  if (*str != NULL) {
290
    printf("%s\n", *str);
291
  } else {
292
    printf("???\n");
293
  }
294

    
295
  bool is_running = details->Get(String::New("running"))->ToBoolean()->Value();
296
  PrintPrompt(is_running);
297
}
298

    
299

    
300
void RemoteDebugger::HandleKeyboardCommand(char* command) {
301
  Locker lock(isolate_);
302
  HandleScope scope(isolate_);
303

    
304
  // Convert the debugger command to a JSON debugger request.
305
  TryCatch try_catch;
306
  Handle<Value> request =
307
      Shell::DebugCommandToJSONRequest(isolate_, String::New(command));
308
  if (try_catch.HasCaught()) {
309
    Shell::ReportException(isolate_, &try_catch);
310
    PrintPrompt();
311
    return;
312
  }
313

    
314
  // If undefined is returned the command was handled internally and there is
315
  // no JSON to send.
316
  if (request->IsUndefined()) {
317
    PrintPrompt();
318
    return;
319
  }
320

    
321
  // Send the JSON debugger request.
322
  i::DebuggerAgentUtil::SendMessage(conn_, Handle<String>::Cast(request));
323
}
324

    
325

    
326
void ReceiverThread::Run() {
327
  // Receive the connect message (with empty body).
328
  i::SmartArrayPointer<char> message =
329
      i::DebuggerAgentUtil::ReceiveMessage(remote_debugger_->conn());
330
  ASSERT(*message == NULL);
331

    
332
  while (true) {
333
    // Receive a message.
334
    i::SmartArrayPointer<char> message =
335
        i::DebuggerAgentUtil::ReceiveMessage(remote_debugger_->conn());
336
    if (*message == NULL) {
337
      remote_debugger_->ConnectionClosed();
338
      return;
339
    }
340

    
341
    // Pass the message to the main thread.
342
    remote_debugger_->MessageReceived(message);
343
  }
344
}
345

    
346

    
347
void KeyboardThread::Run() {
348
  static const int kBufferSize = 256;
349
  while (true) {
350
    // read keyboard input.
351
    char command[kBufferSize];
352
    char* str = fgets(command, kBufferSize, stdin);
353
    if (str == NULL) {
354
      break;
355
    }
356

    
357
    // Pass the keyboard command to the main thread.
358
    remote_debugger_->KeyboardCommand(
359
        i::SmartArrayPointer<char>(i::StrDup(command)));
360
  }
361
}
362

    
363

    
364
}  // namespace v8
365

    
366
#endif  // ENABLE_DEBUGGER_SUPPORT