static void PrintStackContents()

in kotlin-native/tools/minidump-analyzer/src/main/cpp/main.cc [300:459]


static void PrintStackContents(const string& indent,
                               const StackFrame* frame,
                               const StackFrame* prev_frame,
                               const string& cpu,
                               const MemoryRegion* memory,
                               const CodeModules* modules,
                               SourceLineResolverInterface* resolver) {
  // Find stack range.
  int word_length = 0;
  uint64_t stack_begin = 0, stack_end = 0;
  if (cpu == "x86") {
    word_length = 4;
    const StackFrameX86* frame_x86 = static_cast<const StackFrameX86*>(frame);
    const StackFrameX86* prev_frame_x86 =
        static_cast<const StackFrameX86*>(prev_frame);
    if ((frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESP) &&
        (prev_frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESP)) {
      stack_begin = frame_x86->context.esp;
      stack_end = prev_frame_x86->context.esp;
    }
  } else if (cpu == "amd64") {
    word_length = 8;
    const StackFrameAMD64* frame_amd64 =
        static_cast<const StackFrameAMD64*>(frame);
    const StackFrameAMD64* prev_frame_amd64 =
        static_cast<const StackFrameAMD64*>(prev_frame);
    if ((frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RSP) &&
        (prev_frame_amd64->context_validity &
         StackFrameAMD64::CONTEXT_VALID_RSP)) {
      stack_begin = frame_amd64->context.rsp;
      stack_end = prev_frame_amd64->context.rsp;
    }
  } else if (cpu == "arm") {
    word_length = 4;
    const StackFrameARM* frame_arm = static_cast<const StackFrameARM*>(frame);
    const StackFrameARM* prev_frame_arm =
        static_cast<const StackFrameARM*>(prev_frame);
    if ((frame_arm->context_validity &
         StackFrameARM::CONTEXT_VALID_SP) &&
        (prev_frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_SP)) {
      stack_begin = frame_arm->context.iregs[13];
      stack_end = prev_frame_arm->context.iregs[13];
    }
  } else if (cpu == "arm64") {
    word_length = 8;
    const StackFrameARM64* frame_arm64 =
        static_cast<const StackFrameARM64*>(frame);
    const StackFrameARM64* prev_frame_arm64 =
        static_cast<const StackFrameARM64*>(prev_frame);
    if ((frame_arm64->context_validity &
         StackFrameARM64::CONTEXT_VALID_SP) &&
        (prev_frame_arm64->context_validity &
         StackFrameARM64::CONTEXT_VALID_SP)) {
      stack_begin = frame_arm64->context.iregs[31];
      stack_end = prev_frame_arm64->context.iregs[31];
    }
  } else if (cpu == "riscv") {
    word_length = 4;
    const StackFrameRISCV* frame_riscv =
        static_cast<const StackFrameRISCV*>(frame);
    const StackFrameRISCV* prev_frame_riscv =
        static_cast<const StackFrameRISCV*>(prev_frame);
    if ((frame_riscv->context_validity &
         StackFrameRISCV::CONTEXT_VALID_SP) &&
        (prev_frame_riscv->context_validity &
         StackFrameRISCV::CONTEXT_VALID_SP)) {
      stack_begin = frame_riscv->context.sp;
      stack_end = prev_frame_riscv->context.sp;
    }
  } else if (cpu == "riscv64") {
    word_length = 8;
    const StackFrameRISCV64* frame_riscv64 =
        static_cast<const StackFrameRISCV64*>(frame);
    const StackFrameRISCV64* prev_frame_riscv64 =
        static_cast<const StackFrameRISCV64*>(prev_frame);
    if ((frame_riscv64->context_validity &
         StackFrameRISCV64::CONTEXT_VALID_SP) &&
        (prev_frame_riscv64->context_validity &
         StackFrameRISCV64::CONTEXT_VALID_SP)) {
      stack_begin = frame_riscv64->context.sp;
      stack_end = prev_frame_riscv64->context.sp;
    }
  }
  if (!word_length || !stack_begin || !stack_end)
    return;

  // Print stack contents.
  printf("\n%sStack contents:", indent.c_str());
  for(uint64_t address = stack_begin; address < stack_end; ) {
    // Print the start address of this row.
    if (word_length == 4)
      printf("\n%s %08x", indent.c_str(), static_cast<uint32_t>(address));
    else
      printf("\n%s %016" PRIx64, indent.c_str(), address);

    // Print data in hex.
    const int kBytesPerRow = 16;
    string data_as_string;
    for (int i = 0; i < kBytesPerRow; ++i, ++address) {
      uint8_t value = 0;
      if (address < stack_end &&
          memory->GetMemoryAtAddress(address, &value)) {
        printf(" %02x", value);
        data_as_string.push_back(isprint(value) ? value : '.');
      } else {
        printf("   ");
        data_as_string.push_back(' ');
      }
    }
    // Print data as string.
    printf("  %s", data_as_string.c_str());
  }

  // Try to find instruction pointers from stack.
  printf("\n%sPossible instruction pointers:\n", indent.c_str());
  for (uint64_t address = stack_begin; address < stack_end;
       address += word_length) {
    StackFrame pointee_frame;

    // Read a word (possible instruction pointer) from stack.
    if (word_length == 4) {
      uint32_t data32 = 0;
      memory->GetMemoryAtAddress(address, &data32);
      pointee_frame.instruction = data32;
    } else {
      uint64_t data64 = 0;
      memory->GetMemoryAtAddress(address, &data64);
      pointee_frame.instruction = data64;
    }
    pointee_frame.module =
        modules->GetModuleForAddress(pointee_frame.instruction);

    // Try to look up the function name.
    std::deque<unique_ptr<StackFrame>> inlined_frames;
    if (pointee_frame.module)
      resolver->FillSourceLineInfo(&pointee_frame, &inlined_frames);

    // Print function name.
    auto print_function_name = [&](StackFrame* frame) {
      if (!frame->function_name.empty()) {
        if (word_length == 4) {
          printf("%s *(0x%08x) = 0x%08x", indent.c_str(),
                 static_cast<uint32_t>(address),
                 static_cast<uint32_t>(frame->instruction));
        } else {
          printf("%s *(0x%016" PRIx64 ") = 0x%016" PRIx64, indent.c_str(),
                 address, frame->instruction);
        }
        printf(
            " <%s> [%s : %d + 0x%" PRIx64 "]\n", frame->function_name.c_str(),
            PathnameStripper::File(frame->source_file_name).c_str(),
            frame->source_line, frame->instruction - frame->source_line_base);
      }
    };
    print_function_name(&pointee_frame);
    for (unique_ptr<StackFrame> &frame : inlined_frames)
      print_function_name(frame.get());
  }
  printf("\n");
}