Skip to content

Commit

Permalink
src, test: support reading contents from buffers
Browse files Browse the repository at this point in the history
Fixes: nodejs#89
PR-URL: nodejs#116
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
  • Loading branch information
hhellyer authored Aug 14, 2017
2 parents f3147ef + ca670cd commit 75c6e9a
Show file tree
Hide file tree
Showing 4 changed files with 190 additions and 16 deletions.
83 changes: 71 additions & 12 deletions src/llv8.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

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

#include "llv8-inl.h"
#include "llv8.h"
Expand Down Expand Up @@ -86,6 +87,27 @@ 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);
if (sberr.Fail()) {
err = Error::Failure("Failed to load V8 raw buffer");
delete[] buf;
return std::string();
}

std::string res;
char tmp[10];
for (int i = 0; i < length; ++i) {
snprintf(tmp, sizeof(tmp), "%s%02x", (i == 0 ? "" : ", "), buf[i]);
res += tmp;
}
delete[] buf;
return res;
}

std::string LLV8::LoadString(int64_t addr, int64_t length, Error& err) {
if (length < 0) {
err = Error::Failure("Failed to load V8 one byte string - Invalid length");
Expand Down Expand Up @@ -775,12 +797,12 @@ std::string HeapObject::Inspect(InspectOptions* options, Error& err) {

if (type == v8()->types()->kJSArrayBufferType) {
JSArrayBuffer buf(this);
return pre + buf.Inspect(err);
return pre + buf.Inspect(options, err);
}

if (type == v8()->types()->kJSTypedArrayType) {
JSArrayBufferView view(this);
return pre + view.Inspect(err);
return pre + view.Inspect(options, err);
}

if (type == v8()->types()->kJSDateType) {
Expand Down Expand Up @@ -1073,8 +1095,7 @@ std::string Oddball::Inspect(Error& err) {
return "<Oddball>";
}


std::string JSArrayBuffer::Inspect(Error& err) {
std::string JSArrayBuffer::Inspect(InspectOptions* options, Error& err) {
bool neutered = WasNeutered(err);
if (err.Fail()) return std::string();

Expand All @@ -1086,14 +1107,34 @@ std::string JSArrayBuffer::Inspect(Error& err) {
Smi length = ByteLength(err);
if (err.Fail()) return std::string();

int byte_length = static_cast<int>(length.GetValue());

char tmp[128];
snprintf(tmp, sizeof(tmp), "<ArrayBuffer 0x%016" PRIx64 ":%d>", data,
static_cast<int>(length.GetValue()));
return tmp;
snprintf(tmp, sizeof(tmp),
"<ArrayBuffer: backingStore=0x%016" PRIx64 ", byteLength=%d",
data, byte_length);

std::string res;
res += tmp;
if (options->detailed) {
res += ": [\n ";

int display_length = std::min<int>(byte_length, options->array_length);
res += v8()->LoadBytes(display_length, data, err);

if (display_length < byte_length) {
res += " ...";
}
res += "\n]>";
} else {
res += ">";
}

return res;
}


std::string JSArrayBufferView::Inspect(Error& err) {
std::string JSArrayBufferView::Inspect(InspectOptions* options, Error& err) {
JSArrayBuffer buf = Buffer(err);
if (err.Fail()) return std::string();

Expand All @@ -1111,11 +1152,29 @@ std::string JSArrayBufferView::Inspect(Error& err) {
Smi length = ByteLength(err);
if (err.Fail()) return std::string();

int byte_length = static_cast<int>(length.GetValue());
int byte_offset = static_cast<int>(off.GetValue());
char tmp[128];
snprintf(tmp, sizeof(tmp), "<ArrayBufferView 0x%016" PRIx64 "+%d:%d>", data,
static_cast<int>(off.GetValue()),
static_cast<int>(length.GetValue()));
return tmp;
snprintf(tmp, sizeof(tmp),
"<ArrayBufferView: backingStore=0x%016" PRIx64 ", byteOffset=%d, byteLength=%d",
data, byte_offset, byte_length);

std::string res;
res += tmp;
if (options->detailed) {
res += ": [\n ";

int display_length = std::min<int>(byte_length, options->array_length);
res += v8()->LoadBytes(display_length, data + byte_offset, err);

if (display_length < byte_length) {
res += " ...";
}
res += "\n]>";
} else {
res += ">";
}
return res;
}


Expand Down
6 changes: 4 additions & 2 deletions src/llv8.h
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,8 @@ class JSArrayBuffer : public HeapObject {

inline bool WasNeutered(Error& err);

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

};

class JSArrayBufferView : public HeapObject {
Expand All @@ -415,7 +416,7 @@ class JSArrayBufferView : public HeapObject {
inline Smi ByteOffset(Error& err);
inline Smi ByteLength(Error& err);

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

class JSFrame : public Value {
Expand Down Expand Up @@ -450,6 +451,7 @@ class LLV8 {
int64_t LoadConstant(const char* name);
int64_t LoadPtr(int64_t addr, Error& err);
double LoadDouble(int64_t addr, Error& err);
std::string LoadBytes(int64_t length, int64_t addr, Error& err);
std::string LoadString(int64_t addr, int64_t length, Error& err);
std::string LoadTwoByteString(int64_t addr, int64_t length, Error& err);
uint8_t* LoadChunk(int64_t addr, int64_t length, Error& err);
Expand Down
7 changes: 7 additions & 0 deletions test/fixtures/inspect-scenario.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ function closure() {
c.hashmap['cons-string'] += c.hashmap['cons-string'];
c.hashmap['array'] = [true, 1, undefined, null, 'test', Class];
c.hashmap['long-array'] = new Array(20).fill(5);
c.hashmap['array-buffer'] = new Uint8Array(
[0x01, 0x02, 0x03, 0x04, 0x05]
).buffer;
c.hashmap['uint8-array'] = new Uint8Array(
[0x01, 0x40, 0x60, 0x80, 0xf0, 0xff]
);
c.hashmap['buffer'] = Buffer.from([0xff, 0xf0, 0x80, 0x0f, 0x01, 0x00]);

c.hashmap[0] = null;
c.hashmap[4] = undefined;
Expand Down
110 changes: 108 additions & 2 deletions test/inspect-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ tape('v8 inspect', (t) => {
let arrowFunc = null;
let array = null;
let longArray = null;
let arrayBuffer = null;
let uint8Array = null;
let buffer = null;

sess.wait(/Object/, (line) => {
t.notEqual(line.indexOf(hashmap), -1, 'addr of `Object` should match');
Expand Down Expand Up @@ -84,6 +87,26 @@ tape('v8 inspect', (t) => {
t.ok(longArrayMatch, '.array JSArray property');
longArray = longArrayMatch[1];

const arrayBufferRe = new RegExp('.array-buffer=(0x[0-9a-f]+):' +
'<ArrayBuffer: backingStore=0x[0-9a-f]+, byteLength=5>');
const arrayBufferMatch = lines.match(arrayBufferRe);
t.ok(arrayBufferMatch, '.array-buffer JSArrayBuffer property');
arrayBuffer = arrayBufferMatch[1];

const uint8ArrayRe = new RegExp('.uint8-array=(0x[0-9a-f]+):' +
'<ArrayBufferView: backingStore=0x[0-9a-f]+, byteOffset=\\d+, ' +
'byteLength=6>');
const uint8ArrayMatch = lines.match(uint8ArrayRe);
t.ok(uint8ArrayMatch, '.uint8-array JSArrayBufferView property');
uint8Array = uint8ArrayMatch[1];

const bufferRe = new RegExp('.buffer=(0x[0-9a-f]+):' +
'<ArrayBufferView: backingStore=0x[0-9a-f]+, byteOffset=\\d+, ' +
'byteLength=6>');
const bufferMatch = lines.match(bufferRe);
t.ok(bufferMatch, '.buffer JSArrayBufferView property');
buffer = bufferMatch[1];

const consMatch = lines.match(
/.cons-string=(0x[0-9a-f]+):<String: "this could be a ...">/);
t.ok(consMatch, '.cons-string ConsString property');
Expand Down Expand Up @@ -139,12 +162,95 @@ tape('v8 inspect', (t) => {
lines.indexOf('<Array: length=20'),
-1,
'long array length');
t.ok(
lines.match(/\[9\]=<Smi: 5>}>$/),
'long array content');
sess.send(`v8 inspect ${arrayBuffer}`);
});

sess.linesUntil(/\]>/, (lines) => {
lines = lines.join('\n');
const re = new RegExp(
'0x[0-9a-f]+:' +
'<ArrayBuffer: backingStore=0x[0-9a-f]+, byteLength=5: \\[\n' +
' 01, 02, 03, 04, 05\n' +
']>');
t.ok(
lines.match(/\[9\]=<Smi: 5>}>$/),
'long array content');
re.test(lines),
'array buffer content');
sess.send(`v8 inspect --array-length 1 ${arrayBuffer}`);
});

sess.linesUntil(/]>/, (lines) => {
lines = lines.join('\n');
const re = new RegExp(
'0x[0-9a-f]+:' +
'<ArrayBuffer: backingStore=0x[0-9a-f]+, byteLength=5: \\[\n' +
' 01 ...\n' +
']>');
t.ok(
re.test(lines),
'array buffer content with maximum length 1');
sess.send(`v8 inspect ${uint8Array}`);
});

sess.linesUntil(/]>/, (lines) => {
lines = lines.join('\n');
const re = new RegExp(
'0x[0-9a-f]+:' +
'<ArrayBufferView: backingStore=0x[0-9a-f]+, byteOffset=\\d+, ' +
'byteLength=6: \\[\n' +
' 01, 40, 60, 80, f0, ff\n' +
']>');
t.ok(
re.test(lines),
'typed array content');
sess.send(`v8 inspect --array-length 1 ${uint8Array}`);
});

sess.linesUntil(/]>/, (lines) => {
lines = lines.join('\n');
const re = new RegExp(
'0x[0-9a-f]+:' +
'<ArrayBufferView: backingStore=0x[0-9a-f]+, byteOffset=\\d+, ' +
'byteLength=6: \\[\n' +
' 01 ...\n' +
']>');
t.ok(
re.test(lines),
'typed array content with maximum length 1');
sess.send(`v8 inspect ${buffer}`);
});

sess.linesUntil(/]>/, (lines) => {
lines = lines.join('\n');
const re = new RegExp(
'0x[0-9a-f]+:' +
'<ArrayBufferView: backingStore=0x[0-9a-f]+, byteOffset=\\d+, ' +
'byteLength=6: \\[\n' +
' ff, f0, 80, 0f, 01, 00\n' +
']>');
t.ok(
re.test(lines),
'buffer content');
sess.send(`v8 inspect --array-length 1 ${buffer}`);
});

sess.linesUntil(/]>/, (lines) => {
lines = lines.join('\n');
const re = new RegExp(
'0x[0-9a-f]+:' +
'<ArrayBufferView: backingStore=0x[0-9a-f]+, byteOffset=\\d+, ' +
'byteLength=6: \\[\n' +
' ff ...\n' +
']>');
t.ok(
re.test(lines),
'buffer content with maximum length 1');
sess.send(`v8 inspect -s ${arrowFunc}`);
});


sess.linesUntil(/^>/, (lines) => {
lines = lines.join('\n');
// Include 'source:' and '>' to act as boundaries. (Avoid
Expand Down

0 comments on commit 75c6e9a

Please sign in to comment.