blob: 3f90b6d2fd30f8f37b032e286fba21f3568de600 [file] [log] [blame]
// Copyright 2025 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_LIB_UNWINDER_FRAME_H_
#define SRC_LIB_UNWINDER_FRAME_H_
#include <cstring>
#include "src/lib/unwinder/error.h"
#include "src/lib/unwinder/registers.h"
namespace unwinder {
struct Frame {
// LINT.IfChange
enum class Trust {
kScan, // From scanning the stack with heuristics, least reliable.
kSCS, // From the shadow call stack.
kSigReturn, // From a sigreturn trampoline.
kFP, // From the frame pointer.
kPLT, // From PLT unwinder.
kArmEhAbi, // From the ARM Exception Handling ABI .ARM.exidx/.ARM.extab sections.
kCFI, // From call frame info / .eh_frame section.
kContext, // From the input / context, most reliable.
};
// LINT.ThenChange(//src/developer/debug/ipc/records.h)
// Register status at each return site. Unknown registers may be included.
Registers regs;
// Whether the PC in |regs| is a return address or a precise code location.
//
// PC is usually a precise location for the first frame and a return address for the rest frames.
// However, it could also be a precise location when it's not a regular function call, e.g., in
// signal frames or when unwinding into restricted mode in Starnix.
bool pc_is_return_address;
// This flag is set to true if the CFI for this frame was associated with a CIE containing an 'S'
// character in its augmentation string.
//
// The 'S' augmentation is poorly documented and is not a part of the DWARF standard, but is a de
// facto standard to mark unwind information for signal trampolines. Unfortunately it's also not
// mentioned in any of the Linux Standard Base (LSB) nor in any of the ARM vendor DWARF extension
// specifications or other standards referenced by this unwinder. In practice, this is set by hand
// writing CFI directives (.cfi_signal_frame in particular).
//
// The best references that can be found are in source code of other unwinders: libgcc has the
// canonical implementation of this augmentation [1], and libunwind also implements it [2].
//
// .cfi_signal_frame is not always set on functions that are actually signal frames, so this flag
// can be set by probing the instruction sequence set at |pc| for a particular sigreturn method,
// which has a predictable and short instruction sequence. This approach is only taken in the case
// the CFI unwinder failed to find the 'S' augmentation.
//
// [1]: https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libgcc/unwind-dw2.c;h=883b1c7a13dbdf620e64724a2179ffcbfdfa9c69;hb=HEAD#l498
// [2]: https://github.com/llvm/llvm-project/blob/main/libunwind/src/DwarfParser.hpp#L395
bool is_signal_frame = false;
// Trust level of the frame.
Trust trust;
// Error when unwinding from this frame, which could be non-fatal and present in any frames.
Error error = Success();
// Whether the above error is fatal and aborts the unwinding, causing the stack to be incomplete.
// This could only be true for the last frame.
bool fatal_error = false;
// Disallow default constructors.
Frame(Registers regs, bool pc_is_return_address, Trust trust)
: regs(std::move(regs)), pc_is_return_address(pc_is_return_address), trust(trust) {}
// Useful for debugging.
std::string Describe() const;
};
} // namespace unwinder
#endif // SRC_LIB_UNWINDER_FRAME_H_