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;
@@ -62,6 +67,9 @@ static void PrintJavaScriptErrorStack(JSONWriter* writer,
62
67
Isolate* isolate,
63
68
Local<Value> 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);
@@ -269,8 +277,6 @@ static void WriteNodeReport(Isolate* isolate,
269
277
// Report summary JavaScript error stack backtrace
270
278
PrintJavaScriptErrorStack (&writer, isolate, 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
+ Local<Value >(),
321
327
os);
322
328
323
329
Mutex::ScopedLock lock (workers_mutex);
@@ -534,19 +540,80 @@ 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
604
Local<Value> error,
541
605
const char * trigger) {
606
+ if (error.IsEmpty ()) {
607
+ return PrintJavaScriptStack (writer, isolate, trigger);
608
+ }
609
+
542
610
TryCatch try_catch (isolate);
543
611
HandleScope scope (isolate);
544
612
Local<Context> context = isolate->GetCurrentContext ();
545
613
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 " ;
614
+ if (!ErrorToString (isolate, context, error).To (&ss)) {
615
+ PrintEmptyJavaScriptStack (writer);
616
+ return ;
550
617
}
551
618
552
619
int line = ss.find (' \n ' );
@@ -569,6 +636,9 @@ static void PrintJavaScriptErrorStack(JSONWriter* writer,
569
636
}
570
637
writer->json_arrayend ();
571
638
}
639
+
640
+ // Report summary JavaScript error properties backtrace
641
+ PrintJavaScriptErrorProperties (writer, isolate, error);
572
642
}
573
643
574
644
// Report a native stack backtrace
0 commit comments