brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.7 KiB · 706a3d0 Raw
113 lines · cpp
1//===- bolt/Rewrite/BuildIDRewriter.cpp -----------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Read and update build ID stored in ELF note section.10//11//===----------------------------------------------------------------------===//12 13#include "bolt/Rewrite/MetadataRewriter.h"14#include "bolt/Rewrite/MetadataRewriters.h"15#include "llvm/Support/Errc.h"16 17using namespace llvm;18using namespace bolt;19 20namespace {21 22/// The build-id is typically a stream of 20 bytes. Return these bytes in23/// printable hexadecimal form.24std::string getPrintableBuildID(StringRef BuildID) {25  std::string Str;26  raw_string_ostream OS(Str);27  for (const char &Char : BuildID)28    OS << format("%.2x", static_cast<unsigned char>(Char));29 30  return OS.str();31}32 33class BuildIDRewriter final : public MetadataRewriter {34 35  /// Information about binary build ID.36  ErrorOr<BinarySection &> BuildIDSection{std::errc::bad_address};37  StringRef BuildID;38  std::optional<uint64_t> BuildIDOffset;39  std::optional<uint64_t> BuildIDSize;40 41public:42  BuildIDRewriter(StringRef Name, BinaryContext &BC)43      : MetadataRewriter(Name, BC) {}44 45  Error sectionInitializer() override;46 47  Error postEmitFinalizer() override;48};49 50Error BuildIDRewriter::sectionInitializer() {51  // Typically, build ID will reside in .note.gnu.build-id section. However,52  // a linker script can change the section name and such is the case with53  // the Linux kernel. Hence, we iterate over all note sections.54  for (BinarySection &NoteSection : BC.sections()) {55    if (!NoteSection.isNote())56      continue;57 58    StringRef Buf = NoteSection.getContents();59    DataExtractor DE = DataExtractor(Buf, BC.AsmInfo->isLittleEndian(),60                                     BC.AsmInfo->getCodePointerSize());61    DataExtractor::Cursor Cursor(0);62    while (Cursor && !DE.eof(Cursor)) {63      const uint32_t NameSz = DE.getU32(Cursor);64      const uint32_t DescSz = DE.getU32(Cursor);65      const uint32_t Type = DE.getU32(Cursor);66 67      StringRef Name =68          NameSz ? Buf.slice(Cursor.tell(), Cursor.tell() + NameSz) : "<empty>";69      Cursor.seek(alignTo(Cursor.tell() + NameSz, 4));70 71      const uint64_t DescOffset = Cursor.tell();72      StringRef Desc =73          DescSz ? Buf.slice(DescOffset, DescOffset + DescSz) : "<empty>";74      Cursor.seek(alignTo(DescOffset + DescSz, 4));75 76      if (!Cursor)77        return createStringError(errc::executable_format_error,78                                 "out of bounds while reading note section: %s",79                                 toString(Cursor.takeError()).c_str());80 81      if (Type == ELF::NT_GNU_BUILD_ID && Name.starts_with("GNU") && DescSz) {82        BuildIDSection = NoteSection;83        BuildID = Desc;84        BC.setFileBuildID(getPrintableBuildID(Desc));85        BuildIDOffset = DescOffset;86        BuildIDSize = DescSz;87 88        return Error::success();89      }90    }91  }92 93  return Error::success();94}95 96Error BuildIDRewriter::postEmitFinalizer() {97  if (!BuildIDSection || !BuildIDOffset)98    return Error::success();99 100  const uint8_t LastByte = BuildID[BuildID.size() - 1];101  SmallVector<char, 1> Patch = {static_cast<char>(LastByte ^ 1)};102  BuildIDSection->addPatch(*BuildIDOffset + BuildID.size() - 1, Patch);103  BC.outs() << "BOLT-INFO: patched build-id (flipped last bit)\n";104 105  return Error::success();106}107} // namespace108 109std::unique_ptr<MetadataRewriter>110llvm::bolt::createBuildIDRewriter(BinaryContext &BC) {111  return std::make_unique<BuildIDRewriter>("build-id-rewriter", BC);112}113