diff --git a/compiler-rt/lib/xray/xray_interface.cpp b/compiler-rt/lib/xray/xray_interface.cpp --- a/compiler-rt/lib/xray/xray_interface.cpp +++ b/compiler-rt/lib/xray/xray_interface.cpp @@ -264,14 +264,14 @@ // now we're assuming we can mprotect the whole section of text between the // minimum sled address and the maximum sled address (+ the largest sled // size). - auto MinSled = InstrMap.Sleds[0]; - auto MaxSled = InstrMap.Sleds[InstrMap.Entries - 1]; + auto *MinSled = &InstrMap.Sleds[0]; + auto *MaxSled = &InstrMap.Sleds[InstrMap.Entries - 1]; for (std::size_t I = 0; I < InstrMap.Entries; I++) { const auto &Sled = InstrMap.Sleds[I]; - if (Sled.Address < MinSled.Address) - MinSled = Sled; - if (Sled.Address > MaxSled.Address) - MaxSled = Sled; + if (Sled.address() < MinSled->address()) + MinSled = &Sled; + if (Sled.address() > MaxSled->address()) + MaxSled = &Sled; } const size_t PageSize = flags()->xray_page_size_override > 0 @@ -283,9 +283,10 @@ } void *PageAlignedAddr = - reinterpret_cast(MinSled.Address & ~(PageSize - 1)); + reinterpret_cast(MinSled->address() & ~(PageSize - 1)); size_t MProtectLen = - (MaxSled.Address - reinterpret_cast(PageAlignedAddr)) + cSledLength; + (MaxSled->address() - reinterpret_cast(PageAlignedAddr)) + + cSledLength; MProtectHelper Protector(PageAlignedAddr, MProtectLen, PageSize); if (Protector.MakeWriteable() == -1) { Report("Failed mprotect: %d\n", errno); @@ -337,20 +338,21 @@ auto SledRange = InstrMap.SledsIndex[FuncId - 1]; auto *f = SledRange.Begin; auto *e = SledRange.End; - auto MinSled = *f; - auto MaxSled = *(SledRange.End - 1); + auto *MinSled = f; + auto *MaxSled = (SledRange.End - 1); while (f != e) { - if (f->Address < MinSled.Address) - MinSled = *f; - if (f->Address > MaxSled.Address) - MaxSled = *f; + if (f->address() < MinSled->address()) + MinSled = f; + if (f->address() > MaxSled->address()) + MaxSled = f; ++f; } void *PageAlignedAddr = - reinterpret_cast(MinSled.Address & ~(PageSize - 1)); + reinterpret_cast(MinSled->address() & ~(PageSize - 1)); size_t MProtectLen = - (MaxSled.Address - reinterpret_cast(PageAlignedAddr)) + cSledLength; + (MaxSled->address() - reinterpret_cast(PageAlignedAddr)) + + cSledLength; MProtectHelper Protector(PageAlignedAddr, MProtectLen, PageSize); if (Protector.MakeWriteable() == -1) { Report("Failed mprotect: %d\n", errno); diff --git a/compiler-rt/lib/xray/xray_interface_internal.h b/compiler-rt/lib/xray/xray_interface_internal.h --- a/compiler-rt/lib/xray/xray_interface_internal.h +++ b/compiler-rt/lib/xray/xray_interface_internal.h @@ -29,6 +29,14 @@ unsigned char AlwaysInstrument; unsigned char Version; unsigned char Padding[13]; // Need 32 bytes + uint64_t address() const { +#if defined(__x86_64__) + // The target address is relative to the location of the Address variable. + return reinterpret_cast(&Address) + Address; +#else + return Address; +#endif + } #elif SANITIZER_WORDSIZE == 32 uint32_t Address; uint32_t Function; @@ -36,6 +44,7 @@ unsigned char AlwaysInstrument; unsigned char Version; unsigned char Padding[5]; // Need 16 bytes + uint32_t address() const { return Address; } #else #error "Unsupported word size." #endif diff --git a/compiler-rt/lib/xray/xray_x86_64.cpp b/compiler-rt/lib/xray/xray_x86_64.cpp --- a/compiler-rt/lib/xray/xray_x86_64.cpp +++ b/compiler-rt/lib/xray/xray_x86_64.cpp @@ -151,7 +151,7 @@ // opcode and first operand. // // Prerequisite is to compute the relative offset to the trampoline's address. - const uint64_t Address = Sled.Address; + const uint64_t Address = Sled.address(); int64_t TrampolineOffset = reinterpret_cast(Trampoline) - (static_cast(Address) + 11); if (TrampolineOffset < MinOffset || TrampolineOffset > MaxOffset) { @@ -197,7 +197,7 @@ // // Prerequisite is to compute the relative offset fo the // __xray_FunctionExit function's address. - const uint64_t Address = Sled.Address; + const uint64_t Address = Sled.address(); int64_t TrampolineOffset = reinterpret_cast(__xray_FunctionExit) - (static_cast(Address) + 11); if (TrampolineOffset < MinOffset || TrampolineOffset > MaxOffset) { @@ -225,7 +225,7 @@ const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT { // Here we do the dance of replacing the tail call sled with a similar // sequence as the entry sled, but calls the tail exit sled instead. - const uint64_t Address = Sled.Address; + const uint64_t Address = Sled.address(); int64_t TrampolineOffset = reinterpret_cast(__xray_FunctionTailExit) - (static_cast(Address) + 11); @@ -275,7 +275,7 @@ // The jump offset is now 15 bytes (0x0f), so when restoring the nopw back // to a jmp, use 15 bytes instead. // - const uint64_t Address = Sled.Address; + const uint64_t Address = Sled.address(); if (Enable) { std::atomic_store_explicit( reinterpret_cast *>(Address), NopwSeq, @@ -317,7 +317,7 @@ // unstashes the registers and returns. If the arguments are already in // the correct registers, the stashing and unstashing become equivalently // sized nops. - const uint64_t Address = Sled.Address; + const uint64_t Address = Sled.address(); if (Enable) { std::atomic_store_explicit( reinterpret_cast *>(Address), NopwSeq, diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h --- a/llvm/include/llvm/CodeGen/AsmPrinter.h +++ b/llvm/include/llvm/CodeGen/AsmPrinter.h @@ -286,7 +286,7 @@ const class Function *Fn; uint8_t Version; - void emit(int, MCStreamer *, const MCSymbol *) const; + void emit(int, MCStreamer *, const MCExpr *, const MCSymbol *) const; }; // All the sleds to be emitted. diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -3185,8 +3185,12 @@ // 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 { - Out->emitSymbolValue(Sled, Bytes); + if (Location) + Out->emitValueImpl(Location, Bytes); + else + Out->emitSymbolValue(Sled, Bytes); Out->emitSymbolValue(CurrentFnSym, Bytes); auto Kind8 = static_cast(Kind); Out->emitBinaryData(StringRef(reinterpret_cast(&Kind8), 1)); @@ -3206,9 +3210,13 @@ const Function &F = MF->getFunction(); MCSection *InstMap = nullptr; MCSection *FnSledIndex = nullptr; - if (MF->getSubtarget().getTargetTriple().isOSBinFormatELF()) { + const Triple &TT = TM.getTargetTriple(); + bool PCRel = TT.isX86(); + if (TT.isOSBinFormatELF()) { auto LinkedToSym = cast(CurrentFnSym); - auto Flags = ELF::SHF_WRITE | ELF::SHF_ALLOC | ELF::SHF_LINK_ORDER; + auto Flags = ELF::SHF_ALLOC | ELF::SHF_LINK_ORDER; + if (!PCRel) + Flags |= ELF::SHF_WRITE; StringRef GroupName; if (F.hasComdat()) { Flags |= ELF::SHF_GROUP; @@ -3237,8 +3245,17 @@ MCSymbol *SledsStart = OutContext.createTempSymbol("xray_sleds_start", true); OutStreamer->SwitchSection(InstMap); OutStreamer->emitLabel(SledsStart); - for (const auto &Sled : Sleds) - Sled.emit(WordSizeBytes, OutStreamer.get(), CurrentFnSym); + for (const auto &Sled : Sleds) { + const MCExpr *Location = nullptr; + if (PCRel) { + MCSymbol *Dot = OutContext.createTempSymbol(); + OutStreamer->emitLabel(Dot); + Location = MCBinaryExpr::createSub( + MCSymbolRefExpr::create(Sled.Sled, OutContext), + MCSymbolRefExpr::create(Dot, OutContext), OutContext); + } + Sled.emit(WordSizeBytes, OutStreamer.get(), Location, CurrentFnSym); + } 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 --- a/llvm/lib/XRay/InstrumentationMap.cpp +++ b/llvm/lib/XRay/InstrumentationMap.cpp @@ -58,20 +58,26 @@ InstrumentationMap Map; // Find the section named "xray_instr_map". + Triple::ArchType Arch = ObjFile.getBinary()->getArch(); if ((!ObjFile.getBinary()->isELF() && !ObjFile.getBinary()->isMachO()) || - !(ObjFile.getBinary()->getArch() == Triple::x86_64 || - ObjFile.getBinary()->getArch() == Triple::ppc64le || - ObjFile.getBinary()->getArch() == Triple::aarch64)) + !(Arch == Triple::aarch64 || Arch == Triple::ppc64le || + Arch == Triple::x86_64)) return make_error( - "File format not supported (only does ELF and Mach-O little endian 64-bit).", + "File format not supported (only does ELF and Mach-O little endian " + "64-bit).", std::make_error_code(std::errc::not_supported)); + uint64_t Location = 0; StringRef Contents = ""; const auto &Sections = ObjFile.getBinary()->sections(); auto I = llvm::find_if(Sections, [&](object::SectionRef Section) { Expected NameOrErr = Section.getName(); - if (NameOrErr) - return *NameOrErr == "xray_instr_map"; + if (NameOrErr) { + if (*NameOrErr != "xray_instr_map") + return false; + Location = Section.getAddress(); + return true; + } consumeError(NameOrErr.takeError()); return false; }); @@ -143,7 +149,7 @@ int32_t FuncId = 1; uint64_t CurFn = 0; - for (; C != Contents.bytes_end(); C += ELF64SledEntrySize) { + for (; C != Contents.bytes_end(); C += ELF64SledEntrySize, Location += 8) { DataExtractor Extractor( StringRef(reinterpret_cast(C), ELF64SledEntrySize), true, 8); @@ -152,6 +158,8 @@ uint64_t OffsetPtr = 0; uint64_t AddrOff = OffsetPtr; Entry.Address = RelocateOrElse(AddrOff, Extractor.getU64(&OffsetPtr)); + if (Arch == Triple::x86_64) + Entry.Address += Location; uint64_t FuncOff = OffsetPtr; Entry.Function = RelocateOrElse(FuncOff, Extractor.getU64(&OffsetPtr)); auto Kind = Extractor.getU8(&OffsetPtr); diff --git a/llvm/test/CodeGen/X86/xray-attribute-instrumentation.ll b/llvm/test/CodeGen/X86/xray-attribute-instrumentation.ll --- a/llvm/test/CodeGen/X86/xray-attribute-instrumentation.ll +++ b/llvm/test/CodeGen/X86/xray-attribute-instrumentation.ll @@ -49,9 +49,12 @@ } ; CHECK-LABEL: xray_instr_map ; CHECK-LABEL: Lxray_sleds_start1: -; CHECK: .quad {{.*}}xray_sled_2 -; CHECK: .quad {{.*}}xray_sled_3 -; CHECK: .quad {{.*}}xray_sled_4 +; CHECK: Ltmp2: +; CHECK-NEXT: .quad {{.*}}xray_sled_2-{{\.?}}Ltmp2 +; CHECK: Ltmp3: +; CHECK-NEXT: .quad {{.*}}xray_sled_3-{{\.?}}Ltmp3 +; CHECK: Ltmp4: +; CHECK-NEXT: .quad {{.*}}xray_sled_4-{{\.?}}Ltmp4 ; CHECK-LABEL: Lxray_sleds_end1: ; CHECK-LABEL: xray_fn_idx ; CHECK: .quad {{.*}}xray_sleds_start1 diff --git a/llvm/test/CodeGen/X86/xray-section-group.ll b/llvm/test/CodeGen/X86/xray-section-group.ll --- a/llvm/test/CodeGen/X86/xray-section-group.ll +++ b/llvm/test/CodeGen/X86/xray-section-group.ll @@ -5,14 +5,14 @@ define i32 @foo() nounwind noinline uwtable "function-instrument"="xray-always" { ; CHECK: .section .text.foo,"ax",@progbits ret i32 0 -; CHECK: .section xray_instr_map,"awo",@progbits,foo{{$}} +; CHECK: .section xray_instr_map,"ao",@progbits,foo{{$}} } $bar = comdat any define i32 @bar() nounwind noinline uwtable "function-instrument"="xray-always" comdat($bar) { ; CHECK: .section .text.bar,"axG",@progbits,bar,comdat ret i32 1 -; CHECK: .section xray_instr_map,"aGwo",@progbits,bar,comdat,bar{{$}} +; CHECK: .section xray_instr_map,"aGo",@progbits,bar,comdat,bar{{$}} } ; CHECK-OBJ: section xray_instr_map: diff --git a/llvm/test/DebugInfo/X86/xray-split-dwarf-interaction.ll b/llvm/test/DebugInfo/X86/xray-split-dwarf-interaction.ll --- a/llvm/test/DebugInfo/X86/xray-split-dwarf-interaction.ll +++ b/llvm/test/DebugInfo/X86/xray-split-dwarf-interaction.ll @@ -25,11 +25,11 @@ ; `a::b()` is actually associated with the function's symbol instead of the ; .debug_types.dwo section. ; -; CHECK-ASM: xray_fn_idx,"awo",@progbits,_ZN1a1bEv{{$}} +; CHECK-ASM: xray_fn_idx,"ao",@progbits,_ZN1a1bEv{{$}} ; ; CHECK-ELF-DAG: [[FSECT:[0-9]+]]] .text._ZN1a1bEv PROGBITS ; CHECK-ELF-DAG: [{{.*}}] .debug_types.dwo PROGBITS -; CHECK-ELF-DAG: [{{.*}}] xray_instr_map PROGBITS {{.*}} {{.*}} {{.*}} {{.*}} WAL [[FSECT]] +; CHECK-ELF-DAG: [{{.*}}] xray_instr_map PROGBITS {{.*}} {{.*}} {{.*}} {{.*}} AL [[FSECT]] target triple = "x86_64-pc-linux" %class.a = type { i8 } diff --git a/llvm/test/tools/llvm-xray/X86/extract-instrmap-macho.ll b/llvm/test/tools/llvm-xray/X86/extract-instrmap-macho.ll --- a/llvm/test/tools/llvm-xray/X86/extract-instrmap-macho.ll +++ b/llvm/test/tools/llvm-xray/X86/extract-instrmap-macho.ll @@ -1,9 +1,10 @@ ; This test makes sure we can extract the instrumentation map from an ; XRay-instrumented object file. +; FIXME: Convert instr-map-mach.o to a reduced YAML and change xray_instr_map to be PC-relative. ; ; RUN: llvm-xray extract %S/Inputs/instr-map-mach.o -s | FileCheck %s ; CHECK: --- -; CHECK-NEXT: - { id: 1, address: 0x0000000000000000, function: 0x0000000000000000, kind: function-enter, always-instrument: true, function-name: 'task(void*)' } -; CHECK-NEXT: - { id: 1, address: 0x0000000000000162, function: 0x0000000000000000, kind: function-exit, always-instrument: true, function-name: 'task(void*)' } +; CHECK-NEXT: - { id: 1, address: 0x00000000000002B8, function: 0x0000000000000000, kind: function-enter, always-instrument: true, function-name: 'task(void*)' } +; CHECK-NEXT: - { id: 1, address: 0x0000000000000422, function: 0x0000000000000000, kind: function-exit, always-instrument: true, function-name: 'task(void*)' } ; CHECK-NEXT: ... diff --git a/llvm/test/tools/llvm-xray/X86/extract-instrmap-pie.ll b/llvm/test/tools/llvm-xray/X86/extract-instrmap-pie.ll --- a/llvm/test/tools/llvm-xray/X86/extract-instrmap-pie.ll +++ b/llvm/test/tools/llvm-xray/X86/extract-instrmap-pie.ll @@ -3,9 +3,11 @@ ; ; RUN: llvm-xray extract %S/Inputs/elf64-pie.bin -s | FileCheck %s +;; FIXME: Convert elf64-example.bin to a reduced YAML and change xray_instr_map to be PC-relative. + ; CHECK: --- -; CHECK-NEXT: - { id: 1, address: 0x00000000000299C0, function: 0x00000000000299C0, kind: function-enter, always-instrument: true, function-name: {{.*foo.*}} } -; CHECK-NEXT: - { id: 1, address: 0x00000000000299D0, function: 0x00000000000299C0, kind: function-exit, always-instrument: true, function-name: {{.*foo.*}} } -; CHECK-NEXT: - { id: 2, address: 0x00000000000299E0, function: 0x00000000000299E0, kind: function-enter, always-instrument: true, function-name: {{.*bar.*}} } -; CHECK-NEXT: - { id: 2, address: 0x00000000000299F6, function: 0x00000000000299E0, kind: function-exit, always-instrument: true, function-name: {{.*bar.*}} } +; CHECK-NEXT: - { id: 1, address: 0x00000000000562A8, function: 0x00000000000299C0, kind: function-enter, always-instrument: true, function-name: {{.*foo.*}} } +; CHECK-NEXT: - { id: 1, address: 0x00000000000562C0, function: 0x00000000000299C0, kind: function-exit, always-instrument: true, function-name: {{.*foo.*}} } +; CHECK-NEXT: - { id: 2, address: 0x00000000000562D8, function: 0x00000000000299E0, kind: function-enter, always-instrument: true, function-name: {{.*bar.*}} } +; CHECK-NEXT: - { id: 2, address: 0x00000000000562F6, function: 0x00000000000299E0, kind: function-exit, always-instrument: true, function-name: {{.*bar.*}} } ; CHECK-NEXT: ... diff --git a/llvm/test/tools/llvm-xray/X86/extract-instrmap-symbolize.ll b/llvm/test/tools/llvm-xray/X86/extract-instrmap-symbolize.ll deleted file mode 100644 --- a/llvm/test/tools/llvm-xray/X86/extract-instrmap-symbolize.ll +++ /dev/null @@ -1,10 +0,0 @@ -; This tests that we can extract the instrumentation map and symbolize the -; function addresses. -; RUN: llvm-xray extract %S/Inputs/elf64-example.bin -s | FileCheck %s - -; CHECK: --- -; CHECK-NEXT: - { id: 1, address: 0x000000000041C900, function: 0x000000000041C900, kind: function-enter, always-instrument: true, function-name: {{.*foo.*}} } -; CHECK-NEXT: - { id: 1, address: 0x000000000041C912, function: 0x000000000041C900, kind: function-exit, always-instrument: true, function-name: {{.*foo.*}} } -; CHECK-NEXT: - { id: 2, address: 0x000000000041C930, function: 0x000000000041C930, kind: function-enter, always-instrument: true, function-name: {{.*bar.*}} } -; CHECK-NEXT: - { id: 2, address: 0x000000000041C946, function: 0x000000000041C930, kind: function-exit, always-instrument: true, function-name: {{.*bar.*}} } -; CHECK-NEXT: ... diff --git a/llvm/test/tools/llvm-xray/X86/extract-instrmap.ll b/llvm/test/tools/llvm-xray/X86/extract-instrmap.ll --- a/llvm/test/tools/llvm-xray/X86/extract-instrmap.ll +++ b/llvm/test/tools/llvm-xray/X86/extract-instrmap.ll @@ -1,11 +1,17 @@ ; This test makes sure we can extract the instrumentation map from an ; XRay-instrumented object file. +; FIXME: Convert elf64-example.bin to a reduced YAML and change xray_instr_map to be PC-relative. ; ; RUN: llvm-xray extract %S/Inputs/elf64-example.bin | FileCheck %s +; RUN: llvm-xray extract %S/Inputs/elf64-example.bin -s | FileCheck --check-prefixes=CHECK,SYM %s ; CHECK: --- -; CHECK-NEXT: - { id: 1, address: 0x000000000041C900, function: 0x000000000041C900, kind: function-enter, always-instrument: true{{.*}} } -; CHECK-NEXT: - { id: 1, address: 0x000000000041C912, function: 0x000000000041C900, kind: function-exit, always-instrument: true{{.*}} } -; CHECK-NEXT: - { id: 2, address: 0x000000000041C930, function: 0x000000000041C930, kind: function-enter, always-instrument: true{{.*}} } -; CHECK-NEXT: - { id: 2, address: 0x000000000041C946, function: 0x000000000041C930, kind: function-exit, always-instrument: true{{.*}} } +; CHECK-NEXT: - { id: 1, address: 0x000000000083F7D1, function: 0x000000000041C900, kind: function-enter, always-instrument: true, +; SYM-SAME: function-name: 'foo()' +; CHECK-NEXT: - { id: 1, address: 0x000000000083F7EB, function: 0x000000000041C900, kind: function-exit, always-instrument: true, +; SYM-SAME: function-name: 'foo()' +; CHECK-NEXT: - { id: 2, address: 0x000000000083F811, function: 0x000000000041C930, kind: function-enter, always-instrument: true, +; SYM-SAME: function-name: 'bar()' +; CHECK-NEXT: - { id: 2, address: 0x000000000083F82F, function: 0x000000000041C930, kind: function-exit, always-instrument: true, +; SYM-SAME: function-name: 'bar()' ; CHECK-NEXT: ...