From 01473111ba2cab8af01a4ec3bb2f4d1b6e4f409a Mon Sep 17 00:00:00 2001 From: Matheus Marchini Date: Tue, 13 Mar 2018 17:43:38 -0300 Subject: [PATCH] src: add node's internals constants This commit refactors llv8-constants to make it easier to introduce Node's internals constants. Common code for llv8 and node constants is now on src/constants.h. Also moved the Error class to its own file, removing the dependency on src/llv8.h to use Errors. --- llnode.gyp.json | 3 + src/constants.cc | 121 +++++++++++++++++++++++++++++++++++ src/constants.h | 47 ++++++++++++++ src/error.cc | 44 +++++++++++++ src/error.h | 37 +++++++++++ src/llnode.cc | 9 +-- src/llscan.cc | 45 ++++++------- src/llscan.h | 40 ++++++------ src/llv8-constants.cc | 107 ++----------------------------- src/llv8-constants.h | 96 +++++++++++----------------- src/llv8-inl.h | 4 ++ src/llv8.cc | 42 ------------ src/llv8.h | 36 +++-------- src/node-constants.cc | 145 ++++++++++++++++++++++++++++++++++++++++++ src/node-constants.h | 102 +++++++++++++++++++++++++++++ 15 files changed, 601 insertions(+), 277 deletions(-) create mode 100644 src/constants.cc create mode 100644 src/constants.h create mode 100644 src/error.cc create mode 100644 src/error.h create mode 100644 src/node-constants.cc create mode 100644 src/node-constants.h diff --git a/llnode.gyp.json b/llnode.gyp.json index ce6bd42d..3c2a0bfe 100644 --- a/llnode.gyp.json +++ b/llnode.gyp.json @@ -16,10 +16,13 @@ ], "sources": [ + "src/constants.cc", + "src/error.cc", "src/llnode.cc", "src/llv8.cc", "src/llv8-constants.cc", "src/llscan.cc", + "src/node-constants.cc", ], "conditions": [ diff --git a/src/constants.cc b/src/constants.cc new file mode 100644 index 00000000..782f0fd6 --- /dev/null +++ b/src/constants.cc @@ -0,0 +1,121 @@ +#include + +#include + +#include "src/constants.h" + +using lldb::SBAddress; +using lldb::SBError; +using lldb::SBSymbol; +using lldb::SBSymbolContext; +using lldb::SBSymbolContextList; + +namespace llnode { + +template +T ReadSymbolFromTarget(SBTarget& target, SBAddress& start, const char* name, + Error& err) { + SBError sberr; + T res = 0; + target.ReadMemory(start, &res, sizeof(T), sberr); + if (!sberr.Fail()) { + err = Error::Ok(); + } else { + err = Error::Failure("Failed to read symbol %s", name); + } + return res; +} + +int64_t Constants::LookupConstant(SBTarget target, const char* name, + int64_t def, Error& err) { + int64_t res = 0; + res = def; + + SBSymbolContextList context_list = target.FindSymbols(name); + + if (!context_list.IsValid() || context_list.GetSize() == 0) { + err = Error::Failure("Failed to find symbol %s", name); + return res; + } + + SBSymbolContext context = context_list.GetContextAtIndex(0); + SBSymbol symbol = context.GetSymbol(); + if (!symbol.IsValid()) { + err = Error::Failure("Failed to fetch symbol %s from context", name); + return res; + } + + SBAddress start = symbol.GetStartAddress(); + SBAddress end = symbol.GetEndAddress(); + uint32_t size = end.GetOffset() - start.GetOffset(); + + // NOTE: size could be bigger for at the end symbols + if (size >= 8) { + res = ReadSymbolFromTarget(target, start, name, err); + } else if (size == 4) { + int32_t tmp = ReadSymbolFromTarget(target, start, name, err); + res = static_cast(tmp); + } else if (size == 2) { + int16_t tmp = ReadSymbolFromTarget(target, start, name, err); + res = static_cast(tmp); + } else if (size == 1) { + int8_t tmp = ReadSymbolFromTarget(target, start, name, err); + res = static_cast(tmp); + } else { + err = Error::Failure("Unexpected symbol size %" PRIu32 " of symbol %s", + size, name); + } + + return res; +} + +void Constants::Assign(SBTarget target) { + loaded_ = false; + target_ = target; +} + + +int64_t Constants::LoadRawConstant(const char* name, int64_t def) { + Error err; + int64_t v = Constants::LookupConstant(target_, name, def, err); + if (err.Fail()) { + Error::PrintInDebugMode( + "Failed to load raw constant %s, default to %" PRId64, name, def); + } + + return v; +} + +int64_t Constants::LoadConstant(const char* name, Error& err, int64_t def) { + int64_t v = Constants::LookupConstant( + target_, (constant_prefix() + name).c_str(), def, err); + return v; +} + +int64_t Constants::LoadConstant(const char* name, int64_t def) { + Error err; + int64_t v = LoadConstant(name, err, def); + if (err.Fail()) { + Error::PrintInDebugMode("Failed to load constant %s, default to %" PRId64, + name, def); + } + + return v; +} + +int64_t Constants::LoadConstant(const char* name, const char* fallback, + int64_t def) { + Error err; + int64_t v = LoadConstant(name, err, def); + if (err.Fail()) v = LoadConstant(fallback, err, def); + if (err.Fail()) { + Error::PrintInDebugMode( + "Failed to load constant %s, fallback %s, default to %" PRId64, name, + fallback, def); + } + + return v; +} + + +} // namespace llnode diff --git a/src/constants.h b/src/constants.h new file mode 100644 index 00000000..aefec402 --- /dev/null +++ b/src/constants.h @@ -0,0 +1,47 @@ +#ifndef SRC_CONSTANTS_H_ +#define SRC_CONSTANTS_H_ + +#include +#include + +#include "src/error.h" + +using lldb::SBTarget; + +namespace llnode { + +#define CONSTANTS_DEFAULT_METHODS(NAME) \ + inline NAME* operator()() { \ + if (loaded_) return this; \ + loaded_ = true; \ + Load(); \ + return this; \ + } + +class Constants { + public: + Constants() : loaded_(false) {} + + inline bool is_loaded() const { return loaded_; } + + void Assign(lldb::SBTarget target); + + inline virtual std::string constant_prefix() { return ""; }; + + static int64_t LookupConstant(SBTarget target, const char* name, int64_t def, + Error& err); + + protected: + int64_t LoadRawConstant(const char* name, int64_t def = -1); + int64_t LoadConstant(const char* name, Error& err, 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_; +}; + +} // namespace llnode + +#endif diff --git a/src/error.cc b/src/error.cc new file mode 100644 index 00000000..f144e36a --- /dev/null +++ b/src/error.cc @@ -0,0 +1,44 @@ +#include "error.h" + +namespace llnode { +bool Error::is_debug_mode = false; + +Error::Error(bool failed, const char* format, ...) { + failed_ = failed; + char tmp[kMaxMessageLength]; + va_list arglist; + va_start(arglist, format); + vsnprintf(tmp, sizeof(tmp), format, arglist); + va_end(arglist); + msg_ = tmp; +} + + +void Error::PrintInDebugMode(const char* format, ...) { + if (!is_debug_mode) { + return; + } + char fmt[kMaxMessageLength]; + snprintf(fmt, sizeof(fmt), "[llv8] %s\n", format); + va_list arglist; + va_start(arglist, format); + vfprintf(stderr, fmt, arglist); + va_end(arglist); +} + + +Error Error::Failure(std::string msg) { + PrintInDebugMode("%s", msg.c_str()); + return Error(true, msg); +} + + +Error Error::Failure(const char* format, ...) { + char tmp[kMaxMessageLength]; + va_list arglist; + va_start(arglist, format); + vsnprintf(tmp, sizeof(tmp), format, arglist); + va_end(arglist); + return Error::Failure(std::string(tmp)); +} +} // namespace llnode diff --git a/src/error.h b/src/error.h new file mode 100644 index 00000000..73018c9b --- /dev/null +++ b/src/error.h @@ -0,0 +1,37 @@ +#ifndef SRC_ERROR_H_ +#define SRC_ERROR_H_ + +#include + +namespace llnode { + +class Error { + public: + Error() : failed_(false), msg_("") {} + Error(bool failed, std::string msg) : failed_(failed), msg_(msg) {} + Error(bool failed, const char* format, ...) + __attribute__((format(printf, 3, 4))); + + static inline Error Ok() { return Error(false, "ok"); } + static Error Failure(std::string msg); + static Error Failure(const char* format, ...) + __attribute__((format(printf, 1, 2))); + static void PrintInDebugMode(const char* format, ...) + __attribute__((format(printf, 1, 2))); + + inline bool Success() const { return !Fail(); } + inline bool Fail() const { return failed_; } + + inline const char* GetMessage() { return msg_.c_str(); } + + static void SetDebugMode(bool mode) { is_debug_mode = mode; } + + private: + bool failed_; + std::string msg_; + static const size_t kMaxMessageLength = 128; + static bool is_debug_mode; +}; +} // namespace llnode + +#endif diff --git a/src/llnode.cc b/src/llnode.cc index 4a9cc7d1..5e4acf1e 100644 --- a/src/llnode.cc +++ b/src/llnode.cc @@ -7,6 +7,7 @@ #include +#include "src/error.h" #include "src/llnode.h" #include "src/llscan.h" #include "src/llv8.h" @@ -121,7 +122,7 @@ bool BacktraceCmd::DoExecute(SBDebugger d, char** cmd, const uint64_t pc = frame.GetPC(); if (!frame.GetSymbol().IsValid()) { - v8::Error err; + Error err; v8::JSFrame v8_frame(llv8_, static_cast(frame.GetFP())); std::string res = v8_frame.Inspect(true, err); if (err.Success()) { @@ -197,7 +198,7 @@ bool PrintCmd::DoExecute(SBDebugger d, char** cmd, llv8_->Load(target); v8::Value v8_value(llv8_, value.GetValueAsSigned()); - v8::Error err; + Error err; std::string res = v8_value.Inspect(&inspect_options, err); if (err.Fail()) { result.SetError(err.GetMessage()); @@ -276,7 +277,7 @@ bool ListCmd::DoExecute(SBDebugger d, char** cmd, } // V8 frame - v8::Error err; + Error err; v8::JSFrame v8_frame(llv8_, static_cast(frame.GetFP())); const static uint32_t kDisplayLines = 4; @@ -307,7 +308,7 @@ void InitDebugMode() { is_debug_mode = true; } - v8::Error::SetDebugMode(is_debug_mode); + Error::SetDebugMode(is_debug_mode); } } // namespace llnode diff --git a/src/llscan.cc b/src/llscan.cc index dd2a6a7d..e59665f2 100644 --- a/src/llscan.cc +++ b/src/llscan.cc @@ -10,6 +10,7 @@ #include +#include "src/error.h" #include "src/llnode.h" #include "src/llscan.h" #include "src/llv8-inl.h" @@ -164,7 +165,7 @@ bool FindInstancesCmd::DoExecute(SBDebugger d, char** cmd, TypeRecord* t = instance_it->second; for (std::set::iterator it = t->GetInstances().begin(); it != t->GetInstances().end(); ++it) { - v8::Error err; + Error err; v8::Value v8_value(llscan_->v8(), *it); std::string res = v8_value.Inspect(&inspect_options, err); result.Printf("%s\n", res.c_str()); @@ -206,7 +207,7 @@ bool NodeInfoCmd::DoExecute(SBDebugger d, char** cmd, TypeRecord* t = instance_it->second; for (std::set::iterator it = t->GetInstances().begin(); it != t->GetInstances().end(); ++it) { - v8::Error err; + Error err; // The properties object should be a JSObject v8::JSObject process_obj(llscan_->v8(), *it); @@ -474,7 +475,7 @@ void FindReferencesCmd::ScanForReferences(ObjectScanner* scanner) { for (auto const entry : mapstoinstances) { TypeRecord* typerecord = entry.second; for (uint64_t addr : typerecord->GetInstances()) { - v8::Error err; + Error err; v8::Value obj_value(llscan_->v8(), addr); v8::HeapObject heap_object(obj_value); int64_t type = heap_object.GetType(err); @@ -513,7 +514,7 @@ void FindReferencesCmd::PrintReferences(SBCommandReturnObject& result, // Walk all the object instances and handle them according to their type. TypeRecordMap mapstoinstances = llscan_->GetMapsToInstances(); for (uint64_t addr : *references) { - v8::Error err; + Error err; v8::Value obj_value(llscan_->v8(), addr); v8::HeapObject heap_object(obj_value); int64_t type = heap_object.GetType(err); @@ -600,7 +601,7 @@ char** FindReferencesCmd::ParseScanOptions(char** cmd, ScanType* type) { void FindReferencesCmd::ReferenceScanner::PrintRefs( - SBCommandReturnObject& result, v8::JSObject& js_obj, v8::Error& err) { + SBCommandReturnObject& result, v8::JSObject& js_obj, Error& err) { int64_t length = js_obj.GetArrayLength(err); for (int64_t i = 0; i < length; ++i) { v8::Value v = js_obj.GetArrayElement(i, err); @@ -635,7 +636,7 @@ void FindReferencesCmd::ReferenceScanner::PrintRefs( void FindReferencesCmd::ReferenceScanner::PrintRefs( - SBCommandReturnObject& result, v8::String& str, v8::Error& err) { + SBCommandReturnObject& result, v8::String& str, Error& err) { v8::LLV8* v8 = str.v8(); int64_t repr = str.Representation(err); @@ -681,7 +682,7 @@ void FindReferencesCmd::ReferenceScanner::PrintRefs( void FindReferencesCmd::ReferenceScanner::ScanRefs(v8::JSObject& js_obj, - v8::Error& err) { + Error& err) { ReferencesVector* references; std::set already_saved; @@ -718,7 +719,7 @@ void FindReferencesCmd::ReferenceScanner::ScanRefs(v8::JSObject& js_obj, void FindReferencesCmd::ReferenceScanner::ScanRefs(v8::String& str, - v8::Error& err) { + Error& err) { ReferencesVector* references; std::set already_saved; @@ -776,7 +777,7 @@ ReferencesVector* FindReferencesCmd::ReferenceScanner::GetReferences() { void FindReferencesCmd::PropertyScanner::PrintRefs( - SBCommandReturnObject& result, v8::JSObject& js_obj, v8::Error& err) { + SBCommandReturnObject& result, v8::JSObject& js_obj, Error& err) { // (Note: We skip array elements as they don't have names.) // Walk all the properties in this object. @@ -802,7 +803,7 @@ void FindReferencesCmd::PropertyScanner::PrintRefs( void FindReferencesCmd::PropertyScanner::ScanRefs(v8::JSObject& js_obj, - v8::Error& err) { + Error& err) { // (Note: We skip array elements as they don't have names.) // Walk all the properties in this object. @@ -837,7 +838,7 @@ ReferencesVector* FindReferencesCmd::PropertyScanner::GetReferences() { void FindReferencesCmd::StringScanner::PrintRefs(SBCommandReturnObject& result, v8::JSObject& js_obj, - v8::Error& err) { + Error& err) { v8::LLV8* v8 = js_obj.v8(); int64_t length = js_obj.GetArrayLength(err); @@ -902,8 +903,7 @@ void FindReferencesCmd::StringScanner::PrintRefs(SBCommandReturnObject& result, void FindReferencesCmd::StringScanner::PrintRefs(SBCommandReturnObject& result, - v8::String& str, - v8::Error& err) { + v8::String& str, Error& err) { v8::LLV8* v8 = str.v8(); // Concatenated and sliced strings refer to other strings so @@ -972,7 +972,7 @@ void FindReferencesCmd::StringScanner::PrintRefs(SBCommandReturnObject& result, void FindReferencesCmd::StringScanner::ScanRefs(v8::JSObject& js_obj, - v8::Error& err) { + Error& err) { v8::LLV8* v8 = js_obj.v8(); ReferencesVector* references; std::set already_saved; @@ -1032,8 +1032,7 @@ void FindReferencesCmd::StringScanner::ScanRefs(v8::JSObject& js_obj, } -void FindReferencesCmd::StringScanner::ScanRefs(v8::String& str, - v8::Error& err) { +void FindReferencesCmd::StringScanner::ScanRefs(v8::String& str, Error& err) { v8::LLV8* v8 = str.v8(); ReferencesVector* references; @@ -1117,7 +1116,7 @@ FindJSObjectsVisitor::FindJSObjectsVisitor(SBTarget& target, LLScan* llscan) uint64_t FindJSObjectsVisitor::Visit(uint64_t location, uint64_t word) { v8::Value v8_value(llscan_->v8(), word); - v8::Error err; + Error err; // Test if this is SMI // Skip inspecting things that look like Smi's, they aren't objects. v8::Smi smi(v8_value); @@ -1165,7 +1164,7 @@ uint64_t FindJSObjectsVisitor::Visit(uint64_t location, uint64_t word) { void FindJSObjectsVisitor::InsertOnMapsToInstances( uint64_t word, v8::Map map, FindJSObjectsVisitor::MapCacheEntry map_info, - v8::Error& err) { + Error& err) { TypeRecord* t; auto entry = std::make_pair(map_info.type_name, nullptr); @@ -1184,7 +1183,7 @@ void FindJSObjectsVisitor::InsertOnMapsToInstances( void FindJSObjectsVisitor::InsertOnDetailedMapsToInstances( uint64_t word, v8::Map map, FindJSObjectsVisitor::MapCacheEntry map_info, - v8::Error& err) { + Error& err) { DetailedTypeRecord* t; auto type_name_with_properties = map_info.GetTypeNameWithProperties(); @@ -1211,7 +1210,7 @@ void FindJSObjectsVisitor::InsertOnDetailedMapsToInstances( } -bool FindJSObjectsVisitor::IsAHistogramType(v8::Map& map, v8::Error& err) { +bool FindJSObjectsVisitor::IsAHistogramType(v8::Map& map, Error& err) { int64_t type = map.GetType(err); if (err.Fail()) return false; @@ -1280,8 +1279,7 @@ bool LLScan::ScanHeapForObjects(lldb::SBTarget target, return true; } -std::string -FindJSObjectsVisitor::MapCacheEntry::GetTypeNameWithProperties( +std::string FindJSObjectsVisitor::MapCacheEntry::GetTypeNameWithProperties( ShowArrayLength show_array_length, size_t max_properties) { std::string type_name_with_properties(type_name); @@ -1306,8 +1304,7 @@ FindJSObjectsVisitor::MapCacheEntry::GetTypeNameWithProperties( bool FindJSObjectsVisitor::MapCacheEntry::Load(v8::Map map, v8::HeapObject heap_object, - v8::LLV8* llv8, - v8::Error& err) { + v8::LLV8* llv8, Error& err) { // Check type first is_histogram = FindJSObjectsVisitor::IsAHistogramType(map, err); diff --git a/src/llscan.h b/src/llscan.h index b1cf1abb..cef45585 100644 --- a/src/llscan.h +++ b/src/llscan.h @@ -4,6 +4,8 @@ #include #include #include + +#include "src/error.h" #include "src/llnode.h" namespace llnode { @@ -78,13 +80,13 @@ class FindReferencesCmd : public CommandBase { virtual ReferencesVector* GetReferences() { return nullptr; }; - virtual void ScanRefs(v8::JSObject& js_obj, v8::Error& err){}; - virtual void ScanRefs(v8::String& str, v8::Error& err){}; + virtual void ScanRefs(v8::JSObject& js_obj, Error& err){}; + virtual void ScanRefs(v8::String& str, Error& err){}; virtual void PrintRefs(lldb::SBCommandReturnObject& result, - v8::JSObject& js_obj, v8::Error& err) {} + v8::JSObject& js_obj, Error& err) {} virtual void PrintRefs(lldb::SBCommandReturnObject& result, v8::String& str, - v8::Error& err) {} + Error& err) {} }; void PrintReferences(lldb::SBCommandReturnObject& result, @@ -101,13 +103,13 @@ class FindReferencesCmd : public CommandBase { ReferencesVector* GetReferences() override; - void ScanRefs(v8::JSObject& js_obj, v8::Error& err) override; - void ScanRefs(v8::String& str, v8::Error& err) override; + void ScanRefs(v8::JSObject& js_obj, Error& err) override; + void ScanRefs(v8::String& str, Error& err) override; void PrintRefs(lldb::SBCommandReturnObject& result, v8::JSObject& js_obj, - v8::Error& err) override; + Error& err) override; void PrintRefs(lldb::SBCommandReturnObject& result, v8::String& str, - v8::Error& err) override; + Error& err) override; private: LLScan* llscan_; @@ -123,12 +125,12 @@ class FindReferencesCmd : public CommandBase { ReferencesVector* GetReferences() override; - void ScanRefs(v8::JSObject& js_obj, v8::Error& err) override; + void ScanRefs(v8::JSObject& js_obj, Error& err) override; // We only scan properties on objects not Strings, use default no-op impl // of PrintRefs for Strings. void PrintRefs(lldb::SBCommandReturnObject& result, v8::JSObject& js_obj, - v8::Error& err) override; + Error& err) override; private: LLScan* llscan_; @@ -145,13 +147,13 @@ class FindReferencesCmd : public CommandBase { ReferencesVector* GetReferences() override; - void ScanRefs(v8::JSObject& js_obj, v8::Error& err) override; - void ScanRefs(v8::String& str, v8::Error& err) override; + void ScanRefs(v8::JSObject& js_obj, Error& err) override; + void ScanRefs(v8::String& str, Error& err) override; void PrintRefs(lldb::SBCommandReturnObject& result, v8::JSObject& js_obj, - v8::Error& err) override; + Error& err) override; void PrintRefs(lldb::SBCommandReturnObject& result, v8::String& str, - v8::Error& err) override; + Error& err) override; private: LLScan* llscan_; @@ -257,18 +259,18 @@ class FindJSObjectsVisitor : MemoryVisitor { ShowArrayLength show_array_length = kShowArrayLength, size_t max_properties = 0); - bool Load(v8::Map map, v8::HeapObject heap_object, - v8::LLV8* llv8, v8::Error& err); + bool Load(v8::Map map, v8::HeapObject heap_object, v8::LLV8* llv8, + Error& err); }; - static bool IsAHistogramType(v8::Map& map, v8::Error& err); + static bool IsAHistogramType(v8::Map& map, Error& err); void InsertOnMapsToInstances(uint64_t word, v8::Map map, FindJSObjectsVisitor::MapCacheEntry map_info, - v8::Error& err); + Error& err); void InsertOnDetailedMapsToInstances( uint64_t word, v8::Map map, FindJSObjectsVisitor::MapCacheEntry map_info, - v8::Error& err); + Error& err); lldb::SBTarget& target_; uint32_t address_byte_size_; diff --git a/src/llv8-constants.cc b/src/llv8-constants.cc index 4dc1a6e4..c9c72702 100644 --- a/src/llv8-constants.cc +++ b/src/llv8-constants.cc @@ -22,8 +22,6 @@ using lldb::SBSymbolContextList; using lldb::SBTarget; using lldb::addr_t; -static std::string kConstantPrefix = "v8dbg_"; - void Module::Assign(SBTarget target, Common* common) { loaded_ = false; target_ = target; @@ -31,107 +29,6 @@ void Module::Assign(SBTarget target, Common* common) { } -template -T ReadSymbolFromTarget(SBTarget& target, SBAddress& start, - const char* name, Error& err) { - SBError sberr; - T res = 0; - target.ReadMemory(start, &res, sizeof(T), sberr); - if (!sberr.Fail()) { - err = Error::Ok(); - } else { - err = Error::Failure("Failed to read symbol %s", name); - } - return res; -} - -static int64_t LookupConstant(SBTarget target, const char* name, int64_t def, - Error& err) { - int64_t res = 0; - res = def; - - SBSymbolContextList context_list = target.FindSymbols(name); - - if (!context_list.IsValid() || context_list.GetSize() == 0) { - err = Error::Failure("Failed to find symbol %s", name); - return res; - } - - SBSymbolContext context = context_list.GetContextAtIndex(0); - SBSymbol symbol = context.GetSymbol(); - if (!symbol.IsValid()) { - err = Error::Failure("Failed to fetch symbol %s from context", name); - return res; - } - - SBAddress start = symbol.GetStartAddress(); - SBAddress end = symbol.GetEndAddress(); - uint32_t size = end.GetOffset() - start.GetOffset(); - - // NOTE: size could be bigger for at the end symbols - if (size >= 8) { - res = ReadSymbolFromTarget(target, start, name, err); - } else if (size == 4) { - int32_t tmp = ReadSymbolFromTarget(target, start, name, err); - res = static_cast(tmp); - } else if (size == 2) { - int16_t tmp = ReadSymbolFromTarget(target, start, name, err); - res = static_cast(tmp); - } else if (size == 1) { - int8_t tmp = ReadSymbolFromTarget(target, start, name, err); - res = static_cast(tmp); - } else { - err = Error::Failure("Unexpected symbol size %" PRIu32 " of symbol %s", - size, name); - } - - return res; -} - - -int64_t Module::LoadRawConstant(const char* name, int64_t def) { - Error err; - int64_t v = LookupConstant(target_, name, def, err); - if (err.Fail()) { - Error::PrintInDebugMode( - "Failed to load raw constant %s, default to %" PRId64, name, def); - } - - return v; -} - -int64_t Module::LoadConstant(const char* name, Error& err, int64_t def) { - int64_t v = - LookupConstant(target_, (kConstantPrefix + name).c_str(), def, err); - return v; -} - -int64_t Module::LoadConstant(const char* name, int64_t def) { - Error err; - int64_t v = LoadConstant(name, err, def); - if (err.Fail()) { - Error::PrintInDebugMode("Failed to load constant %s, default to %" PRId64, - name, def); - } - - return v; -} - -int64_t Module::LoadConstant(const char* name, const char* fallback, - int64_t def) { - Error err; - int64_t v = LoadConstant(name, err, def); - if (err.Fail()) v = LoadConstant(fallback, err, def); - if (err.Fail()) { - Error::PrintInDebugMode( - "Failed to load constant %s, fallback %s, default to %" PRId64, name, - fallback, def); - } - - return v; -} - - void Common::Load() { kPointerSize = 1 << LoadConstant("PointerSizeLog2"); kVersionMajor = LoadRawConstant("v8::internal::Version::major_"); @@ -342,6 +239,10 @@ 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"); } diff --git a/src/llv8-constants.h b/src/llv8-constants.h index 9c237153..b6859ceb 100644 --- a/src/llv8-constants.h +++ b/src/llv8-constants.h @@ -3,49 +3,29 @@ #include +#include "constants.h" + namespace llnode { namespace v8 { - -class Error; - namespace constants { // Forward declarations class Common; -class Module { +class Module : public Constants { public: - Module() : loaded_(false) {} - - inline bool is_loaded() const { return loaded_; } - void Assign(lldb::SBTarget target, Common* common = nullptr); - protected: - int64_t LoadRawConstant(const char* name, int64_t def = -1); - int64_t LoadConstant(const char* name, Error& err, 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); + inline std::string constant_prefix() override { return "v8dbg_"; } - lldb::SBTarget target_; + protected: Common* common_; - bool loaded_; }; -#define MODULE_DEFAULT_METHODS(NAME) \ - NAME() {} \ - inline NAME* operator()() { \ - if (loaded_) return this; \ - loaded_ = true; \ - Load(); \ - return this; \ - } - class Common : public Module { public: - MODULE_DEFAULT_METHODS(Common); + CONSTANTS_DEFAULT_METHODS(Common); int64_t kPointerSize; int64_t kVersionMajor; @@ -61,7 +41,7 @@ class Common : public Module { class Smi : public Module { public: - MODULE_DEFAULT_METHODS(Smi); + CONSTANTS_DEFAULT_METHODS(Smi); int64_t kTag; int64_t kTagMask; @@ -73,7 +53,7 @@ class Smi : public Module { class HeapObject : public Module { public: - MODULE_DEFAULT_METHODS(HeapObject); + CONSTANTS_DEFAULT_METHODS(HeapObject); int64_t kTag; int64_t kTagMask; @@ -86,7 +66,7 @@ class HeapObject : public Module { class Map : public Module { public: - MODULE_DEFAULT_METHODS(Map); + CONSTANTS_DEFAULT_METHODS(Map); int64_t kMapTypeMask; int64_t kInstanceAttrsOffset; @@ -106,7 +86,7 @@ class Map : public Module { class JSObject : public Module { public: - MODULE_DEFAULT_METHODS(JSObject); + CONSTANTS_DEFAULT_METHODS(JSObject); int64_t kPropertiesOffset; int64_t kElementsOffset; @@ -118,7 +98,7 @@ class JSObject : public Module { class HeapNumber : public Module { public: - MODULE_DEFAULT_METHODS(HeapNumber); + CONSTANTS_DEFAULT_METHODS(HeapNumber); int64_t kValueOffset; @@ -128,7 +108,7 @@ class HeapNumber : public Module { class JSArray : public Module { public: - MODULE_DEFAULT_METHODS(JSArray); + CONSTANTS_DEFAULT_METHODS(JSArray); int64_t kLengthOffset; @@ -138,7 +118,7 @@ class JSArray : public Module { class JSFunction : public Module { public: - MODULE_DEFAULT_METHODS(JSFunction); + CONSTANTS_DEFAULT_METHODS(JSFunction); int64_t kSharedInfoOffset; int64_t kContextOffset; @@ -149,7 +129,7 @@ class JSFunction : public Module { class JSRegExp : public Module { public: - MODULE_DEFAULT_METHODS(JSRegExp); + CONSTANTS_DEFAULT_METHODS(JSRegExp); int64_t kSourceOffset; @@ -159,7 +139,7 @@ class JSRegExp : public Module { class JSDate : public Module { public: - MODULE_DEFAULT_METHODS(JSDate); + CONSTANTS_DEFAULT_METHODS(JSDate); int64_t kValueOffset; @@ -169,7 +149,7 @@ class JSDate : public Module { class SharedInfo : public Module { public: - MODULE_DEFAULT_METHODS(SharedInfo); + CONSTANTS_DEFAULT_METHODS(SharedInfo); int64_t kNameOffset; int64_t kInferredNameOffset; @@ -190,7 +170,7 @@ class SharedInfo : public Module { class Code : public Module { public: - MODULE_DEFAULT_METHODS(Code) + CONSTANTS_DEFAULT_METHODS(Code) int64_t kStartOffset; int64_t kSizeOffset; @@ -201,7 +181,7 @@ class Code : public Module { class ScopeInfo : public Module { public: - MODULE_DEFAULT_METHODS(ScopeInfo); + CONSTANTS_DEFAULT_METHODS(ScopeInfo); int64_t kParameterCountOffset; int64_t kStackLocalCountOffset; @@ -214,11 +194,13 @@ class ScopeInfo : public Module { class Context : public Module { public: - MODULE_DEFAULT_METHODS(Context); + CONSTANTS_DEFAULT_METHODS(Context); int64_t kClosureIndex; int64_t kGlobalObjectIndex; int64_t kPreviousIndex; + int64_t kNativeIndex; + int64_t kEmbedderDataIndex; int64_t kMinContextSlots; protected: @@ -227,7 +209,7 @@ class Context : public Module { class Script : public Module { public: - MODULE_DEFAULT_METHODS(Script); + CONSTANTS_DEFAULT_METHODS(Script); int64_t kNameOffset; int64_t kLineOffsetOffset; @@ -240,7 +222,7 @@ class Script : public Module { class String : public Module { public: - MODULE_DEFAULT_METHODS(String); + CONSTANTS_DEFAULT_METHODS(String); int64_t kEncodingMask; int64_t kRepresentationMask; @@ -264,7 +246,7 @@ class String : public Module { class OneByteString : public Module { public: - MODULE_DEFAULT_METHODS(OneByteString); + CONSTANTS_DEFAULT_METHODS(OneByteString); int64_t kCharsOffset; @@ -274,7 +256,7 @@ class OneByteString : public Module { class TwoByteString : public Module { public: - MODULE_DEFAULT_METHODS(TwoByteString); + CONSTANTS_DEFAULT_METHODS(TwoByteString); int64_t kCharsOffset; @@ -284,7 +266,7 @@ class TwoByteString : public Module { class ConsString : public Module { public: - MODULE_DEFAULT_METHODS(ConsString); + CONSTANTS_DEFAULT_METHODS(ConsString); int64_t kFirstOffset; int64_t kSecondOffset; @@ -295,7 +277,7 @@ class ConsString : public Module { class SlicedString : public Module { public: - MODULE_DEFAULT_METHODS(SlicedString); + CONSTANTS_DEFAULT_METHODS(SlicedString); int64_t kParentOffset; int64_t kOffsetOffset; @@ -306,7 +288,7 @@ class SlicedString : public Module { class ThinString : public Module { public: - MODULE_DEFAULT_METHODS(ThinString); + CONSTANTS_DEFAULT_METHODS(ThinString); int64_t kActualOffset; @@ -316,7 +298,7 @@ class ThinString : public Module { class FixedArrayBase : public Module { public: - MODULE_DEFAULT_METHODS(FixedArrayBase); + CONSTANTS_DEFAULT_METHODS(FixedArrayBase); int64_t kLengthOffset; @@ -326,7 +308,7 @@ class FixedArrayBase : public Module { class FixedArray : public Module { public: - MODULE_DEFAULT_METHODS(FixedArray); + CONSTANTS_DEFAULT_METHODS(FixedArray); int64_t kDataOffset; @@ -336,7 +318,7 @@ class FixedArray : public Module { class FixedTypedArrayBase : public Module { public: - MODULE_DEFAULT_METHODS(FixedTypedArrayBase); + CONSTANTS_DEFAULT_METHODS(FixedTypedArrayBase); int64_t kBasePointerOffset; int64_t kExternalPointerOffset; @@ -347,7 +329,7 @@ class FixedTypedArrayBase : public Module { class Oddball : public Module { public: - MODULE_DEFAULT_METHODS(Oddball); + CONSTANTS_DEFAULT_METHODS(Oddball); int64_t kKindOffset; @@ -365,7 +347,7 @@ class Oddball : public Module { class JSArrayBuffer : public Module { public: - MODULE_DEFAULT_METHODS(JSArrayBuffer); + CONSTANTS_DEFAULT_METHODS(JSArrayBuffer); int64_t kKindOffset; @@ -382,7 +364,7 @@ class JSArrayBuffer : public Module { class JSArrayBufferView : public Module { public: - MODULE_DEFAULT_METHODS(JSArrayBufferView); + CONSTANTS_DEFAULT_METHODS(JSArrayBufferView); int64_t kBufferOffset; int64_t kByteOffsetOffset; @@ -394,7 +376,7 @@ class JSArrayBufferView : public Module { class DescriptorArray : public Module { public: - MODULE_DEFAULT_METHODS(DescriptorArray); + CONSTANTS_DEFAULT_METHODS(DescriptorArray); int64_t kDetailsOffset; int64_t kKeyOffset; @@ -438,7 +420,7 @@ class DescriptorArray : public Module { class NameDictionary : public Module { public: - MODULE_DEFAULT_METHODS(NameDictionary); + CONSTANTS_DEFAULT_METHODS(NameDictionary); int64_t kKeyOffset; int64_t kValueOffset; @@ -453,7 +435,7 @@ class NameDictionary : public Module { class Frame : public Module { public: - MODULE_DEFAULT_METHODS(Frame); + CONSTANTS_DEFAULT_METHODS(Frame); int64_t kContextOffset; int64_t kFunctionOffset; @@ -476,7 +458,7 @@ class Frame : public Module { class Types : public Module { public: - MODULE_DEFAULT_METHODS(Types); + CONSTANTS_DEFAULT_METHODS(Types); int64_t kFirstNonstringType; @@ -503,8 +485,6 @@ class Types : public Module { void Load(); }; -#undef MODULE_DEFAULT_METHODS - } // namespace constants } // namespace v8 } // namespace llnode diff --git a/src/llv8-inl.h b/src/llv8-inl.h index 6d726222..48d0a213 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..68174b7e 100644 --- a/src/llv8.cc +++ b/src/llv8.cc @@ -58,48 +58,6 @@ void LLV8::Load(SBTarget target) { types.Assign(target, &common); } -bool Error::is_debug_mode = false; - -Error::Error(bool failed, const char* format, ...) { - failed_ = failed; - char tmp[kMaxMessageLength]; - va_list arglist; - va_start(arglist, format); - vsnprintf(tmp, sizeof(tmp), format, arglist); - va_end(arglist); - msg_ = tmp; -} - - -void Error::PrintInDebugMode(const char* format, ...) { - if (!is_debug_mode) { - return; - } - char fmt[kMaxMessageLength]; - snprintf(fmt, sizeof(fmt), "[llv8] %s\n", format); - va_list arglist; - va_start(arglist, format); - vfprintf(stderr, fmt, arglist); - va_end(arglist); -} - - -Error Error::Failure(std::string msg) { - PrintInDebugMode("%s", msg.c_str()); - return Error(true, msg); -} - - -Error Error::Failure(const char* format, ...) { - char tmp[kMaxMessageLength]; - va_list arglist; - va_start(arglist, format); - vsnprintf(tmp, sizeof(tmp), format, arglist); - va_end(arglist); - return Error::Failure(std::string(tmp)); -} - - int64_t LLV8::LoadPtr(int64_t addr, Error& err) { SBError sberr; int64_t value = diff --git a/src/llv8.h b/src/llv8.h index f67eb28a..62af7095 100644 --- a/src/llv8.h +++ b/src/llv8.h @@ -6,10 +6,17 @@ #include +#include "src/error.h" #include "src/llv8-constants.h" namespace llnode { +namespace node { +namespace constants { +class Environment; +} +} // namespace node + class FindJSObjectsVisitor; class FindReferencesCmd; class FindObjectsCmd; @@ -20,33 +27,6 @@ namespace v8 { class LLV8; class CodeMap; -class Error { - public: - Error() : failed_(false), msg_("") {} - Error(bool failed, std::string msg) : failed_(failed), msg_(msg) {} - Error(bool failed, const char* format, ...) - __attribute__((format(printf, 3, 4))); - - static inline Error Ok() { return Error(false, "ok"); } - static Error Failure(std::string msg); - static Error Failure(const char* format, ...) - __attribute__((format(printf, 1, 2))); - static void PrintInDebugMode(const char* format, ...) - __attribute__((format(printf, 1, 2))); - - inline bool Success() const { return !Fail(); } - inline bool Fail() const { return failed_; } - - inline const char* GetMessage() { return msg_.c_str(); } - - static void SetDebugMode(bool mode) { is_debug_mode = mode; } - - private: - bool failed_; - std::string msg_; - static const size_t kMaxMessageLength = 128; - static bool is_debug_mode; -}; #define V8_VALUE_DEFAULT_METHODS(NAME, PARENT) \ NAME(const NAME& v) = default; \ @@ -394,6 +374,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); @@ -553,6 +534,7 @@ class LLV8 { friend class llnode::FindJSObjectsVisitor; friend class llnode::FindObjectsCmd; friend class llnode::FindReferencesCmd; + friend class llnode::node::constants::Environment; }; #undef V8_VALUE_DEFAULT_METHODS diff --git a/src/node-constants.cc b/src/node-constants.cc new file mode 100644 index 00000000..4851469e --- /dev/null +++ b/src/node-constants.cc @@ -0,0 +1,145 @@ +#include + +#include "src/llv8-inl.h" +#include "src/node-constants.h" + +using lldb::SBFrame; +using lldb::SBProcess; +using lldb::SBStream; +using lldb::SBThread; + +namespace llnode { +namespace node { +namespace constants { + +void Environment::Load() { + kReqWrapQueueOffset = LoadConstant( + "offset_Environment__req_wrap_queue___Environment_ReqWrapQueue"); + kHandleWrapQueueOffset = LoadConstant( + "offset_Environment__handle_wrap_queue___Environment_HandleWrapQueue"); + kEnvContextEmbedderDataIndex = + LoadConstant("const_Environment__kContextEmbedderDataIndex__int"); + + Error err; + kCurrentEnvironment = LoadCurrentEnvironment(err); +} + +addr_t Environment::LoadCurrentEnvironment(Error& err) { + if (kEnvContextEmbedderDataIndex == -1) { + err = Error::Failure("Missing Node's embedder data index"); + return 0; + } + addr_t currentEnvironment = 0; + SBProcess process = target_.GetProcess(); + SBThread thread = process.GetSelectedThread(); + if (!thread.IsValid()) { + err = Error::Failure("Invalid thread"); + return 0; + } + + llv8()->Load(target_); + + SBStream desc; + if (!thread.GetDescription(desc)) { + err = Error::Failure("Couldn't get thread description"); + return 0; + } + SBFrame selected_frame = thread.GetSelectedFrame(); + + uint32_t num_frames = thread.GetNumFrames(); + + // Heuristically finds the native context and gets the Environment from its + // embedder data. + for (uint32_t i = 0; i < num_frames; i++) { + SBFrame frame = thread.GetFrameAtIndex(i); + + if (!frame.GetSymbol().IsValid()) { + Error v8_err; + v8::JSFrame v8_frame(llv8(), static_cast(frame.GetFP())); + v8::JSFunction v8_function = v8_frame.GetFunction(v8_err); + if (v8_err.Fail()) { + continue; + } + v8::Value val; + val = v8_function.GetContext(v8_err); + if (v8_err.Fail()) { + continue; + } + bool found = false; + while (!found) { + v8::Context context(val); + v8::Value native = context.Native(v8_err); + if (v8_err.Success()) { + if (native.raw() == context.raw()) { + found = true; + currentEnvironment = CurrentEnvironmentFromContext(native, err); + break; + } + } + + val = context.Previous(v8_err); + if (v8_err.Fail()) { + break; + } + } + if (found) { + break; + } + } + } + + if (!currentEnvironment) { + err = + Error::Failure("Couldn't find the Environemnt from the native context"); + } + + return currentEnvironment; +} + +addr_t Environment::CurrentEnvironmentFromContext(v8::Value context, + Error& err) { + llv8()->Load(target_); + + v8::FixedArray contextArray = v8::FixedArray(context); + v8::FixedArray embed = contextArray.Get( + llv8()->context()->kEmbedderDataIndex, err); + if (err.Fail()) { + return 0; + } + v8::Smi encodedEnv = embed.Get(kEnvContextEmbedderDataIndex, err); + if (err.Fail()) { + return 0; + } + return encodedEnv.raw(); +} + + +void ReqWrapQueue::Load() { + kHeadOffset = LoadConstant( + "offset_Environment_ReqWrapQueue__head___ListNode_ReqWrapQueue"); + kNextOffset = LoadConstant("offset_ListNode_ReqWrap__next___uintptr_t"); +} + +void ReqWrap::Load() { + kListNodeOffset = + LoadConstant("offset_ReqWrap__req_wrap_queue___ListNode_ReqWrapQueue"); +} + +void HandleWrapQueue::Load() { + kHeadOffset = LoadConstant( + "offset_Environment_HandleWrapQueue__head___ListNode_HandleWrap"); + kNextOffset = LoadConstant("offset_ListNode_HandleWrap__next___uintptr_t"); +} + +void HandleWrap::Load() { + kListNodeOffset = LoadConstant( + "offset_HandleWrap__handle_wrap_queue___ListNode_HandleWrap"); +} + +void BaseObject::Load() { + kPersistentHandleOffset = LoadConstant( + "offset_BaseObject__persistent_handle___v8_Persistent_v8_Object"); +} +} // namespace constants +} // namespace node +} // namespace llnode diff --git a/src/node-constants.h b/src/node-constants.h new file mode 100644 index 00000000..ec89f3e6 --- /dev/null +++ b/src/node-constants.h @@ -0,0 +1,102 @@ +#ifndef SRC_NODE_CONSTANTS_H_ +#define SRC_NODE_CONSTANTS_H_ + +#include +#include "src/constants.h" +#include "src/llv8.h" + +using lldb::addr_t; + +namespace llnode { +namespace node { +namespace constants { + +#define NODE_CONSTANTS_DEFAULT_METHODS(Class) \ + Class(v8::LLV8* llv8) : Module(llv8) {} \ + CONSTANTS_DEFAULT_METHODS(Class) + + +class Module : public Constants { + public: + Module(v8::LLV8* llv8) : llv8_(llv8) {} + inline std::string constant_prefix() override { return "nodedbg_"; }; + + inline v8::LLV8* llv8() { return llv8_; } + + private: + v8::LLV8* llv8_; +}; + +class Environment : public Module { + public: + NODE_CONSTANTS_DEFAULT_METHODS(Environment); + + int64_t kReqWrapQueueOffset; + int64_t kHandleWrapQueueOffset; + int64_t kEnvContextEmbedderDataIndex; + addr_t kCurrentEnvironment; + + protected: + void Load(); + + private: + addr_t LoadCurrentEnvironment(Error& err); + addr_t CurrentEnvironmentFromContext(v8::Value context, Error& err); +}; + +class ReqWrapQueue : public Module { + public: + NODE_CONSTANTS_DEFAULT_METHODS(ReqWrapQueue); + + int64_t kHeadOffset; + int64_t kNextOffset; + + protected: + void Load(); +}; + +class ReqWrap : public Module { + public: + NODE_CONSTANTS_DEFAULT_METHODS(ReqWrap); + + int64_t kListNodeOffset; + + protected: + void Load(); +}; + +class HandleWrapQueue : public Module { + public: + NODE_CONSTANTS_DEFAULT_METHODS(HandleWrapQueue); + + int64_t kHeadOffset; + int64_t kNextOffset; + + protected: + void Load(); +}; + +class HandleWrap : public Module { + public: + NODE_CONSTANTS_DEFAULT_METHODS(HandleWrap); + + int64_t kListNodeOffset; + + protected: + void Load(); +}; + +class BaseObject : public Module { + public: + NODE_CONSTANTS_DEFAULT_METHODS(BaseObject); + + int64_t kPersistentHandleOffset; + + protected: + void Load(); +}; +} +} // namespace node +} // namespace llnode + +#endif