Skip to content

Commit baf4cae

Browse files
author
Matheus Marchini
committed
src: add commands to inspect the workqueue
Add two new commands: `v8 getactivehandles` and `v8 getactiverequests`. These comamnds will print all pending handles and requests. The result should be similar to running process._getActiveHandles() and process._getActiveRequests() on the living process. PR-URL: #210 Fixes: #100 Reviewed-By: Joyee Cheung <[email protected]>
1 parent 775dd6c commit baf4cae

File tree

11 files changed

+482
-4
lines changed

11 files changed

+482
-4
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,12 @@ The following subcommands are supported:
230230
* -n, --name name - all properties with the specified name
231231
* -s, --string string - all properties that refer to the specified JavaScript string value
232232
233+
getactivehandles -- Print all pending handles in the queue. Equivalent to running process._getActiveHandles() on
234+
the living process.
235+
236+
getactiverequests -- Print all pending handles in the queue. Equivalent to running process._getActiveHandles() on
237+
the living process.
238+
233239
inspect -- Print detailed description and contents of the JavaScript value.
234240
235241
Possible flags (all optional):

binding.gyp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
"src/llv8.cc",
7878
"src/llv8-constants.cc",
7979
"src/llscan.cc",
80+
"src/node.cc",
8081
"src/node-constants.cc",
8182
],
8283
"conditions": [

src/llnode.cc

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@
44
#include <string.h>
55

66
#include <cinttypes>
7+
#include <sstream>
8+
#include <string>
79

810
#include <lldb/API/SBExpressionOptions.h>
911

1012
#include "src/error.h"
1113
#include "src/llnode.h"
1214
#include "src/llscan.h"
1315
#include "src/llv8.h"
16+
#include "src/node-inl.h"
1417

1518
namespace llnode {
1619

@@ -245,6 +248,100 @@ bool ListCmd::DoExecute(SBDebugger d, char** cmd,
245248
return true;
246249
}
247250

251+
bool WorkqueueCmd::DoExecute(SBDebugger d, char** cmd,
252+
SBCommandReturnObject& result) {
253+
SBTarget target = d.GetSelectedTarget();
254+
SBThread thread = target.GetProcess().GetSelectedThread();
255+
if (!thread.IsValid()) {
256+
result.SetError("No valid process, please start something\n");
257+
return false;
258+
}
259+
260+
std::string result_message;
261+
Error err;
262+
263+
llv8_->Load(target);
264+
node_->Load(target);
265+
266+
node::Environment env = node::Environment::GetCurrent(node_, err);
267+
if (err.Fail()) {
268+
result.SetError(err.GetMessage());
269+
return false;
270+
}
271+
272+
result_message = GetResultMessage(&env, err);
273+
if (err.Fail()) {
274+
result.SetError(err.GetMessage());
275+
return false;
276+
}
277+
278+
result.Printf("%s", result_message.c_str());
279+
return true;
280+
}
281+
282+
std::string GetActiveHandlesCmd::GetResultMessage(node::Environment* env,
283+
Error& err) {
284+
int active_handles = 0;
285+
v8::Value::InspectOptions inspect_options;
286+
inspect_options.detailed = true;
287+
std::ostringstream result_message;
288+
289+
for (auto w : env->handle_wrap_queue()) {
290+
addr_t persistent = w.Persistent(err);
291+
if (err.Fail()) break;
292+
if (persistent == 0) continue;
293+
294+
addr_t raw_object = w.Object(err);
295+
if (err.Fail()) break;
296+
297+
v8::JSObject v8_object(llv8(), raw_object);
298+
std::string res = v8_object.Inspect(&inspect_options, err);
299+
if (err.Fail()) {
300+
Error::PrintInDebugMode("Failed to load object at address %" PRIx64,
301+
raw_object);
302+
break;
303+
}
304+
305+
active_handles++;
306+
result_message << res.c_str() << std::endl;
307+
}
308+
309+
result_message << "Total: " << active_handles << std::endl;
310+
return result_message.str();
311+
}
312+
313+
314+
std::string GetActiveRequestsCmd::GetResultMessage(node::Environment* env,
315+
Error& err) {
316+
int active_requests = 0;
317+
v8::Value::InspectOptions inspect_options;
318+
inspect_options.detailed = true;
319+
std::ostringstream result_message;
320+
321+
for (auto w : env->req_wrap_queue()) {
322+
addr_t persistent = w.Persistent(err);
323+
if (err.Fail()) break;
324+
if (persistent == 0) continue;
325+
326+
addr_t raw_object = w.Object(err);
327+
if (err.Fail()) break;
328+
329+
v8::JSObject v8_object(llv8(), raw_object);
330+
std::string res = v8_object.Inspect(&inspect_options, err);
331+
if (err.Fail()) {
332+
Error::PrintInDebugMode("Failed to load object at address %" PRIx64,
333+
raw_object);
334+
break;
335+
}
336+
337+
active_requests++;
338+
result_message << res.c_str() << std::endl;
339+
}
340+
341+
result_message << "Total: " << active_requests << std::endl;
342+
return result_message.str();
343+
}
344+
248345

249346
void InitDebugMode() {
250347
bool is_debug_mode = false;
@@ -264,6 +361,7 @@ bool PluginInitialize(SBDebugger d) {
264361
llnode::InitDebugMode();
265362

266363
static llnode::v8::LLV8 llv8;
364+
static llnode::node::Node node(&llv8);
267365
static llnode::LLScan llscan = llnode::LLScan(&llv8);
268366

269367
SBCommandInterpreter interpreter = d.GetCommandInterpreter();
@@ -349,6 +447,16 @@ bool PluginInitialize(SBDebugger d) {
349447
"JavaScript string value\n"
350448
"\n");
351449

450+
v8.AddCommand("getactivehandles",
451+
new llnode::GetActiveHandlesCmd(&llv8, &node),
452+
"Print all pending handles in the queue. Equivalent to running "
453+
"process._getActiveHandles() on the living process.\n");
454+
455+
v8.AddCommand(
456+
"getactiverequests", new llnode::GetActiveRequestsCmd(&llv8, &node),
457+
"Print all pending requests in the queue. Equivalent to "
458+
"running process._getActiveRequests() on the living process.\n");
459+
352460
return true;
353461
}
354462

src/llnode.h

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66
#include <lldb/API/LLDB.h>
77

88
#include "src/llv8.h"
9+
#include "src/node.h"
910

1011
namespace llnode {
1112

12-
class CommandBase : public lldb::SBCommandPluginInterface {
13-
};
13+
class CommandBase : public lldb::SBCommandPluginInterface {};
1414

1515
class BacktraceCmd : public CommandBase {
1616
public:
@@ -50,6 +50,43 @@ class ListCmd : public CommandBase {
5050
v8::LLV8* llv8_;
5151
};
5252

53+
class WorkqueueCmd : public CommandBase {
54+
public:
55+
WorkqueueCmd(v8::LLV8* llv8, node::Node* node) : llv8_(llv8), node_(node) {}
56+
~WorkqueueCmd() override {}
57+
58+
inline v8::LLV8* llv8() { return llv8_; };
59+
inline node::Node* node() { return node_; };
60+
61+
bool DoExecute(lldb::SBDebugger d, char** cmd,
62+
lldb::SBCommandReturnObject& result) override;
63+
64+
virtual std::string GetResultMessage(node::Environment* env, Error& err) {
65+
return std::string();
66+
};
67+
68+
private:
69+
v8::LLV8* llv8_;
70+
node::Node* node_;
71+
};
72+
73+
class GetActiveHandlesCmd : public WorkqueueCmd {
74+
public:
75+
GetActiveHandlesCmd(v8::LLV8* llv8, node::Node* node)
76+
: WorkqueueCmd(llv8, node) {}
77+
78+
std::string GetResultMessage(node::Environment* env, Error& err) override;
79+
};
80+
81+
class GetActiveRequestsCmd : public WorkqueueCmd {
82+
public:
83+
GetActiveRequestsCmd(v8::LLV8* llv8, node::Node* node)
84+
: WorkqueueCmd(llv8, node) {}
85+
86+
std::string GetResultMessage(node::Environment* env, Error& err) override;
87+
};
88+
89+
5390
} // namespace llnode
5491

5592
#endif // SRC_LLNODE_H_

src/node-constants.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ void Environment::Load() {
1919
kHandleWrapQueueOffset = LoadConstant(
2020
"offset_Environment__handle_wrap_queue___Environment_HandleWrapQueue");
2121
kEnvContextEmbedderDataIndex =
22-
LoadConstant("const_Environment__kContextEmbedderDataIndex__int");
22+
LoadConstant("const_Environment__kContextEmbedderDataIndex__int",
23+
"const_ContextEmbedderIndex__kEnvironment__int");
2324

2425
Error err;
2526
kCurrentEnvironment = LoadCurrentEnvironment(err);

src/node-inl.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#include "node.h"
2+
3+
namespace llnode {
4+
namespace node {
5+
6+
template <typename T, typename C>
7+
T Queue<T, C>::Iterator::operator*() const {
8+
return T::GetItemFromList(node_, current_);
9+
}
10+
11+
template <typename T, typename C>
12+
const typename Queue<T, C>::Iterator Queue<T, C>::Iterator::operator++() {
13+
lldb::SBError sberr;
14+
15+
current_ = node_->process().ReadPointerFromMemory(
16+
current_ + constants_->kNextOffset, sberr);
17+
return Iterator(node_, current_, constants_);
18+
}
19+
20+
template <typename T, typename C>
21+
bool Queue<T, C>::Iterator::operator!=(const Iterator& that) const {
22+
return current_ != that.current_;
23+
}
24+
25+
template <typename T, typename C>
26+
typename Queue<T, C>::Iterator Queue<T, C>::begin() const {
27+
lldb::SBError sberr;
28+
29+
addr_t first = node_->process().ReadPointerFromMemory(next(head()), sberr);
30+
return Iterator(node_, first, constants_);
31+
}
32+
33+
template <typename T, typename C>
34+
typename Queue<T, C>::Iterator Queue<T, C>::end() const {
35+
return Iterator(node_, head(), constants_);
36+
}
37+
} // namespace node
38+
} // namespace llnode

src/node.cc

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#include "node.h"
2+
3+
namespace llnode {
4+
namespace node {
5+
6+
addr_t BaseObject::Persistent(Error& err) {
7+
lldb::SBError sberr;
8+
9+
addr_t persistent_ptr = raw_ + node_->base_object()->kPersistentHandleOffset;
10+
addr_t persistent =
11+
node_->process().ReadPointerFromMemory(persistent_ptr, sberr);
12+
if (sberr.Fail()) {
13+
err = Error::Failure("Failed to load persistent handle");
14+
return 0;
15+
}
16+
return persistent;
17+
}
18+
19+
addr_t BaseObject::Object(Error& err) {
20+
lldb::SBError sberr;
21+
22+
addr_t persistent = Persistent(err);
23+
addr_t obj = node_->process().ReadPointerFromMemory(persistent, sberr);
24+
if (sberr.Fail()) {
25+
err = Error::Failure("Failed to load object from persistent handle");
26+
return 0;
27+
}
28+
return obj;
29+
}
30+
31+
HandleWrap HandleWrap::GetItemFromList(Node* node, addr_t list_node_addr) {
32+
return HandleWrap(node,
33+
list_node_addr - node->handle_wrap()->kListNodeOffset);
34+
}
35+
36+
ReqWrap ReqWrap::GetItemFromList(Node* node, addr_t list_node_addr) {
37+
return ReqWrap(node, list_node_addr - node->req_wrap()->kListNodeOffset);
38+
}
39+
40+
Environment Environment::GetCurrent(Node* node, Error& err) {
41+
addr_t envAddr = node->env()->kCurrentEnvironment;
42+
if (envAddr == 0) {
43+
err = Error::Failure("Couldn't get node's Environment");
44+
}
45+
46+
return Environment(node, envAddr);
47+
}
48+
49+
HandleWrapQueue Environment::handle_wrap_queue() const {
50+
return HandleWrapQueue(node_, raw_ + node_->env()->kHandleWrapQueueOffset,
51+
node_->handle_wrap_queue());
52+
}
53+
54+
ReqWrapQueue Environment::req_wrap_queue() const {
55+
return ReqWrapQueue(node_, raw_ + node_->env()->kReqWrapQueueOffset,
56+
node_->req_wrap_queue());
57+
}
58+
59+
void Node::Load(SBTarget target) {
60+
// Reload process anyway
61+
process_ = target.GetProcess();
62+
63+
// No need to reload
64+
if (target_ == target) return;
65+
66+
target_ = target;
67+
68+
env.Assign(target);
69+
req_wrap_queue.Assign(target);
70+
req_wrap.Assign(target);
71+
handle_wrap_queue.Assign(target);
72+
handle_wrap.Assign(target);
73+
base_object.Assign(target);
74+
}
75+
} // namespace node
76+
} // namespace llnode

0 commit comments

Comments
 (0)