Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

src: support thin strings and stub frames #121

Merged
merged 2 commits into from
Aug 22, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/llnode.cc
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,8 @@ bool BacktraceCmd::DoExecute(SBDebugger d, char** cmd,
lldb::SBMemoryRegionInfo info;
if (target.GetProcess().GetMemoryRegionInfo(pc, info).Success() &&
info.IsExecutable() && info.IsWritable()) {
result.Printf(" %c frame #%u: 0x%016" PRIx64 " <builtin>\n", star, i, pc);
result.Printf(" %c frame #%u: 0x%016" PRIx64 " <builtin>\n", star, i,
pc);
continue;
}
}
Expand Down
16 changes: 16 additions & 0 deletions src/llscan.cc
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,14 @@ void FindReferencesCmd::ReferenceScanner::PrintRefs(
result.Printf("0x%" PRIx64 ": %s.%s=0x%" PRIx64 "\n", str.raw(),
type_name.c_str(), "<Second>", search_value_.raw());
}
} else if (repr == v8->string()->kThinStringTag) {
v8::ThinString thin_str(str);
v8::String actual = thin_str.Actual(err);
if (err.Success() && actual.raw() == search_value_.raw()) {
std::string type_name = thin_str.GetTypeName(err);
result.Printf("0x%" PRIx64 ": %s.%s=0x%" PRIx64 "\n", str.raw(),
type_name.c_str(), "<Actual>", search_value_.raw());
}
}
// Nothing to do for other kinds of string.
}
Expand Down Expand Up @@ -694,6 +702,14 @@ void FindReferencesCmd::ReferenceScanner::ScanRefs(v8::String& str,
references = llscan.GetReferencesByValue(second.raw());
references->push_back(str.raw());
}
} else if (repr == v8->string()->kThinStringTag) {
v8::ThinString thin_str(str);
v8::String actual = thin_str.Actual(err);

if (err.Success()) {
references = llscan.GetReferencesByValue(actual.raw());
references->push_back(str.raw());
}
}
// Nothing to do for other kinds of string.
}
Expand Down
5 changes: 5 additions & 0 deletions src/llv8-constants.cc
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ void String::Load() {
kConsStringTag = LoadConstant("ConsStringTag");
kSlicedStringTag = LoadConstant("SlicedStringTag");
kExternalStringTag = LoadConstant("ExternalStringTag");
kThinStringTag = LoadConstant("ThinStringTag");

kLengthOffset = LoadConstant("class_String__length__SMI");
}
Expand Down Expand Up @@ -362,6 +363,9 @@ void SlicedString::Load() {
kOffsetOffset = LoadConstant("class_SlicedString__offset__SMI");
}

void ThinString::Load() {
kActualOffset = LoadConstant("class_ThinString__actual__String");
}

void FixedArrayBase::Load() {
kLengthOffset = LoadConstant("class_FixedArrayBase__length__SMI");
Expand Down Expand Up @@ -518,6 +522,7 @@ void Frame::Load() {
kConstructFrame = LoadConstant("frametype_ConstructFrame");
kJSFrame = LoadConstant("frametype_JavaScriptFrame");
kOptimizedFrame = LoadConstant("frametype_OptimizedFrame");
kStubFrame = LoadConstant("frametype_StubFrame");
}


Expand Down
12 changes: 12 additions & 0 deletions src/llv8-constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ class String : public Module {
int64_t kConsStringTag;
int64_t kSlicedStringTag;
int64_t kExternalStringTag;
int64_t kThinStringTag;

int64_t kLengthOffset;

Expand Down Expand Up @@ -297,6 +298,16 @@ class SlicedString : public Module {
void Load();
};

class ThinString : public Module {
public:
MODULE_DEFAULT_METHODS(ThinString);

int64_t kActualOffset;

protected:
void Load();
};

class FixedArrayBase : public Module {
public:
MODULE_DEFAULT_METHODS(FixedArrayBase);
Expand Down Expand Up @@ -441,6 +452,7 @@ class Frame : public Module {
int64_t kConstructFrame;
int64_t kJSFrame;
int64_t kOptimizedFrame;
int64_t kStubFrame;

protected:
void Load();
Expand Down
12 changes: 12 additions & 0 deletions src/llv8-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,8 @@ ACCESSOR(ConsString, Second, cons_string()->kSecondOffset, String);
ACCESSOR(SlicedString, Parent, sliced_string()->kParentOffset, String);
ACCESSOR(SlicedString, Offset, sliced_string()->kOffsetOffset, Smi);

ACCESSOR(ThinString, Actual, thin_string()->kActualOffset, String);

ACCESSOR(FixedArrayBase, Length, fixed_array_base()->kLengthOffset, Smi);

inline std::string OneByteString::ToString(Error& err) {
Expand Down Expand Up @@ -319,6 +321,16 @@ inline std::string SlicedString::ToString(Error& err) {
return tmp.substr(offset.GetValue(), length.GetValue());
}

inline std::string ThinString::ToString(Error& err) {
String actual = Actual(err);
if (err.Fail()) return std::string();

std::string tmp = actual.ToString(err);
if (err.Fail()) return std::string();

return tmp;
}

inline int64_t FixedArray::LeaData() const {
return LeaField(v8()->fixed_array()->kDataOffset);
}
Expand Down
21 changes: 14 additions & 7 deletions src/llv8.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

#include <algorithm>
#include <cinttypes>
#include <algorithm>

#include "llv8-inl.h"
#include "llv8.h"
Expand Down Expand Up @@ -43,6 +42,7 @@ void LLV8::Load(SBTarget target) {
two_byte_string.Assign(target, &common);
cons_string.Assign(target, &common);
sliced_string.Assign(target, &common);
thin_string.Assign(target, &common);
fixed_array_base.Assign(target, &common);
fixed_array.Assign(target, &common);
oddball.Assign(target, &common);
Expand Down Expand Up @@ -90,8 +90,7 @@ double LLV8::LoadDouble(int64_t addr, Error& err) {
std::string LLV8::LoadBytes(int64_t length, int64_t addr, Error& err) {
uint8_t* buf = new uint8_t[length + 1];
SBError sberr;
process_.ReadMemory(addr, buf,
static_cast<size_t>(length), sberr);
process_.ReadMemory(addr, buf, static_cast<size_t>(length), sberr);
if (sberr.Fail()) {
err = Error::Failure("Failed to load V8 raw buffer");
delete[] buf;
Expand Down Expand Up @@ -268,6 +267,8 @@ std::string JSFrame::Inspect(bool with_args, Error& err) {
return "<internal>";
} else if (value == v8()->frame()->kConstructFrame) {
return "<constructor>";
} else if (value == v8()->frame()->kStubFrame) {
return "<stub>";
} else if (value != v8()->frame()->kJSFrame &&
value != v8()->frame()->kOptimizedFrame) {
err = Error::Failure("Unknown frame marker");
Expand Down Expand Up @@ -957,6 +958,11 @@ std::string String::ToString(Error& err) {
return std::string("(external)");
}

if (repr == v8()->string()->kThinStringTag) {
ThinString thin(this);
return thin.ToString(err);
}

err = Error::Failure("Unsupported string representation");
return std::string();
}
Expand Down Expand Up @@ -1111,9 +1117,9 @@ std::string JSArrayBuffer::Inspect(InspectOptions* options, Error& err) {

char tmp[128];
snprintf(tmp, sizeof(tmp),
"<ArrayBuffer: backingStore=0x%016" PRIx64 ", byteLength=%d",
data, byte_length);
"<ArrayBuffer: backingStore=0x%016" PRIx64 ", byteLength=%d", data,
byte_length);

std::string res;
res += tmp;
if (options->detailed) {
Expand Down Expand Up @@ -1156,7 +1162,8 @@ std::string JSArrayBufferView::Inspect(InspectOptions* options, Error& err) {
int byte_offset = static_cast<int>(off.GetValue());
char tmp[128];
snprintf(tmp, sizeof(tmp),
"<ArrayBufferView: backingStore=0x%016" PRIx64 ", byteOffset=%d, byteLength=%d",
"<ArrayBufferView: backingStore=0x%016" PRIx64
", byteOffset=%d, byteLength=%d",
data, byte_offset, byte_length);

std::string res;
Expand Down
12 changes: 11 additions & 1 deletion src/llv8.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,15 @@ class SlicedString : public String {
inline std::string ToString(Error& err);
};

class ThinString : public String {
public:
V8_VALUE_DEFAULT_METHODS(ThinString, String)

inline String Actual(Error& err);

inline std::string ToString(Error& err);
};

class HeapNumber : public HeapObject {
public:
V8_VALUE_DEFAULT_METHODS(HeapNumber, HeapObject)
Expand Down Expand Up @@ -405,7 +414,6 @@ class JSArrayBuffer : public HeapObject {
inline bool WasNeutered(Error& err);

std::string Inspect(InspectOptions* options, Error& err);

};

class JSArrayBufferView : public HeapObject {
Expand Down Expand Up @@ -477,6 +485,7 @@ class LLV8 {
constants::TwoByteString two_byte_string;
constants::ConsString cons_string;
constants::SlicedString sliced_string;
constants::ThinString thin_string;
constants::FixedArrayBase fixed_array_base;
constants::FixedArray fixed_array;
constants::Oddball oddball;
Expand All @@ -503,6 +512,7 @@ class LLV8 {
friend class TwoByteString;
friend class ConsString;
friend class SlicedString;
friend class ThinString;
friend class HeapNumber;
friend class JSObject;
friend class JSArray;
Expand Down
10 changes: 10 additions & 0 deletions test/fixtures/inspect-scenario.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ let outerVar = 'outer variable';

exports.holder = {};

function makeThin(a, b) {
var str = a + b;
var obj = {};
obj[str]; // Turn the cons string into a thin string.
return str;
}

function closure() {

function Class() {
Expand All @@ -28,6 +35,9 @@ function closure() {
c.hashmap['cons-string'] =
'this could be a bit smaller, but v8 wants big str.';
c.hashmap['cons-string'] += c.hashmap['cons-string'];
c.hashmap['internalized-string'] = 'foobar';
// This thin string points to the previous 'foobar'.
c.hashmap['thin-string'] = makeThin('foo', 'bar');
c.hashmap['array'] = [true, 1, undefined, null, 'test', Class];
c.hashmap['long-array'] = new Array(20).fill(5);
c.hashmap['array-buffer'] = new Uint8Array(
Expand Down
2 changes: 1 addition & 1 deletion test/frame-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ tape('v8 stack', (t) => {
// FIXME(bnoordhuis) This can fail with versions of lldb that don't
// support the GetMemoryRegions() API; llnode won't be able to identify
// V8 builtins stack frames, it just prints them as anonymous frames.
lines = lines.filter((s) => !/<builtin>/.test(s));
lines = lines.filter((s) => !/<builtin>|<stub>/.test(s));
const eyecatcher = lines[0];
const adapter = lines[1];
const crasher = lines[2];
Expand Down
15 changes: 15 additions & 0 deletions test/inspect-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ tape('v8 inspect', (t) => {

let regexp = null;
let cons = null;
let thin = null;
let arrowFunc = null;
let array = null;
let longArray = null;
Expand Down Expand Up @@ -112,6 +113,11 @@ tape('v8 inspect', (t) => {
t.ok(consMatch, '.cons-string ConsString property');
cons = consMatch[1];

const thinMatch = lines.match(
/.thin-string=(0x[0-9a-f]+):<String: "foobar">/);
t.ok(thinMatch, '.thin-string ThinString property');
thin = thinMatch[1];

sess.send(`v8 inspect ${regexp}`);
sess.send(`v8 inspect -F ${cons}`);
});
Expand Down Expand Up @@ -141,6 +147,15 @@ tape('v8 inspect', (t) => {
-1,
'--string-length truncates the string');

sess.send(`v8 inspect ${thin}`);
});

sess.linesUntil(/">/, (lines) => {
lines = lines.join('\n');
t.ok(
/0x[0-9a-f]+:<String: "foobar">/.test(lines),
'thin string content');

sess.send(`v8 inspect ${array}`);
});

Expand Down