Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
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.

Fixes: #100
  • Loading branch information
Matheus Marchini
Matheus Marchini committed Jun 28, 2018
commit 2b695fdafb4706782922aacb6e3f9f51ef8f07de
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,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
2 changes: 2 additions & 0 deletions binding.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"<(lldb_include_dir)",
],


"cflags" : [ "-std=c++11" ],

"conditions": [
Expand Down Expand Up @@ -76,6 +77,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 @@ -245,6 +249,112 @@ bool ListCmd::DoExecute(SBDebugger d, char** cmd,
return true;
}

bool WorkqueueCmd::DoExecute(SBDebugger d, char** cmd,
SBCommandReturnObject& result) {
SBTarget>
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 @@ -264,6 +374,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 @@ -349,6 +460,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 @@ -50,6 +51,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_
3 changes: 2 additions & 1 deletion src/node-constants.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ void Environment::Load() {
kHandleWrapQueueOffset = LoadConstant(
"offset_Environment__handle_wrap_queue___Environment_HandleWrapQueue");
kEnvContextEmbedderDataIndex =
LoadConstant("const_Environment__kContextEmbedderDataIndex__int");
LoadConstant("const_Environment__kContextEmbedderDataIndex__int",
"const_ContextEmbedderIndex__kEnvironment__int");

Error err;
kCurrentEnvironment = LoadCurrentEnvironment(err);
Expand Down
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