Skip to content

Commit 4846299

Browse files
authoredDec 19, 2017
src: print more debug info when LLNODE_DEBUG=true
PR-URL: #151 Refs: nodejs/post-mortem#50 Reviewed-By: Ben Noordhuis <[email protected]>
1 parent 182e764 commit 4846299

File tree

7 files changed

+167
-54
lines changed

7 files changed

+167
-54
lines changed
 

‎Makefile

+28-7
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,53 @@
1+
TEST_LLDB_BINARY ?= $(shell which lldb-3.9)
2+
3+
.PHONY: all
14
all:
25
@echo "Please take a look at README.md"
36

7+
.PHONY: install-osx
48
install-osx:
59
mkdir -p ~/Library/Application\ Support/LLDB/PlugIns/
610
cp -rf ./out/Release/llnode.dylib \
711
~/Library/Application\ Support/LLDB/PlugIns/
812

13+
.PHONY: uninstall-osx
914
uninstall-osx:
1015
rm ~/Library/Application\ Support/LLDB/PlugIns/llnode.dylib
1116

17+
.PHONY: install-linux
1218
install-linux:
1319
mkdir -p /usr/lib/lldb/plugins
1420
cp -rf ./out/Release/lib.target/llnode.so /usr/lib/lldb/plugins
1521

22+
.PHONY: uninstall-linux
1623
uninstall-linux:
1724
rm /usr/lib/lldb/plugins/llnode.so
1825

26+
.PHONY: format
1927
format:
2028
clang-format -i src/*
2129

22-
configure: scripts/configure.js
30+
# This depends on the system setting e.g. $PATH so can't actually be skipped
31+
.PHONY: configure
32+
configure:
2333
node scripts/configure.js
34+
./gyp_llnode
2435

36+
.PHONY: plugin
2537
plugin: configure
26-
./gyp_llnode
2738
$(MAKE) -C out/
28-
29-
_travis: plugin
30-
TEST_LLDB_BINARY=`which lldb-3.9` TEST_LLNODE_DEBUG=true npm test
31-
32-
.PHONY: all
39+
node scripts/cleanup.js
40+
41+
.PHONY: _travis
42+
_travis:
43+
TEST_LLDB_BINARY="$(TEST_LLDB_BINARY)" \
44+
TEST_LLNODE_DEBUG=true \
45+
LLNODE_DEBUG=true \
46+
npm test
47+
48+
.PHONY: clean
49+
clean:
50+
$(RM) -r out
51+
$(RM) options.gypi
52+
$(RM) lldb
53+
$(RM) llnode.so llnode.dylib

‎package.json

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"url": "git+ssh://git@github.com/nodejs/llnode.git"
2222
},
2323
"files": [
24+
"Makefile",
2425
"llnode.gyp.json",
2526
"gyp_llnode",
2627
"common.gypi",

‎src/llnode.cc

+13
Original file line numberDiff line numberDiff line change
@@ -299,11 +299,24 @@ bool ListCmd::DoExecute(SBDebugger d, char** cmd,
299299
return true;
300300
}
301301

302+
303+
void InitDebugMode() {
304+
bool is_debug_mode = false;
305+
char* var = getenv("LLNODE_DEBUG");
306+
if (var != nullptr && strlen(var) != 0) {
307+
is_debug_mode = true;
308+
}
309+
310+
v8::Error::SetDebugMode(is_debug_mode);
311+
}
312+
302313
} // namespace llnode
303314

304315
namespace lldb {
305316

306317
bool PluginInitialize(SBDebugger d) {
318+
llnode::InitDebugMode();
319+
307320
SBCommandInterpreter interpreter = d.GetCommandInterpreter();
308321

309322
SBCommand v8 = interpreter.AddMultiwordCommand("v8", "Node.js helpers");

‎src/llv8-constants.cc

+17-16
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <stdlib.h>
22
#include <string.h>
33

4+
#include <cinttypes>
45
#include <string>
56

67
#include <lldb/API/SBExpressionOptions.h>
@@ -23,14 +24,6 @@ using lldb::addr_t;
2324

2425
static std::string kConstantPrefix = "v8dbg_";
2526

26-
static bool IsDebugMode() {
27-
char* var = getenv("LLNODE_DEBUG");
28-
if (var == nullptr) return false;
29-
30-
return strlen(var) != 0;
31-
}
32-
33-
3427
void Module::Assign(SBTarget target, Common* common) {
3528
loaded_ = false;
3629
target_ = target;
@@ -46,20 +39,20 @@ static int64_t LookupConstant(SBTarget target, const char* name, int64_t def,
4639

4740
SBSymbolContextList context_list = target.FindSymbols(name);
4841
if (!context_list.IsValid() || context_list.GetSize() == 0) {
49-
err = Error::Failure("Failed to find symbol");
42+
err = Error::Failure("Failed to find symbol %s", name);
5043
return res;
5144
}
5245

5346
SBSymbolContext context = context_list.GetContextAtIndex(0);
5447
SBSymbol symbol = context.GetSymbol();
5548
if (!symbol.IsValid()) {
56-
err = Error::Failure("Failed to fetch symbol");
49+
err = Error::Failure("Failed to fetch symbol %s", name);
5750
return res;
5851
}
5952

6053
SBAddress start = symbol.GetStartAddress();
6154
SBAddress end = symbol.GetEndAddress();
62-
size_t size = end.GetOffset() - start.GetOffset();
55+
uint32_t size = end.GetOffset() - start.GetOffset();
6356

6457
SBError sberr;
6558

@@ -79,12 +72,13 @@ static int64_t LookupConstant(SBTarget target, const char* name, int64_t def,
7972
int8_t tmp = process.ReadUnsignedFromMemory(addr, size, sberr);
8073
res = static_cast<int64_t>(tmp);
8174
} else {
82-
err = Error::Failure("Unexpected symbol size");
75+
err = Error::Failure("Unexpected symbol size %" PRIu32 " of symbol %s",
76+
size, name);
8377
return res;
8478
}
8579

8680
if (sberr.Fail())
87-
err = Error::Failure("Failed to load symbol");
81+
err = Error::Failure("Failed to load symbol %s", name);
8882
else
8983
err = Error::Ok();
9084

@@ -95,7 +89,9 @@ static int64_t LookupConstant(SBTarget target, const char* name, int64_t def,
9589
int64_t Module::LoadRawConstant(const char* name, int64_t def) {
9690
Error err;
9791
int64_t v = LookupConstant(target_, name, def, err);
98-
if (err.Fail() && IsDebugMode()) fprintf(stderr, "Failed to load %s\n", name);
92+
if (err.Fail()) {
93+
Error::PrintInDebugMode("Failed to load raw constant %s", name);
94+
}
9995

10096
return v;
10197
}
@@ -105,7 +101,9 @@ int64_t Module::LoadConstant(const char* name, int64_t def) {
105101
Error err;
106102
int64_t v =
107103
LookupConstant(target_, (kConstantPrefix + name).c_str(), def, err);
108-
if (err.Fail() && IsDebugMode()) fprintf(stderr, "Failed to load %s\n", name);
104+
if (err.Fail()) {
105+
Error::PrintInDebugMode("Failed to load constant %s", name);
106+
}
109107

110108
return v;
111109
}
@@ -118,7 +116,10 @@ int64_t Module::LoadConstant(const char* name, const char* fallback,
118116
LookupConstant(target_, (kConstantPrefix + name).c_str(), def, err);
119117
if (err.Fail())
120118
v = LookupConstant(target_, (kConstantPrefix + fallback).c_str(), def, err);
121-
if (err.Fail() && IsDebugMode()) fprintf(stderr, "Failed to load %s\n", name);
119+
if (err.Fail()) {
120+
Error::PrintInDebugMode("Failed to load constant %s, fallback %s", name,
121+
fallback);
122+
}
122123

123124
return v;
124125
}

‎src/llv8-inl.h

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#ifndef SRC_LLV8_INL_H_
22
#define SRC_LLV8_INL_H_
33

4+
#include <cinttypes>
45
#include "llv8.h"
56

67
namespace llnode {
@@ -19,7 +20,9 @@ inline T LLV8::LoadValue(int64_t addr, Error& err) {
1920

2021
T res = T(this, ptr);
2122
if (!res.Check()) {
22-
err = Error::Failure("Invalid value");
23+
// TODO(joyeecheung): use Error::Failure() to report information when
24+
// there is less noise from here.
25+
err = Error(true, "Invalid value");
2326
return T();
2427
}
2528

@@ -63,7 +66,8 @@ inline T HeapObject::LoadFieldValue(int64_t off, Error& err) {
6366
T res = v8()->LoadValue<T>(LeaField(off), err);
6467
if (err.Fail()) return T();
6568
if (!res.Check()) {
66-
err = Error::Failure("Invalid value");
69+
err = Error::Failure("Invalid field value %s at 0x%016" PRIx64,
70+
T::ClassName(), off);
6771
return T();
6872
}
6973

‎src/llv8.cc

+81-22
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include <algorithm>
44
#include <cinttypes>
5+
#include <cstdarg>
56

67
#include "llv8-inl.h"
78
#include "llv8.h"
@@ -57,14 +58,56 @@ void LLV8::Load(SBTarget target) {
5758
types.Assign(target, &common);
5859
}
5960

61+
bool Error::is_debug_mode = false;
62+
63+
Error::Error(bool failed, const char* format, ...) {
64+
failed_ = failed;
65+
char tmp[kMaxMessageLength];
66+
va_list arglist;
67+
va_start(arglist, format);
68+
vsnprintf(tmp, sizeof(tmp), format, arglist);
69+
va_end(arglist);
70+
msg_ = tmp;
71+
}
72+
73+
74+
void Error::PrintInDebugMode(const char* format, ...) {
75+
if (!is_debug_mode) {
76+
return;
77+
}
78+
char fmt[kMaxMessageLength];
79+
snprintf(fmt, sizeof(fmt), "[llv8] %s\n", format);
80+
va_list arglist;
81+
va_start(arglist, format);
82+
vfprintf(stderr, fmt, arglist);
83+
va_end(arglist);
84+
}
85+
86+
87+
Error Error::Failure(std::string msg) {
88+
PrintInDebugMode("%s", msg.c_str());
89+
return Error(true, msg);
90+
}
91+
92+
93+
Error Error::Failure(const char* format, ...) {
94+
char tmp[kMaxMessageLength];
95+
va_list arglist;
96+
va_start(arglist, format);
97+
vsnprintf(tmp, sizeof(tmp), format, arglist);
98+
va_end(arglist);
99+
return Error::Failure(std::string(tmp));
100+
}
101+
60102

61103
int64_t LLV8::LoadPtr(int64_t addr, Error& err) {
62104
SBError sberr;
63105
int64_t value =
64106
process_.ReadPointerFromMemory(static_cast<addr_t>(addr), sberr);
65107
if (sberr.Fail()) {
66-
// TODO(indutny): add more information
67-
err = Error::Failure("Failed to load V8 value");
108+
// TODO(joyeecheung): use Error::Failure() to report information when
109+
// there is less noise from here.
110+
err = Error(true, "Failed to load pointer from v8 memory");
68111
return -1;
69112
}
70113

@@ -79,8 +122,9 @@ int64_t LLV8::LoadUnsigned(int64_t addr, uint32_t byte_size, Error& err) {
79122
byte_size, sberr);
80123

81124
if (sberr.Fail()) {
82-
// TODO(indutny): add more information
83-
err = Error::Failure("Failed to load V8 value");
125+
// TODO(joyeecheung): use Error::Failure() to report information when
126+
// there is less noise from here.
127+
err = Error(true, "Failed to load unsigned from v8 memory");
84128
return -1;
85129
}
86130

@@ -94,8 +138,10 @@ double LLV8::LoadDouble(int64_t addr, Error& err) {
94138
int64_t value = process_.ReadUnsignedFromMemory(static_cast<addr_t>(addr),
95139
sizeof(double), sberr);
96140
if (sberr.Fail()) {
97-
// TODO(indutny): add more information
98-
err = Error::Failure("Failed to load V8 double value");
141+
err = Error::Failure(
142+
"Failed to load double from v8 memory, "
143+
"addr=0x%016" PRIx64,
144+
addr);
99145
return -1.0;
100146
}
101147

@@ -104,12 +150,15 @@ double LLV8::LoadDouble(int64_t addr, Error& err) {
104150
}
105151

106152

107-
std::string LLV8::LoadBytes(int64_t length, int64_t addr, Error& err) {
153+
std::string LLV8::LoadBytes(int64_t addr, int64_t length, Error& err) {
108154
uint8_t* buf = new uint8_t[length + 1];
109155
SBError sberr;
110156
process_.ReadMemory(addr, buf, static_cast<size_t>(length), sberr);
111157
if (sberr.Fail()) {
112-
err = Error::Failure("Failed to load V8 raw buffer");
158+
err = Error::Failure(
159+
"Failed to load v8 backing store memory, "
160+
"addr=0x%016" PRIx64 ", length=%" PRId64,
161+
addr, length);
113162
delete[] buf;
114163
return std::string();
115164
}
@@ -135,8 +184,10 @@ std::string LLV8::LoadString(int64_t addr, int64_t length, Error& err) {
135184
process_.ReadMemory(static_cast<addr_t>(addr), buf,
136185
static_cast<size_t>(length), sberr);
137186
if (sberr.Fail()) {
138-
// TODO(indutny): add more information
139-
err = Error::Failure("Failed to load V8 one byte string");
187+
err = Error::Failure(
188+
"Failed to load v8 one byte string memory, "
189+
"addr=0x%016" PRIx64 ", length=%" PRId64,
190+
addr, length);
140191
delete[] buf;
141192
return std::string();
142193
}
@@ -161,8 +212,10 @@ std::string LLV8::LoadTwoByteString(int64_t addr, int64_t length, Error& err) {
161212
process_.ReadMemory(static_cast<addr_t>(addr), buf,
162213
static_cast<size_t>(length * 2), sberr);
163214
if (sberr.Fail()) {
164-
// TODO(indutny): add more information
165-
err = Error::Failure("Failed to load V8 two byte string");
215+
err = Error::Failure(
216+
"Failed to load V8 two byte string memory, "
217+
"addr=0x%016" PRIx64 ", length=%" PRId64,
218+
addr, length);
166219
delete[] buf;
167220
return std::string();
168221
}
@@ -183,8 +236,10 @@ uint8_t* LLV8::LoadChunk(int64_t addr, int64_t length, Error& err) {
183236
process_.ReadMemory(static_cast<addr_t>(addr), buf,
184237
static_cast<size_t>(length), sberr);
185238
if (sberr.Fail()) {
186-
// TODO(indutny): add more information
187-
err = Error::Failure("Failed to load V8 memory chunk");
239+
err = Error::Failure(
240+
"Failed to load V8 chunk memory, "
241+
"addr=0x%016" PRIx64 ", length=%" PRId64,
242+
addr, length);
188243
delete[] buf;
189244
return nullptr;
190245
}
@@ -235,7 +290,7 @@ uint32_t JSFrame::GetSourceForDisplay(bool reset_line, uint32_t line_start,
235290
if (err.Fail()) {
236291
const char* msg = err.GetMessage();
237292
if (msg == nullptr) {
238-
err = Error(true, "Failed to get Function Source");
293+
err = Error::Failure("Failed to get Function Source");
239294
}
240295
return line_start;
241296
}
@@ -288,7 +343,7 @@ std::string JSFrame::Inspect(bool with_args, Error& err) {
288343
return "<stub>";
289344
} else if (value != v8()->frame()->kJSFrame &&
290345
value != v8()->frame()->kOptimizedFrame) {
291-
err = Error::Failure("Unknown frame marker");
346+
err = Error::Failure("Unknown frame marker %" PRId64, value);
292347
return std::string();
293348
}
294349
}
@@ -432,7 +487,7 @@ std::string JSFunction::GetSource(Error& err) {
432487

433488
// No source
434489
if (source_type > v8()->types()->kFirstNonstringType) {
435-
err = Error(true, "No source");
490+
err = Error::Failure("No source, source_type=%" PRId64, source_type);
436491
return std::string();
437492
}
438493

@@ -591,7 +646,7 @@ void Script::GetLines(uint64_t start_line, std::string lines[],
591646

592647
// No source
593648
if (type > v8()->types()->kFirstNonstringType) {
594-
err = Error(true, "No source");
649+
err = Error::Failure("No source, source_type=%" PRId64, type);
595650
return;
596651
}
597652

@@ -828,6 +883,8 @@ std::string HeapObject::Inspect(InspectOptions* options, Error& err) {
828883
return pre + date.Inspect(err);
829884
}
830885

886+
Error::PrintInDebugMode(
887+
"Unknown HeapObject Type %" PRId64 " at 0x%016" PRIx64 "", type, raw());
831888
return pre + "<unknown>";
832889
}
833890

@@ -956,7 +1013,7 @@ std::string String::ToString(Error& err) {
9561013
return two.ToString(err);
9571014
}
9581015

959-
err = Error::Failure("Unsupported seq string encoding");
1016+
err = Error::Failure("Unsupported seq string encoding %" PRId64, encoding);
9601017
return std::string();
9611018
}
9621019

@@ -980,7 +1037,7 @@ std::string String::ToString(Error& err) {
9801037
return thin.ToString(err);
9811038
}
9821039

983-
err = Error::Failure("Unsupported string representation");
1040+
err = Error::Failure("Unsupported string representation %" PRId64, repr);
9841041
return std::string();
9851042
}
9861043

@@ -1143,7 +1200,7 @@ std::string JSArrayBuffer::Inspect(InspectOptions* options, Error& err) {
11431200
res += ": [\n ";
11441201

11451202
int display_length = std::min<int>(byte_length, options->length);
1146-
res += v8()->LoadBytes(display_length, data, err);
1203+
res += v8()->LoadBytes(data, display_length, err);
11471204

11481205
if (display_length < byte_length) {
11491206
res += " ...";
@@ -1201,7 +1258,7 @@ std::string JSArrayBufferView::Inspect(InspectOptions* options, Error& err) {
12011258
res += ": [\n ";
12021259

12031260
int display_length = std::min<int>(byte_length, options->length);
1204-
res += v8()->LoadBytes(display_length, data + byte_offset, err);
1261+
res += v8()->LoadBytes(data + byte_offset, display_length, err);
12051262

12061263
if (display_length < byte_length) {
12071264
res += " ...";
@@ -1502,6 +1559,8 @@ std::string JSObject::InspectDescriptors(Map map, Error& err) {
15021559

15031560
// Skip non-fields for now
15041561
if (!descriptors.IsFieldDetails(details)) {
1562+
Error::PrintInDebugMode("Unknown field Type %" PRId64,
1563+
details.GetValue());
15051564
res += "<unknown field type>";
15061565
continue;
15071566
}

‎src/llv8.h

+21-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#ifndef SRC_LLV8_H_
22
#define SRC_LLV8_H_
33

4+
#include <cstring>
45
#include <string>
56

67
#include <lldb/API/LLDB.h>
@@ -20,28 +21,39 @@ class CodeMap;
2021

2122
class Error {
2223
public:
23-
Error() : failed_(false), msg_(nullptr) {}
24-
Error(bool failed, const char* msg) : failed_(failed), msg_(msg) {}
24+
Error() : failed_(false), msg_("") {}
25+
Error(bool failed, std::string msg) : failed_(failed), msg_(msg) {}
26+
Error(bool failed, const char* format, ...)
27+
__attribute__((format(printf, 3, 4)));
2528

2629
static inline Error Ok() { return Error(false, "ok"); }
27-
static inline Error Failure(const char* msg) { return Error(true, msg); }
30+
static Error Failure(std::string msg);
31+
static Error Failure(const char* format, ...)
32+
__attribute__((format(printf, 1, 2)));
33+
static void PrintInDebugMode(const char* format, ...)
34+
__attribute__((format(printf, 1, 2)));
2835

2936
inline bool Success() const { return !Fail(); }
3037
inline bool Fail() const { return failed_; }
3138

32-
inline const char* GetMessage() { return msg_; }
39+
inline const char* GetMessage() { return msg_.c_str(); }
40+
41+
static void SetDebugMode(bool mode) { is_debug_mode = mode; }
3342

3443
private:
3544
bool failed_;
36-
const char* msg_;
45+
std::string msg_;
46+
static const size_t kMaxMessageLength = 128;
47+
static bool is_debug_mode;
3748
};
3849

3950
#define V8_VALUE_DEFAULT_METHODS(NAME, PARENT) \
4051
NAME(const NAME& v) = default; \
4152
NAME() : PARENT() {} \
4253
NAME(LLV8* v8, int64_t raw) : PARENT(v8, raw) {} \
4354
NAME(Value& v) : PARENT(v) {} \
44-
NAME(Value* v) : PARENT(v->v8(), v->raw()) {}
55+
NAME(Value* v) : PARENT(v->v8(), v->raw()) {} \
56+
static inline const char* ClassName() { return #NAME; }
4557

4658
class Value {
4759
public:
@@ -78,6 +90,8 @@ class Value {
7890
std::string GetTypeName(Error& err);
7991
std::string ToString(Error& err);
8092

93+
static inline const char* ClassName() { return "Value"; }
94+
8195
protected:
8296
LLV8* v8_;
8397
int64_t raw_;
@@ -464,7 +478,7 @@ class LLV8 {
464478
int64_t LoadPtr(int64_t addr, Error& err);
465479
int64_t LoadUnsigned(int64_t addr, uint32_t byte_size, Error& err);
466480
double LoadDouble(int64_t addr, Error& err);
467-
std::string LoadBytes(int64_t length, int64_t addr, Error& err);
481+
std::string LoadBytes(int64_t addr, int64_t length, Error& err);
468482
std::string LoadString(int64_t addr, int64_t length, Error& err);
469483
std::string LoadTwoByteString(int64_t addr, int64_t length, Error& err);
470484
uint8_t* LoadChunk(int64_t addr, int64_t length, Error& err);

0 commit comments

Comments
 (0)
Please sign in to comment.