26
26
constexpr int NODE_REPORT_VERSION = 2 ;
27
27
constexpr int NANOS_PER_SEC = 1000 * 1000 * 1000 ;
28
28
constexpr double SEC_PER_MICROS = 1e-6 ;
29
+ constexpr int MAX_FRAME_COUNT = 10 ;
29
30
30
31
namespace node {
31
32
namespace report {
@@ -43,6 +44,10 @@ using v8::Maybe;
43
44
using v8::MaybeLocal;
44
45
using v8::Nothing;
45
46
using v8::Object;
47
+ using v8::RegisterState;
48
+ using v8::SampleInfo;
49
+ using v8::StackFrame;
50
+ using v8::StackTrace;
46
51
using v8::String;
47
52
using v8::TryCatch;
48
53
using v8::V8;
@@ -55,13 +60,16 @@ static void WriteNodeReport(Isolate* isolate,
55
60
const char * trigger,
56
61
const std::string& filename,
57
62
std::ostream& out,
58
- Local <Value> error ,
63
+ MaybeLocal <Value> maybe_error ,
59
64
bool compact);
60
65
static void PrintVersionInformation (JSONWriter* writer);
61
66
static void PrintJavaScriptErrorStack (JSONWriter* writer,
62
67
Isolate* isolate,
63
- Local <Value> error ,
68
+ MaybeLocal <Value> maybe_error ,
64
69
const char * trigger);
70
+ static void PrintJavaScriptStack (JSONWriter* writer,
71
+ Isolate* isolate,
72
+ const char * trigger);
65
73
static void PrintJavaScriptErrorProperties (JSONWriter* writer,
66
74
Isolate* isolate,
67
75
Local<Value> error);
@@ -81,7 +89,7 @@ std::string TriggerNodeReport(Isolate* isolate,
81
89
const char * message,
82
90
const char * trigger,
83
91
const std::string& name,
84
- Local <Value> error) {
92
+ MaybeLocal <Value> error) {
85
93
std::string filename;
86
94
87
95
// Determine the required report filename. In order of priority:
@@ -166,9 +174,9 @@ void GetNodeReport(Isolate* isolate,
166
174
Environment* env,
167
175
const char * message,
168
176
const char * trigger,
169
- Local <Value> error ,
177
+ MaybeLocal <Value> maybe_error ,
170
178
std::ostream& out) {
171
- WriteNodeReport (isolate, env, message, trigger, " " , out, error , false );
179
+ WriteNodeReport (isolate, env, message, trigger, " " , out, maybe_error , false );
172
180
}
173
181
174
182
// Internal function to coordinate and write the various
@@ -179,7 +187,7 @@ static void WriteNodeReport(Isolate* isolate,
179
187
const char * trigger,
180
188
const std::string& filename,
181
189
std::ostream& out,
182
- Local <Value> error ,
190
+ MaybeLocal <Value> maybe_error ,
183
191
bool compact) {
184
192
// Obtain the current time and the pid.
185
193
TIME_TYPE tm_struct;
@@ -267,10 +275,8 @@ static void WriteNodeReport(Isolate* isolate,
267
275
if (isolate != nullptr ) {
268
276
writer.json_objectstart (" javascriptStack" );
269
277
// Report summary JavaScript error stack backtrace
270
- PrintJavaScriptErrorStack (&writer, isolate, error , trigger);
278
+ PrintJavaScriptErrorStack (&writer, isolate, maybe_error , trigger);
271
279
272
- // Report summary JavaScript error properties backtrace
273
- PrintJavaScriptErrorProperties (&writer, isolate, error);
274
280
writer.json_objectend (); // the end of 'javascriptStack'
275
281
276
282
// Report V8 Heap and Garbage Collector information
@@ -317,7 +323,7 @@ static void WriteNodeReport(Isolate* isolate,
317
323
env,
318
324
" Worker thread subreport" ,
319
325
trigger,
320
- Local<Object >(),
326
+ MaybeLocal<Value >(),
321
327
os);
322
328
323
329
Mutex::ScopedLock lock (workers_mutex);
@@ -534,19 +540,81 @@ static Maybe<std::string> ErrorToString(Isolate* isolate,
534
540
return Just<>(std::string (*sv, sv.length ()));
535
541
}
536
542
543
+ static void PrintEmptyJavaScriptStack (JSONWriter* writer) {
544
+ writer->json_keyvalue (" message" , " No stack." );
545
+ writer->json_arraystart (" stack" );
546
+ writer->json_element (" Unavailable." );
547
+ writer->json_arrayend ();
548
+
549
+ writer->json_objectstart (" errorProperties" );
550
+ writer->json_objectend ();
551
+ }
552
+
553
+ // Do our best to report the JavaScript stack without calling into JavaScript.
554
+ static void PrintJavaScriptStack (JSONWriter* writer,
555
+ Isolate* isolate,
556
+ const char * trigger) {
557
+ // Can not capture the stacktrace when the isolate is in a OOM state.
558
+ if (!strcmp (trigger, " OOMError" )) {
559
+ PrintEmptyJavaScriptStack (writer);
560
+ return ;
561
+ }
562
+
563
+ HandleScope scope (isolate);
564
+ RegisterState state;
565
+ state.pc = nullptr ;
566
+ state.fp = &state;
567
+ state.sp = &state;
568
+
569
+ // in-out params
570
+ SampleInfo info;
571
+ void * samples[MAX_FRAME_COUNT];
572
+ isolate->GetStackSample (state, samples, MAX_FRAME_COUNT, &info);
573
+
574
+ Local<StackTrace> stack = StackTrace::CurrentStackTrace (
575
+ isolate, MAX_FRAME_COUNT, StackTrace::kDetailed );
576
+
577
+ if (stack->GetFrameCount () == 0 ) {
578
+ PrintEmptyJavaScriptStack (writer);
579
+ return ;
580
+ }
581
+
582
+ writer->json_keyvalue (" message" , trigger);
583
+ writer->json_arraystart (" stack" );
584
+ for (int i = 0 ; i < stack->GetFrameCount (); i++) {
585
+ Local<StackFrame> frame = stack->GetFrame (isolate, i);
586
+
587
+ Utf8Value function_name (isolate, frame->GetFunctionName ());
588
+ Utf8Value script_name (isolate, frame->GetScriptName ());
589
+ const int line_number = frame->GetLineNumber ();
590
+ const int column = frame->GetColumn ();
591
+
592
+ std::string stack_line = SPrintF (
593
+ " at %s (%s:%d:%d)" , *function_name, *script_name, line_number, column);
594
+ writer->json_element (stack_line);
595
+ }
596
+ writer->json_arrayend ();
597
+ writer->json_objectstart (" errorProperties" );
598
+ writer->json_objectend ();
599
+ }
600
+
537
601
// Report the JavaScript stack.
538
602
static void PrintJavaScriptErrorStack (JSONWriter* writer,
539
603
Isolate* isolate,
540
- Local <Value> error ,
604
+ MaybeLocal <Value> maybe_error ,
541
605
const char * trigger) {
606
+ Local<Value> error;
607
+ if (!maybe_error.ToLocal (&error)) {
608
+ return PrintJavaScriptStack (writer, isolate, trigger);
609
+ }
610
+
542
611
TryCatch try_catch (isolate);
543
612
HandleScope scope (isolate);
544
613
Local<Context> context = isolate->GetCurrentContext ();
545
614
std::string ss = " " ;
546
- if ((!strcmp (trigger, " FatalError" )) ||
547
- (!strcmp (trigger, " Signal" )) ||
548
- (!ErrorToString (isolate, context, error).To (&ss))) {
549
- ss = " No stack.\n Unavailable.\n " ;
615
+ if (!ErrorToString (isolate, context, error).To (&ss)) {
616
+ PrintEmptyJavaScriptStack (writer);
617
+ return ;
550
618
}
551
619
552
620
int line = ss.find (' \n ' );
@@ -569,6 +637,9 @@ static void PrintJavaScriptErrorStack(JSONWriter* writer,
569
637
}
570
638
writer->json_arrayend ();
571
639
}
640
+
641
+ // Report summary JavaScript error properties backtrace
642
+ PrintJavaScriptErrorProperties (writer, isolate, error);
572
643
}
573
644
574
645
// Report a native stack backtrace
0 commit comments