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 @ 40c0f755

History | View | Annotate | Download (9.76 KB)

1
// Copyright 2008 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 "d8.h"
30
#include "d8-debug.h"
31
#include "platform.h"
32
#include "debug-agent.h"
33

    
34

    
35
namespace v8 {
36

    
37

    
38
void HandleDebugEvent(DebugEvent event,
39
                      Handle<Object> exec_state,
40
                      Handle<Object> event_data,
41
                      Handle<Value> data) {
42
  HandleScope scope;
43

    
44
  // Check for handled event.
45
  if (event != Break && event != Exception && event != AfterCompile) {
46
    return;
47
  }
48

    
49
  TryCatch try_catch;
50

    
51
  // Get the toJSONProtocol function on the event and get the JSON format.
52
  Local<String> to_json_fun_name = String::New("toJSONProtocol");
53
  Local<Function> to_json_fun =
54
      Function::Cast(*event_data->Get(to_json_fun_name));
55
  Local<Value> event_json = to_json_fun->Call(event_data, 0, NULL);
56
  if (try_catch.HasCaught()) {
57
    Shell::ReportException(&try_catch);
58
    return;
59
  }
60

    
61
  // Print the event details.
62
  Handle<Object> details =
63
      Shell::DebugMessageDetails(Handle<String>::Cast(event_json));
64
  if (try_catch.HasCaught()) {
65
    Shell::ReportException(&try_catch);
66
    return;
67
  }
68
  String::Utf8Value str(details->Get(String::New("text")));
69
  if (str.length() == 0) {
70
    // Empty string is used to signal not to process this event.
71
    return;
72
  }
73
  printf("%s\n", *str);
74

    
75
  // Get the debug command processor.
76
  Local<String> fun_name = String::New("debugCommandProcessor");
77
  Local<Function> fun = Function::Cast(*exec_state->Get(fun_name));
78
  Local<Object> cmd_processor =
79
      Object::Cast(*fun->Call(exec_state, 0, NULL));
80
  if (try_catch.HasCaught()) {
81
    Shell::ReportException(&try_catch);
82
    return;
83
  }
84

    
85
  static const int kBufferSize = 256;
86
  bool running = false;
87
  while (!running) {
88
    char command[kBufferSize];
89
    printf("dbg> ");
90
    char* str = fgets(command, kBufferSize, stdin);
91
    if (str == NULL) break;
92

    
93
    // Ignore empty commands.
94
    if (strlen(command) == 0) continue;
95

    
96
    TryCatch try_catch;
97

    
98
    // Convert the debugger command to a JSON debugger request.
99
    Handle<Value> request =
100
        Shell::DebugCommandToJSONRequest(String::New(command));
101
    if (try_catch.HasCaught()) {
102
      Shell::ReportException(&try_catch);
103
      continue;
104
    }
105

    
106
    // If undefined is returned the command was handled internally and there is
107
    // no JSON to send.
108
    if (request->IsUndefined()) {
109
      continue;
110
    }
111

    
112
    Handle<String> fun_name;
113
    Handle<Function> fun;
114
    // All the functions used below take one argument.
115
    static const int kArgc = 1;
116
    Handle<Value> args[kArgc];
117

    
118
    // Invoke the JavaScript to convert the debug command line to a JSON
119
    // request, invoke the JSON request and convert the JSON respose to a text
120
    // representation.
121
    fun_name = String::New("processDebugRequest");
122
    fun = Handle<Function>::Cast(cmd_processor->Get(fun_name));
123
    args[0] = request;
124
    Handle<Value> response_val = fun->Call(cmd_processor, kArgc, args);
125
    if (try_catch.HasCaught()) {
126
      Shell::ReportException(&try_catch);
127
      continue;
128
    }
129
    Handle<String> response = Handle<String>::Cast(response_val);
130

    
131
    // Convert the debugger response into text details and the running state.
132
    Handle<Object> response_details = Shell::DebugMessageDetails(response);
133
    if (try_catch.HasCaught()) {
134
      Shell::ReportException(&try_catch);
135
      continue;
136
    }
137
    String::Utf8Value text_str(response_details->Get(String::New("text")));
138
    if (text_str.length() > 0) {
139
      printf("%s\n", *text_str);
140
    }
141
    running =
142
        response_details->Get(String::New("running"))->ToBoolean()->Value();
143
  }
144
}
145

    
146

    
147
void RunRemoteDebugger(int port) {
148
  RemoteDebugger debugger(port);
149
  debugger.Run();
150
}
151

    
152

    
153
void RemoteDebugger::Run() {
154
  bool ok;
155

    
156
  // Make sure that socket support is initialized.
157
  ok = i::Socket::Setup();
158
  if (!ok) {
159
    printf("Unable to initialize socket support %d\n", i::Socket::LastError());
160
    return;
161
  }
162

    
163
  // Connect to the debugger agent.
164
  conn_ = i::OS::CreateSocket();
165
  static const int kPortStrSize = 6;
166
  char port_str[kPortStrSize];
167
  i::OS::SNPrintF(i::Vector<char>(port_str, kPortStrSize), "%d", port_);
168
  ok = conn_->Connect("localhost", port_str);
169
  if (!ok) {
170
    printf("Unable to connect to debug agent %d\n", i::Socket::LastError());
171
    return;
172
  }
173

    
174
  // Start the receiver thread.
175
  ReceiverThread receiver(this);
176
  receiver.Start();
177

    
178
  // Start the keyboard thread.
179
  KeyboardThread keyboard(this);
180
  keyboard.Start();
181

    
182
  // Process events received from debugged VM and from the keyboard.
183
  bool terminate = false;
184
  while (!terminate) {
185
    event_available_->Wait();
186
    RemoteDebuggerEvent* event = GetEvent();
187
    switch (event->type()) {
188
      case RemoteDebuggerEvent::kMessage:
189
        HandleMessageReceived(event->data());
190
        break;
191
      case RemoteDebuggerEvent::kKeyboard:
192
        HandleKeyboardCommand(event->data());
193
        break;
194
      case RemoteDebuggerEvent::kDisconnect:
195
        terminate = true;
196
        break;
197

    
198
      default:
199
        UNREACHABLE();
200
    }
201
    delete event;
202
  }
203

    
204
  // Wait for the receiver thread to end.
205
  receiver.Join();
206
}
207

    
208

    
209
void RemoteDebugger::MessageReceived(i::SmartPointer<char> message) {
210
  RemoteDebuggerEvent* event =
211
      new RemoteDebuggerEvent(RemoteDebuggerEvent::kMessage, message);
212
  AddEvent(event);
213
}
214

    
215

    
216
void RemoteDebugger::KeyboardCommand(i::SmartPointer<char> command) {
217
  RemoteDebuggerEvent* event =
218
      new RemoteDebuggerEvent(RemoteDebuggerEvent::kKeyboard, command);
219
  AddEvent(event);
220
}
221

    
222

    
223
void RemoteDebugger::ConnectionClosed() {
224
  RemoteDebuggerEvent* event =
225
      new RemoteDebuggerEvent(RemoteDebuggerEvent::kDisconnect,
226
                              i::SmartPointer<char>());
227
  AddEvent(event);
228
}
229

    
230

    
231
void RemoteDebugger::AddEvent(RemoteDebuggerEvent* event) {
232
  i::ScopedLock lock(event_access_);
233
  if (head_ == NULL) {
234
    ASSERT(tail_ == NULL);
235
    head_ = event;
236
    tail_ = event;
237
  } else {
238
    ASSERT(tail_ != NULL);
239
    tail_->set_next(event);
240
    tail_ = event;
241
  }
242
  event_available_->Signal();
243
}
244

    
245

    
246
RemoteDebuggerEvent* RemoteDebugger::GetEvent() {
247
  i::ScopedLock lock(event_access_);
248
  ASSERT(head_ != NULL);
249
  RemoteDebuggerEvent* result = head_;
250
  head_ = head_->next();
251
  if (head_ == NULL) {
252
    ASSERT(tail_ == result);
253
    tail_ = NULL;
254
  }
255
  return result;
256
}
257

    
258

    
259
void RemoteDebugger::HandleMessageReceived(char* message) {
260
  HandleScope scope;
261

    
262
  // Print the event details.
263
  TryCatch try_catch;
264
  Handle<Object> details =
265
      Shell::DebugMessageDetails(Handle<String>::Cast(String::New(message)));
266
  if (try_catch.HasCaught()) {
267
      Shell::ReportException(&try_catch);
268
    return;
269
  }
270
  String::Utf8Value str(details->Get(String::New("text")));
271
  if (str.length() == 0) {
272
    // Empty string is used to signal not to process this event.
273
    return;
274
  }
275
  if (*str != NULL) {
276
    printf("%s\n", *str);
277
  } else {
278
    printf("???\n");
279
  }
280
  printf("dbg> ");
281
}
282

    
283

    
284
void RemoteDebugger::HandleKeyboardCommand(char* command) {
285
  HandleScope scope;
286

    
287
  // Convert the debugger command to a JSON debugger request.
288
  TryCatch try_catch;
289
  Handle<Value> request =
290
      Shell::DebugCommandToJSONRequest(String::New(command));
291
  if (try_catch.HasCaught()) {
292
    Shell::ReportException(&try_catch);
293
    return;
294
  }
295

    
296
  // If undefined is returned the command was handled internally and there is
297
  // no JSON to send.
298
  if (request->IsUndefined()) {
299
    return;
300
  }
301

    
302
  // Send the JSON debugger request.
303
  i::DebuggerAgentUtil::SendMessage(conn_, Handle<String>::Cast(request));
304
}
305

    
306

    
307
void ReceiverThread::Run() {
308
  // Receive the connect message (with empty body).
309
  i::SmartPointer<char> message =
310
    i::DebuggerAgentUtil::ReceiveMessage(remote_debugger_->conn());
311
  ASSERT(*message == NULL);
312

    
313
  while (true) {
314
    // Receive a message.
315
    i::SmartPointer<char> message =
316
      i::DebuggerAgentUtil::ReceiveMessage(remote_debugger_->conn());
317
    if (*message == NULL) {
318
      remote_debugger_->ConnectionClosed();
319
      return;
320
    }
321

    
322
    // Pass the message to the main thread.
323
    remote_debugger_->MessageReceived(message);
324
  }
325
}
326

    
327

    
328
void KeyboardThread::Run() {
329
  static const int kBufferSize = 256;
330
  while (true) {
331
    // read keyboard input.
332
    char command[kBufferSize];
333
    char* str = fgets(command, kBufferSize, stdin);
334
    if (str == NULL) {
335
      break;
336
    }
337

    
338
    // Pass the keyboard command to the main thread.
339
    remote_debugger_->KeyboardCommand(
340
        i::SmartPointer<char>(i::StrDup(command)));
341
  }
342
}
343

    
344

    
345
}  // namespace v8