@@ -24247,6 +24247,8 @@ const char* StackTrace::ToCString() const {
24247
24247
// for each frame.
24248
24248
intptr_t frame_index = 0;
24249
24249
uint32_t frame_skip = 0;
24250
+ // If we're already in a gap, don't print multiple gap markers.
24251
+ bool in_gap = false;
24250
24252
do {
24251
24253
for (intptr_t i = frame_skip; i < stack_trace.Length(); i++) {
24252
24254
code_object = stack_trace.CodeAtFrame(i);
@@ -24260,72 +24262,87 @@ const char* StackTrace::ToCString() const {
24260
24262
// To account for gap frames.
24261
24263
frame_index += Smi::Value(stack_trace.PcOffsetAtFrame(i));
24262
24264
}
24263
- } else if (code_object.raw() == StubCode::AsynchronousGapMarker().raw()) {
24264
- buffer.AddString("<asynchronous suspension>\n");
24265
- } else {
24266
- intptr_t pc_offset = Smi::Value(stack_trace.PcOffsetAtFrame(i));
24267
- ASSERT(code_object.IsCode());
24268
- code ^= code_object.raw();
24269
- ASSERT(code.IsFunctionCode());
24270
- function = code.function();
24271
- const uword pc = code.PayloadStart() + pc_offset;
24272
- #if defined(DART_PRECOMPILED_RUNTIME)
24273
- // When printing non-symbolic frames, we normally print call
24274
- // addresses, not return addresses, by subtracting one from the PC to
24275
- // get an address within the preceding instruction.
24276
- //
24277
- // The one exception is a normal closure registered as a listener on a
24278
- // future. In this case, the returned pc_offset is 0, as the closure
24279
- // is invoked with the value of the resolved future. Thus, we must
24280
- // report the return address, as returning a value before the closure
24281
- // payload will cause failures to decode the frame using DWARF info.
24282
- const bool is_future_listener = pc_offset == 0;
24283
- const uword call_addr = is_future_listener ? pc : pc - 1;
24284
- if (FLAG_dwarf_stack_traces_mode) {
24285
- // If we have access to the owning function and it would be
24286
- // invisible in a symbolic stack trace, don't show this frame.
24287
- // (We can't do the same for inlined functions, though.)
24288
- if (!FLAG_show_invisible_frames && !function.IsNull() &&
24289
- !function.is_visible()) {
24290
- continue;
24291
- }
24292
- // This output is formatted like Android's debuggerd. Note debuggerd
24293
- // prints call addresses instead of return addresses.
24294
- buffer.Printf(" #%02" Pd " abs %" Pp "", frame_index, call_addr);
24295
- PrintNonSymbolicStackFrameBody(&buffer, call_addr,
24296
- isolate_instructions, vm_instructions);
24297
- frame_index++;
24298
- continue;
24299
- } else if (function.IsNull()) {
24300
- // We can't print the symbolic information since the owner was not
24301
- // retained, so instead print the static symbol + offset like the
24302
- // non-symbolic stack traces.
24303
- PrintSymbolicStackFrameIndex(&buffer, frame_index);
24304
- PrintNonSymbolicStackFrameBody(&buffer, call_addr,
24305
- isolate_instructions, vm_instructions);
24306
- frame_index++;
24307
- continue;
24265
+ continue;
24266
+ }
24267
+
24268
+ if (code_object.raw() == StubCode::AsynchronousGapMarker().raw()) {
24269
+ if (!in_gap) {
24270
+ buffer.AddString("<asynchronous suspension>\n");
24308
24271
}
24272
+ in_gap = true;
24273
+ continue;
24274
+ }
24275
+
24276
+ intptr_t pc_offset = Smi::Value(stack_trace.PcOffsetAtFrame(i));
24277
+ ASSERT(code_object.IsCode());
24278
+ code ^= code_object.raw();
24279
+ ASSERT(code.IsFunctionCode());
24280
+ function = code.function();
24281
+ const uword pc = code.PayloadStart() + pc_offset;
24282
+
24283
+ // If the function is not to be shown, skip.
24284
+ if (!FLAG_show_invisible_frames && !function.IsNull() &&
24285
+ !function.is_visible()) {
24286
+ continue;
24287
+ }
24288
+
24289
+ // A visible frame ends any gap we might be in.
24290
+ in_gap = false;
24291
+
24292
+ #if defined(DART_PRECOMPILED_RUNTIME)
24293
+ // When printing non-symbolic frames, we normally print call
24294
+ // addresses, not return addresses, by subtracting one from the PC to
24295
+ // get an address within the preceding instruction.
24296
+ //
24297
+ // The one exception is a normal closure registered as a listener on a
24298
+ // future. In this case, the returned pc_offset is 0, as the closure
24299
+ // is invoked with the value of the resolved future. Thus, we must
24300
+ // report the return address, as returning a value before the closure
24301
+ // payload will cause failures to decode the frame using DWARF info.
24302
+ const bool is_future_listener = pc_offset == 0;
24303
+ const uword call_addr = is_future_listener ? pc : pc - 1;
24304
+
24305
+ if (FLAG_dwarf_stack_traces_mode) {
24306
+ // This output is formatted like Android's debuggerd. Note debuggerd
24307
+ // prints call addresses instead of return addresses.
24308
+ buffer.Printf(" #%02" Pd " abs %" Pp "", frame_index, call_addr);
24309
+ PrintNonSymbolicStackFrameBody(&buffer, call_addr, isolate_instructions,
24310
+ vm_instructions);
24311
+ frame_index++;
24312
+ continue;
24313
+ }
24314
+
24315
+ if (function.IsNull()) {
24316
+ in_gap = false;
24317
+ // We can't print the symbolic information since the owner was not
24318
+ // retained, so instead print the static symbol + offset like the
24319
+ // non-symbolic stack traces.
24320
+ PrintSymbolicStackFrameIndex(&buffer, frame_index);
24321
+ PrintNonSymbolicStackFrameBody(&buffer, call_addr, isolate_instructions,
24322
+ vm_instructions);
24323
+ frame_index++;
24324
+ continue;
24325
+ }
24309
24326
#endif
24310
- if (code.is_optimized() && stack_trace.expand_inlined()) {
24311
- code.GetInlinedFunctionsAtReturnAddress(pc_offset, &inlined_functions,
24312
- &inlined_token_positions);
24313
- ASSERT(inlined_functions.length() >= 1);
24314
- for (intptr_t j = inlined_functions.length() - 1; j >= 0; j--) {
24315
- const auto& inlined = *inlined_functions[j];
24316
- auto const pos = inlined_token_positions[j];
24317
- if (FLAG_show_invisible_frames || function.is_visible()) {
24318
- PrintSymbolicStackFrame(zone, &buffer, inlined, pos, frame_index);
24319
- frame_index++;
24320
- }
24321
- }
24322
- } else if (FLAG_show_invisible_frames || function.is_visible()) {
24323
- auto const pos = code.GetTokenIndexOfPC(pc);
24324
- PrintSymbolicStackFrame(zone, &buffer, function, pos, frame_index);
24327
+
24328
+ if (code.is_optimized() && stack_trace.expand_inlined()) {
24329
+ code.GetInlinedFunctionsAtReturnAddress(pc_offset, &inlined_functions,
24330
+ &inlined_token_positions);
24331
+ ASSERT(inlined_functions.length() >= 1);
24332
+ for (intptr_t j = inlined_functions.length() - 1; j >= 0; j--) {
24333
+ const auto& inlined = *inlined_functions[j];
24334
+ auto const pos = inlined_token_positions[j];
24335
+ PrintSymbolicStackFrame(zone, &buffer, inlined, pos, frame_index);
24325
24336
frame_index++;
24326
24337
}
24338
+ continue;
24327
24339
}
24340
+
24341
+ auto const pos = code.GetTokenIndexOfPC(pc);
24342
+ PrintSymbolicStackFrame(zone, &buffer, function, pos, frame_index);
24343
+ frame_index++;
24328
24344
}
24345
+
24329
24346
// Follow the link.
24330
24347
frame_skip = stack_trace.skip_sync_start_in_parent_stack()
24331
24348
? StackTrace::kSyncAsyncCroppedFrames
0 commit comments