Files
swift-mirror/stdlib/public/RuntimeModule/modules/ImageFormats/PeCoff/pe-coff.h
T
Alastair Houghton 78702e64cb [Backtracing] Fix struct packing for PE-COFF definitions.
Due to unfortunate structure packing rules in C, `struct pe_symbol` ends up
being 20 bytes instead of 18. The upshot is that when presented with a PE-COFF
binary that contains symbols (noting that this is actually a spec violation),
the backtracer will crash.

Unfortunately we often generate such binaries. We shouldn’t crash, though, and
the fix is to get the correct size for `struct pe_symbol`.

rdar://171711254
2026-03-04 12:18:56 +00:00

418 lines
14 KiB
C++

//===--- pe-coff.h - Definitions of PE-COFF structures for Swift ----------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2025 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// Definitions of PE-COFF structures for import into Swift code.
//
// We don't just get these from the Windows headers, because we'd like to be
// able to read PE-COFF binaries on non-Windows machines too.
//
// See <https://learn.microsoft.com/en-us/windows/win32/debug/pe-format>
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_PE_COFF_H_
#define SWIFT_PE_COFF_H_
#include <inttypes.h>
#pragma pack(push, 1)
namespace swift {
namespace runtime {
/* .. Useful macros ......................................................... */
#define PE_ENUM(t,n) \
enum __attribute__((enum_extensibility(open))) n: t
#define PE_OPTIONS(t,n) \
typedef t n; \
enum __attribute__((flag_enum,enum_extensibility(open))): t
/* .. Constants ............................................................. */
// DOS signature
PE_ENUM(uint16_t, pe_dos_signature) {
PE_DOS_SIGNATURE = 0x5a4d, // MZ
};
// PE signature
PE_ENUM(uint32_t, pe_signature) {
PE_SIGNATURE = 0x00004550, // PE..
};
// Machine types
PE_ENUM(uint16_t, pe_machine) {
PE_MACHINE_UNKNOWN = 0,
PE_MACHINE_ALPHA = 0x0184,
PE_MACHINE_ALPHA64 = 0x0284,
PE_MACHINE_AM33 = 0x01d3,
PE_MACHINE_AMD64 = 0x8664,
PE_MACHINE_ARM = 0x01c0,
PE_MACHINE_ARM64 = 0xaa64,
PE_MACHINE_ARM64EC = 0xa641,
PE_MACHINE_ARM64X = 0xa64e,
PE_MACHINE_ARMNT = 0x01c4,
PE_MACHINE_AXP64 = PE_MACHINE_ALPHA64,
PE_MACHINE_EBC = 0x0ebc,
PE_MACHINE_I386 = 0x014c,
PE_MACHINE_IA64 = 0x0200,
PE_MACHINE_LOONGARCH32 = 0x6232,
PE_MACHINE_LOONGARCH64 = 0x6264,
PE_MACHINE_M32R = 0x9041,
PE_MACHINE_MIPS16 = 0x0266,
PE_MACHINE_MIPSFPU = 0x0366,
PE_MACHINE_MIPSFPU16 = 0x0466,
PE_MACHINE_POWERPC = 0x01f0,
PE_MACHINE_POWERPCFP = 0x01f1,
PE_MACHINE_R3000BE = 0x0160,
PE_MACHINE_R3000 = 0x0162,
PE_MACHINE_R4000 = 0x0166,
PE_MACHINE_R10000 = 0x0168,
PE_MACHINE_RISCV32 = 0x5032,
PE_MACHINE_RISCV64 = 0x5064,
PE_MACHINE_RISCV128 = 0x5128,
PE_MACHINE_SH3 = 0x01a2,
PE_MACHINE_SH3DSP = 0x01a3,
PE_MACHINE_SH4 = 0x01a6,
PE_MACHINE_SH5 = 0x0108,
PE_MACHINE_THUMB = 0x01c2,
PE_MACHINE_WCEMIPSV2 = 0x0169,
};
// PE header characteristics
PE_OPTIONS(uint16_t, pe_characteristics) {
PE_RELOCS_STRIPPED = 0x0001,
PE_EXECUTABLE_IMAGE = 0x0002,
PE_LINE_NUMS_STRIPPED = 0x0004,
PE_LOCAL_SYMS_STRIPPED = 0x0008,
PE_AGGRESSIVE_WS_TRIM = 0x0010,
PE_LARGE_ADDRESS_AWARE = 0x0020,
PE_BYTES_REVERSED_LO = 0x0080,
PE_32BIT_MACHINE = 0x0100,
PE_DEBUG_STRIPPED = 0x0200,
PE_REMOVABLE_RUN_FROM_SWAP = 0x0400,
PE_NET_RUN_FROM_SWAP = 0x0800,
PE_SYSTEM = 0x1000,
PE_DLL = 0x2000,
PE_UP_SYSTEM_ONLY = 0x4000,
PE_BYTES_REVERSED_HI = 0x8000,
};
// PE optional header magic
PE_ENUM(uint16_t, pe_optional_magic) {
PE_PE32 = 0x010b,
PE_PE32_PLUS = 0x020b,
};
// Windows subsystems
PE_ENUM(uint16_t, pe_subsystem) {
PE_SUBSYSTEM_UNKNOWN = 0,
PE_SUBSYSTEM_NATIVE = 1,
PE_SUBSYSTEM_WINDOWS_GUI = 2,
PE_SUBSYSTEM_WINDOWS_CUI = 3,
PE_SUBSYSTEM_OS2_CUI = 5,
PE_SUBSYSTEM_POSIX_CUI = 7,
PE_SUBSYSTEM_NATIVE_WINDOWS = 8,
PE_SUBSYSTEM_WINDOWS_CE_GUI = 9,
PE_SUBSYSTEM_EFI_APPLICATION = 10,
PE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER = 11,
PE_SUBSYSTEM_EFI_RUNTIME_DRIVER = 12,
PE_SUBSYSTEM_EFI_ROM = 13,
PE_IMAGE_SUBSYSTEM_XBOX = 14,
PE_IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION = 16,
};
// DLL characteristics
PE_OPTIONS(uint16_t, pe_dll_characteristics) {
PE_DLL_HIGH_ENTROPY_VA = 0x0020,
PE_DLL_DYNAMIC_BASE = 0x0040,
PE_DLL_FORCE_INTEGRITY = 0x0080,
PE_DLL_NX_COMPAT = 0x0100,
PE_DLL_NO_ISOLATION = 0x0200,
PE_DLL_NO_SEH = 0x0400,
PE_DLL_NO_BIND = 0x0800,
PE_DLL_APPCONTAINER = 0x1000,
PE_DLL_WDM_DRIVER = 0x2000,
PE_DLL_GUARD_CF = 0x4000,
PE_DLL_TERMINAL_SERVER_AWARE = 0x8000,
};
// Section characteristics
PE_OPTIONS(uint32_t, pe_section_characteristics) {
PE_SECTION_TYPE_NO_PAD = 0x00000008,
PE_SECTION_CNT_CODE = 0x00000020,
PE_SECTION_CNT_INITIALIZED_DATA = 0x00000040,
PE_SECTION_CNT_UNINITIALIZED_DATA = 0x00000080,
PE_SECTION_LNK_OTHER = 0x00000100,
PE_SECTION_LNK_INFO = 0x00000200,
PE_SECTION_LNK_REMOVE = 0x00000800,
PE_SECTION_GPREL = 0x00008000,
PE_SECTION_MEM_PURGEABLE = 0x00020000,
PE_SECTION_MEM_LOCKED = 0x00040000,
PE_SECTION_MEM_PRELOAD = 0x00080000,
PE_SECTION_ALIGNMENT_MASK = 0x00f00000,
PE_SECTION_LNK_NRELOC_OVFL = 0x01000000,
PE_SECTION_MEM_DISCARDABLE = 0x02000000,
PE_SECTION_MEM_NOT_CACHED = 0x04000000,
PE_SECTION_MEM_NOT_PAGED = 0x08000000,
PE_SECTION_MEM_SHARED = 0x10000000,
PE_SECTION_MEM_EXECUTE = 0x20000000,
PE_SECTION_MEM_READ = 0x40000000,
PE_SECTION_MEM_WRITE = 0x80000000,
};
static inline uint32_t pe_section_alignment(pe_section_characteristics characteristics) {
uint32_t alignment = ((characteristics >> 20) & 0xf);
if (!alignment) return 16;
return 1 << (alignment - 1);
}
// Symbol types
PE_ENUM(uint16_t, pe_symbol_type) {
PE_SYMBOL_TYPE_NULL = 0,
PE_SYMBOL_TYPE_VOID = 1,
PE_SYMBOL_TYPE_CHAR = 2,
PE_SYMBOL_TYPE_SHORT = 3,
PE_SYMBOL_TYPE_INT = 4,
PE_SYMBOL_TYPE_LONG = 5,
PE_SYMBOL_TYPE_FLOAT = 6,
PE_SYMBOL_TYPE_DOUBLE = 7,
PE_SYMBOL_TYPE_STRUCT = 8,
PE_SYMBOL_TYPE_UNION = 9,
PE_SYMBOL_TYPE_ENUM = 10,
PE_SYMBOL_TYPE_MOE = 11,
PE_SYMBOL_TYPE_BYTE = 12,
PE_SYMBOL_TYPE_WORD = 13,
PE_SYMBOL_TYPE_UINT = 14,
PE_SYMBOL_TYPE_DWORD = 15,
};
// Symbol storage classes
PE_ENUM(uint8_t, pe_symbol_class) {
PE_SYMBOL_CLASS_END_OF_FUNCTION = 0xff,
PE_SYMBOL_CLASS_NULL = 0,
PE_SYMBOL_CLASS_AUTOMATIC = 1,
PE_SYMBOL_CLASS_EXTERNAL = 2,
PE_SYMBOL_CLASS_STATIC = 3,
PE_SYMBOL_CLASS_REGISTER = 4,
PE_SYMBOL_CLASS_EXTERNAL_DEF = 5,
PE_SYMBOL_CLASS_LABEL = 6,
PE_SYMBOL_CLASS_UNDEFINED_LABEL = 7,
PE_SYMBOL_CLASS_MEMBER_OF_STRUCT = 8,
PE_SYMBOL_CLASS_ARGUMENT = 9,
PE_SYMBOL_CLASS_STRUCT_TAG = 10,
PE_SYMBOL_CLASS_MEMBER_OF_UNION = 11,
PE_SYMBOL_CLASS_UNION_TAG = 12,
PE_SYMBOL_CLASS_TYPE_DEFINITION = 13,
PE_SYMBOL_CLASS_UNDEFINED_STATIC = 14,
PE_SYMBOL_CLASS_ENUM_TAG = 15,
PE_SYMBOL_CLASS_MEMBER_OF_ENUM = 16,
PE_SYMBOL_CLASS_REGISTER_PARAM = 17,
PE_SYMBOL_CLASS_BIT_FIELD = 18,
PE_SYMBOL_CLASS_BLOCK = 100,
PE_SYMBOL_CLASS_FUNCTION = 101,
PE_SYMBOL_CLASS_END_OF_STRUCT = 102,
PE_SYMBOL_CLASS_FILE = 103,
PE_SYMBOL_CLASS_SECTION = 104,
PE_SYMBOL_CLASS_WEAK_EXTERNAL = 105,
PE_SYMBOL_CLASS_CLR_TOKEN = 107,
};
PE_ENUM(uint32_t, pe_debug_directory_type) {
PE_DEBUG_TYPE_UNKNOWN = 0,
PE_DEBUG_TYPE_COFF = 1,
PE_DEBUG_TYPE_CODEVIEW = 2,
PE_DEBUG_TYPE_FPO = 3,
PE_DEBUG_TYPE_MISC = 4,
PE_DEBUG_TYPE_EXCEPTION = 5,
PE_DEBUG_TYPE_FIXUP = 6,
PE_DEBUG_TYPE_OMAP_TO_SRC = 7,
PE_DEBUG_TYPE_OMAP_FROM_SRC = 8,
PE_DEBUG_TYPE_BORLAND = 9,
PE_DEBUG_TYPE_BBT = 10,
PE_DEBUG_TYPE_CLSID = 11,
PE_DEBUG_TYPE_VC_FEATURE = 12,
PE_DEBUG_TYPE_POGO = 13,
PE_DEBUG_TYPE_ILTCG = 14,
PE_DEBUG_TYPE_MPX = 15,
PE_DEBUG_TYPE_REPRO = 16,
PE_DEBUG_TYPE_SPGO = 18,
PE_DEBUG_TYPE_EX_DLLCHARACTERISTICS = 20
};
// We would do this, but it causes a warning because there are no flags
// defined:
//
// PE_OPTIONS(uint32_t, pe_debug_characteristics) {
// };
//
typedef uint32_t pe_debug_characteristics;
/* .. PE Header ............................................................. */
// DOS header - the only thing we actually care about is the offset to the PE
// header at 0x3c.
struct pe_dos_header {
pe_dos_signature e_magic; // Magic number
uint16_t e_cblp; // Count of bytes in last page
uint16_t e_cp; // Count of pages
uint16_t e_crlc; // Count of relocations
uint16_t e_cparhdr; // Count of paragraphs in header
uint16_t e_minalloc; // Minimum allocation in paragraphs
uint16_t e_maxalloc; // Maximum allocation in paragraphs
uint16_t e_ss; // Initial stack segment
uint16_t e_sp; // Initial stack pointer
uint16_t e_csum; // Checksum
uint16_t e_ip; // Initial instruction pointer
uint16_t e_cs; // Initial code segment
uint16_t e_lfarlc; // Offset to relocation table
uint16_t e_ovno; // Overlay number
uint16_t e_res[4]; // Reserved
uint16_t e_oemid; // OEM identifier
uint16_t e_oeminfo; // OEM information
uint16_t e_res2[10]; // Reserved
uint32_t e_lfanew; // Offset to PE header
};
struct pe_header {
pe_machine Machine;
uint16_t NumberOfSections;
uint32_t TimeDateStamp;
uint32_t PointerToSymbolTable;
uint32_t NumberOfSymbols;
uint16_t SizeOfOptionalHeader;
pe_characteristics Characteristics;
};
struct pe_optional_header {
pe_optional_magic Magic;
uint8_t MajorLinkerVersion;
uint8_t MinorLinkerVersion;
uint32_t SizeOfCode;
uint32_t SizeOfInitializedData;
uint32_t SizeOfUninitializedData;
uint32_t AddressOfEntryPoint;
uint32_t BaseOfCode;
};
struct pe_data_directory_entry {
uint32_t VirtualAddress;
uint32_t Size;
};
struct pe_windows_header32 {
uint32_t ImageBase;
uint32_t SectionAlignment;
uint32_t FileAlignment;
uint16_t MajorOperatingSystemVersion;
uint16_t MinorOperatingSystemVersion;
uint16_t MajorImageVersion;
uint16_t MinorImageVersion;
uint16_t MajorSubsystemVersion;
uint16_t MinorSubsystemVersion;
uint32_t Win32VersionValue;
uint32_t SizeOfImage;
uint32_t SizeOfHeaders;
uint32_t CheckSum;
pe_subsystem Subsystem;
pe_dll_characteristics DllCharacteristics;
uint32_t SizeOfStackReserve;
uint32_t SizeOfStackCommit;
uint32_t SizeOfHeapReserve;
uint32_t SizeOfHeapCommit;
uint32_t LoaderFlags;
uint32_t NumberOfRvaAndSizes;
// Followed by:
// pe_data_directory_entry DataDirectory[NumberOfRvaAndSizes];
} pe_windows_header32;
struct pe_windows_header64 {
uint64_t ImageBase;
uint32_t SectionAlignment;
uint32_t FileAlignment;
uint16_t MajorOperatingSystemVersion;
uint16_t MinorOperatingSystemVersion;
uint16_t MajorImageVersion;
uint16_t MinorImageVersion;
uint16_t MajorSubsystemVersion;
uint16_t MinorSubsystemVersion;
uint32_t Win32VersionValue;
uint32_t SizeOfImage;
uint32_t SizeOfHeaders;
uint32_t CheckSum;
pe_subsystem Subsystem;
pe_dll_characteristics DllCharacteristics;
uint64_t SizeOfStackReserve;
uint64_t SizeOfStackCommit;
uint64_t SizeOfHeapReserve;
uint64_t SizeOfHeapCommit;
uint32_t LoaderFlags;
uint32_t NumberOfRvaAndSizes;
// Followed by:
// pe_data_directory_entry DataDirectory[NumberOfRvaAndSizes];
};
struct pe_section {
char Name[8];
uint32_t VirtualSize;
uint32_t VirtualAddress;
uint32_t SizeOfRawData;
uint32_t PointerToRawData;
uint32_t PointerToRelocations;
uint32_t PointerToLinenumbers;
uint16_t NumberOfRelocations;
uint16_t NumberOfLinenumbers;
pe_section_characteristics Characteristics;
};
/* .. Debug Directory ....................................................... */
struct pe_debug_directory {
pe_debug_characteristics Characteristics;
uint32_t TimeDateStamp;
uint16_t MajorVersion;
uint16_t MinorVersion;
pe_debug_directory_type Type;
uint32_t SizeOfData;
uint32_t AddressOfRawData;
uint32_t PointerToRawData;
};
/* .. COFF symbol table ..................................................... */
struct pe_symbol {
// This is either up to eight characters of short name, or four zero bytes
// followed by an offset into the string table
union {
char ShortName[8];
struct {
uint32_t Zeroes;
uint32_t Offset; // Offset into the string table
} LongName;
};
uint32_t Value;
int16_t SectionNumber;
pe_symbol_type Type;
pe_symbol_class StorageClass;
uint8_t NumberOfAuxSymbols;
};
} // namespace runtime
} // namespace swift
#pragma pack(pop)
#endif // SWIFT_PE_COFF_H_