Skip to content

Commit dceed10

Browse files
Matheus MarchiniMatheus Marchini
authored andcommitted
src: add commands to inspect the workqueue
Added two new commands (getactivehandles and getactiverequests) which prints all pending handles and requests (same return given by process._getActiveHandles() and process._getActiveRequests()). Those changes were built upon the symbols added on nodejs/node#14901, which means it's currently not working with node's latest build. Fixes: nodejs#100 Ref: nodejs/node#14901
1 parent 995d0bb commit dceed10

16 files changed

+822
-4
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,11 @@ The following subcommands are supported:
207207
* -n, --name name - all properties with the specified name
208208
* -s, --string string - all properties that refer to the specified JavaScript string value
209209
210+
<!--- TODO fix indentation for the other commands --->
211+
getactivehandles -- *EXPERIMENTAL* Equivalent to running process._getActiveHandles. This command is still being
212+
developed and for now it only works building node from source.
213+
getactiverequests -- *EXPERIMENTAL* Equivalent to running process._getActiveRequests. This command is still being
214+
developed and for now it only works building node from source.
210215
inspect -- Print detailed description and contents of the JavaScript value.
211216
212217
Possible flags (all optional):

llnode.gyp.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@
1616
],
1717

1818
"sources": [
19+
"src/constants.cc",
1920
"src/llnode.cc",
21+
"src/llnode-module.cc",
22+
"src/llnode-constants.cc",
2023
"src/llv8.cc",
2124
"src/llv8-constants.cc",
2225
"src/llscan.cc",

src/constants.cc

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#include "src/constants.h"
2+
#include "src/llv8.h"
3+
4+
namespace llnode {
5+
using v8::Error;
6+
using v8::constants::IsDebugMode;
7+
using v8::constants::LookupConstant;
8+
namespace constants {
9+
10+
void ConstantsWrapper::Assign(SBTarget target) {
11+
loaded_ = false;
12+
target_ = target;
13+
}
14+
15+
int64_t ConstantsWrapper::LoadRawConstant(const char* name, int64_t def) {
16+
Error err;
17+
int64_t v = LookupConstant(target_, name, def, err);
18+
if (err.Fail() && IsDebugMode()) fprintf(stderr, "Failed to load %s\n", name);
19+
20+
return v;
21+
}
22+
23+
24+
int64_t ConstantsWrapper::LoadConstant(const char* name, int64_t def) {
25+
Error err;
26+
int64_t v =
27+
LookupConstant(target_, (kConstantPrefix() + name).c_str(), def, err);
28+
if (err.Fail() && IsDebugMode()) fprintf(stderr, "Failed to load %s\n", name);
29+
30+
return v;
31+
}
32+
33+
34+
int64_t ConstantsWrapper::LoadConstant(const char* name, const char* fallback,
35+
int64_t def) {
36+
Error err;
37+
int64_t v =
38+
LookupConstant(target_, (kConstantPrefix() + name).c_str(), def, err);
39+
if (err.Fail())
40+
v = LookupConstant(target_, (kConstantPrefix() + fallback).c_str(), def,
41+
err);
42+
if (err.Fail() && IsDebugMode()) fprintf(stderr, "Failed to load %s\n", name);
43+
44+
return v;
45+
}
46+
}
47+
}

src/constants.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#ifndef SRC_CONSTANTS_H_
2+
#define SRC_CONSTANTS_H_
3+
4+
#include <lldb/API/LLDB.h>
5+
#include <string>
6+
using lldb::SBTarget;
7+
8+
namespace llnode {
9+
namespace constants {
10+
11+
class ConstantsWrapper {
12+
public:
13+
ConstantsWrapper() : loaded_(false) {}
14+
15+
inline bool is_loaded() const { return loaded_; }
16+
17+
void Assign(lldb::SBTarget target);
18+
19+
inline virtual std::string kConstantPrefix() { return ""; };
20+
21+
protected:
22+
int64_t LoadRawConstant(const char* name, int64_t def = -1);
23+
int64_t LoadConstant(const char* name, int64_t def = -1);
24+
int64_t LoadConstant(const char* name, const char* fallback,
25+
int64_t def = -1);
26+
27+
lldb::SBTarget target_;
28+
bool loaded_;
29+
};
30+
}
31+
}
32+
33+
#endif

src/llnode-constants.cc

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
#include <lldb/API/LLDB.h>
2+
3+
#include "llnode-constants.h"
4+
#include "llv8-constants.h"
5+
#include "llv8-inl.h"
6+
#include "llv8.h"
7+
8+
using lldb::SBProcess;
9+
using lldb::SBThread;
10+
using lldb::SBError;
11+
using lldb::SBFrame;
12+
using lldb::SBStream;
13+
14+
namespace llnode {
15+
using v8::Error;
16+
using v8::constants::LookupConstant;
17+
namespace node {
18+
namespace constants {
19+
v8::LLV8 llv8;
20+
21+
void Environment::Load() {
22+
kIsolate = LoadRawConstant("node::node_isolate");
23+
kReqWrapQueueOffset = LoadConstant("class__Environment__reqWrapQueue", 1256);
24+
kHandleWrapQueueOffset =
25+
LoadConstant("class__Environment__handleWrapQueue", 1240);
26+
kEnvContextEmbedderDataIndex =
27+
LoadConstant("environment_context_idx_embedder_data", 32);
28+
kCurrentEnvironment = LoadCurrentEnvironment();
29+
}
30+
31+
addr_t Environment::LoadCurrentEnvironment() {
32+
addr_t currentEnvironment = DefaultLoadCurrentEnvironment();
33+
if (currentEnvironment == -1) {
34+
currentEnvironment = FallbackLoadCurrentEnvironment();
35+
}
36+
37+
return currentEnvironment;
38+
}
39+
40+
addr_t Environment::DefaultLoadCurrentEnvironment() {
41+
llv8.Load(target_);
42+
43+
SBProcess process = target_.GetProcess();
44+
SBError sberr;
45+
uint64_t env = -1;
46+
uint64_t isolate_thread = 0;
47+
uint64_t thread_context_ptr = 0;
48+
uint64_t thread_context = 0;
49+
v8::Error err;
50+
51+
if (!(llv8.isolate()->kThreadLocalTopOffset != -1 &&
52+
llv8.thread_local_top()->kContextOffset != -1)) {
53+
return env;
54+
}
55+
56+
isolate_thread = kIsolate + llv8.isolate()->kThreadLocalTopOffset;
57+
58+
thread_context_ptr = isolate_thread + llv8.thread_local_top()->kContextOffset;
59+
thread_context = process.ReadPointerFromMemory(thread_context_ptr, sberr);
60+
if (sberr.Fail()) {
61+
return -1;
62+
}
63+
v8::Context ctx(&llv8, thread_context);
64+
v8::Value native = ctx.Native(err);
65+
if (err.Fail()) {
66+
return -1;
67+
}
68+
env = CurrentEnvironmentFromContext(native);
69+
return env;
70+
}
71+
72+
addr_t Environment::CurrentEnvironmentFromContext(v8::Value context) {
73+
llv8.Load(target_);
74+
v8::Error err;
75+
76+
v8::FixedArray contextArray = v8::FixedArray(context);
77+
v8::FixedArray embed =
78+
contextArray.Get<v8::FixedArray>(llv8.context()->kEmbedderDataIndex, err);
79+
if (err.Fail()) {
80+
return -1;
81+
}
82+
v8::Smi encodedEnv = embed.Get<v8::Smi>(kEnvContextEmbedderDataIndex, err);
83+
if (err.Fail()) {
84+
return -1;
85+
} else {
86+
return encodedEnv.raw();
87+
}
88+
}
89+
90+
addr_t Environment::FallbackLoadCurrentEnvironment() {
91+
addr_t env = -1;
92+
SBProcess process = target_.GetProcess();
93+
SBThread thread = process.GetSelectedThread();
94+
if (!thread.IsValid()) {
95+
return -1;
96+
}
97+
98+
llv8.Load(target_);
99+
100+
SBStream desc;
101+
if (!thread.GetDescription(desc)) {
102+
return -1;
103+
}
104+
SBFrame selected_frame = thread.GetSelectedFrame();
105+
106+
uint32_t num_frames = thread.GetNumFrames();
107+
for (uint32_t i = 0; i < num_frames; i++) {
108+
SBFrame frame = thread.GetFrameAtIndex(i);
109+
110+
if (!frame.GetSymbol().IsValid()) {
111+
v8::Error err;
112+
v8::JSFrame v8_frame(&llv8, static_cast<int64_t>(frame.GetFP()));
113+
v8::JSFunction v8_function = v8_frame.GetFunction(err);
114+
if (err.Fail()) {
115+
continue;
116+
}
117+
v8::Value val;
118+
val = v8_function.GetContext(err);
119+
if (err.Fail()) {
120+
continue;
121+
}
122+
bool found = false;
123+
while (!found) {
124+
v8::Context context(val);
125+
v8::Value native = context.Native(err);
126+
if (err.Success()) {
127+
if (native.raw() == context.raw()) {
128+
found = true;
129+
env = CurrentEnvironmentFromContext(native);
130+
break;
131+
}
132+
}
133+
134+
val = context.Previous(err);
135+
if (err.Fail()) {
136+
break;
137+
}
138+
}
139+
if (found) {
140+
break;
141+
}
142+
}
143+
}
144+
145+
return env;
146+
}
147+
148+
149+
void ReqWrapQueue::Load() {
150+
kHeadOffset = LoadConstant("class__ReqWrapQueue__headOffset", (int64_t)0);
151+
kNextOffset = LoadConstant("class__ReqWrapQueue__nextOffset", (int64_t)8);
152+
}
153+
154+
void ReqWrap::Load() {
155+
kListNodeOffset = LoadConstant("class__ReqWrap__node", (int64_t)48);
156+
}
157+
158+
void HandleWrapQueue::Load() {
159+
kHeadOffset = LoadConstant("class__HandleWrapQueue__headOffset", (int64_t)0);
160+
kNextOffset = LoadConstant("class__HandleWrapQueue__nextOffset", (int64_t)8);
161+
}
162+
163+
void HandleWrap::Load() {
164+
kListNodeOffset = LoadConstant("class__HandleWrap__node", (int64_t)48);
165+
}
166+
167+
void BaseObject::Load() {
168+
kPersistentHandleOffset =
169+
LoadConstant("class__BaseObject__persistent_handle", (int64_t)8);
170+
}
171+
}
172+
}
173+
}

src/llnode-constants.h

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
#ifndef SRC_LLNODE_CONSTANTS_H_
2+
#define SRC_LLNODE_CONSTANTS_H_
3+
4+
#include <lldb/API/LLDB.h>
5+
#include "src/constants.h"
6+
#include "src/llv8.h"
7+
8+
using lldb::addr_t;
9+
10+
namespace llnode {
11+
using constants::ConstantsWrapper;
12+
namespace node {
13+
namespace constants {
14+
#define MODULE_DEFAULT_METHODS(NAME) \
15+
NAME() {} \
16+
inline NAME* operator()() { \
17+
if (loaded_) return this; \
18+
loaded_ = true; \
19+
Load(); \
20+
return this; \
21+
}
22+
23+
24+
class Module : public ConstantsWrapper {
25+
public:
26+
inline std::string kConstantPrefix() override { return "nodedbg_"; };
27+
};
28+
29+
class Environment : public Module {
30+
public:
31+
MODULE_DEFAULT_METHODS(Environment);
32+
33+
int64_t kIsolate;
34+
int64_t kReqWrapQueueOffset;
35+
int64_t kHandleWrapQueueOffset;
36+
int64_t kEnvContextEmbedderDataIndex;
37+
addr_t kCurrentEnvironment;
38+
39+
protected:
40+
void Load();
41+
42+
private:
43+
addr_t LoadCurrentEnvironment();
44+
addr_t DefaultLoadCurrentEnvironment();
45+
addr_t FallbackLoadCurrentEnvironment();
46+
addr_t CurrentEnvironmentFromContext(v8::Value context);
47+
};
48+
49+
class ReqWrapQueue : public Module {
50+
public:
51+
MODULE_DEFAULT_METHODS(ReqWrapQueue);
52+
53+
int64_t kHeadOffset;
54+
int64_t kNextOffset;
55+
56+
protected:
57+
void Load();
58+
};
59+
60+
class ReqWrap : public Module {
61+
public:
62+
MODULE_DEFAULT_METHODS(ReqWrap);
63+
64+
int64_t kListNodeOffset;
65+
66+
protected:
67+
void Load();
68+
};
69+
70+
class HandleWrapQueue : public Module {
71+
public:
72+
MODULE_DEFAULT_METHODS(HandleWrapQueue);
73+
74+
int64_t kHeadOffset;
75+
int64_t kNextOffset;
76+
77+
protected:
78+
void Load();
79+
};
80+
81+
class HandleWrap : public Module {
82+
public:
83+
MODULE_DEFAULT_METHODS(HandleWrap);
84+
85+
int64_t kListNodeOffset;
86+
87+
protected:
88+
void Load();
89+
};
90+
91+
class BaseObject : public Module {
92+
public:
93+
MODULE_DEFAULT_METHODS(BaseObject);
94+
95+
int64_t kPersistentHandleOffset;
96+
97+
protected:
98+
void Load();
99+
};
100+
}
101+
}
102+
}
103+
104+
#endif

0 commit comments

Comments
 (0)