GCC Code Coverage Report
Directory: ../src/ Exec Total Coverage
File: /home/node-core-coverage/node-core-coverage/workdir/node/src/debug-agent.cc Lines: 126 150 84.0 %
Date: 2016-07-18 Branches: 18 46 39.1 %

Line Exec Source
1
// Copyright Fedor Indutny and other Node contributors.
2
//
3
// Permission is hereby granted, free of charge, to any person obtaining a
4
// copy of this software and associated documentation files (the
5
// "Software"), to deal in the Software without restriction, including
6
// without limitation the rights to use, copy, modify, merge, publish,
7
// distribute, sublicense, and/or sell copies of the Software, and to permit
8
// persons to whom the Software is furnished to do so, subject to the
9
// following conditions:
10
//
11
// The above copyright notice and this permission notice shall be included
12
// in all copies or substantial portions of the Software.
13
//
14
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20
// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22
#include "debug-agent.h"
23
24
#include "node.h"
25
#include "node_internals.h"  // arraysize
26
#include "env.h"
27
#include "env-inl.h"
28
#include "v8.h"
29
#include "v8-debug.h"
30
#include "util.h"
31
#include "util-inl.h"
32
33
#include <string.h>
34
35
namespace node {
36
namespace debugger {
37
38
using v8::Context;
39
using v8::Function;
40
using v8::FunctionCallbackInfo;
41
using v8::FunctionTemplate;
42
using v8::HandleScope;
43
using v8::Integer;
44
using v8::Isolate;
45
using v8::Local;
46
using v8::Locker;
47
using v8::NewStringType;
48
using v8::Object;
49
using v8::String;
50
using v8::Value;
51
52
53
1559
Agent::Agent(Environment* env) : state_(kNone),
54
                                 port_(5858),
55
                                 wait_(false),
56
                                 parent_env_(env),
57
                                 child_env_(nullptr),
58
6236
                                 dispatch_handler_(nullptr) {
59
1559
  CHECK_EQ(0, uv_sem_init(&start_sem_, 0));
60
1559
}
61
62
63
6820
Agent::~Agent() {
64
1364
  Stop();
65
66
1364
  uv_sem_destroy(&start_sem_);
67
68
2728
  while (AgentMessage* msg = messages_.PopFront())
69
    delete msg;
70
1364
}
71
72
73
6
bool Agent::Start(const std::string& host, int port, bool wait) {
74
  int err;
75
76
6
  if (state_ == kRunning)
77
    return false;
78
79
6
  err = uv_loop_init(&child_loop_);
80
6
  if (err != 0)
81
    goto loop_init_failed;
82
83
  // Interruption signal handler
84
6
  err = uv_async_init(&child_loop_, &child_signal_, ChildSignalCb);
85
6
  if (err != 0)
86
    goto async_init_failed;
87
6
  uv_unref(reinterpret_cast<uv_handle_t*>(&child_signal_));
88
89
12
  host_ = host;
90
6
  port_ = port;
91
6
  wait_ = wait;
92
93
6
  err = uv_thread_create(&thread_,
94
                         reinterpret_cast<uv_thread_cb>(ThreadCb),
95
6
                         this);
96
6
  if (err != 0)
97
    goto thread_create_failed;
98
99
6
  uv_sem_wait(&start_sem_);
100
101
6
  state_ = kRunning;
102
103
6
  return true;
104
105
 thread_create_failed:
106
  uv_close(reinterpret_cast<uv_handle_t*>(&child_signal_), nullptr);
107
108
 async_init_failed:
109
  err = uv_loop_close(&child_loop_);
110
  CHECK_EQ(err, 0);
111
112
 loop_init_failed:
113
  return false;
114
}
115
116
117
5
void Agent::Enable() {
118
5
  v8::Debug::SetMessageHandler(parent_env()->isolate(), MessageHandler);
119
120
  // Assign environment to the debugger's context
121
  // NOTE: The debugger context is created after `SetMessageHandler()` call
122
5
  auto debug_context = v8::Debug::GetDebugContext(parent_env()->isolate());
123
10
  parent_env()->AssignToContext(debug_context);
124
5
}
125
126
127
1364
void Agent::Stop() {
128
  int err;
129
130
1364
  if (state_ != kRunning) {
131
    return;
132
  }
133
134
  v8::Debug::SetMessageHandler(parent_env()->isolate(), nullptr);
135
136
  // Send empty message to terminate things
137
  EnqueueMessage(new AgentMessage(nullptr, 0));
138
139
  // Signal worker thread to make it stop
140
  err = uv_async_send(&child_signal_);
141
  CHECK_EQ(err, 0);
142
143
  err = uv_thread_join(&thread_);
144
  CHECK_EQ(err, 0);
145
146
  uv_close(reinterpret_cast<uv_handle_t*>(&child_signal_), nullptr);
147
  uv_run(&child_loop_, UV_RUN_NOWAIT);
148
149
  err = uv_loop_close(&child_loop_);
150
  CHECK_EQ(err, 0);
151
152
  state_ = kNone;
153
}
154
155
156
6
void Agent::WorkerRun() {
157
  static const char* argv[] = { "node", "--debug-agent" };
158
6
  Isolate::CreateParams params;
159
6
  ArrayBufferAllocator array_buffer_allocator;
160
6
  params.array_buffer_allocator = &array_buffer_allocator;
161
6
  Isolate* isolate = Isolate::New(params);
162
  {
163
6
    Locker locker(isolate);
164
6
    Isolate::Scope isolate_scope(isolate);
165
166
6
    HandleScope handle_scope(isolate);
167
    IsolateData isolate_data(isolate, &child_loop_,
168
6
                             array_buffer_allocator.zero_fill_field());
169
12
    Local<Context> context = Context::New(isolate);
170
171
6
    Context::Scope context_scope(context);
172
6
    Environment env(&isolate_data, context);
173
174
6
    const bool start_profiler_idle_notifier = false;
175
6
    env.Start(arraysize(argv), argv,
176
6
              arraysize(argv), argv,
177
6
              start_profiler_idle_notifier);
178
179
6
    child_env_ = &env;
180
181
    // Expose API
182
6
    InitAdaptor(&env);
183
6
    LoadEnvironment(&env);
184
185
12
    CHECK_EQ(&child_loop_, env.event_loop());
186
6
    uv_run(&child_loop_, UV_RUN_DEFAULT);
187
188
    // Clean-up peristent
189
    api_.Reset();
190
  }
191
  isolate->Dispose();
192
}
193
194
195
6
void Agent::InitAdaptor(Environment* env) {
196
6
  Isolate* isolate = env->isolate();
197
12
  HandleScope scope(isolate);
198
199
  // Create API adaptor
200
12
  Local<FunctionTemplate> t = FunctionTemplate::New(isolate);
201
12
  t->InstanceTemplate()->SetInternalFieldCount(1);
202
6
  t->SetClassName(String::NewFromUtf8(isolate, "DebugAPI"));
203
204
6
  NODE_SET_PROTOTYPE_METHOD(t, "notifyListen", NotifyListen);
205
6
  NODE_SET_PROTOTYPE_METHOD(t, "notifyWait", NotifyWait);
206
6
  NODE_SET_PROTOTYPE_METHOD(t, "sendCommand", SendCommand);
207
208
  Local<Object> api =
209
24
      t->GetFunction()->NewInstance(env->context()).ToLocalChecked();
210
6
  api->SetAlignedPointerInInternalField(0, this);
211
212
30
  api->Set(String::NewFromUtf8(isolate, "host",
213
                               NewStringType::kNormal).ToLocalChecked(),
214
6
           String::NewFromUtf8(isolate, host_.data(), NewStringType::kNormal,
215
18
                               host_.size()).ToLocalChecked());
216
18
  api->Set(String::NewFromUtf8(isolate, "port"), Integer::New(isolate, port_));
217
218
18
  env->process_object()->Set(String::NewFromUtf8(isolate, "_debugAPI"), api);
219
12
  api_.Reset(env->isolate(), api);
220
6
}
221
222
223
8
Agent* Agent::Unwrap(const v8::FunctionCallbackInfo<v8::Value>& args) {
224
16
  void* ptr = args.Holder()->GetAlignedPointerFromInternalField(0);
225
8
  return reinterpret_cast<Agent*>(ptr);
226
}
227
228
229
6
void Agent::NotifyListen(const FunctionCallbackInfo<Value>& args) {
230
6
  Agent* a = Unwrap(args);
231
232
  // Notify other thread that we are ready to process events
233
6
  uv_sem_post(&a->start_sem_);
234
6
}
235
236
237
1
void Agent::NotifyWait(const FunctionCallbackInfo<Value>& args) {
238
1
  Agent* a = Unwrap(args);
239
240
1
  a->wait_ = false;
241
242
1
  int err = uv_async_send(&a->child_signal_);
243
1
  CHECK_EQ(err, 0);
244
1
}
245
246
247
1
void Agent::SendCommand(const FunctionCallbackInfo<Value>& args) {
248
1
  Agent* a = Unwrap(args);
249
1
  Environment* env = a->child_env();
250
2
  HandleScope scope(env->isolate());
251
252
2
  String::Value v(args[0]);
253
254
1
  v8::Debug::SendCommand(a->parent_env()->isolate(), *v, v.length());
255
1
  if (a->dispatch_handler_ != nullptr)
256
1
    a->dispatch_handler_(a->parent_env());
257
1
}
258
259
260
6
void Agent::ThreadCb(Agent* agent) {
261
6
  agent->WorkerRun();
262
}
263
264
265
5
void Agent::ChildSignalCb(uv_async_t* signal) {
266
5
  Agent* a = ContainerOf(&Agent::child_signal_, signal);
267
5
  Isolate* isolate = a->child_env()->isolate();
268
269
10
  HandleScope scope(isolate);
270
5
  Local<Object> api = PersistentToLocal(isolate, a->api_);
271
272
10
  Mutex::ScopedLock scoped_lock(a->message_mutex_);
273
25
  while (AgentMessage* msg = a->messages_.PopFront()) {
274
    // Time to close everything
275
5
    if (msg->data() == nullptr) {
276
      delete msg;
277
278
      MakeCallback(isolate, api, "onclose", 0, nullptr);
279
      break;
280
    }
281
282
    // Waiting for client, do not send anything just yet
283
5
    if (a->wait_) {
284
      a->messages_.PushFront(msg);  // Push message back into the ready queue.
285
      break;
286
    }
287
288
    Local<Value> argv[] = {
289
      String::NewFromTwoByte(isolate,
290
                             msg->data(),
291
                             String::kNormalString,
292
                             msg->length())
293
10
    };
294
295
    // Emit message
296
    MakeCallback(isolate,
297
                 api,
298
                 "onmessage",
299
5
                 arraysize(argv),
300
5
                 argv);
301
5
    delete msg;
302
  }
303
5
}
304
305
306
5
void Agent::EnqueueMessage(AgentMessage* message) {
307
15
  Mutex::ScopedLock scoped_lock(message_mutex_);
308
10
  messages_.PushBack(message);
309
5
  uv_async_send(&child_signal_);
310
5
}
311
312
313
5
void Agent::MessageHandler(const v8::Debug::Message& message) {
314
5
  Isolate* isolate = message.GetIsolate();
315
5
  Environment* env = Environment::GetCurrent(isolate);
316
5
  if (env == nullptr)
317
    return;  // Called from a non-node context.
318
5
  Agent* a = env->debugger_agent();
319
5
  CHECK_NE(a, nullptr);
320
5
  CHECK_EQ(isolate, a->parent_env()->isolate());
321
322
10
  HandleScope scope(isolate);
323
5
  Local<String> json = message.GetJSON();
324
10
  String::Value v(json);
325
326
5
  AgentMessage* msg = new AgentMessage(*v, v.length());
327
5
  a->EnqueueMessage(msg);
328
}
329
330
}  // namespace debugger
331
}  // namespace node