Skip to content

Commit 089dcc9

Browse files
Driegerjoyeecheung
authored andcommitted
src: show context objects within findrefs
When using `findrefs` we should be able to get all references for the given value, this includes `Context` objects. Refs: #195 PR-URL: #227 Reviewed-By: Matheus Marchini <[email protected]> Reviewed-By: Joyee Cheung <[email protected]>
1 parent 816c46c commit 089dcc9

File tree

7 files changed

+210
-38
lines changed

7 files changed

+210
-38
lines changed

src/llscan.cc

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,10 @@ void FindReferencesCmd::PrintReferences(SBCommandReturnObject& result,
612612
// "\n", type, addr);
613613
}
614614
}
615+
616+
// Print references found directly inside Context objects
617+
Error err;
618+
scanner->PrintContextRefs(result, err);
615619
}
616620

617621

@@ -668,6 +672,39 @@ char** FindReferencesCmd::ParseScanOptions(char** cmd, ScanType* type) {
668672
return &cmd[optind - 1];
669673
}
670674

675+
// Walk all contexts previously stored and print search_value_
676+
// reference if it exists. Not all values are associated with
677+
// a context object. It seems that Function-Local variables are
678+
// stored in the stack, and when some nested closure references
679+
// it is allocated in a Context object.
680+
void FindReferencesCmd::ReferenceScanner::PrintContextRefs(
681+
SBCommandReturnObject& result, Error& err) {
682+
ContextVector* contexts = llscan_->GetContexts();
683+
v8::LLV8* v8 = llscan_->v8();
684+
685+
for (auto ctx : *contexts) {
686+
Error err;
687+
v8::HeapObject context_obj(v8, ctx);
688+
v8::Context c(context_obj);
689+
690+
v8::Context::Locals locals(&c, err);
691+
if (err.Fail()) return;
692+
693+
for (v8::Context::Locals::Iterator it = locals.begin(); it != locals.end();
694+
it++) {
695+
if ((*it).raw() == search_value_.raw()) {
696+
v8::String _name = it.LocalName(err);
697+
if (err.Fail()) return;
698+
699+
std::string name = _name.ToString(err);
700+
if (err.Fail()) return;
701+
702+
result.Printf("0x%" PRIx64 ": Context.%s=0x%" PRIx64 "\n", c.raw(),
703+
name.c_str(), search_value_.raw());
704+
}
705+
}
706+
}
707+
}
671708

672709
void FindReferencesCmd::ReferenceScanner::PrintRefs(
673710
SBCommandReturnObject& result, v8::JSObject& js_obj, Error& err) {
@@ -1193,6 +1230,20 @@ uint64_t FindJSObjectsVisitor::Visit(uint64_t location, uint64_t word) {
11931230
v8::HeapObject heap_object(v8_value);
11941231
if (!heap_object.Check()) return address_byte_size_;
11951232

1233+
bool is_context = v8::Context::IsContext(llscan_->v8(), heap_object, err);
1234+
if (err.Fail()) {
1235+
return address_byte_size_;
1236+
}
1237+
1238+
if (is_context) {
1239+
ContextVector* contexts;
1240+
contexts = llscan_->GetContexts();
1241+
1242+
if (std::find(contexts->begin(), contexts->end(), word) == contexts->end())
1243+
contexts->push_back(word);
1244+
return address_byte_size_;
1245+
}
1246+
11961247
v8::HeapObject map_object = heap_object.GetMap(err);
11971248
if (err.Fail() || !map_object.Check()) return address_byte_size_;
11981249

src/llscan.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ namespace llnode {
1313
class LLScan;
1414

1515
typedef std::vector<uint64_t> ReferencesVector;
16+
typedef std::vector<uint64_t> ContextVector;
1617

1718
typedef std::map<uint64_t, ReferencesVector*> ReferencesByValueMap;
1819
typedef std::map<std::string, ReferencesVector*> ReferencesByPropertyMap;
@@ -89,6 +90,9 @@ class FindReferencesCmd : public CommandBase {
8990
virtual void PrintRefs(lldb::SBCommandReturnObject& result, v8::String& str,
9091
Error& err) {}
9192

93+
virtual void PrintContextRefs(lldb::SBCommandReturnObject& result,
94+
Error& err) {}
95+
9296
static const char* const property_reference_template;
9397
static const char* const array_reference_template;
9498
};
@@ -115,6 +119,9 @@ class FindReferencesCmd : public CommandBase {
115119
void PrintRefs(lldb::SBCommandReturnObject& result, v8::String& str,
116120
Error& err) override;
117121

122+
void PrintContextRefs(lldb::SBCommandReturnObject& result,
123+
Error& err) override;
124+
118125
private:
119126
LLScan* llscan_;
120127
v8::Value search_value_;
@@ -315,6 +322,7 @@ class LLScan {
315322
return references_by_value_[address];
316323
};
317324

325+
// References By Property
318326
inline bool AreReferencesByPropertyLoaded() {
319327
return references_by_property_.size() > 0;
320328
};
@@ -325,6 +333,7 @@ class LLScan {
325333
return references_by_property_[property];
326334
};
327335

336+
// References By String
328337
inline bool AreReferencesByStringLoaded() {
329338
return references_by_string_.size() > 0;
330339
};
@@ -335,6 +344,10 @@ class LLScan {
335344
return references_by_string_[string_value];
336345
};
337346

347+
// Contexts
348+
inline bool AreContextsLoaded() { return contexts_.size() > 0; };
349+
inline ContextVector* GetContexts() { return &contexts_; }
350+
338351
v8::LLV8* llv8_;
339352

340353
private:
@@ -362,6 +375,7 @@ class LLScan {
362375
ReferencesByValueMap references_by_value_;
363376
ReferencesByPropertyMap references_by_property_;
364377
ReferencesByStringMap references_by_string_;
378+
ContextVector contexts_;
365379
};
366380

367381
} // namespace llnode

src/llv8-inl.h

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,15 @@ inline bool Map::IsJSObjectMap(Error& err) {
167167
return InstanceType(err) >= v8()->types()->kFirstJSObjectType;
168168
}
169169

170+
inline bool Context::IsContext(LLV8* v8, HeapObject heap_object, Error& err) {
171+
if (!heap_object.Check()) return false;
172+
173+
int64_t type = heap_object.GetType(err);
174+
if (err.Fail()) return false;
175+
176+
return type >= v8->types()->kFirstContextType &&
177+
type <= v8->types()->kLastContextType;
178+
}
170179

171180
inline int64_t Map::InObjectProperties(Error& err) {
172181
if (!IsJSObjectMap(err)) {
@@ -261,7 +270,6 @@ ACCESSOR(SharedFunctionInfo, scope_info, shared_info()->kScopeInfoOffset,
261270
ACCESSOR(SharedFunctionInfo, name_or_scope_info,
262271
shared_info()->kNameOrScopeInfoOffset, HeapObject)
263272

264-
265273
HeapObject SharedFunctionInfo::GetScopeInfo(Error& err) {
266274
if (v8()->shared_info()->kNameOrScopeInfoOffset == -1) return scope_info(err);
267275

@@ -580,6 +588,19 @@ inline T Context::GetEmbedderData(int64_t index, Error& err) {
580588
return embedder_data.Get<T>(index, err);
581589
}
582590

591+
HeapObject Context::GetScopeInfo(Error& err) {
592+
if (v8()->context()->kScopeInfoIndex != -1) {
593+
return FixedArray::Get<HeapObject>(v8()->context()->kScopeInfoIndex, err);
594+
}
595+
JSFunction closure = Closure(err);
596+
if (err.Fail()) return HeapObject();
597+
598+
SharedFunctionInfo info = closure.Info(err);
599+
if (err.Fail()) return HeapObject();
600+
601+
return info.GetScopeInfo(err);
602+
}
603+
583604
inline Value Context::ContextSlot(int index, Error& err) {
584605
return FixedArray::Get<Value>(v8()->context()->kMinContextSlots + index, err);
585606
}

src/llv8.cc

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -876,6 +876,10 @@ std::string HeapObject::GetTypeName(Error& err) {
876876
if (type == v8()->types()->kMapType) {
877877
return "(Map)";
878878
}
879+
if (type >= v8()->types()->kFirstContextType &&
880+
type <= v8()->types()->kLastContextType) {
881+
return "Context";
882+
}
879883

880884
if (JSObject::IsObjectType(v8(), type)) {
881885
v8::HeapObject map_obj = GetMap(err);
@@ -1058,17 +1062,43 @@ std::string FixedArray::InspectContents(int length, Error& err) {
10581062
return res;
10591063
}
10601064

1061-
HeapObject Context::GetScopeInfo(Error& err) {
1062-
if (v8()->context()->kScopeInfoIndex != -1) {
1063-
return FixedArray::Get<HeapObject>(v8()->context()->kScopeInfoIndex, err);
1064-
}
1065-
JSFunction closure = Closure(err);
1066-
if (err.Fail()) return HeapObject();
1065+
// Context locals iterator implementations
1066+
Context::Locals::Locals(Context* context, Error& err) {
1067+
context_ = context;
1068+
HeapObject scope_obj = context_->GetScopeInfo(err);
1069+
if (err.Fail()) return;
1070+
1071+
scope_info_ = ScopeInfo(scope_obj);
1072+
Smi param_count_smi = scope_info_.ParameterCount(err);
1073+
if (err.Fail()) return;
1074+
Smi stack_count_smi = scope_info_.StackLocalCount(err);
1075+
if (err.Fail()) return;
1076+
Smi local_count_smi = scope_info_.ContextLocalCount(err);
1077+
if (err.Fail()) return;
1078+
1079+
param_count_ = param_count_smi.GetValue();
1080+
stack_count_ = stack_count_smi.GetValue();
1081+
local_count_ = local_count_smi.GetValue();
1082+
}
10671083

1068-
SharedFunctionInfo info = closure.Info(err);
1069-
if (err.Fail()) return HeapObject();
1084+
Context::Locals::Iterator Context::Locals::begin() { return Iterator(0, this); }
10701085

1071-
return info.GetScopeInfo(err);
1086+
Context::Locals::Iterator Context::Locals::end() {
1087+
return Iterator(local_count_, this);
1088+
}
1089+
1090+
const Context::Locals::Iterator Context::Locals::Iterator::operator++(int) {
1091+
current_++;
1092+
return Iterator(current_, this->outer_);
1093+
}
1094+
1095+
bool Context::Locals::Iterator::operator!=(Context::Locals::Iterator that) {
1096+
return current_ != that.current_ || outer_->context_ != that.outer_->context_;
1097+
}
1098+
1099+
v8::Value Context::Locals::Iterator::operator*() {
1100+
Error err;
1101+
return outer_->context_->ContextSlot(current_, err);
10721102
}
10731103

10741104
std::string Context::Inspect(InspectOptions* options, Error& err) {
@@ -1093,13 +1123,6 @@ std::string Context::Inspect(InspectOptions* options, Error& err) {
10931123

10941124
ScopeInfo scope(scope_obj);
10951125

1096-
Smi param_count_smi = scope.ParameterCount(err);
1097-
if (err.Fail()) return std::string();
1098-
Smi stack_count_smi = scope.StackLocalCount(err);
1099-
if (err.Fail()) return std::string();
1100-
Smi local_count_smi = scope.ContextLocalCount(err);
1101-
if (err.Fail()) return std::string();
1102-
11031126
HeapObject heap_previous = HeapObject(previous);
11041127
if (heap_previous.Check()) {
11051128
char tmp[128];
@@ -1145,19 +1168,19 @@ std::string Context::Inspect(InspectOptions* options, Error& err) {
11451168
res += ">";
11461169
}
11471170

1148-
int param_count = param_count_smi.GetValue();
1149-
int stack_count = stack_count_smi.GetValue();
1150-
int local_count = local_count_smi.GetValue();
1151-
for (int i = 0; i < local_count; i++) {
1152-
String name = scope.ContextLocalName(i, param_count, stack_count, err);
1171+
Context::Locals locals(this, err);
1172+
if (err.Fail()) return std::string();
1173+
for (v8::Context::Locals::Iterator it = locals.begin(); it != locals.end();
1174+
it++) {
1175+
String name = it.LocalName(err);
11531176
if (err.Fail()) return std::string();
11541177

11551178
if (!res.empty()) res += ",\n";
11561179

11571180
res += options->get_indent_spaces() + name.ToString(err) + "=";
11581181
if (err.Fail()) return std::string();
11591182

1160-
Value value = ContextSlot(i, err);
1183+
Value value = it.GetValue(err);
11611184
if (err.Fail()) return std::string();
11621185

11631186
InspectOptions val_options;

src/llv8.h

Lines changed: 53 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,19 @@ class NameDictionary : public FixedArray {
384384
inline int64_t Length(Error& err);
385385
};
386386

387+
class ScopeInfo : public FixedArray {
388+
public:
389+
V8_VALUE_DEFAULT_METHODS(ScopeInfo, FixedArray)
390+
391+
inline Smi ParameterCount(Error& err);
392+
inline Smi StackLocalCount(Error& err);
393+
inline Smi ContextLocalCount(Error& err);
394+
395+
inline String ContextLocalName(int index, int param_count, int stack_count,
396+
Error& err);
397+
inline HeapObject MaybeFunctionName(Error& err);
398+
};
399+
387400
class Context : public FixedArray {
388401
public:
389402
V8_VALUE_DEFAULT_METHODS(Context, FixedArray)
@@ -397,23 +410,51 @@ class Context : public FixedArray {
397410
inline Value ContextSlot(int index, Error& err);
398411

399412
std::string Inspect(InspectOptions* options, Error& err);
413+
static inline bool IsContext(LLV8* v8, HeapObject heap_object, Error& err);
414+
415+
// Iterator class to walk all local references on a context
416+
class Locals {
417+
public:
418+
class Iterator {
419+
public:
420+
Value operator*();
421+
const Context::Locals::Iterator operator++(int);
422+
bool operator!=(Context::Locals::Iterator that);
423+
424+
inline Iterator(int current, Locals* outer)
425+
: current_(current), outer_(outer){};
426+
427+
String LocalName(Error& err) {
428+
return outer_->scope_info_.ContextLocalName(
429+
current_, outer_->param_count_, outer_->stack_count_, err);
430+
}
431+
432+
Value GetValue(Error& err) {
433+
return outer_->context_->ContextSlot(current_, err);
434+
}
435+
436+
private:
437+
int current_;
438+
Locals* outer_;
439+
};
440+
441+
Locals(Context* context, Error& err);
442+
443+
Iterator begin();
444+
Iterator end();
445+
446+
private:
447+
int local_count_;
448+
int param_count_;
449+
int stack_count_;
450+
Context* context_;
451+
ScopeInfo scope_info_;
452+
};
400453

401454
private:
402455
inline JSFunction Closure(Error& err);
403456
};
404457

405-
class ScopeInfo : public FixedArray {
406-
public:
407-
V8_VALUE_DEFAULT_METHODS(ScopeInfo, FixedArray)
408-
409-
inline Smi ParameterCount(Error& err);
410-
inline Smi StackLocalCount(Error& err);
411-
inline Smi ContextLocalCount(Error& err);
412-
413-
inline String ContextLocalName(int index, int param_count, int stack_count,
414-
Error& err);
415-
inline HeapObject MaybeFunctionName(Error& err);
416-
};
417458

418459
class Oddball : public HeapObject {
419460
public:

test/common.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ else
3333
exports.llnodePath = path.join(exports.projectDir, pluginName);
3434
exports.saveCoreTimeout = 360 * 1000;
3535
exports.loadCoreTimeout = 60 * 1000;
36-
exports.versionMark = /^lldb-|^lldb version/;
36+
37+
let versionMark = /^lldb-|^lldb version/;
38+
exports.versionMark = versionMark;
3739

3840
function SessionOutput(session, stream, timeout) {
3941
EventEmitter.call(this);
@@ -316,6 +318,20 @@ Session.prototype.send = function send(line, callback) {
316318
this.lldb.stdin.write(line + '\n', callback);
317319
};
318320

321+
Session.prototype.hasSymbol = function hasSymbol(symbol, callback) {
322+
this.send('target modules dump symtab');
323+
this.send('version');
324+
325+
let pattern = new RegExp(symbol);
326+
this.linesUntil(versionMark, (err, lines) => {
327+
if(pattern.test(lines.join('\n'))) {
328+
callback(err, true);
329+
} else {
330+
return callback(err, false);
331+
}
332+
});
333+
}
334+
319335
exports.generateRanges = function generateRanges(core, dest, cb) {
320336
let script;
321337
if (process.platform === 'darwin')

0 commit comments

Comments
 (0)