Skip to content

Commit c5c5014

Browse files
author
Jenkins
committed
merge main into amd-staging
Change-Id: Ibf3ac34e94a95a5a359ac155f5421e4c9e2d63f2
2 parents c232c71 + 6479006 commit c5c5014

File tree

14 files changed

+360
-78
lines changed

14 files changed

+360
-78
lines changed

bolt/lib/Rewrite/LinuxKernelRewriter.cpp

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ static cl::opt<bool>
3535
DumpORC("dump-orc", cl::desc("dump raw ORC unwind information (sorted)"),
3636
cl::init(false), cl::Hidden, cl::cat(BoltCategory));
3737

38+
static cl::opt<bool> DumpStaticCalls("dump-static-calls",
39+
cl::desc("dump Linux kernel static calls"),
40+
cl::init(false), cl::Hidden,
41+
cl::cat(BoltCategory));
42+
3843
} // namespace opts
3944

4045
/// Linux Kernel supports stack unwinding using ORC (oops rewind capability).
@@ -116,6 +121,19 @@ class LinuxKernelRewriter final : public MetadataRewriter {
116121
/// Number of entries in the input file ORC sections.
117122
uint64_t NumORCEntries = 0;
118123

124+
/// Section containing static call table.
125+
ErrorOr<BinarySection &> StaticCallSection = std::errc::bad_address;
126+
uint64_t StaticCallTableAddress = 0;
127+
static constexpr size_t STATIC_CALL_ENTRY_SIZE = 8;
128+
129+
struct StaticCallInfo {
130+
uint32_t ID; /// Identifier of the entry in the table.
131+
BinaryFunction *Function; /// Function containing associated call.
132+
MCSymbol *Label; /// Label attached to the call.
133+
};
134+
using StaticCallListType = std::vector<StaticCallInfo>;
135+
StaticCallListType StaticCallEntries;
136+
119137
/// Insert an LKMarker for a given code pointer \p PC from a non-code section
120138
/// \p SectionName.
121139
void insertLKMarker(uint64_t PC, uint64_t SectionOffset,
@@ -152,6 +170,10 @@ class LinuxKernelRewriter final : public MetadataRewriter {
152170
/// Update ORC data in the binary.
153171
Error rewriteORCTables();
154172

173+
/// Static call table handling.
174+
Error readStaticCalls();
175+
Error rewriteStaticCalls();
176+
155177
/// Mark instructions referenced by kernel metadata.
156178
Error markInstructions();
157179

@@ -167,6 +189,9 @@ class LinuxKernelRewriter final : public MetadataRewriter {
167189
if (Error E = readORCTables())
168190
return E;
169191

192+
if (Error E = readStaticCalls())
193+
return E;
194+
170195
return Error::success();
171196
}
172197

@@ -181,6 +206,9 @@ class LinuxKernelRewriter final : public MetadataRewriter {
181206
if (Error E = rewriteORCTables())
182207
return E;
183208

209+
if (Error E = rewriteStaticCalls())
210+
return E;
211+
184212
return Error::success();
185213
}
186214

@@ -793,6 +821,133 @@ Error LinuxKernelRewriter::rewriteORCTables() {
793821
return Error::success();
794822
}
795823

824+
/// The static call site table is created by objtool and contains entries in the
825+
/// following format:
826+
///
827+
/// struct static_call_site {
828+
/// s32 addr;
829+
/// s32 key;
830+
/// };
831+
///
832+
Error LinuxKernelRewriter::readStaticCalls() {
833+
const BinaryData *StaticCallTable =
834+
BC.getBinaryDataByName("__start_static_call_sites");
835+
if (!StaticCallTable)
836+
return Error::success();
837+
838+
StaticCallTableAddress = StaticCallTable->getAddress();
839+
840+
const BinaryData *Stop = BC.getBinaryDataByName("__stop_static_call_sites");
841+
if (!Stop)
842+
return createStringError(errc::executable_format_error,
843+
"missing __stop_static_call_sites symbol");
844+
845+
ErrorOr<BinarySection &> ErrorOrSection =
846+
BC.getSectionForAddress(StaticCallTableAddress);
847+
if (!ErrorOrSection)
848+
return createStringError(errc::executable_format_error,
849+
"no section matching __start_static_call_sites");
850+
851+
StaticCallSection = *ErrorOrSection;
852+
if (!StaticCallSection->containsAddress(Stop->getAddress() - 1))
853+
return createStringError(errc::executable_format_error,
854+
"__stop_static_call_sites not in the same section "
855+
"as __start_static_call_sites");
856+
857+
if ((Stop->getAddress() - StaticCallTableAddress) % STATIC_CALL_ENTRY_SIZE)
858+
return createStringError(errc::executable_format_error,
859+
"static call table size error");
860+
861+
const uint64_t SectionAddress = StaticCallSection->getAddress();
862+
DataExtractor DE(StaticCallSection->getContents(),
863+
BC.AsmInfo->isLittleEndian(),
864+
BC.AsmInfo->getCodePointerSize());
865+
DataExtractor::Cursor Cursor(StaticCallTableAddress - SectionAddress);
866+
uint32_t EntryID = 0;
867+
while (Cursor && Cursor.tell() < Stop->getAddress() - SectionAddress) {
868+
const uint64_t CallAddress =
869+
SectionAddress + Cursor.tell() + (int32_t)DE.getU32(Cursor);
870+
const uint64_t KeyAddress =
871+
SectionAddress + Cursor.tell() + (int32_t)DE.getU32(Cursor);
872+
873+
// Consume the status of the cursor.
874+
if (!Cursor)
875+
return createStringError(errc::executable_format_error,
876+
"out of bounds while reading static calls");
877+
878+
++EntryID;
879+
880+
if (opts::DumpStaticCalls) {
881+
outs() << "Static Call Site: " << EntryID << '\n';
882+
outs() << "\tCallAddress: 0x" << Twine::utohexstr(CallAddress) << '\n'
883+
<< "\tKeyAddress: 0x" << Twine::utohexstr(KeyAddress) << '\n';
884+
}
885+
886+
BinaryFunction *BF = BC.getBinaryFunctionContainingAddress(CallAddress);
887+
if (!BF)
888+
continue;
889+
890+
if (!BC.shouldEmit(*BF))
891+
continue;
892+
893+
if (!BF->hasInstructions())
894+
continue;
895+
896+
MCInst *Inst = BF->getInstructionAtOffset(CallAddress - BF->getAddress());
897+
if (!Inst)
898+
return createStringError(errc::executable_format_error,
899+
"no instruction at call site address 0x%" PRIx64,
900+
CallAddress);
901+
902+
// Check for duplicate entries.
903+
if (BC.MIB->hasAnnotation(*Inst, "StaticCall"))
904+
return createStringError(errc::executable_format_error,
905+
"duplicate static call site at 0x%" PRIx64,
906+
CallAddress);
907+
908+
BC.MIB->addAnnotation(*Inst, "StaticCall", EntryID);
909+
910+
MCSymbol *Label = BC.MIB->getLabel(*Inst);
911+
if (!Label) {
912+
Label = BC.Ctx->createTempSymbol("__SC_");
913+
BC.MIB->setLabel(*Inst, Label);
914+
}
915+
916+
StaticCallEntries.push_back({EntryID, BF, Label});
917+
}
918+
919+
outs() << "BOLT-INFO: parsed " << StaticCallEntries.size()
920+
<< " static call entries\n";
921+
922+
return Error::success();
923+
}
924+
925+
/// The static call table is sorted during boot time in
926+
/// static_call_sort_entries(). This makes it possible to update existing
927+
/// entries in-place ignoring their relative order.
928+
Error LinuxKernelRewriter::rewriteStaticCalls() {
929+
if (!StaticCallTableAddress || !StaticCallSection)
930+
return Error::success();
931+
932+
for (auto &Entry : StaticCallEntries) {
933+
if (!Entry.Function)
934+
continue;
935+
936+
BinaryFunction &BF = *Entry.Function;
937+
if (!BC.shouldEmit(BF))
938+
continue;
939+
940+
// Create a relocation against the label.
941+
const uint64_t EntryOffset = StaticCallTableAddress -
942+
StaticCallSection->getAddress() +
943+
(Entry.ID - 1) * STATIC_CALL_ENTRY_SIZE;
944+
StaticCallSection->addRelocation(EntryOffset, Entry.Label,
945+
ELF::R_X86_64_PC32, /*Addend*/ 0);
946+
}
947+
948+
return Error::success();
949+
}
950+
796951
} // namespace
797952

798953
std::unique_ptr<MetadataRewriter>

bolt/test/X86/linux-static-calls.s

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# REQUIRES: system-linux
2+
3+
## Check that BOLT correctly updates the Linux kernel static calls table.
4+
5+
# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o
6+
# RUN: %clang %cflags -nostdlib %t.o -o %t.exe \
7+
# RUN: -Wl,--image-base=0xffffffff80000000,--no-dynamic-linker,--no-eh-frame-hdr
8+
9+
## Verify static calls bindings to instructions.
10+
11+
# RUN: llvm-bolt %t.exe --print-normalized -o %t.out --keep-nops=0 \
12+
# RUN: --bolt-info=0 |& FileCheck %s
13+
14+
## Verify the bindings again on the rewritten binary with nops removed.
15+
16+
# RUN: llvm-bolt %t.out -o %t.out.1 --print-normalized |& FileCheck %s
17+
18+
# CHECK: BOLT-INFO: Linux kernel binary detected
19+
# CHECK: BOLT-INFO: parsed 2 static call entries
20+
21+
.text
22+
.globl _start
23+
.type _start, %function
24+
_start:
25+
# CHECK: Binary Function "_start"
26+
nop
27+
.L0:
28+
call foo
29+
# CHECK: callq foo # {{.*}} StaticCall: 1
30+
nop
31+
.L1:
32+
jmp foo
33+
# CHECK: jmp foo # {{.*}} StaticCall: 2
34+
.size _start, .-_start
35+
36+
.globl foo
37+
.type foo, %function
38+
foo:
39+
ret
40+
.size foo, .-foo
41+
42+
43+
## Static call table.
44+
.rodata
45+
.globl __start_static_call_sites
46+
.type __start_static_call_sites, %object
47+
__start_static_call_sites:
48+
.long .L0 - .
49+
.long 0
50+
.long .L1 - .
51+
.long 0
52+
53+
.globl __stop_static_call_sites
54+
.type __stop_static_call_sites, %object
55+
__stop_static_call_sites:
56+
57+
## Fake Linux Kernel sections.
58+
.section __ksymtab,"a",@progbits
59+
.section __ksymtab_gpl,"a",@progbits

clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -706,13 +706,17 @@ void LoopConvertCheck::doConversion(
706706
ReplaceText = Usage.Kind == Usage::UK_MemberThroughArrow
707707
? VarNameOrStructuredBinding + "."
708708
: VarNameOrStructuredBinding;
709-
auto Parents = Context->getParents(*Usage.Expression);
709+
const DynTypedNodeList Parents = Context->getParents(*Usage.Expression);
710710
if (Parents.size() == 1) {
711711
if (const auto *Paren = Parents[0].get<ParenExpr>()) {
712712
// Usage.Expression will be replaced with the new index variable,
713713
// and parenthesis around a simple DeclRefExpr can always be
714-
// removed.
715-
Range = Paren->getSourceRange();
714+
// removed except in case of a `sizeof` operator call.
715+
const DynTypedNodeList GrandParents = Context->getParents(*Paren);
716+
if (GrandParents.size() != 1 ||
717+
GrandParents[0].get<UnaryExprOrTypeTraitExpr>() == nullptr) {
718+
Range = Paren->getSourceRange();
719+
}
716720
} else if (const auto *UOP = Parents[0].get<UnaryOperator>()) {
717721
// If we are taking the address of the loop variable, then we must
718722
// not use a copy, as it would mean taking the address of the loop's

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,11 @@ Changes in existing checks
170170
`AllowStringArrays` option, enabling the exclusion of array types with deduced
171171
length initialized from string literals.
172172

173+
- Improved :doc:`modernize-loop-convert
174+
<clang-tidy/checks/modernize/loop-convert>` check by ensuring that fix-its
175+
don't remove parentheses used in ``sizeof`` calls when they have array index
176+
accesses as arguments.
177+
173178
- Improved :doc:`modernize-use-override
174179
<clang-tidy/checks/modernize/use-override>` check to also remove any trailing
175180
whitespace when deleting the ``virtual`` keyword.

clang-tools-extra/test/clang-tidy/checkers/modernize/loop-convert-basic.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,19 @@ void f() {
8888
// CHECK-FIXES-NEXT: printf("Fibonacci number %d has address %p\n", I, &I);
8989
// CHECK-FIXES-NEXT: Sum += I + 2;
9090

91+
int Matrix[N][12];
92+
unsigned size = 0;
93+
for (int I = 0; I < N; ++I) {
94+
size += sizeof(Matrix[I]);
95+
size += sizeof Matrix[I];
96+
size += sizeof((Matrix[I]));
97+
}
98+
// CHECK-MESSAGES: :[[@LINE-5]]:3: warning: use range-based for loop instead
99+
// CHECK-FIXES: for (auto & I : Matrix)
100+
// CHECK-FIXES-NEXT: size += sizeof(I);
101+
// CHECK-FIXES-NEXT: size += sizeof I;
102+
// CHECK-FIXES-NEXT: size += sizeof(I);
103+
91104
Val Teas[N];
92105
for (int I = 0; I < N; ++I) {
93106
Teas[I].g();

clang/lib/CodeGen/CoverageMappingGen.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1942,6 +1942,8 @@ struct CounterCoverageMappingBuilder
19421942

19431943
extendRegion(E->getTrueExpr());
19441944
OutCount = propagateCounts(TrueCount, E->getTrueExpr());
1945+
} else {
1946+
OutCount = TrueCount;
19451947
}
19461948

19471949
extendRegion(E->getFalseExpr());
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// RUN: %clang_cc1 -mllvm -emptyline-comment-coverage=false -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only %s | FileCheck %s
2+
3+
// CHECK-LABEL: binary_conditional:
4+
// CHECK-NEXT: File 0, [[@LINE+4]]:31 -> {{[0-9]+}}:2 = #0
5+
// CHECK-NEXT: File 0, [[@LINE+4]]:7 -> [[@LINE+4]]:8 = #0
6+
// CHECK-NEXT: Branch,File 0, [[@LINE+3]]:7 -> [[@LINE+3]]:8 = #1, (#0 - #1)
7+
// CHECK-NEXT: File 0, [[@LINE+2]]:13 -> [[@LINE+2]]:14 = (#0 - #1)
8+
int binary_conditional(int x) {
9+
x = x ? : 4;
10+
int y = x;
11+
return y;
12+
}
13+
14+
// CHECK-LABEL: ternary_conditional:
15+
// CHECK-NEXT: File 0, [[@LINE+6]]:32 -> {{[0-9]+}}:2 = #0
16+
// CHECK-NEXT: File 0, [[@LINE+6]]:7 -> [[@LINE+6]]:8 = #0
17+
// CHECK-NEXT: Branch,File 0, [[@LINE+5]]:7 -> [[@LINE+5]]:8 = #1, (#0 - #1)
18+
// CHECK-NEXT: Gap,File 0, [[@LINE+4]]:10 -> [[@LINE+4]]:11 = #1
19+
// CHECK-NEXT: File 0, [[@LINE+3]]:11 -> [[@LINE+3]]:12 = #1
20+
// CHECK-NEXT: File 0, [[@LINE+2]]:15 -> [[@LINE+2]]:16 = (#0 - #1)
21+
int ternary_conditional(int x) {
22+
x = x ? x : 4;
23+
int y = x;
24+
return y;
25+
}

0 commit comments

Comments
 (0)