[LLVM][IR] Use splat syntax when printing ConstantExpr based splats. (#116856)
[llvm-project.git] / bolt / lib / Rewrite / BuildIDRewriter.cpp
blob83d0c9bfe182aeb91dd7d897c62f200dc95790b6
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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Read and update build ID stored in ELF note section.
11 //===----------------------------------------------------------------------===//
13 #include "bolt/Rewrite/MetadataRewriter.h"
14 #include "bolt/Rewrite/MetadataRewriters.h"
15 #include "llvm/Support/Errc.h"
17 using namespace llvm;
18 using namespace bolt;
20 namespace {
22 /// The build-id is typically a stream of 20 bytes. Return these bytes in
23 /// printable hexadecimal form.
24 std::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));
30 return OS.str();
33 class BuildIDRewriter final : public MetadataRewriter {
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;
41 public:
42 BuildIDRewriter(StringRef Name, BinaryContext &BC)
43 : MetadataRewriter(Name, BC) {}
45 Error sectionInitializer() override;
47 Error postEmitFinalizer() override;
50 Error BuildIDRewriter::sectionInitializer() {
51 // Typically, build ID will reside in .note.gnu.build-id section. Howerver,
52 // a linker script can change the section name and such is the case with
53 // the Linux kernel. Hence, we iterate over all note sections.
54 for (BinarySection &NoteSection : BC.sections()) {
55 if (!NoteSection.isNote())
56 continue;
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);
67 StringRef Name =
68 NameSz ? Buf.slice(Cursor.tell(), Cursor.tell() + NameSz) : "<empty>";
69 Cursor.seek(alignTo(Cursor.tell() + NameSz, 4));
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));
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());
81 if (Type == ELF::NT_GNU_BUILD_ID && Name.substr(0, 3) == "GNU" &&
82 DescSz) {
83 BuildIDSection = NoteSection;
84 BuildID = Desc;
85 BC.setFileBuildID(getPrintableBuildID(Desc));
86 BuildIDOffset = DescOffset;
87 BuildIDSize = DescSz;
89 return Error::success();
94 return Error::success();
97 Error BuildIDRewriter::postEmitFinalizer() {
98 if (!BuildIDSection || !BuildIDOffset)
99 return Error::success();
101 const uint8_t LastByte = BuildID[BuildID.size() - 1];
102 SmallVector<char, 1> Patch = {static_cast<char>(LastByte ^ 1)};
103 BuildIDSection->addPatch(*BuildIDOffset + BuildID.size() - 1, Patch);
104 BC.outs() << "BOLT-INFO: patched build-id (flipped last bit)\n";
106 return Error::success();
108 } // namespace
110 std::unique_ptr<MetadataRewriter>
111 llvm::bolt::createBuildIDRewriter(BinaryContext &BC) {
112 return std::make_unique<BuildIDRewriter>("build-id-rewriter", BC);