Skip to content

Commit e55641b

Browse files
committed
Merge branch 'main' into hgh/libcxx/P3060R3-Add-std_views_indices
2 parents 394a10c + 98766d2 commit e55641b

File tree

561 files changed

+22757
-8762
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

561 files changed

+22757
-8762
lines changed
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
//===- bolt/Core/MCInstUtils.h ----------------------------------*- C++ -*-===//
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+
#ifndef BOLT_CORE_MCINSTUTILS_H
10+
#define BOLT_CORE_MCINSTUTILS_H
11+
12+
#include "bolt/Core/BinaryBasicBlock.h"
13+
#include <map>
14+
#include <variant>
15+
16+
namespace llvm {
17+
class MCCodeEmitter;
18+
}
19+
20+
namespace llvm {
21+
namespace bolt {
22+
23+
class BinaryFunction;
24+
25+
/// MCInstReference represents a reference to a constant MCInst as stored either
26+
/// in a BinaryFunction (i.e. before a CFG is created), or in a BinaryBasicBlock
27+
/// (after a CFG is created).
28+
///
29+
/// The reference may be invalidated when the function containing the referenced
30+
/// instruction is modified.
31+
class MCInstReference {
32+
public:
33+
using nocfg_const_iterator = std::map<uint32_t, MCInst>::const_iterator;
34+
35+
/// Constructs an empty reference.
36+
MCInstReference() : Reference(RefInBB(nullptr, /*Index=*/0)) {}
37+
38+
/// Constructs a reference to the instruction inside the basic block.
39+
MCInstReference(const BinaryBasicBlock &BB, const MCInst &Inst)
40+
: Reference(RefInBB(&BB, getInstIndexInBB(BB, Inst))) {}
41+
/// Constructs a reference to the instruction inside the basic block.
42+
MCInstReference(const BinaryBasicBlock &BB, unsigned Index)
43+
: Reference(RefInBB(&BB, Index)) {}
44+
45+
/// Constructs a reference to the instruction inside the function without
46+
/// CFG information.
47+
MCInstReference(const BinaryFunction &BF, nocfg_const_iterator It)
48+
: Reference(RefInBF(&BF, It)) {}
49+
50+
/// Locates an instruction inside a function and returns a reference.
51+
static MCInstReference get(const MCInst &Inst, const BinaryFunction &BF);
52+
53+
bool operator==(const MCInstReference &Other) const {
54+
return Reference == Other.Reference;
55+
}
56+
57+
const MCInst &getMCInst() const {
58+
assert(!empty() && "Empty reference");
59+
if (auto *Ref = tryGetRefInBB()) {
60+
[[maybe_unused]] unsigned NumInstructions = Ref->BB->size();
61+
assert(Ref->Index < NumInstructions && "Invalid reference");
62+
return Ref->BB->getInstructionAtIndex(Ref->Index);
63+
}
64+
return getRefInBF().It->second;
65+
}
66+
67+
operator const MCInst &() const { return getMCInst(); }
68+
69+
bool empty() const {
70+
if (auto *Ref = tryGetRefInBB())
71+
return Ref->BB == nullptr;
72+
return getRefInBF().BF == nullptr;
73+
}
74+
75+
bool hasCFG() const { return !empty() && tryGetRefInBB() != nullptr; }
76+
77+
const BinaryFunction *getFunction() const {
78+
assert(!empty() && "Empty reference");
79+
if (auto *Ref = tryGetRefInBB())
80+
return Ref->BB->getFunction();
81+
return getRefInBF().BF;
82+
}
83+
84+
const BinaryBasicBlock *getBasicBlock() const {
85+
assert(!empty() && "Empty reference");
86+
if (auto *Ref = tryGetRefInBB())
87+
return Ref->BB;
88+
return nullptr;
89+
}
90+
91+
/// Computes the original address of the instruction (or offset from base
92+
/// for PIC), assuming the containing function was not modified.
93+
///
94+
/// This function is intended for the use cases like debug printing, as it
95+
/// is only as precise as BinaryContext::computeCodeSize() is and requires
96+
/// iterating over the prefix of the basic block (when CFG is available).
97+
///
98+
/// MCCodeEmitter is not thread safe and the default instance from
99+
/// BinaryContext is used by default, thus pass an instance explicitly if
100+
/// this function may be called from multithreaded code.
101+
uint64_t computeAddress(const MCCodeEmitter *Emitter = nullptr) const;
102+
103+
raw_ostream &print(raw_ostream &OS) const;
104+
105+
private:
106+
static unsigned getInstIndexInBB(const BinaryBasicBlock &BB,
107+
const MCInst &Inst) {
108+
// Usage of pointer arithmetic assumes the instructions are stored in a
109+
// vector, see BasicBlockStorageIsVector in MCInstUtils.cpp.
110+
const MCInst *FirstInstInBB = &*BB.begin();
111+
return &Inst - FirstInstInBB;
112+
}
113+
114+
// Two cases are possible:
115+
// * functions with CFG reconstructed - a function stores a collection of
116+
// basic blocks, each basic block stores a contiguous vector of MCInst
117+
// * functions without CFG - there are no basic blocks created,
118+
// the instructions are directly stored in std::map in BinaryFunction
119+
//
120+
// In both cases, the direct parent of MCInst is stored together with an
121+
// index or iterator pointing to the instruction.
122+
123+
// Helper struct: CFG is available, the direct parent is a basic block.
124+
struct RefInBB {
125+
RefInBB(const BinaryBasicBlock *BB, unsigned Index)
126+
: BB(BB), Index(Index) {}
127+
RefInBB(const RefInBB &Other) = default;
128+
RefInBB &operator=(const RefInBB &Other) = default;
129+
130+
const BinaryBasicBlock *BB;
131+
unsigned Index;
132+
133+
bool operator==(const RefInBB &Other) const {
134+
return BB == Other.BB && Index == Other.Index;
135+
}
136+
};
137+
138+
// Helper struct: CFG is *not* available, the direct parent is a function,
139+
// iterator's type is std::map<uint32_t, MCInst>::iterator (the mapped value
140+
// is an instruction's offset).
141+
struct RefInBF {
142+
RefInBF(const BinaryFunction *BF, nocfg_const_iterator It)
143+
: BF(BF), It(It) {}
144+
RefInBF(const RefInBF &Other) = default;
145+
RefInBF &operator=(const RefInBF &Other) = default;
146+
147+
const BinaryFunction *BF;
148+
nocfg_const_iterator It;
149+
150+
bool operator==(const RefInBF &Other) const {
151+
return BF == Other.BF && It->first == Other.It->first;
152+
}
153+
};
154+
155+
std::variant<RefInBB, RefInBF> Reference;
156+
157+
// Utility methods to be used like this:
158+
//
159+
// if (auto *Ref = tryGetRefInBB())
160+
// return Ref->doSomething(...);
161+
// return getRefInBF().doSomethingElse(...);
162+
const RefInBB *tryGetRefInBB() const {
163+
assert(std::get_if<RefInBB>(&Reference) ||
164+
std::get_if<RefInBF>(&Reference));
165+
return std::get_if<RefInBB>(&Reference);
166+
}
167+
const RefInBF &getRefInBF() const {
168+
assert(std::get_if<RefInBF>(&Reference));
169+
return *std::get_if<RefInBF>(&Reference);
170+
}
171+
};
172+
173+
static inline raw_ostream &operator<<(raw_ostream &OS,
174+
const MCInstReference &Ref) {
175+
return Ref.print(OS);
176+
}
177+
178+
} // namespace bolt
179+
} // namespace llvm
180+
181+
#endif

bolt/include/bolt/Passes/PAuthGadgetScanner.h

Lines changed: 1 addition & 175 deletions
Original file line numberDiff line numberDiff line change
@@ -11,187 +11,13 @@
1111

1212
#include "bolt/Core/BinaryContext.h"
1313
#include "bolt/Core/BinaryFunction.h"
14+
#include "bolt/Core/MCInstUtils.h"
1415
#include "bolt/Passes/BinaryPasses.h"
1516
#include "llvm/Support/raw_ostream.h"
1617
#include <memory>
1718

1819
namespace llvm {
1920
namespace bolt {
20-
21-
/// @brief MCInstReference represents a reference to an MCInst as stored either
22-
/// in a BinaryFunction (i.e. before a CFG is created), or in a BinaryBasicBlock
23-
/// (after a CFG is created). It aims to store the necessary information to be
24-
/// able to find the specific MCInst in either the BinaryFunction or
25-
/// BinaryBasicBlock data structures later, so that e.g. the InputAddress of
26-
/// the corresponding instruction can be computed.
27-
28-
struct MCInstInBBReference {
29-
BinaryBasicBlock *BB;
30-
int64_t BBIndex;
31-
MCInstInBBReference(BinaryBasicBlock *BB, int64_t BBIndex)
32-
: BB(BB), BBIndex(BBIndex) {}
33-
MCInstInBBReference() : BB(nullptr), BBIndex(0) {}
34-
static MCInstInBBReference get(const MCInst *Inst, BinaryFunction &BF) {
35-
for (BinaryBasicBlock &BB : BF)
36-
for (size_t I = 0; I < BB.size(); ++I)
37-
if (Inst == &BB.getInstructionAtIndex(I))
38-
return MCInstInBBReference(&BB, I);
39-
return {};
40-
}
41-
bool operator==(const MCInstInBBReference &RHS) const {
42-
return BB == RHS.BB && BBIndex == RHS.BBIndex;
43-
}
44-
bool operator<(const MCInstInBBReference &RHS) const {
45-
return std::tie(BB, BBIndex) < std::tie(RHS.BB, RHS.BBIndex);
46-
}
47-
operator MCInst &() const {
48-
assert(BB != nullptr);
49-
return BB->getInstructionAtIndex(BBIndex);
50-
}
51-
uint64_t getAddress() const {
52-
// 4 bytes per instruction on AArch64.
53-
// FIXME: the assumption of 4 byte per instruction needs to be fixed before
54-
// this method gets used on any non-AArch64 binaries (but should be fine for
55-
// pac-ret analysis, as that is an AArch64-specific feature).
56-
return BB->getFunction()->getAddress() + BB->getOffset() + BBIndex * 4;
57-
}
58-
};
59-
60-
raw_ostream &operator<<(raw_ostream &OS, const MCInstInBBReference &);
61-
62-
struct MCInstInBFReference {
63-
BinaryFunction *BF;
64-
uint64_t Offset;
65-
MCInstInBFReference(BinaryFunction *BF, uint64_t Offset)
66-
: BF(BF), Offset(Offset) {}
67-
68-
static MCInstInBFReference get(const MCInst *Inst, BinaryFunction &BF) {
69-
for (auto &I : BF.instrs())
70-
if (Inst == &I.second)
71-
return MCInstInBFReference(&BF, I.first);
72-
return {};
73-
}
74-
75-
MCInstInBFReference() : BF(nullptr), Offset(0) {}
76-
bool operator==(const MCInstInBFReference &RHS) const {
77-
return BF == RHS.BF && Offset == RHS.Offset;
78-
}
79-
bool operator<(const MCInstInBFReference &RHS) const {
80-
return std::tie(BF, Offset) < std::tie(RHS.BF, RHS.Offset);
81-
}
82-
operator MCInst &() const {
83-
assert(BF != nullptr);
84-
return *BF->getInstructionAtOffset(Offset);
85-
}
86-
87-
uint64_t getOffset() const { return Offset; }
88-
89-
uint64_t getAddress() const { return BF->getAddress() + getOffset(); }
90-
};
91-
92-
raw_ostream &operator<<(raw_ostream &OS, const MCInstInBFReference &);
93-
94-
struct MCInstReference {
95-
enum Kind { FunctionParent, BasicBlockParent };
96-
Kind ParentKind;
97-
union U {
98-
MCInstInBBReference BBRef;
99-
MCInstInBFReference BFRef;
100-
U(MCInstInBBReference BBRef) : BBRef(BBRef) {}
101-
U(MCInstInBFReference BFRef) : BFRef(BFRef) {}
102-
} U;
103-
MCInstReference(MCInstInBBReference BBRef)
104-
: ParentKind(BasicBlockParent), U(BBRef) {}
105-
MCInstReference(MCInstInBFReference BFRef)
106-
: ParentKind(FunctionParent), U(BFRef) {}
107-
MCInstReference(BinaryBasicBlock *BB, int64_t BBIndex)
108-
: MCInstReference(MCInstInBBReference(BB, BBIndex)) {}
109-
MCInstReference(BinaryFunction *BF, uint32_t Offset)
110-
: MCInstReference(MCInstInBFReference(BF, Offset)) {}
111-
112-
static MCInstReference get(const MCInst *Inst, BinaryFunction &BF) {
113-
if (BF.hasCFG())
114-
return MCInstInBBReference::get(Inst, BF);
115-
return MCInstInBFReference::get(Inst, BF);
116-
}
117-
118-
bool operator<(const MCInstReference &RHS) const {
119-
if (ParentKind != RHS.ParentKind)
120-
return ParentKind < RHS.ParentKind;
121-
switch (ParentKind) {
122-
case BasicBlockParent:
123-
return U.BBRef < RHS.U.BBRef;
124-
case FunctionParent:
125-
return U.BFRef < RHS.U.BFRef;
126-
}
127-
llvm_unreachable("");
128-
}
129-
130-
bool operator==(const MCInstReference &RHS) const {
131-
if (ParentKind != RHS.ParentKind)
132-
return false;
133-
switch (ParentKind) {
134-
case BasicBlockParent:
135-
return U.BBRef == RHS.U.BBRef;
136-
case FunctionParent:
137-
return U.BFRef == RHS.U.BFRef;
138-
}
139-
llvm_unreachable("");
140-
}
141-
142-
operator MCInst &() const {
143-
switch (ParentKind) {
144-
case BasicBlockParent:
145-
return U.BBRef;
146-
case FunctionParent:
147-
return U.BFRef;
148-
}
149-
llvm_unreachable("");
150-
}
151-
152-
operator bool() const {
153-
switch (ParentKind) {
154-
case BasicBlockParent:
155-
return U.BBRef.BB != nullptr;
156-
case FunctionParent:
157-
return U.BFRef.BF != nullptr;
158-
}
159-
llvm_unreachable("");
160-
}
161-
162-
uint64_t getAddress() const {
163-
switch (ParentKind) {
164-
case BasicBlockParent:
165-
return U.BBRef.getAddress();
166-
case FunctionParent:
167-
return U.BFRef.getAddress();
168-
}
169-
llvm_unreachable("");
170-
}
171-
172-
BinaryFunction *getFunction() const {
173-
switch (ParentKind) {
174-
case FunctionParent:
175-
return U.BFRef.BF;
176-
case BasicBlockParent:
177-
return U.BBRef.BB->getFunction();
178-
}
179-
llvm_unreachable("");
180-
}
181-
182-
BinaryBasicBlock *getBasicBlock() const {
183-
switch (ParentKind) {
184-
case FunctionParent:
185-
return nullptr;
186-
case BasicBlockParent:
187-
return U.BBRef.BB;
188-
}
189-
llvm_unreachable("");
190-
}
191-
};
192-
193-
raw_ostream &operator<<(raw_ostream &OS, const MCInstReference &);
194-
19521
namespace PAuthGadgetScanner {
19622

19723
// The report classes are designed to be used in an immutable manner.

bolt/lib/Core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ add_llvm_library(LLVMBOLTCore
3232
GDBIndex.cpp
3333
HashUtilities.cpp
3434
JumpTable.cpp
35+
MCInstUtils.cpp
3536
MCPlusBuilder.cpp
3637
ParallelUtilities.cpp
3738
Relocation.cpp

0 commit comments

Comments
 (0)