diff --git a/README.md b/README.md index ebbbb4e0..b08f47f7 100644 --- a/README.md +++ b/README.md @@ -199,6 +199,11 @@ 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 -- *EXPERIMENTAL* Equivalent to running process._getActiveHandles. This command is still being + developed and for now it only works building node from source. + getactiverequests -- *EXPERIMENTAL* Equivalent to running process._getActiveRequests. This command is still being + developed and for now it only works building node from source. inspect -- Print detailed description and contents of the JavaScript value. Possible flags (all optional): diff --git a/llnode.gyp.json b/llnode.gyp.json index ce6bd42d..423b45ce 100644 --- a/llnode.gyp.json +++ b/llnode.gyp.json @@ -16,7 +16,10 @@ ], "sources": [ + "src/constants.cc", "src/llnode.cc", + "src/llnode-module.cc", + "src/llnode-constants.cc", "src/llv8.cc", "src/llv8-constants.cc", "src/llscan.cc", diff --git a/src/constants.cc b/src/constants.cc new file mode 100644 index 00000000..93b5f48f --- /dev/null +++ b/src/constants.cc @@ -0,0 +1,47 @@ +#include "src/constants.h" +#include "src/llv8.h" + +namespace llnode { +using v8::Error; +using v8::constants::IsDebugMode; +using v8::constants::LookupConstant; +namespace constants { + +void ConstantsWrapper::Assign(SBTarget target) { + loaded_ = false; + target_ = target; +} + +int64_t ConstantsWrapper::LoadRawConstant(const char* name, int64_t def) { + Error err; + int64_t v = LookupConstant(target_, name, def, err); + if (err.Fail() && IsDebugMode()) fprintf(stderr, "Failed to load %s\n", name); + + return v; +} + + +int64_t ConstantsWrapper::LoadConstant(const char* name, int64_t def) { + Error err; + int64_t v = + LookupConstant(target_, (kConstantPrefix() + name).c_str(), def, err); + if (err.Fail() && IsDebugMode()) fprintf(stderr, "Failed to load %s\n", name); + + return v; +} + + +int64_t ConstantsWrapper::LoadConstant(const char* name, const char* fallback, + int64_t def) { + Error err; + int64_t v = + LookupConstant(target_, (kConstantPrefix() + name).c_str(), def, err); + if (err.Fail()) + v = LookupConstant(target_, (kConstantPrefix() + fallback).c_str(), def, + err); + if (err.Fail() && IsDebugMode()) fprintf(stderr, "Failed to load %s\n", name); + + return v; +} +} +} diff --git a/src/constants.h b/src/constants.h new file mode 100644 index 00000000..610728b5 --- /dev/null +++ b/src/constants.h @@ -0,0 +1,32 @@ +#ifndef SRC_CONSTANTS_H_ +#define SRC_CONSTANTS_H_ + +#include +using lldb::SBTarget; + +namespace llnode { +namespace constants { + +class ConstantsWrapper { + public: + ConstantsWrapper() : loaded_(false) {} + + inline bool is_loaded() const { return loaded_; } + + void Assign(lldb::SBTarget target); + + inline virtual std::string kConstantPrefix() { return ""; }; + + protected: + int64_t LoadRawConstant(const char* name, int64_t def = -1); + int64_t LoadConstant(const char* name, int64_t def = -1); + int64_t LoadConstant(const char* name, const char* fallback, + int64_t def = -1); + + lldb::SBTarget target_; + bool loaded_; +}; +} +} + +#endif diff --git a/src/llnode-constants.cc b/src/llnode-constants.cc new file mode 100644 index 00000000..63abbf24 --- /dev/null +++ b/src/llnode-constants.cc @@ -0,0 +1,173 @@ +#include + +#include "llnode-constants.h" +#include "llv8-constants.h" +#include "llv8-inl.h" +#include "llv8.h" + +using lldb::SBProcess; +using lldb::SBThread; +using lldb::SBError; +using lldb::SBFrame; +using lldb::SBStream; + +namespace llnode { +using v8::Error; +using v8::constants::LookupConstant; +namespace node { +namespace constants { +v8::LLV8 llv8; + +void Environment::Load() { + kIsolate = LoadRawConstant("node::node_isolate"); + kReqWrapQueueOffset = LoadConstant("class__Environment__reqWrapQueue", 1256); + kHandleWrapQueueOffset = + LoadConstant("class__Environment__handleWrapQueue", 1240); + kEnvContextEmbedderDataIndex = + LoadConstant("environment_context_idx_embedder_data", 32); + kCurrentEnvironment = LoadCurrentEnvironment(); +} + +addr_t Environment::LoadCurrentEnvironment() { + addr_t currentEnvironment = DefaultLoadCurrentEnvironment(); + if (currentEnvironment == -1) { + currentEnvironment = FallbackLoadCurrentEnvironment(); + } + + return currentEnvironment; +} + +addr_t Environment::DefaultLoadCurrentEnvironment() { + llv8.Load(target_); + + SBProcess process = target_.GetProcess(); + SBError sberr; + uint64_t env = -1; + uint64_t isolate_thread = 0; + uint64_t thread_context_ptr = 0; + uint64_t thread_context = 0; + v8::Error err; + + if (!(llv8.isolate()->kThreadLocalTopOffset != -1 && + llv8.thread_local_top()->kContextOffset != -1)) { + return env; + } + + isolate_thread = kIsolate + llv8.isolate()->kThreadLocalTopOffset; + + thread_context_ptr = isolate_thread + llv8.thread_local_top()->kContextOffset; + thread_context = process.ReadPointerFromMemory(thread_context_ptr, sberr); + if (sberr.Fail()) { + return -1; + } + v8::Context ctx(&llv8, thread_context); + v8::Value native = ctx.Native(err); + if (err.Fail()) { + return -1; + } + env = CurrentEnvironmentFromContext(native); + return env; +} + +addr_t Environment::CurrentEnvironmentFromContext(v8::Value context) { + llv8.Load(target_); + v8::Error err; + + v8::FixedArray contextArray = v8::FixedArray(context); + v8::FixedArray embed = + contextArray.Get(llv8.context()->kEmbedderDataIndex, err); + if (err.Fail()) { + return -1; + } + v8::Smi encodedEnv = embed.Get(kEnvContextEmbedderDataIndex, err); + if (err.Fail()) { + return -1; + } else { + return encodedEnv.raw(); + } +} + +addr_t Environment::FallbackLoadCurrentEnvironment() { + addr_t env = -1; + SBProcess process = target_.GetProcess(); + SBThread thread = process.GetSelectedThread(); + if (!thread.IsValid()) { + return -1; + } + + llv8.Load(target_); + + SBStream desc; + if (!thread.GetDescription(desc)) { + return -1; + } + SBFrame selected_frame = thread.GetSelectedFrame(); + + uint32_t num_frames = thread.GetNumFrames(); + for (uint32_t i = 0; i < num_frames; i++) { + SBFrame frame = thread.GetFrameAtIndex(i); + + if (!frame.GetSymbol().IsValid()) { + v8::Error err; + v8::JSFrame v8_frame(&llv8, static_cast(frame.GetFP())); + v8::JSFunction v8_function = v8_frame.GetFunction(err); + if (err.Fail()) { + continue; + } + v8::Value val; + val = v8_function.GetContext(err); + if (err.Fail()) { + continue; + } + bool found = false; + while (!found) { + v8::Context context(val); + v8::Value native = context.Native(err); + if (err.Success()) { + if (native.raw() == context.raw()) { + found = true; + env = CurrentEnvironmentFromContext(native); + break; + } + } + + val = context.Previous(err); + if (err.Fail()) { + break; + } + } + if (found) { + break; + } + } + } + + return env; +} + + +void ReqWrapQueue::Load() { + kHeadOffset = LoadConstant("class__ReqWrapQueue__headOffset", (int64_t)0); + kNextOffset = LoadConstant("class__ReqWrapQueue__nextOffset", (int64_t)8); +} + +void ReqWrap::Load() { + kListNodeOffset = LoadConstant("class__ReqWrap__node", (int64_t)48); +} + +void HandleWrapQueue::Load() { + kHeadOffset = LoadConstant("class__HandleWrapQueue__headOffset", (int64_t)0); + kNextOffset = LoadConstant("class__HandleWrapQueue__nextOffset", (int64_t)8); +} + +void HandleWrap::Load() { + kListNodeOffset = LoadConstant("class__HandleWrap__node", (int64_t)48); +} + +void BaseObject::Load() { + kPersistentHandleOffset = + LoadConstant("class__BaseObject__persistent_handle", (int64_t)8); +} +} +} +} diff --git a/src/llnode-constants.h b/src/llnode-constants.h new file mode 100644 index 00000000..519e9757 --- /dev/null +++ b/src/llnode-constants.h @@ -0,0 +1,104 @@ +#ifndef SRC_LLNODE_CONSTANTS_H_ +#define SRC_LLNODE_CONSTANTS_H_ + +#include +#include "src/constants.h" +#include "src/llv8.h" + +using lldb::addr_t; + +namespace llnode { +using constants::ConstantsWrapper; +namespace node { +namespace constants { +#define MODULE_DEFAULT_METHODS(NAME) \ + NAME() {} \ + inline NAME* operator()() { \ + if (loaded_) return this; \ + loaded_ = true; \ + Load(); \ + return this; \ + } + + +class Module : public ConstantsWrapper { + public: + inline std::string kConstantPrefix() override { return "nodedbg_"; }; +}; + +class Environment : public Module { + public: + MODULE_DEFAULT_METHODS(Environment); + + int64_t kIsolate; + int64_t kReqWrapQueueOffset; + int64_t kHandleWrapQueueOffset; + int64_t kEnvContextEmbedderDataIndex; + addr_t kCurrentEnvironment; + + protected: + void Load(); + + private: + addr_t LoadCurrentEnvironment(); + addr_t DefaultLoadCurrentEnvironment(); + addr_t FallbackLoadCurrentEnvironment(); + addr_t CurrentEnvironmentFromContext(v8::Value context); +}; + +class ReqWrapQueue : public Module { + public: + MODULE_DEFAULT_METHODS(ReqWrapQueue); + + int64_t kHeadOffset; + int64_t kNextOffset; + + protected: + void Load(); +}; + +class ReqWrap : public Module { + public: + MODULE_DEFAULT_METHODS(ReqWrap); + + int64_t kListNodeOffset; + + protected: + void Load(); +}; + +class HandleWrapQueue : public Module { + public: + MODULE_DEFAULT_METHODS(HandleWrapQueue); + + int64_t kHeadOffset; + int64_t kNextOffset; + + protected: + void Load(); +}; + +class HandleWrap : public Module { + public: + MODULE_DEFAULT_METHODS(HandleWrap); + + int64_t kListNodeOffset; + + protected: + void Load(); +}; + +class BaseObject : public Module { + public: + MODULE_DEFAULT_METHODS(BaseObject); + + int64_t kPersistentHandleOffset; + + protected: + void Load(); +}; +} +} +} + +#endif diff --git a/src/llnode-module-inl.h b/src/llnode-module-inl.h new file mode 100644 index 00000000..8af5e83e --- /dev/null +++ b/src/llnode-module-inl.h @@ -0,0 +1,44 @@ +#include "llnode-module.h" + +namespace llnode { +namespace node { + +template +T Queue::Iterator::operator*() const { + return T::FromListNode(node_, current_); +} + +template +const typename Queue::Iterator Queue::Iterator::operator++() { + // TODO (mmarchini) check errors + lldb::SBError sberr; + + addr_t current = current_ + constants_->kNextOffset; + current = node_->process().ReadPointerFromMemory(current, sberr); + current_ = current; + return Iterator(node_, current, constants_); +} + +template +bool Queue::Iterator::operator!=(const Iterator& that) const { + return current_ != that.current_; +} + +template +typename Queue::Iterator Queue::begin() const { + // TODO (mmarchini) check errors + 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 Queue::Iterator Queue::end() const { + return Iterator(node_, raw_ + constants_->kHeadOffset, constants_); +} +} +} diff --git a/src/llnode-module.cc b/src/llnode-module.cc new file mode 100644 index 00000000..f5afa310 --- /dev/null +++ b/src/llnode-module.cc @@ -0,0 +1,75 @@ +#include "llnode-module.h" + +namespace llnode { +namespace node { + +addr_t BaseObject::persistent_addr() { + lldb::SBError sberr; + + addr_t persistentHandlePtr = + raw_ + node_->base_object()->kPersistentHandleOffset; + addr_t persistentHandle = + node_->process().ReadPointerFromMemory(persistentHandlePtr, sberr); + if (sberr.Fail()) { + return -1; + } + return persistentHandle; +} + +addr_t BaseObject::v8_object_addr() { + lldb::SBError sberr; + + addr_t persistentHandle = persistent_addr(); + addr_t obj = node_->process().ReadPointerFromMemory(persistentHandle, sberr); + if (sberr.Fail()) { + return -1; + } + return obj; +} + +HandleWrap HandleWrap::FromListNode(LLNode *node, addr_t list_node_addr) { + return HandleWrap(node, + list_node_addr - node->handle_wrap()->kListNodeOffset); +} + +ReqWrap ReqWrap::FromListNode(LLNode *node, addr_t list_node_addr) { + return ReqWrap(node, list_node_addr - node->req_wrap()->kListNodeOffset); +} + +Environment Environment::GetCurrent(LLNode *node) { + // TODO (mmarchini): maybe throw some warning here when env is not valid + addr_t envAddr = node->env()->kCurrentEnvironment; + + return Environment(node, envAddr); +} + +Queue Environment::handle_wrap_queue() + const { + return Queue( + node_, raw_ + node_->env()->kHandleWrapQueueOffset, + node_->handle_wrap_queue()); +} + +Queue Environment::req_wrap_queue() const { + return Queue( + node_, raw_ + node_->env()->kReqWrapQueueOffset, node_->req_wrap_queue()); +} + +void LLNode::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); +} +} +} diff --git a/src/llnode-module.h b/src/llnode-module.h new file mode 100644 index 00000000..77633d4b --- /dev/null +++ b/src/llnode-module.h @@ -0,0 +1,123 @@ +#ifndef SRC_LLNODE_MODULE_H_ +#define SRC_LLNODE_MODULE_H_ + +#include +#include + +#include "llnode-constants.h" + +namespace llnode { +namespace node { + +class LLNode; +class HandleWrap; +class ReqWrap; +template +class Queue; + +class BaseNode { + public: + BaseNode(LLNode *node) : node_(node){}; + + protected: + LLNode *node_; +}; + +class Environment : public BaseNode { + public: + Environment(LLNode *node, addr_t raw) : BaseNode(node), raw_(raw){}; + inline addr_t raw() { return raw_; }; + + static Environment GetCurrent(LLNode *node); + + Queue handle_wrap_queue() const; + Queue req_wrap_queue() const; + + private: + addr_t raw_; +}; + +class BaseObject : public BaseNode { + public: + BaseObject(LLNode *node, addr_t raw) : BaseNode(node), raw_(raw){}; + + addr_t persistent_addr(); + + addr_t v8_object_addr(); + + + private: + addr_t raw_; +}; + +class AsyncWrap : public BaseObject { + public: + AsyncWrap(LLNode *node, addr_t raw) : BaseObject(node, raw){}; +}; + +class HandleWrap : public AsyncWrap { + public: + HandleWrap(LLNode *node, addr_t raw) : AsyncWrap(node, raw){}; + + static HandleWrap FromListNode(LLNode *node, addr_t list_node_addr); +}; + +class ReqWrap : public AsyncWrap { + public: + ReqWrap(LLNode *node, addr_t raw) : AsyncWrap(node, raw){}; + + static ReqWrap FromListNode(LLNode *node, addr_t list_node_addr); +}; + +class LLNode { + public: + LLNode() : target_(lldb::SBTarget()) {} + + inline lldb::SBProcess process() { return process_; }; + + void Load(lldb::SBTarget target); + + constants::Environment env; + constants::ReqWrapQueue req_wrap_queue; + constants::ReqWrap req_wrap; + constants::HandleWrapQueue handle_wrap_queue; + constants::HandleWrap handle_wrap; + constants::BaseObject base_object; + + private: + lldb::SBTarget target_; + lldb::SBProcess process_; +}; + +template +class Queue : public BaseNode { + class Iterator : public BaseNode { + public: + inline T operator*() const; + inline const Iterator operator++(); + inline bool operator!=(const Iterator &that) const; + + + inline Iterator(LLNode *node, addr_t current, C *constants) + : BaseNode(node), current_(current), constants_(constants){}; + + public: + addr_t current_; + C *constants_; + }; + + public: + inline Queue(LLNode *node, addr_t raw, C *constants) + : BaseNode(node), raw_(raw), constants_(constants){}; + + inline Iterator begin() const; + inline Iterator end() const; + + private: + addr_t raw_; + C *constants_; +}; +} +} + +#endif diff --git a/src/llnode.cc b/src/llnode.cc index 92cc9ff6..76f57217 100644 --- a/src/llnode.cc +++ b/src/llnode.cc @@ -4,11 +4,16 @@ #include #include +#include #include +#include "src/llnode-module-inl.h" +#include "src/llnode-module.h" #include "src/llnode.h" #include "src/llscan.h" +#include "src/llv8-constants.h" +#include "src/llv8-inl.h" #include "src/llv8.h" namespace llnode { @@ -26,8 +31,16 @@ using lldb::SBThread; using lldb::SBValue; using lldb::eReturnStatusFailed; using lldb::eReturnStatusSuccessFinishResult; +using lldb::SBProcess; +using lldb::SBAddress; +using lldb::SBSymbolContext; +using lldb::SBSymbolContextList; +using lldb::addr_t; +using v8::constants::LookupConstant; v8::LLV8 llv8; +// TODO (mmarchini) better name +node::LLNode nodeMod; char** CommandBase::ParseInspectOptions(char** cmd, v8::Value::InspectOptions* options) { @@ -312,6 +325,114 @@ void InitDebugMode() { v8::Error::SetDebugMode(is_debug_mode); } + +bool GetActiveHandlesCmd::DoExecute(SBDebugger d, char** cmd, + SBCommandReturnObject& result) { + int activeHandles = 0; + SBTarget target = d.GetSelectedTarget(); + SBProcess process = target.GetProcess(); + SBThread thread = process.GetSelectedThread(); + std::ostringstream resultMsg; + v8::Value::InspectOptions inspect_options; + inspect_options.detailed = true; + + llv8.Load(target); + nodeMod.Load(target); + + if (!thread.IsValid()) { + result.SetError("No valid process, please start something\n"); + return false; + } + + node::Environment env = node::Environment::GetCurrent(&nodeMod); + if(env.raw() == -1) { + result.SetError("Node version doesn't support this command\n"); + return false; + } + for (auto w : env.handle_wrap_queue()) { + if (w.persistent_addr() == 0) { + continue; + } else if (w.persistent_addr() == -1) { + result.SetError("Failed to load persistent handle"); + activeHandles = -1; + break; + } + + v8::JSObject v8_object(&llv8, w.v8_object_addr()); + v8::Error err; + std::string res = v8_object.Inspect(&inspect_options, err); + if (err.Fail()) { + result.SetError("Failed to load object"); + activeHandles = -1; + break; + } + + activeHandles++; + resultMsg << res.c_str() << std::endl; + } + if(activeHandles == -1) { + return false; + } + + result.Printf("Active handles: %d\n\n", activeHandles); + result.Printf("%s", resultMsg.str().c_str()); + return true; +} + +bool GetActiveRequestsCmd::DoExecute(SBDebugger d, char** cmd, + SBCommandReturnObject& result) { + int activeRequests = 0; + SBTarget target = d.GetSelectedTarget(); + SBProcess process = target.GetProcess(); + SBThread thread = process.GetSelectedThread(); + SBError sberr; + std::ostringstream resultMsg; + v8::Value::InspectOptions inspect_options; + inspect_options.detailed = true; + + llv8.Load(target); + nodeMod.Load(target); + + if (!thread.IsValid()) { + result.SetError("No valid process, please start something\n"); + return false; + } + + node::Environment env = node::Environment::GetCurrent(&nodeMod); + if(env.raw() == -1) { + result.SetError("Node version doesn't support this command\n"); + return false; + } + for (auto w : env.req_wrap_queue()) { + if (w.persistent_addr() == 0) { + continue; + } else if (w.persistent_addr() == -1) { + result.SetError("Failed to load persistent handle"); + activeRequests = -1; + break; + } + + v8::JSObject v8_object(&llv8, w.v8_object_addr()); + v8::Error err; + std::string res = v8_object.Inspect(&inspect_options, err); + if (err.Fail()) { + result.SetError("Failed to load object"); + activeRequests = -1; + break; + } + + activeRequests++; + resultMsg << res.c_str() << std::endl; + } + if(activeRequests == -1) { + return false; + } + + result.Printf("Active requests: %d\n\n", activeRequests); + result.Printf("%s", resultMsg.str().c_str()); + return true; +} + } // namespace llnode namespace lldb { @@ -401,6 +522,18 @@ bool PluginInitialize(SBDebugger d) { "JavaScript string value\n" "\n"); + v8.AddCommand( + "getactivehandles", new llnode::GetActiveHandlesCmd(), + "*EXPERIMENTAL* Equivalent to running process._getActiveHandles. " + "This command is still being developed and for now it only works " + "building node from source.\n"); + + v8.AddCommand( + "getactiverequests", new llnode::GetActiveRequestsCmd(), + "*EXPERIMENTAL* Equivalent to running process._getActiveRequests. " + "This command is still being developed and for now it only works " + "building node from source.\n"); + return true; } diff --git a/src/llnode.h b/src/llnode.h index b46bc7ef..755a342d 100644 --- a/src/llnode.h +++ b/src/llnode.h @@ -35,6 +35,22 @@ class PrintCmd : public CommandBase { bool detailed_; }; +class GetActiveHandlesCmd : public CommandBase { + public: + ~GetActiveHandlesCmd() override {} + + bool DoExecute(lldb::SBDebugger d, char** cmd, + lldb::SBCommandReturnObject& result) override; +}; + +class GetActiveRequestsCmd : public CommandBase { + public: + ~GetActiveRequestsCmd() override {} + + bool DoExecute(lldb::SBDebugger d, char** cmd, + lldb::SBCommandReturnObject& result) override; +}; + class ListCmd : public CommandBase { public: ~ListCmd() override {} diff --git a/src/llv8-constants.cc b/src/llv8-constants.cc index c08bbdeb..f239902c 100644 --- a/src/llv8-constants.cc +++ b/src/llv8-constants.cc @@ -24,6 +24,16 @@ using lldb::addr_t; static std::string kConstantPrefix = "v8dbg_"; + +// TODO (mmarchini) should be moved to constants.h +bool IsDebugMode() { + char* var = getenv("LLNODE_DEBUG"); + if (var == nullptr) return false; + + return strlen(var) != 0; +} + + void Module::Assign(SBTarget target, Common* common) { loaded_ = false; target_ = target; @@ -45,9 +55,10 @@ T ReadSymbolFromTarget(SBTarget& target, SBAddress& start, return res; } -static int64_t LookupConstant(SBTarget target, const char* name, int64_t def, - Error& err) { - int64_t res = 0; +// TODO (mmarchini) should be moved to constants.h +int64_t LookupConstant(SBTarget target, const char* name, int64_t def, + Error& err) { + int64_t res; res = def; SBSymbolContextList context_list = target.FindSymbols(name); @@ -329,6 +340,9 @@ void Context::Load() { LoadConstant("class_Context__closure_index__int", "context_idx_closure"); kPreviousIndex = LoadConstant("class_Context__previous_index__int", "context_idx_prev"); + kNativeIndex = + LoadConstant("class_Context__native_index__int", "context_idx_native"); + kEmbedderDataIndex = LoadConstant("context_idx_embedder_data", (int)5); kMinContextSlots = LoadConstant("class_Context__min_context_slots__int", "context_min_slots"); } @@ -586,6 +600,14 @@ void Types::Load() { } } +void Isolate::Load() { + kThreadLocalTopOffset = LoadConstant("isolate_threadlocaltop_offset"); +} + +void ThreadLocalTop::Load() { + kContextOffset = LoadConstant("threadlocaltop_context_offset"); +} + } // namespace constants } // namespace v8 } // namespace llnode diff --git a/src/llv8-constants.h b/src/llv8-constants.h index f7f2315c..62aca4e7 100644 --- a/src/llv8-constants.h +++ b/src/llv8-constants.h @@ -3,10 +3,16 @@ #include +using lldb::SBTarget; + namespace llnode { namespace v8 { +class Error; namespace constants { +int64_t LookupConstant(SBTarget target, const char* name, int64_t def, + Error& err); +bool IsDebugMode(); // Forward declarations class Common; @@ -213,6 +219,8 @@ class Context : public Module { int64_t kClosureIndex; int64_t kGlobalObjectIndex; int64_t kPreviousIndex; + int64_t kNativeIndex; + int64_t kEmbedderDataIndex; int64_t kMinContextSlots; protected: @@ -497,6 +505,24 @@ class Types : public Module { void Load(); }; +class Isolate : public Module { + public: + MODULE_DEFAULT_METHODS(Isolate); + int64_t kThreadLocalTopOffset; + + protected: + void Load(); +}; + +class ThreadLocalTop : public Module { + public: + MODULE_DEFAULT_METHODS(ThreadLocalTop); + int64_t kContextOffset; + + protected: + void Load(); +}; + #undef MODULE_DEFAULT_METHODS } // namespace constants diff --git a/src/llv8-inl.h b/src/llv8-inl.h index 8a3ce863..e3391773 100644 --- a/src/llv8-inl.h +++ b/src/llv8-inl.h @@ -458,6 +458,10 @@ inline Value Context::Previous(Error& err) { return FixedArray::Get(v8()->context()->kPreviousIndex, err); } +inline Value Context::Native(Error& err) { + return FixedArray::Get(v8()->context()->kNativeIndex, err); +} + inline Value Context::ContextSlot(int index, Error& err) { return FixedArray::Get(v8()->context()->kMinContextSlots + index, err); } diff --git a/src/llv8.cc b/src/llv8.cc index 0bc972dc..fee7e313 100644 --- a/src/llv8.cc +++ b/src/llv8.cc @@ -56,6 +56,8 @@ void LLV8::Load(SBTarget target) { name_dictionary.Assign(target, &common); frame.Assign(target, &common); types.Assign(target, &common); + isolate.Assign(target, &common); + thread_local_top.Assign(target, &common); } bool Error::is_debug_mode = false; diff --git a/src/llv8.h b/src/llv8.h index f67eb28a..20de99db 100644 --- a/src/llv8.h +++ b/src/llv8.h @@ -6,6 +6,7 @@ #include +#include "src/constants.h" #include "src/llv8-constants.h" namespace llnode { @@ -394,6 +395,7 @@ class Context : public FixedArray { inline JSFunction Closure(Error& err); inline Value Previous(Error& err); + inline Value Native(Error& err); inline Value ContextSlot(int index, Error& err); std::string Inspect(Error& err); @@ -471,6 +473,10 @@ class LLV8 { void Load(lldb::SBTarget target); + constants::Isolate isolate; + constants::ThreadLocalTop thread_local_top; + constants::Context context; + private: template inline T LoadValue(int64_t addr, Error& err); @@ -498,7 +504,6 @@ class LLV8 { constants::SharedInfo shared_info; constants::Code code; constants::ScopeInfo scope_info; - constants::Context context; constants::Script script; constants::String string; constants::OneByteString one_byte_string; @@ -553,6 +558,7 @@ class LLV8 { friend class llnode::FindJSObjectsVisitor; friend class llnode::FindObjectsCmd; friend class llnode::FindReferencesCmd; + friend class llnode::constants::ConstantsWrapper; }; #undef V8_VALUE_DEFAULT_METHODS