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");
}