-
Notifications
You must be signed in to change notification settings - Fork 100
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
src: refactor of workqueue related code
All code related to the workqueue commands were refactored by assigning constants in a different file and by creating helper classes to access some node internal properties. Besides that, a new fallback method to determine the current environment was added. This method uses a heuristic approach to try to find the root context of the process. With this, those new commands will work most of the time even without the new symbols added to V8.
- Loading branch information
Matheus Marchini
committed
Aug 29, 2017
1 parent
ff614a9
commit 71c965d
Showing
14 changed files
with
666 additions
and
111 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
#include "src/constants.h" | ||
// TODO(mmarchini): This file shouldn't import llv8-constants nor llv8, as the | ||
// intention is to inherit llv8-constants.h from constants.h | ||
#include <iostream> | ||
#include "src/llv8-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; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
#ifndef SRC_CONSTANTS_H_ | ||
#define SRC_CONSTANTS_H_ | ||
|
||
#include <lldb/API/LLDB.h> | ||
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
#include <iostream> | ||
|
||
#include <lldb/API/LLDB.h> | ||
|
||
#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)) { | ||
// TODO warn user | ||
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); | ||
v8::Context ctx(&llv8, thread_context); | ||
v8::Value native = ctx.Native(err); | ||
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<v8::FixedArray>(llv8.context()->kEmbedderDataIndex, err); | ||
v8::Smi encodedEnv = embed.Get<v8::Smi>(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; | ||
} | ||
|
||
// Load V8 constants from postmortem data | ||
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<int64_t>(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); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
#ifndef SRC_LLNODE_CONSTANTS_H_ | ||
#define SRC_LLNODE_CONSTANTS_H_ | ||
|
||
#include <lldb/API/LLDB.h> | ||
#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 |
Oops, something went wrong.