cb424d7448
verify-patch-sanity.py validates every active recipe .patch has internally- consistent hunk line counts — catching the 'malformed patch at line N' failure at commit/CI/preflight time instead of hours into a cook. This cycle hit that class three times (qtwaylandscanner, sddm, xwayland), each only discovered when cookbook tried to apply the patch. Running it across the repo found 29 latent malformed patches (validated against GNU patch: e.g. relibc/P3-sysv-ipc reproduces 'malformed patch at line 22'). They were harmless only because they sit in vendored recipes (baked, not re- applied) — but would fail on any version-bump re-derivation. --fix recounts the hunk headers (body untouched) and repaired all 29. Wired into build-preflight.sh (Phase 1.0D) and redbear-ci.yml, with a unit test (test-patch-sanity.sh). Skips archived/legacy trees and unvalidatable formats (empty placeholders, bare-@@ git hunks).
117 lines
4.3 KiB
C++
117 lines
4.3 KiB
C++
//===- EhFrame.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 LLD_MACHO_EH_FRAME_H
|
|
#define LLD_MACHO_EH_FRAME_H
|
|
|
|
#include "InputSection.h"
|
|
#include "Relocations.h"
|
|
|
|
#include "lld/Common/LLVM.h"
|
|
#include "llvm/ADT/ArrayRef.h"
|
|
#include "llvm/ADT/PointerUnion.h"
|
|
#include "llvm/ADT/SmallVector.h"
|
|
|
|
/*
|
|
* NOTE: The main bulk of the EH frame parsing logic is in InputFiles.cpp as it
|
|
* is closely coupled with other file parsing logic; EhFrame.h just contains a
|
|
* few helpers.
|
|
*/
|
|
|
|
/*
|
|
* === The EH frame format ===
|
|
*
|
|
* EH frames can either be Common Information Entries (CIEs) or Frame
|
|
* Description Entries (FDEs). CIEs contain information that is common amongst
|
|
* several FDEs. Each FDE contains a pointer to its CIE. Thus all the EH frame
|
|
* entries together form a forest of two-level trees, with CIEs as the roots
|
|
* and FDEs as the leaves. Note that a CIE must precede the FDEs which point
|
|
* to it.
|
|
*
|
|
* A CIE comprises the following fields in order:
|
|
* 1. Length of the entry (4 or 12 bytes)
|
|
* 2. CIE offset (4 bytes; always 0 for CIEs)
|
|
* 3. CIE version (byte)
|
|
* 4. Null-terminated augmentation string
|
|
* 5-8. LEB128 values that we don't care about
|
|
* 9. Augmentation data, to be interpreted using the aug string
|
|
* 10. DWARF instructions (ignored by LLD)
|
|
*
|
|
* An FDE comprises of the following:
|
|
* 1. Length of the entry (4 or 12 bytes)
|
|
* 2. CIE offset (4 bytes pcrel offset that points backwards to this FDE's CIE)
|
|
* 3. Function address (pointer-sized pcrel offset)
|
|
* 4. (std::optional) Augmentation data length
|
|
* 5. (std::optional) LSDA address (pointer-sized pcrel offset)
|
|
* 6. DWARF instructions (ignored by LLD)
|
|
*/
|
|
namespace lld::macho {
|
|
|
|
class EhReader {
|
|
public:
|
|
EhReader(const ObjFile *file, ArrayRef<uint8_t> data, size_t dataOff)
|
|
: file(file), data(data), dataOff(dataOff) {}
|
|
size_t size() const { return data.size(); }
|
|
// Read and validate the length field.
|
|
uint64_t readLength(size_t *off) const;
|
|
// Skip the length field without doing validation.
|
|
void skipValidLength(size_t *off) const;
|
|
uint8_t readByte(size_t *off) const;
|
|
uint32_t readU32(size_t *off) const;
|
|
uint64_t readPointer(size_t *off, uint8_t size) const;
|
|
StringRef readString(size_t *off) const;
|
|
void skipLeb128(size_t *off) const;
|
|
void failOn(size_t errOff, const Twine &msg) const;
|
|
|
|
private:
|
|
const ObjFile *file;
|
|
ArrayRef<uint8_t> data;
|
|
// The offset of the data array within its section. Used only for error
|
|
// reporting.
|
|
const size_t dataOff;
|
|
};
|
|
|
|
// The EH frame format, when emitted by llvm-mc, consists of a number of
|
|
// "abs-ified" relocations, i.e. relocations that are implicitly encoded as
|
|
// pcrel offsets in the section data. The offsets refer to the locations of
|
|
// symbols in the input object file. When we ingest these EH frames, we convert
|
|
// these implicit relocations into explicit Relocs.
|
|
//
|
|
// These pcrel relocations are semantically similar to X86_64_RELOC_SIGNED_4.
|
|
// However, we need this operation to be cross-platform, and ARM does not have a
|
|
// similar relocation that is applicable. We therefore use the more verbose (but
|
|
// more generic) subtractor relocation to encode these pcrel values. ld64
|
|
// appears to do something similar -- its `-r` output contains these explicit
|
|
// subtractor relocations.
|
|
class EhRelocator {
|
|
public:
|
|
EhRelocator(InputSection *isec) : isec(isec) {}
|
|
|
|
// For the next two methods, let `PC` denote `isec address + off`.
|
|
// Create relocs writing the value of target - PC to PC.
|
|
void makePcRel(uint64_t off,
|
|
llvm::PointerUnion<Symbol *, InputSection *> target,
|
|
uint8_t length);
|
|
// Create relocs writing the value of PC - target to PC.
|
|
void makeNegativePcRel(uint64_t off,
|
|
llvm::PointerUnion<Symbol *, InputSection *> target,
|
|
uint8_t length);
|
|
// Insert the new relocations into isec->relocs.
|
|
void commit();
|
|
|
|
private:
|
|
InputSection *isec;
|
|
// Insert new relocs here so that we don't invalidate iterators into the
|
|
// existing relocs vector.
|
|
SmallVector<Reloc, 6> newRelocs;
|
|
};
|
|
|
|
} // namespace lld::macho
|
|
|
|
#endif
|