diff --git a/src/llnode.cc b/src/llnode.cc index d7eb70f2..ec2aa36b 100644 --- a/src/llnode.cc +++ b/src/llnode.cc @@ -11,7 +11,19 @@ namespace llnode { -using namespace lldb; +using lldb::SBCommandInterpreter; +using lldb::SBCommandReturnObject; +using lldb::SBDebugger; +using lldb::SBError; +using lldb::SBExpressionOptions; +using lldb::SBFrame; +using lldb::SBStream; +using lldb::SBSymbol; +using lldb::SBTarget; +using lldb::SBThread; +using lldb::SBValue; +using lldb::eReturnStatusFailed; +using lldb::eReturnStatusSuccessFinishResult; v8::LLV8 llv8; @@ -97,30 +109,37 @@ bool BacktraceCmd::DoExecute(SBDebugger d, char** cmd, if (number != -1) num_frames = number; for (uint32_t i = 0; i < num_frames; i++) { SBFrame frame = thread.GetFrameAtIndex(i); - SBSymbol symbol = frame.GetSymbol(); - - // C++ symbol - if (symbol.IsValid()) { - SBStream desc; - if (!frame.GetDescription(desc)) continue; - result.Printf(frame == selected_frame ? " * %s" : " %s", - desc.GetData()); - continue; + const char star = (frame == selected_frame ? '*' : ' '); + const uint64_t pc = frame.GetPC(); + + if (!frame.GetSymbol().IsValid()) { + v8::Error err; + v8::JSFrame v8_frame(&llv8, static_cast(frame.GetFP())); + std::string res = v8_frame.Inspect(true, err); + if (err.Success()) { + result.Printf(" %c frame #%u: 0x%016llx %s\n", star, i, pc, + res.c_str()); + continue; + } } - // V8 frame - v8::Error err; - v8::JSFrame v8_frame(&llv8, static_cast(frame.GetFP())); - std::string res = v8_frame.Inspect(true, err); - - // Skip invalid frames - if (err.Fail()) continue; +#ifdef LLDB_SBMemoryRegionInfoList_h_ + // Heuristic: a PC in WX memory is almost certainly a V8 builtin. + // TODO(bnoordhuis) Find a way to map the PC to the builtin's name. + { + lldb::SBMemoryRegionInfo info; + if (target.GetProcess().GetMemoryRegionInfo(pc, info).Success() && + info.IsExecutable() && info.IsWritable()) { + result.Printf(" %c frame #%u: 0x%016llx \n", star, i, pc); + continue; + } + } +#endif // LLDB_SBMemoryRegionInfoList_h_ - // V8 symbol - result.Printf(frame == selected_frame ? " * frame #%u: 0x%016llx %s\n" - : " frame #%u: 0x%016llx %s\n", - i, static_cast(frame.GetPC()), - res.c_str()); + // C++ stack frame. + SBStream desc; + if (frame.GetDescription(desc)) + result.Printf(" %c %s", star, desc.GetData()); } result.SetStatus(eReturnStatusSuccessFinishResult); diff --git a/src/llscan.cc b/src/llscan.cc index 821068c1..ddc7d935 100644 --- a/src/llscan.cc +++ b/src/llscan.cc @@ -17,13 +17,23 @@ namespace llnode { +using lldb::SBCommandReturnObject; +using lldb::SBDebugger; +using lldb::SBError; +using lldb::SBExpressionOptions; +using lldb::SBMemoryRegionInfo; +using lldb::SBMemoryRegionInfoList; +using lldb::SBStream; +using lldb::SBTarget; +using lldb::SBValue; +using lldb::eReturnStatusFailed; +using lldb::eReturnStatusSuccessFinishResult; + // Defined in llnode.cc extern v8::LLV8 llv8; LLScan llscan; -using namespace lldb; - bool FindObjectsCmd::DoExecute(SBDebugger d, char** cmd, SBCommandReturnObject& result) { diff --git a/src/llv8-constants.cc b/src/llv8-constants.cc index 93cca3c5..d36cec53 100644 --- a/src/llv8-constants.cc +++ b/src/llv8-constants.cc @@ -12,7 +12,14 @@ namespace llnode { namespace v8 { namespace constants { -using namespace lldb; +using lldb::SBAddress; +using lldb::SBError; +using lldb::SBProcess; +using lldb::SBSymbol; +using lldb::SBSymbolContext; +using lldb::SBSymbolContextList; +using lldb::SBTarget; +using lldb::addr_t; static std::string kConstantPrefix = "v8dbg_"; diff --git a/src/llv8.cc b/src/llv8.cc index af1ba80c..e59591f5 100644 --- a/src/llv8.cc +++ b/src/llv8.cc @@ -8,7 +8,9 @@ namespace llnode { namespace v8 { -using namespace lldb; +using lldb::SBError; +using lldb::SBTarget; +using lldb::addr_t; static std::string kConstantPrefix = "v8dbg_"; diff --git a/test/frame-test.js b/test/frame-test.js index a9c4068f..69861344 100644 --- a/test/frame-test.js +++ b/test/frame-test.js @@ -15,6 +15,10 @@ tape('v8 stack', (t) => { sess.linesUntil(/eyecatcher/, (lines) => { lines.reverse(); t.ok(lines.length > 4, 'frame count'); + // 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) => !//.test(s)); const eyecatcher = lines[0]; const adapter = lines[1]; const crasher = lines[2]; diff --git a/test/scan-test.js b/test/scan-test.js index b90ec05b..496c3f58 100644 --- a/test/scan-test.js +++ b/test/scan-test.js @@ -69,12 +69,12 @@ tape('v8 findrefs and friends', (t) => { sess.linesUntil(/lldb\-/, (lines) => { // `class Deflate extends Zlib` makes instances show up as - // Transform objects (which Zlib inherits from) in node.js >= 8. - // Note that the version check will have to be redone for node.js >= 10 - // but that is still a year out and by then llnode probably needs more - // fixups anyway. + // Transform objects (which Zlib inherits from) in node.js 8.0.0. + // That change was reverted in https://github.com/nodejs/node/pull/13374 + // and released in 8.1.0. const re = - (process.version >= 'v8.' ? /Transform\._handle/ : /Deflate\._handle/); + (process.version === 'v8.0.0' ? + /Transform\._handle/ : /Deflate\._handle/); t.ok(re.test(lines.join('\n')), 'Should find reference'); t.ok(/Object\.holder/.test(lines.join('\n')), 'Should find reference #2'); t.ok(/\(Array\)\[1\]/.test(lines.join('\n')), 'Should find reference #3');