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
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
@@ -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;
}
}
16 changes: 16 additions & 0 deletions src/llscan.cc
Original file line number Diff line number Diff line change
@@ -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.
}
@@ -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.
}
5 changes: 5 additions & 0 deletions src/llv8-constants.cc
Original file line number Diff line number Diff line change
@@ -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");
}
@@ -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");
@@ -518,6 +522,7 @@ void Frame::Load() {
kConstructFrame = LoadConstant("frametype_ConstructFrame");
kJSFrame = LoadConstant("frametype_JavaScriptFrame");
kOptimizedFrame = LoadConstant("frametype_OptimizedFrame");
kStubFrame = LoadConstant("frametype_StubFrame");
}


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

int64_t kLengthOffset;

@@ -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);
@@ -441,6 +452,7 @@ class Frame : public Module {
int64_t kConstructFrame;
int64_t kJSFrame;
int64_t kOptimizedFrame;
int64_t kStubFrame;

protected:
void Load();
12 changes: 12 additions & 0 deletions src/llv8-inl.h
Original file line number Diff line number Diff line change
@@ -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) {
@@ -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);
}
21 changes: 14 additions & 7 deletions src/llv8.cc
Original file line number Diff line number Diff line change
@@ -2,7 +2,6 @@

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

#include "llv8-inl.h"
#include "llv8.h"
@@ -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);
@@ -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;
@@ -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");
@@ -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();
}
@@ -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) {
@@ -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;
12 changes: 11 additions & 1 deletion src/llv8.h
Original file line number Diff line number Diff line change
@@ -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)
@@ -405,7 +414,6 @@ class JSArrayBuffer : public HeapObject {
inline bool WasNeutered(Error& err);

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

};

class JSArrayBufferView : public HeapObject {
@@ -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;
@@ -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;
10 changes: 10 additions & 0 deletions test/fixtures/inspect-scenario.js
Original file line number Diff line number Diff line change
@@ -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() {
@@ -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(
2 changes: 1 addition & 1 deletion test/frame-test.js
Original file line number Diff line number Diff line change
@@ -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];
15 changes: 15 additions & 0 deletions test/inspect-test.js
Original file line number Diff line number Diff line change
@@ -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;
@@ -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}`);
});
@@ -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}`);
});