From 3f085888602ad40460698bfb5bc47c34653f1206 Mon Sep 17 00:00:00 2001 From: Matheus Marchini Date: Mon, 25 Feb 2019 15:47:46 -0300 Subject: [PATCH] src: inspcet arguments from an Error object stack This is useful when the process aborts later than a thrown error (for example, when there's an async rethrow or an unhandled Promise rejection). V8 changes to make this possible landed in https://github.com/v8/v8/commit/3724a125. --- src/llv8.cc | 59 ++++++++++++++++++++++++++++++++++++++++---------- src/llv8.h | 6 +++++ src/printer.cc | 17 +++++++++++++-- 3 files changed, 68 insertions(+), 14 deletions(-) diff --git a/src/llv8.cc b/src/llv8.cc index 63e6803e..ed90e6cf 100644 --- a/src/llv8.cc +++ b/src/llv8.cc @@ -1259,15 +1259,10 @@ StackTrace::StackTrace(JSArray frame_array, Error& err) len_ = v8::Smi(maybe_stack_len).GetValue(); - multiplier_ = 5; - // On Node.js v8.x, the first array element is the stack size, and each - // stack frame use 5 elements. - if ((len_ * multiplier_ + 1) != frame_array_.GetArrayLength(err)) { - // On Node.js v6.x, the first array element is zero, and each stack frame - // use 4 element. - multiplier_ = 4; - if ((len_ != 0) || - ((frame_array_.GetArrayLength(err) - 1) % multiplier_ != 0)) { + // On Node.js v6.x, the first array element is zero, and each stack frame + // use 4 element. + if (len_ == 0) { + if ((frame_array_.GetArrayLength(err) - 1) % multiplier_ != 0) { Error::PrintInDebugMode( "JSArray doesn't look like a Stack Frames array. stack_len: %lld " "array_len: %lld", @@ -1276,7 +1271,24 @@ StackTrace::StackTrace(JSArray frame_array, Error& err) multiplier_ = -1; return; } + multiplier_ = 4; len_ = (frame_array_.GetArrayLength(err) - 1) / multiplier_; + } else { + // On Node.js v8.x and later, the first array element is the stack size, + // and each stack frame use 5 or 6 elements. + multiplier_ = (frame_array_.GetArrayLength(err) - 1) / len_; + if (multiplier_ == 6) { + // If stack frame has 6 elements, it has parameters information + has_parameters_ = true; + } else if (multiplier_ != 5) { + Error::PrintInDebugMode( + "JSArray doesn't look like a Stack Frames array. stack_len: %lld " + "array_len: %lld", + len_, frame_array_.GetArrayLength(err)); + len_ = -1; + multiplier_ = -1; + return; + } } } @@ -1294,17 +1306,40 @@ StackFrame::StackFrame(StackTrace* stack_trace, int index) : stack_trace_(stack_trace), index_(index) {} JSFunction StackFrame::GetFunction(Error& err) { + int js_function_pos = frame_array_index() + 1; JSArray frame_array = stack_trace_->frame_array_; - v8::Value maybe_fn = frame_array.GetArrayElement(frame_array_index(), err); + v8::Value maybe_fn = frame_array.GetArrayElement(js_function_pos, err); if (err.Fail()) return JSFunction(); return JSFunction(maybe_fn); } +Value StackFrame::GetReceiver(Error& err) { + int receiver_pos = frame_array_index(); + JSArray frame_array = stack_trace_->frame_array_; + v8::Value maybe_receiver = frame_array.GetArrayElement(receiver_pos, err); + if (err.Fail()) return Value(); + return maybe_receiver; +} + +bool StackFrame::HasParameters(Error& err) { + return stack_trace_->has_parameters_; +} + +FixedArray StackFrame::GetParameters(Error& err) { + if (!HasParameters(err)) { + return FixedArray(); + } + const int parameters_pos = frame_array_index() + 5; + JSArray frame_array = stack_trace_->frame_array_; + v8::Value maybe_parameters = frame_array.GetArrayElement(parameters_pos, err); + if (err.Fail()) return FixedArray(); + return FixedArray(maybe_parameters); +} + int StackFrame::frame_array_index() { int multiplier = stack_trace_->multiplier_; - const int js_function_pos = 1; const int begin_offset = 1; - return begin_offset + js_function_pos + (index_ * multiplier); + return begin_offset + (index_ * multiplier); } diff --git a/src/llv8.h b/src/llv8.h index c0c80896..42bbe77b 100644 --- a/src/llv8.h +++ b/src/llv8.h @@ -290,9 +290,14 @@ class JSError : public JSObject { inline std::string stack_trace_property(); }; +class FixedArray; class StackFrame { public: + Value GetReceiver(Error& err); JSFunction GetFunction(Error& err); + FixedArray GetParameters(Error& err); + + bool HasParameters(Error& err); private: friend StackTrace; @@ -346,6 +351,7 @@ class StackTrace { JSArray frame_array_; int multiplier_ = -1; int len_ = -1; + int has_parameters_ = false; }; diff --git a/src/printer.cc b/src/printer.cc index 56fd1a53..69a8f9ea 100644 --- a/src/printer.cc +++ b/src/printer.cc @@ -559,14 +559,27 @@ std::string Printer::Stringify(v8::JSError js_error, Error& err) { Printer printer(llv8_); for (v8::StackFrame frame : stack_trace) { v8::JSFunction js_function = frame.GetFunction(err); + v8::Value receiver = frame.GetReceiver(err); if (err.Fail()) { error_stack << rang::fg::gray << " " << std::endl; continue; } - error_stack << " " + error_stack << " { fn=" << printer.Stringify(js_function, err) - << std::endl; + << ", this=" << printer.Stringify(receiver, err); + if (frame.HasParameters(err)) { + v8::FixedArray parameters = frame.GetParameters(err); + int64_t param_len = parameters.Length(err).GetValue(); + error_stack << ", args=["; + for(int64_t p = 0; p < param_len; p++) { + v8::Value param = parameters.Get(p, err); + error_stack << printer.Stringify(param, err); + if (p < param_len - 1) error_stack << ", "; + } + error_stack << "]"; + } + error_stack << " }" << std::endl; } error_stack << " }"; output << error_stack.str();