blob: b85d25e3a499c60cd64aed50c4a5f3febebaccab [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_ARM_EHABI_MODULE_H_
#define SRC_LIB_UNWINDER_ARM_EHABI_MODULE_H_
#include "gtest/gtest_prod.h"
#include "src/lib/unwinder/memory.h"
#include "src/lib/unwinder/registers.h"
namespace unwinder {
inline uint32_t SignExtendPrel31(uint32_t data) { return data | ((data & 0x40000000u) << 1); }
inline int32_t DecodePrel31(uint32_t ptr) { return static_cast<int32_t>(SignExtendPrel31(ptr)); }
class ArmEhAbiModule {
public:
ArmEhAbiModule(Memory* elf, uint32_t elf_ptr) : elf_(elf), elf_ptr_(elf_ptr) {}
// Load the .ARM.exidx binary search table.
[[nodiscard]] Error Load();
[[nodiscard]] Error Step(Memory* stack, const Registers& current, Registers& next);
struct IdxHeaderData {
uint32_t fn_addr = 0;
// Either the encoded handling table entry if the high bit is 1, otherwise a prel31 encoded
// offset from the start of the table to the handling table entry in ARM.extab.
uint32_t data = 0;
};
struct IdxHeader {
IdxHeaderData header;
enum class Type {
// |header.data| is an offset into .ARM.extab for the unwinding instructions.
kCompact,
// |header.data| is an inlined compact model containing the unwinding instructions directly.
kCompactInline,
// The encoding instructions are inlined into |header.data|.
kUnknown,
} type = Type::kUnknown;
};
private:
FRIEND_TEST(ArmEhAbiModule, Search);
FRIEND_TEST(ArmEhAbiParser, CollectInstructionsTableLookup);
// Performs an upper bounds search for PC in the exidx table.
Error Search(uint32_t pc, IdxHeader& entry);
Memory* const elf_ = nullptr;
const uint32_t elf_ptr_ = 0;
// This is the start of the binary search lookup table. Each table entry is two 32 bit integers.
uint32_t arm_exidx_start_ = 0;
uint32_t arm_exidx_end_ = 0;
};
} // namespace unwinder
#endif // SRC_LIB_UNWINDER_ARM_EHABI_MODULE_H_