From 10bc12588dac532fad044b2851dde8e7b9121e88 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Fri, 24 Apr 2020 13:39:02 -0700 Subject: [PATCH] [XRay] Change Sled.Function to PC-relative for sled version 2 and make llvm-xray support sled version 2 addresses Follow-up of D78082 and D78590. Otherwise, because xray_instr_map is now read-only, the absolute relocation used for Sled.Function will cause a text relocation. --- compiler-rt/lib/xray/xray_interface.cpp | 4 +-- compiler-rt/lib/xray/xray_interface_internal.h | 12 +++++++ llvm/include/llvm/CodeGen/AsmPrinter.h | 2 +- llvm/include/llvm/XRay/InstrumentationMap.h | 4 +++ llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 35 +++++++++++-------- llvm/lib/XRay/InstrumentationMap.cpp | 15 ++++++-- .../Mips/xray-mips-attribute-instrumentation.ll | 40 +++++++++++----------- .../PowerPC/xray-attribute-instrumentation.ll | 6 ++-- llvm/test/CodeGen/X86/xray-log-args.ll | 11 +++--- llvm/tools/llvm-xray/xray-extract.cpp | 6 ++-- 10 files changed, 86 insertions(+), 49 deletions(-) diff --git a/compiler-rt/lib/xray/xray_interface.cpp b/compiler-rt/lib/xray/xray_interface.cpp index 29dad43..082aaf4 100644 --- a/compiler-rt/lib/xray/xray_interface.cpp +++ b/compiler-rt/lib/xray/xray_interface.cpp @@ -295,7 +295,7 @@ XRayPatchingStatus controlPatching(bool Enable) XRAY_NEVER_INSTRUMENT { for (std::size_t I = 0; I < InstrMap.Entries; ++I) { auto &Sled = InstrMap.Sleds[I]; - auto F = Sled.Function; + auto F = Sled.function(); if (CurFun == 0) CurFun = F; if (F != CurFun) { @@ -466,7 +466,7 @@ uintptr_t __xray_function_address(int32_t FuncId) XRAY_NEVER_INSTRUMENT { SpinMutexLock Guard(&XRayInstrMapMutex); if (FuncId <= 0 || static_cast(FuncId) > XRayInstrMap.Functions) return 0; - return XRayInstrMap.SledsIndex[FuncId - 1].Begin->Function + return XRayInstrMap.SledsIndex[FuncId - 1].Begin->function() // On PPC, function entries are always aligned to 16 bytes. The beginning of a // sled might be a local entry, which is always +8 based on the global entry. // Always return the global entry. diff --git a/compiler-rt/lib/xray/xray_interface_internal.h b/compiler-rt/lib/xray/xray_interface_internal.h index cdd1b9cb..390f389 100644 --- a/compiler-rt/lib/xray/xray_interface_internal.h +++ b/compiler-rt/lib/xray/xray_interface_internal.h @@ -29,6 +29,12 @@ struct XRaySledEntry { unsigned char AlwaysInstrument; unsigned char Version; unsigned char Padding[13]; // Need 32 bytes + uint64_t function() const { + if (Version < 2) + return Function; + // The target address is relative to the location of the Function variable. + return reinterpret_cast(&Function) + Function; + } uint64_t address() const { if (Version < 2) return Address; @@ -42,6 +48,12 @@ struct XRaySledEntry { unsigned char AlwaysInstrument; unsigned char Version; unsigned char Padding[5]; // Need 16 bytes + uint32_t function() const { + if (Version < 2) + return Function; + // The target address is relative to the location of the Function variable. + return reinterpret_cast(&Function) + Function; + } uint32_t address() const { if (Version < 2) return Address; diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h index b4aa4798..ff9ec9c 100644 --- a/llvm/include/llvm/CodeGen/AsmPrinter.h +++ b/llvm/include/llvm/CodeGen/AsmPrinter.h @@ -280,7 +280,7 @@ public: const class Function *Fn; uint8_t Version; - void emit(int, MCStreamer *, const MCExpr *, const MCSymbol *) const; + void emit(int, MCStreamer *) const; }; // All the sleds to be emitted. diff --git a/llvm/include/llvm/XRay/InstrumentationMap.h b/llvm/include/llvm/XRay/InstrumentationMap.h index 5cbe5c4..aae9034 100644 --- a/llvm/include/llvm/XRay/InstrumentationMap.h +++ b/llvm/include/llvm/XRay/InstrumentationMap.h @@ -50,6 +50,8 @@ struct SledEntry { /// Whether the sled was annotated to always be instrumented. bool AlwaysInstrument; + + unsigned char Version; }; struct YAMLXRaySledEntry { @@ -59,6 +61,7 @@ struct YAMLXRaySledEntry { SledEntry::FunctionKinds Kind; bool AlwaysInstrument; std::string FunctionName; + unsigned char Version; }; /// The InstrumentationMap represents the computed function id's and indicated @@ -120,6 +123,7 @@ template <> struct MappingTraits { IO.mapRequired("kind", Entry.Kind); IO.mapRequired("always-instrument", Entry.AlwaysInstrument); IO.mapOptional("function-name", Entry.FunctionName); + IO.mapOptional("version", Entry.Version, 0); } static constexpr bool flow = true; diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 7b9bcb6..0d31a9d 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1767,6 +1767,8 @@ void AsmPrinter::SetupMachineFunction(MachineFunction &MF) { CurExceptionSym = nullptr; bool NeedsLocalForSize = MAI->needsLocalForSize(); if (F.hasFnAttribute("patchable-function-entry") || + F.hasFnAttribute("function-instrument") || + F.hasFnAttribute("xray-instruction-threshold") || needFuncLabelsForEHOrDebugInfo(MF, MMI) || NeedsLocalForSize || MF.getTarget().Options.EmitStackSizeSection) { CurrentFnBegin = createTempSymbol("func_begin"); @@ -3174,14 +3176,7 @@ void AsmPrinterHandler::markFunctionEnd() {} // In the binary's "xray_instr_map" section, an array of these function entries // describes each instrumentation point. When XRay patches your code, the index // into this table will be given to your handler as a patch point identifier. -void AsmPrinter::XRayFunctionEntry::emit(int Bytes, MCStreamer *Out, - const MCExpr *Location, - const MCSymbol *CurrentFnSym) const { - if (Location) - Out->emitValueImpl(Location, Bytes); - else - Out->emitSymbolValue(Sled, Bytes); - Out->emitSymbolValue(CurrentFnSym, Bytes); +void AsmPrinter::XRayFunctionEntry::emit(int Bytes, MCStreamer *Out) const { auto Kind8 = static_cast(Kind); Out->emitBinaryData(StringRef(reinterpret_cast(&Kind8), 1)); Out->emitBinaryData( @@ -3234,19 +3229,31 @@ void AsmPrinter::emitXRayTable() { // Now we switch to the instrumentation map section. Because this is done // per-function, we are able to create an index entry that will represent the // range of sleds associated with a function. + auto &Ctx = OutContext; MCSymbol *SledsStart = OutContext.createTempSymbol("xray_sleds_start", true); OutStreamer->SwitchSection(InstMap); OutStreamer->emitLabel(SledsStart); for (const auto &Sled : Sleds) { - const MCExpr *Location = nullptr; if (PCRel) { - MCSymbol *Dot = OutContext.createTempSymbol(); + MCSymbol *Dot = Ctx.createTempSymbol(); OutStreamer->emitLabel(Dot); - Location = MCBinaryExpr::createSub( - MCSymbolRefExpr::create(Sled.Sled, OutContext), - MCSymbolRefExpr::create(Dot, OutContext), OutContext); + OutStreamer->emitValueImpl( + MCBinaryExpr::createSub(MCSymbolRefExpr::create(Sled.Sled, Ctx), + MCSymbolRefExpr::create(Dot, Ctx), Ctx), + WordSizeBytes); + OutStreamer->emitValueImpl( + MCBinaryExpr::createSub( + MCSymbolRefExpr::create(CurrentFnBegin, Ctx), + MCBinaryExpr::createAdd( + MCSymbolRefExpr::create(Dot, Ctx), + MCConstantExpr::create(WordSizeBytes, Ctx), Ctx), + Ctx), + WordSizeBytes); + } else { + OutStreamer->emitSymbolValue(Sled.Sled, WordSizeBytes); + OutStreamer->emitSymbolValue(CurrentFnSym, WordSizeBytes); } - Sled.emit(WordSizeBytes, OutStreamer.get(), Location, CurrentFnSym); + Sled.emit(WordSizeBytes, OutStreamer.get()); } MCSymbol *SledsEnd = OutContext.createTempSymbol("xray_sleds_end", true); OutStreamer->emitLabel(SledsEnd); diff --git a/llvm/lib/XRay/InstrumentationMap.cpp b/llvm/lib/XRay/InstrumentationMap.cpp index 1e9b69a..b095d71 100644 --- a/llvm/lib/XRay/InstrumentationMap.cpp +++ b/llvm/lib/XRay/InstrumentationMap.cpp @@ -68,10 +68,13 @@ loadObj(StringRef Filename, object::OwningBinary &ObjFile, StringRef Contents = ""; const auto &Sections = ObjFile.getBinary()->sections(); + uint64_t Address = 0; auto I = llvm::find_if(Sections, [&](object::SectionRef Section) { Expected NameOrErr = Section.getName(); - if (NameOrErr) + if (NameOrErr) { + Address = Section.getAddress(); return *NameOrErr == "xray_instr_map"; + } consumeError(NameOrErr.takeError()); return false; }); @@ -141,6 +144,7 @@ loadObj(StringRef Filename, object::OwningBinary &ObjFile, return Address; }; + const int WordSize = 8; int32_t FuncId = 1; uint64_t CurFn = 0; for (; C != Contents.bytes_end(); C += ELF64SledEntrySize) { @@ -165,6 +169,11 @@ loadObj(StringRef Filename, object::OwningBinary &ObjFile, std::make_error_code(std::errc::executable_format_error)); Entry.Kind = Kinds[Kind]; Entry.AlwaysInstrument = Extractor.getU8(&OffsetPtr) != 0; + Entry.Version = Extractor.getU8(&OffsetPtr); + if (Entry.Version >= 2) { + Entry.Address += C - Contents.bytes_begin() + Address; + Entry.Function += C - Contents.bytes_begin() + WordSize + Address; + } // We do replicate the function id generation scheme implemented in the // XRay runtime. @@ -209,8 +218,8 @@ loadYAML(sys::fs::file_t Fd, size_t FileSize, StringRef Filename, for (const auto &Y : YAMLSleds) { FunctionAddresses[Y.FuncId] = Y.Function; FunctionIds[Y.Function] = Y.FuncId; - Sleds.push_back( - SledEntry{Y.Address, Y.Function, Y.Kind, Y.AlwaysInstrument}); + Sleds.push_back(SledEntry{Y.Address, Y.Function, Y.Kind, Y.AlwaysInstrument, + Y.Version}); } return Error::success(); } diff --git a/llvm/test/CodeGen/Mips/xray-mips-attribute-instrumentation.ll b/llvm/test/CodeGen/Mips/xray-mips-attribute-instrumentation.ll index a7c859a..b78909d 100644 --- a/llvm/test/CodeGen/Mips/xray-mips-attribute-instrumentation.ll +++ b/llvm/test/CodeGen/Mips/xray-mips-attribute-instrumentation.ll @@ -7,8 +7,8 @@ define i32 @foo() nounwind noinline uwtable "function-instrument"="xray-always" ; CHECK: .p2align 2 ; CHECK-MIPS64-LABEL: .Lxray_sled_0: ; CHECK-MIPS32-LABEL: $xray_sled_0: -; CHECK-MIPS64: b .Ltmp0 -; CHECK-MIPS32: b $tmp0 +; CHECK-MIPS64: b .Ltmp1 +; CHECK-MIPS32: b $tmp1 ; CHECK-NEXT: nop ; CHECK-NEXT: nop ; CHECK-NEXT: nop @@ -24,15 +24,15 @@ define i32 @foo() nounwind noinline uwtable "function-instrument"="xray-always" ; CHECK-MIPS64: nop ; CHECK-MIPS64: nop ; CHECK-MIPS64: nop -; CHECK-MIPS64-LABEL: .Ltmp0: -; CHECK-MIPS32-LABEL: $tmp0: +; CHECK-MIPS64-LABEL: .Ltmp1: +; CHECK-MIPS32-LABEL: $tmp1: ; CHECK-MIPS32: addiu $25, $25, 52 ret i32 0 ; CHECK: .p2align 2 ; CHECK-MIPS64-LABEL: .Lxray_sled_1: +; CHECK-MIPS64-NEXT: b .Ltmp2 ; CHECK-MIPS32-LABEL: $xray_sled_1: -; CHECK-MIPS64: b .Ltmp1 -; CHECK-MIPS32: b $tmp1 +; CHECK-MIPS32-NEXT: b $tmp2 ; CHECK-NEXT: nop ; CHECK-NEXT: nop ; CHECK-NEXT: nop @@ -48,8 +48,8 @@ define i32 @foo() nounwind noinline uwtable "function-instrument"="xray-always" ; CHECK-MIPS64: nop ; CHECK-MIPS64: nop ; CHECK-MIPS64: nop -; CHECK-MIPS64-LABEL: .Ltmp1: -; CHECK-MIPS32-LABEL: $tmp1: +; CHECK-MIPS64-LABEL: .Ltmp2: +; CHECK-MIPS32-LABEL: $tmp2: ; CHECK-MIPS32: addiu $25, $25, 52 } ; CHECK: .section xray_instr_map,{{.*}} @@ -63,9 +63,9 @@ define i32 @foo() nounwind noinline uwtable "function-instrument"="xray-always" define i32 @bar(i32 %i) nounwind noinline uwtable "function-instrument"="xray-always" { ; CHECK: .p2align 2 ; CHECK-MIPS64-LABEL: .Lxray_sled_2: +; CHECK-MIPS64-NEXT: b .Ltmp4 ; CHECK-MIPS32-LABEL: $xray_sled_2: -; CHECK-MIPS64: b .Ltmp2 -; CHECK-MIPS32: b $tmp2 +; CHECK-MIPS32-NEXT: b $tmp4 ; CHECK-NEXT: nop ; CHECK-NEXT: nop ; CHECK-NEXT: nop @@ -81,8 +81,8 @@ define i32 @bar(i32 %i) nounwind noinline uwtable "function-instrument"="xray-al ; CHECK-MIPS64: nop ; CHECK-MIPS64: nop ; CHECK-MIPS64: nop -; CHECK-MIPS64-LABEL: .Ltmp2: -; CHECK-MIPS32-LABEL: $tmp2: +; CHECK-MIPS64-LABEL: .Ltmp4: +; CHECK-MIPS32-LABEL: $tmp4: ; CHECK-MIPS32: addiu $25, $25, 52 Test: %cond = icmp eq i32 %i, 0 @@ -91,9 +91,9 @@ IsEqual: ret i32 0 ; CHECK: .p2align 2 ; CHECK-MIPS64-LABEL: .Lxray_sled_3: +; CHECK-MIPS64-NEXT: b .Ltmp5 ; CHECK-MIPS32-LABEL: $xray_sled_3: -; CHECK-MIPS64: b .Ltmp3 -; CHECK-MIPS32: b $tmp3 +; CHECK-MIPS32-NEXT: b $tmp5 ; CHECK-NEXT: nop ; CHECK-NEXT: nop ; CHECK-NEXT: nop @@ -109,16 +109,16 @@ IsEqual: ; CHECK-MIPS64: nop ; CHECK-MIPS64: nop ; CHECK-MIPS64: nop -; CHECK-MIPS64-LABEL: .Ltmp3: -; CHECK-MIPS32-LABEL: $tmp3: +; CHECK-MIPS64-LABEL: .Ltmp5: +; CHECK-MIPS32-LABEL: $tmp5: ; CHECK-MIPS32: addiu $25, $25, 52 NotEqual: ret i32 1 ; CHECK: .p2align 2 ; CHECK-MIPS64-LABEL: .Lxray_sled_4: +; CHECK-MIPS64-NEXT: b .Ltmp6 ; CHECK-MIPS32-LABEL: $xray_sled_4: -; CHECK-MIPS64: b .Ltmp4 -; CHECK-MIPS32: b $tmp4 +; CHECK-MIPS32-NEXT: b $tmp6 ; CHECK-NEXT: nop ; CHECK-NEXT: nop ; CHECK-NEXT: nop @@ -134,8 +134,8 @@ NotEqual: ; CHECK-MIPS64: nop ; CHECK-MIPS64: nop ; CHECK-MIPS64: nop -; CHECK-MIPS64-LABEL: .Ltmp4: -; CHECK-MIPS32-LABEL: $tmp4: +; CHECK-MIPS64-LABEL: .Ltmp6: +; CHECK-MIPS32-LABEL: $tmp6: ; CHECK-MIPS32: addiu $25, $25, 52 } ; CHECK: .section xray_instr_map,{{.*}} diff --git a/llvm/test/CodeGen/PowerPC/xray-attribute-instrumentation.ll b/llvm/test/CodeGen/PowerPC/xray-attribute-instrumentation.ll index 63c34be..f736790 100644 --- a/llvm/test/CodeGen/PowerPC/xray-attribute-instrumentation.ll +++ b/llvm/test/CodeGen/PowerPC/xray-attribute-instrumentation.ll @@ -3,6 +3,8 @@ ; RUN: -relocation-model=pic < %s | FileCheck %s define i32 @foo() nounwind noinline uwtable "function-instrument"="xray-always" { +; CHECK-LABEL: foo: +; CHECK-NEXT: .Lfunc_begin0: ; CHECK-LABEL: .Ltmp0: ; CHECK: b .Ltmp1 ; CHECK-NEXT: nop @@ -26,14 +28,14 @@ define i32 @foo() nounwind noinline uwtable "function-instrument"="xray-always" ; CHECK: .Lxray_sleds_start0: ; CHECK-NEXT: .Ltmp3: ; CHECK-NEXT: .quad .Ltmp0-.Ltmp3 -; CHECK-NEXT: .quad foo +; CHECK-NEXT: .quad .Lfunc_begin0-(.Ltmp3+8) ; CHECK-NEXT: .byte 0x00 ; CHECK-NEXT: .byte 0x01 ; CHECK-NEXT: .byte 0x02 ; CHECK-NEXT: .space 13 ; CHECK-NEXT: .Ltmp4: ; CHECK-NEXT: .quad .Ltmp2-.Ltmp4 -; CHECK-NEXT: .quad foo +; CHECK-NEXT: .quad .Lfunc_begin0-(.Ltmp4+8) ; CHECK-NEXT: .byte 0x01 ; CHECK-NEXT: .byte 0x01 ; CHECK-NEXT: .byte 0x02 diff --git a/llvm/test/CodeGen/X86/xray-log-args.ll b/llvm/test/CodeGen/X86/xray-log-args.ll index 7ec1b34..812e04a 100644 --- a/llvm/test/CodeGen/X86/xray-log-args.ll +++ b/llvm/test/CodeGen/X86/xray-log-args.ll @@ -6,17 +6,20 @@ define i32 @callee(i32 %arg) nounwind noinline uwtable "function-instrument"="xray-always" "xray-log-args"="1" { ret i32 %arg } +; CHECK-LABEL: callee: +; CHECK-NEXT: Lfunc_begin0: + ; CHECK-LABEL: Lxray_sleds_start0: ; CHECK-NEXT: Ltmp0: ; CHECK-NEXT: .quad {{\.?}}Lxray_sled_0-{{\.?}}Ltmp0 -; CHECK-NEXT: .quad {{_?}}callee +; CHECK-NEXT: .quad {{\.?}}Lfunc_begin0-({{\.?}}Ltmp0+8) ; CHECK-NEXT: .byte 0x03 ; CHECK-NEXT: .byte 0x01 ; CHECK-NEXT: .byte 0x02 ; CHECK: .{{(zero|space)}} 13 ; CHECK: Ltmp1: ; CHECK-NEXT: .quad {{\.?}}Lxray_sled_1-{{\.?}}Ltmp1 -; CHECK-NEXT: .quad {{_?}}callee +; CHECK-NEXT: .quad {{\.?}}Lfunc_begin0-({{\.?}}Ltmp1+8) ; CHECK-NEXT: .byte 0x01 ; CHECK-NEXT: .byte 0x01 ; CHECK-NEXT: .byte 0x02 @@ -29,14 +32,14 @@ define i32 @caller(i32 %arg) nounwind noinline uwtable "function-instrument"="xr ; CHECK-LABEL: Lxray_sleds_start1: ; CHECK-NEXT: Ltmp3: ; CHECK-NEXT: .quad {{\.?}}Lxray_sled_2-{{\.?}}Ltmp3 -; CHECK-NEXT: .quad {{_?}}caller +; CHECK-NEXT: .quad {{\.?}}Lfunc_begin1-({{\.?}}Ltmp3+8) ; CHECK-NEXT: .byte 0x03 ; CHECK-NEXT: .byte 0x01 ; CHECK-NEXT: .byte 0x02 ; CHECK: .{{(zero|space)}} 13 ; CHECK: Ltmp4: ; CHECK-NEXT: .quad {{\.?}}Lxray_sled_3-{{\.?}}Ltmp4 -; CHECK-NEXT: .quad {{_?}}caller +; CHECK-NEXT: .quad {{\.?}}Lfunc_begin1-({{\.?}}Ltmp4+8) ; CHECK-NEXT: .byte 0x02 ; CHECK-NEXT: .byte 0x01 ; CHECK-NEXT: .byte 0x02 diff --git a/llvm/tools/llvm-xray/xray-extract.cpp b/llvm/tools/llvm-xray/xray-extract.cpp index 6ea0f59..8304d2d 100644 --- a/llvm/tools/llvm-xray/xray-extract.cpp +++ b/llvm/tools/llvm-xray/xray-extract.cpp @@ -63,9 +63,9 @@ void exportAsYAML(const InstrumentationMap &Map, raw_ostream &OS, auto FuncId = Map.getFunctionId(Sled.Function); if (!FuncId) return; - YAMLSleds.push_back({*FuncId, Sled.Address, Sled.Function, Sled.Kind, - Sled.AlwaysInstrument, - ExtractSymbolize ? FH.SymbolOrNumber(*FuncId) : ""}); + YAMLSleds.push_back( + {*FuncId, Sled.Address, Sled.Function, Sled.Kind, Sled.AlwaysInstrument, + ExtractSymbolize ? FH.SymbolOrNumber(*FuncId) : "", Sled.Version}); } Output Out(OS, nullptr, 0); Out << YAMLSleds; -- 2.7.4