Skip to content

Commit

Permalink
src: add commands to inspect the workqueue
Browse files Browse the repository at this point in the history
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.

Fixes: nodejs#100
  • Loading branch information
Matheus Marchini committed Apr 2, 2018
1 parent 6d070af commit 179b3b3
Show file tree
Hide file tree
Showing 10 changed files with 502 additions and 5 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,12 @@ The following subcommands are supported:
* -n, --name name - all properties with the specified name
* -s, --string string - all properties that refer to the specified JavaScript string value
getactivehandles -- Print all pending handles in the queue. Equivalent to running process._getActiveHandles() on
the living process.
getactiverequests -- Print all pending handles in the queue. Equivalent to running process._getActiveHandles() on
the living process.
inspect -- Print detailed description and contents of the JavaScript value.
Possible flags (all optional):
Expand Down
1 change: 1 addition & 0 deletions binding.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"src/llv8.cc",
"src/llv8-constants.cc",
"src/llscan.cc",
"src/node.cc",
"src/node-constants.cc",
],

Expand Down
121 changes: 121 additions & 0 deletions src/llnode.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@
#include <string.h>

#include <cinttypes>
#include <sstream>
#include <string>

#include <lldb/API/SBExpressionOptions.h>

#include "src/error.h"
#include "src/llnode.h"
#include "src/llscan.h"
#include "src/llv8.h"
#include "src/node-inl.h"

namespace llnode {

Expand All @@ -20,6 +23,7 @@ using lldb::SBDebugger;
using lldb::SBError;
using lldb::SBExpressionOptions;
using lldb::SBFrame;
using lldb::SBProcess;
using lldb::SBStream;
using lldb::SBSymbol;
using lldb::SBTarget;
Expand Down Expand Up @@ -300,6 +304,112 @@ bool ListCmd::DoExecute(SBDebugger d, char** cmd,
return true;
}

bool WorkqueueCmd::DoExecute(SBDebugger d, char** cmd,
SBCommandReturnObject& result) {
SBTarget target = d.GetSelectedTarget();
SBProcess process = target.GetProcess();
SBThread thread = process.GetSelectedThread();
std::string result_message;
Error err;

llv8_->Load(target);
node_->Load(target);

if (!thread.IsValid()) {
result.SetError("No valid process, please start something\n");
return false;
}

node::Environment env = node::Environment::GetCurrent(node_, err);
if (err.Fail()) {
result.SetError(err.GetMessage());
return false;
}

result_message = GetResultMessage(&env, err);

if (err.Fail()) {
result.SetError(err.GetMessage());
return false;
}

result.Printf("%s", result_message.c_str());
return true;
}

std::string GetActiveHandlesCmd::GetResultMessage(node::Environment* env,
Error& err) {
int active_handles = 0;
v8::Value::InspectOptions inspect_options;
inspect_options.detailed = true;
std::ostringstream result_message;

for (auto w : env->handle_wrap_queue()) {
addr_t persistent_addr = w.persistent_addr(err);
if (err.Fail()) {
break;
}
if (persistent_addr == 0) {
continue;
}

addr_t v8_object_addr = w.v8_object_addr(err);
if (err.Fail()) {
break;
}
v8::JSObject v8_object(llv8(), v8_object_addr);
std::string res = v8_object.Inspect(&inspect_options, err);
if (err.Fail()) {
Error::PrintInDebugMode("Failed to load object at address %" PRIx64,
v8_object_addr);
break;
}

active_handles++;
result_message << res.c_str() << std::endl;
}

result_message << "Total: " << active_handles << std::endl;
return result_message.str();
}


std::string GetActiveRequestsCmd::GetResultMessage(node::Environment* env,
Error& err) {
int active_handles = 0;
v8::Value::InspectOptions inspect_options;
inspect_options.detailed = true;
std::ostringstream result_message;

for (auto w : env->req_wrap_queue()) {
addr_t persistent_addr = w.persistent_addr(err);
if (err.Fail()) {
break;
}
if (persistent_addr == 0) {
continue;
}

addr_t v8_object_addr = w.v8_object_addr(err);
if (err.Fail()) {
break;
}
v8::JSObject v8_object(llv8(), v8_object_addr);
std::string res = v8_object.Inspect(&inspect_options, err);
if (err.Fail()) {
Error::PrintInDebugMode("Failed to load object at address %" PRIx64,
v8_object_addr);
break;
}

active_handles++;
result_message << res.c_str() << std::endl;
}

result_message << "Total: " << active_handles << std::endl;
return result_message.str();
}


void InitDebugMode() {
bool is_debug_mode = false;
Expand All @@ -319,6 +429,7 @@ bool PluginInitialize(SBDebugger d) {
llnode::InitDebugMode();

static llnode::v8::LLV8 llv8;
static llnode::node::Node node(&llv8);
static llnode::LLScan llscan = llnode::LLScan(&llv8);

SBCommandInterpreter interpreter = d.GetCommandInterpreter();
Expand Down Expand Up @@ -404,6 +515,16 @@ bool PluginInitialize(SBDebugger d) {
"JavaScript string value\n"
"\n");

v8.AddCommand("getactivehandles",
new llnode::GetActiveHandlesCmd(&llv8, &node),
"Print all pending handles in the queue. Equivalent to running "
"process._getActiveHandles() on the living process.\n");

v8.AddCommand(
"getactiverequests", new llnode::GetActiveRequestsCmd(&llv8, &node),
"Print all pending requests in the queue. Equivalent to "
"running process._getActiveRequests() on the living process.\n");

return true;
}

Expand Down
38 changes: 38 additions & 0 deletions src/llnode.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <lldb/API/LLDB.h>

#include "src/llv8.h"
#include "src/node.h"

namespace llnode {

Expand Down Expand Up @@ -52,6 +53,43 @@ class ListCmd : public CommandBase {
v8::LLV8* llv8_;
};

class WorkqueueCmd : public CommandBase {
public:
WorkqueueCmd(v8::LLV8* llv8, node::Node* node) : llv8_(llv8), node_(node) {}
~WorkqueueCmd() override {}

inline v8::LLV8* llv8() { return llv8_; };
inline node::Node* node() { return node_; };

bool DoExecute(lldb::SBDebugger d, char** cmd,
lldb::SBCommandReturnObject& result) override;

virtual std::string GetResultMessage(node::Environment* env, Error& err) {
return std::string();
};

private:
v8::LLV8* llv8_;
node::Node* node_;
};

class GetActiveHandlesCmd : public WorkqueueCmd {
public:
GetActiveHandlesCmd(v8::LLV8* llv8, node::Node* node)
: WorkqueueCmd(llv8, node) {}

std::string GetResultMessage(node::Environment* env, Error& err) override;
};

class GetActiveRequestsCmd : public WorkqueueCmd {
public:
GetActiveRequestsCmd(v8::LLV8* llv8, node::Node* node)
: WorkqueueCmd(llv8, node) {}

std::string GetResultMessage(node::Environment* env, Error& err) override;
};


} // namespace llnode

#endif // SRC_LLNODE_H_
42 changes: 42 additions & 0 deletions src/node-inl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#include "node.h"

namespace llnode {
namespace node {

template <typename T, typename C>
T Queue<T, C>::Iterator::operator*() const {
return T::FromListNode(node_, current_);
}

template <typename T, typename C>
const typename Queue<T, C>::Iterator Queue<T, C>::Iterator::operator++() {
lldb::SBError sberr;

addr_t current = current_ + constants_->kNextOffset;
current = node_->process().ReadPointerFromMemory(current, sberr);
current_ = current;
return Iterator(node_, current, constants_);
}

template <typename T, typename C>
bool Queue<T, C>::Iterator::operator!=(const Iterator& that) const {
return current_ != that.current_;
}

template <typename T, typename C>
typename Queue<T, C>::Iterator Queue<T, C>::begin() const {
lldb::SBError sberr;
addr_t currentNode = raw_ + constants_->kHeadOffset;

currentNode = currentNode + constants_->kNextOffset;
currentNode = node_->process().ReadPointerFromMemory(currentNode, sberr);

return Iterator(node_, currentNode, constants_);
}

template <typename T, typename C>
typename Queue<T, C>::Iterator Queue<T, C>::end() const {
return Iterator(node_, raw_ + constants_->kHeadOffset, constants_);
}
} // namespace node
} // namespace llnode
77 changes: 77 additions & 0 deletions src/node.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#include "node.h"

namespace llnode {
namespace node {

addr_t BaseObject::persistent_addr(Error& err) {
lldb::SBError sberr;

addr_t persistentHandlePtr =
raw_ + node_->base_object()->kPersistentHandleOffset;
addr_t persistentHandle =
node_->process().ReadPointerFromMemory(persistentHandlePtr, sberr);
if (sberr.Fail()) {
err = Error::Failure("Failed to load persistent handle");
return 0;
}
return persistentHandle;
}

addr_t BaseObject::v8_object_addr(Error& err) {
lldb::SBError sberr;

addr_t persistentHandle = persistent_addr(err);
addr_t obj = node_->process().ReadPointerFromMemory(persistentHandle, sberr);
if (sberr.Fail()) {
err = Error::Failure("Failed to load object from persistent handle");
return 0;
}
return obj;
}

HandleWrap HandleWrap::FromListNode(Node* node, addr_t list_node_addr) {
return HandleWrap(node,
list_node_addr - node->handle_wrap()->kListNodeOffset);
}

ReqWrap ReqWrap::FromListNode(Node* node, addr_t list_node_addr) {
return ReqWrap(node, list_node_addr - node->req_wrap()->kListNodeOffset);
}

Environment Environment::GetCurrent(Node* node, Error& err) {
addr_t envAddr = node->env()->kCurrentEnvironment;
if (envAddr == 0) {
err = Error::Failure("Couldn't get node's Environment");
}

return Environment(node, envAddr);
}

HandleWrapQueue Environment::handle_wrap_queue() const {
return HandleWrapQueue(node_, raw_ + node_->env()->kHandleWrapQueueOffset,
node_->handle_wrap_queue());
}

ReqWrapQueue Environment::req_wrap_queue() const {
return ReqWrapQueue(node_, raw_ + node_->env()->kReqWrapQueueOffset,
node_->req_wrap_queue());
}

void Node::Load(SBTarget target) {
// Reload process anyway
process_ = target.GetProcess();

// No need to reload
if (target_ == target) return;

target_ = target;

env.Assign(target);
req_wrap_queue.Assign(target);
req_wrap.Assign(target);
handle_wrap_queue.Assign(target);
handle_wrap.Assign(target);
base_object.Assign(target);
}
} // namespace node
} // namespace llnode
Loading

0 comments on commit 179b3b3

Please sign in to comment.