Skip to content

[Object] Beginnings of SFrame parser and dumper #147294

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
171 changes: 171 additions & 0 deletions llvm/include/llvm/BinaryFormat/SFrame.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
//===-- llvm/BinaryFormat/SFrame.h ---SFrame Data Structures ----*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
/// \file
/// This file contains data-structure definitions and constants to support
/// unwinding based on .sframe sections. This only supports SFRAME_VERSION_2
/// as described at https://sourceware.org/binutils/docs/sframe-spec.html
///
/// Naming conventions follow the spec document. #defines converted to constants
/// and enums for better C++ compatibility.
//===----------------------------------------------------------------------===//

#ifndef LLVM_BINARYFORMAT_SFRAME_H
#define LLVM_BINARYFORMAT_SFRAME_H

#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/DataTypes.h"

namespace llvm {

template <typename T> struct EnumEntry;

namespace sframe {

constexpr uint16_t SFRAME_MAGIC = 0xDEE2;

enum : uint8_t {
#define HANDLE_SFRAME_VERSION(CODE, NAME) SFRAME_##NAME = CODE,
#include "llvm/BinaryFormat/SFrameConstants.def"
};

/// sframe_preable.sfp_flags flags.
enum : uint8_t {
#define HANDLE_SFRAME_HEADER_FLAG(CODE, NAME) SFRAME_F_##NAME = CODE,
#include "llvm/BinaryFormat/SFrameConstants.def"
};

/// Possible values for sframe_header.sfh_abi_arch.
enum : uint8_t {
#define HANDLE_SFRAME_ABI(CODE, NAME) SFRAME_ABI_##NAME = CODE,
#include "llvm/BinaryFormat/SFrameConstants.def"
};

/// SFrame FRE Types. Bits 0-3 of sframe_func_desc_entry.sfde_func_info.
enum : uint8_t {
SFRAME_FRE_TYPE_ADDR1 = 0,
SFRAME_FRE_TYPE_ADDR2 = 1,
SFRAME_FRE_TYPE_ADDR4 = 2,
};

/// SFrame FDE Types. Bit 4 of sframe_func_desc_entry.sfde_func_info.
enum : uint8_t {
SFRAME_FDE_TYPE_PCINC = 0,
SFRAME_FDE_TYPE_PCMASK = 1,
};

/// Speficies key used for signing return addresses. Bit 5 of
/// sframe_func_desc_entry.sfde_func_info.
enum : uint8_t {
SFRAME_AARCH64_PAUTH_KEY_A = 0,
SFRAME_AARCH64_PAUTH_KEY_B = 1,
};

/// Size of stack offsets. Bits 5-6 of sframe_fre_info.fre_info.
enum : uint8_t {
SFRAME_FRE_OFFSET_1B = 0,
SFRAME_FRE_OFFSET_2B = 1,
SFRAME_FRE_OFFSET_4B = 2,
};

/// Stack frame base register. Bit 0 of sframe_fre_info.fre_info.
enum : uint8_t { SFRAME_BASE_REG_FP = 0, SFRAME_BASE_REG_SP = 1 };

LLVM_PACKED_START

struct sframe_preamble {
uint16_t sfp_magic;
uint8_t sfp_version;
uint8_t sfp_flags;
};

struct sframe_header {
sframe_preamble sfh_preamble;
uint8_t sfh_abi_arch;
int8_t sfh_cfa_fixed_fp_offset;
int8_t sfh_cfa_fixed_ra_offset;
uint8_t sfh_auxhdr_len;
uint32_t sfh_num_fdes;
uint32_t sfh_num_fres;
uint32_t sfh_fre_len;
uint32_t sfh_fdeoff;
uint32_t sfh_freoff;
};

struct sframe_func_desc_entry {
int32_t sfde_func_start_address;
uint32_t sfde_func_size;
uint32_t sfde_func_start_fre_off;
uint32_t sfde_func_num_fres;
uint8_t sfde_func_info;
uint8_t sfde_func_rep_size;
uint16_t sfde_func_padding2;

uint8_t getPAuthKey() const { return (sfde_func_info >> 5) & 1; }
uint8_t getFDEType() const { return (sfde_func_info >> 4) & 1; }
uint8_t getFREType() const { return sfde_func_info & 0xf; }
void setPAuthKey(uint8_t P) { setFuncInfo(P, getFDEType(), getFREType()); }
void setFDEType(uint8_t D) { setFuncInfo(getPAuthKey(), D, getFREType()); }
void setFREType(uint8_t R) { setFuncInfo(getPAuthKey(), getFDEType(), R); }
void setFuncInfo(uint8_t PAuthKey, uint8_t FDEType, uint8_t FREType) {
sfde_func_info =
((PAuthKey & 1) << 5) | ((FDEType & 1) << 4) | (FREType & 0xf);
}
};

struct sframe_fre_info {
uint8_t fre_info;

bool isReturnAddressSigned() const { return fre_info >> 7; }
uint8_t getOffsetSize() const { return (fre_info >> 5) & 3; }
uint8_t getOffsetCount() const { return (fre_info >> 1) & 0xf; }
uint8_t getBaseRegister() const { return fre_info & 1; }
void setReturnAddressSigned(bool RA) {
setFREInfo(RA, getOffsetSize(), getOffsetCount(), getBaseRegister());
}
void setOffsetSize(uint8_t Sz) {
setFREInfo(isReturnAddressSigned(), Sz, getOffsetCount(),
getBaseRegister());
}
void setOffsetCount(uint8_t N) {
setFREInfo(isReturnAddressSigned(), getOffsetSize(), N, getBaseRegister());
}
void setBaseRegister(uint8_t Reg) {
setFREInfo(isReturnAddressSigned(), getOffsetSize(), getOffsetCount(), Reg);
}
void setFREInfo(bool RA, uint8_t Sz, uint8_t N, uint8_t Reg) {
fre_info = ((RA & 1) << 7) | ((Sz & 3) << 5) | ((N & 0xf) << 1) | (Reg & 1);
}
};

struct sframe_frame_row_entry_addr1 {
uint8_t sfre_start_address;
sframe_fre_info sfre_info;
};

struct sframe_frame_row_entry_addr2 {
uint16_t sfre_start_address;
sframe_fre_info sfre_info;
};

struct sframe_frame_row_entry_addr4 {
uint32_t sfre_start_address;
sframe_fre_info sfre_info;
};

LLVM_PACKED_END

ArrayRef<EnumEntry<uint8_t>> getVersions();
ArrayRef<EnumEntry<uint8_t>> getHeaderFlags();
ArrayRef<EnumEntry<uint8_t>> getABIs();

} // namespace sframe
} // namespace llvm

#endif // LLVM_BINARYFORMAT_SFRAME_H
38 changes: 38 additions & 0 deletions llvm/include/llvm/BinaryFormat/SFrameConstants.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//===- SFrameConstants.def --------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#if !(defined(HANDLE_SFRAME_VERSION) || defined(HANDLE_SFRAME_HEADER_FLAG) || \
defined(HANDLE_SFRAME_ABI))
#error "Missing HANDLE_SFRAME definition"
#endif

#ifndef HANDLE_SFRAME_VERSION
#define HANDLE_SFRAME_VERSION(CODE, NAME)
#endif

#ifndef HANDLE_SFRAME_HEADER_FLAG
#define HANDLE_SFRAME_HEADER_FLAG(CODE, NAME)
#endif

#ifndef HANDLE_SFRAME_ABI
#define HANDLE_SFRAME_ABI(CODE, NAME)
#endif

HANDLE_SFRAME_VERSION(0x01, VERSION_1)
HANDLE_SFRAME_VERSION(0x02, VERSION_2)

HANDLE_SFRAME_HEADER_FLAG(0x01, FDE_SORTED)
HANDLE_SFRAME_HEADER_FLAG(0x02, FRAME_POINTER)

HANDLE_SFRAME_ABI(0x01, AARCH64_ENDIAN_BIG)
HANDLE_SFRAME_ABI(0x02, AARCH64_ENDIAN_LITTLE)
HANDLE_SFRAME_ABI(0x03, AMD64_ENDIAN_LITTLE)

#undef HANDLE_SFRAME_VERSION
#undef HANDLE_SFRAME_HEADER_FLAG
#undef HANDLE_SFRAME_ABI
47 changes: 47 additions & 0 deletions llvm/include/llvm/Object/SFrameParser.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//===- SFrameParser.h -------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_OBJECT_SFRAME_H
#define LLVM_OBJECT_SFRAME_H

#include "llvm/BinaryFormat/SFrame.h"
#include "llvm/Support/DataExtractor.h"
#include "llvm/Support/Error.h"
#include <cstdint>

namespace llvm {
namespace object {

class SFrameParser {
public:
static Expected<SFrameParser> create(ArrayRef<uint8_t> Contents);

const sframe::sframe_preamble &getPreamble() const {
return Header.sfh_preamble;
}
const sframe::sframe_header &getHeader() const { return Header; }

bool usesFixedRAOffset() const {
return Header.sfh_abi_arch == sframe::SFRAME_ABI_AMD64_ENDIAN_LITTLE;
}
bool usesFixedFPOffset() const {
return false; // Not used in any currently defined ABI.
}

private:
DataExtractor Data;
sframe::sframe_header Header;

SFrameParser(DataExtractor Data, sframe::sframe_header Header)
: Data(Data), Header(Header) {}
};

} // end namespace object
} // end namespace llvm

#endif // LLVM_OBJECT_SFRAME_H
1 change: 1 addition & 0 deletions llvm/lib/BinaryFormat/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ add_llvm_component_library(LLVMBinaryFormat
MsgPackDocumentYAML.cpp
MsgPackReader.cpp
MsgPackWriter.cpp
SFrame.cpp
Wasm.cpp
XCOFF.cpp

Expand Down
40 changes: 40 additions & 0 deletions llvm/lib/BinaryFormat/SFrame.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//===-- SFrame.cpp -----------------------------------------------*- C++-*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "llvm/BinaryFormat/SFrame.h"
#include "llvm/Support/ScopedPrinter.h"

using namespace llvm;

ArrayRef<EnumEntry<uint8_t>> sframe::getVersions() {
static constexpr EnumEntry<uint8_t> Versions[] = {
#define HANDLE_SFRAME_VERSION(CODE, NAME) \
{"SFRAME_" #NAME, sframe::SFRAME_##NAME},
#include "llvm/BinaryFormat/SFrameConstants.def"
};

return ArrayRef(Versions);
}

ArrayRef<EnumEntry<uint8_t>> sframe::getHeaderFlags() {
static constexpr EnumEntry<uint8_t> Flags[] = {
#define HANDLE_SFRAME_HEADER_FLAG(CODE, NAME) \
{"SFRAME_F_" #NAME, sframe::SFRAME_F_##NAME},
#include "llvm/BinaryFormat/SFrameConstants.def"
};
return ArrayRef(Flags);
}

ArrayRef<EnumEntry<uint8_t>> sframe::getABIs() {
static constexpr EnumEntry<uint8_t> ABIs[] = {
#define HANDLE_SFRAME_ABI(CODE, NAME) \
{"SFRAME_ABI_" #NAME, sframe::SFRAME_ABI_##NAME},
#include "llvm/BinaryFormat/SFrameConstants.def"
};
return ArrayRef(ABIs);
}
1 change: 1 addition & 0 deletions llvm/lib/Object/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ add_llvm_component_library(LLVMObject
OffloadBundle.cpp
RecordStreamer.cpp
RelocationResolver.cpp
SFrameParser.cpp
SymbolicFile.cpp
SymbolSize.cpp
TapiFile.cpp
Expand Down
65 changes: 65 additions & 0 deletions llvm/lib/Object/SFrameParser.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//===- SFrameParser.cpp ---------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "llvm/Object/SFrameParser.h"
#include "llvm/Object/Error.h"

using namespace llvm;
using namespace llvm::object;
using namespace llvm::sframe;

Expected<SFrameParser> SFrameParser::create(ArrayRef<uint8_t> Contents) {
sframe_header Header;
sframe_preamble &Preamble = Header.sfh_preamble;

// IsLittleEndian will be swapped if needed, AddressSize is unused.
DataExtractor Data(Contents, /*IsLittleEndian=*/true, /*AddressSize=*/0);
DataExtractor::Cursor Cursor(0);
Preamble.sfp_magic = Data.getU16(Cursor);
if (!Cursor)
return Cursor.takeError();

switch (Preamble.sfp_magic) {
case SFRAME_MAGIC:
break;
case byteswap(SFRAME_MAGIC):
// Fix endianness.
Preamble.sfp_magic = SFRAME_MAGIC;
// And make sure everything that comes afterwards is read correctly.
Data = DataExtractor(Data.getData(), !Data.isLittleEndian(),
Data.getAddressSize());
break;
default:
return make_error<GenericBinaryError>("invalid magic number",
object_error::parse_failed);
}
Preamble.sfp_version = Data.getU8(Cursor);
Preamble.sfp_flags = Data.getU8(Cursor);
if (!Cursor)
return Cursor.takeError();

if (Preamble.sfp_version != SFRAME_VERSION_2) {
return make_error<GenericBinaryError>("invalid/unsupported version number",
object_error::parse_failed);
}

Header.sfh_abi_arch = Data.getU8(Cursor);
Header.sfh_cfa_fixed_fp_offset = (int8_t)Data.getU8(Cursor);
Header.sfh_cfa_fixed_ra_offset = (int8_t)Data.getU8(Cursor);
Header.sfh_auxhdr_len = Data.getU8(Cursor);
Header.sfh_num_fdes = Data.getU32(Cursor);
Header.sfh_num_fres = Data.getU32(Cursor);
Header.sfh_fre_len = Data.getU32(Cursor);
Header.sfh_fdeoff = Data.getU32(Cursor);
Header.sfh_freoff = Data.getU32(Cursor);

if (!Cursor)
return Cursor.takeError();

return SFrameParser(Data, Header);
}
Loading
Loading