diff --git a/llvm/include/llvm/Object/ELFObjectFile.h b/llvm/include/llvm/Object/ELFObjectFile.h --- a/llvm/include/llvm/Object/ELFObjectFile.h +++ b/llvm/include/llvm/Object/ELFObjectFile.h @@ -64,6 +64,7 @@ virtual uint64_t getSectionOffset(DataRefImpl Sec) const = 0; virtual Expected getRelocationAddend(DataRefImpl Rel) const = 0; + virtual int64_t getOptionalRelocationAddend(DataRefImpl Rel) const = 0; virtual Error getBuildAttributes(ELFAttributeParser &Attributes) const = 0; public: @@ -198,6 +199,10 @@ Expected getAddend() const { return getObject()->getRelocationAddend(getRawDataRefImpl()); } + + int64_t getOptionalAddend() const { + return getObject()->getOptionalRelocationAddend(getRawDataRefImpl()); + } }; class elf_relocation_iterator : public relocation_iterator { @@ -423,6 +428,7 @@ section_iterator section_end() const override; Expected getRelocationAddend(DataRefImpl Rel) const override; + int64_t getOptionalRelocationAddend(DataRefImpl Rel) const override; uint8_t getBytesInAddress() const override; StringRef getFileFormatName() const override; @@ -949,6 +955,14 @@ } template +int64_t +ELFObjectFile::getOptionalRelocationAddend(DataRefImpl Rel) const { + if (getRelSection(Rel)->sh_type != ELF::SHT_RELA) + return 0; + return (int64_t)getRela(Rel)->r_addend; +} + +template const typename ELFObjectFile::Elf_Rel * ELFObjectFile::getRel(DataRefImpl Rel) const { assert(getRelSection(Rel)->sh_type == ELF::SHT_REL); 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 @@ -52,18 +52,20 @@ static Error loadObj(StringRef Filename, object::OwningBinary &ObjFile, - InstrumentationMap::SledContainer &Sleds, - InstrumentationMap::FunctionAddressMap &FunctionAddresses, - InstrumentationMap::FunctionAddressReverseMap &FunctionIds) { + InstrumentationMap::SledContainer &Sleds, + InstrumentationMap::FunctionAddressMap &FunctionAddresses, + InstrumentationMap::FunctionAddressReverseMap &FunctionIds) { InstrumentationMap Map; // Find the section named "xray_instr_map". if ((!ObjFile.getBinary()->isELF() && !ObjFile.getBinary()->isMachO()) || !(ObjFile.getBinary()->getArch() == Triple::x86_64 || ObjFile.getBinary()->getArch() == Triple::ppc64le || + ObjFile.getBinary()->getArch() == Triple::arm || ObjFile.getBinary()->getArch() == Triple::aarch64)) return make_error( - "File format not supported (only does ELF and Mach-O little endian 64-bit).", + Twine("File format not supported. Supports: " + "AArch64/ARM/ppc64le/x86-64."), std::make_error_code(std::errc::not_supported)); StringRef Contents = ""; @@ -94,11 +96,14 @@ uint32_t RelativeRelocation = [](object::ObjectFile *ObjFile) { if (const auto *ELFObj = dyn_cast(ObjFile)) return ELFObj->getELFFile()->getRelativeRelocationType(); - else if (const auto *ELFObj = dyn_cast(ObjFile)) + else if (const auto *ELFObj = + dyn_cast(ObjFile)) return ELFObj->getELFFile()->getRelativeRelocationType(); - else if (const auto *ELFObj = dyn_cast(ObjFile)) + else if (const auto *ELFObj = + dyn_cast(ObjFile)) return ELFObj->getELFFile()->getRelativeRelocationType(); - else if (const auto *ELFObj = dyn_cast(ObjFile)) + else if (const auto *ELFObj = + dyn_cast(ObjFile)) return ELFObj->getELFFile()->getRelativeRelocationType(); else return static_cast(0); @@ -112,16 +117,15 @@ for (const object::SectionRef &Section : Sections) { for (const object::RelocationRef &Reloc : Section.relocations()) { if (SupportsRelocation && SupportsRelocation(Reloc.getType())) { - auto AddendOrErr = object::ELFRelocationRef(Reloc).getAddend(); - auto A = AddendOrErr ? *AddendOrErr : 0; + auto A = object::ELFRelocationRef(Reloc).getOptionalAddend(); Expected ValueOrErr = Reloc.getSymbol()->getValue(); if (!ValueOrErr) // TODO: Test this error. return ValueOrErr.takeError(); Relocs.insert({Reloc.getOffset(), Resolver(Reloc, *ValueOrErr, A)}); } else if (Reloc.getType() == RelativeRelocation) { - if (auto AddendOrErr = object::ELFRelocationRef(Reloc).getAddend()) - Relocs.insert({Reloc.getOffset(), *AddendOrErr}); + auto A = object::ELFRelocationRef(Reloc).getOptionalAddend(); + Relocs.insert({Reloc.getOffset(), A}); } } } @@ -129,12 +133,13 @@ // Copy the instrumentation map data into the Sleds data structure. auto C = Contents.bytes_begin(); - static constexpr size_t ELF64SledEntrySize = 32; + bool Is32Bit = ObjFile.getBinary()->makeTriple().isArch32Bit(); + size_t ELFSledEntrySize = Is32Bit ? 16 : 32; - if ((C - Contents.bytes_end()) % ELF64SledEntrySize != 0) + if ((C - Contents.bytes_end()) % ELFSledEntrySize != 0) return make_error( Twine("Instrumentation map entries not evenly divisible by size of " - "an XRay sled entry in ELF64."), + "an XRay sled entry."), std::make_error_code(std::errc::executable_format_error)); auto RelocateOrElse = [&](uint64_t Offset, uint64_t Address) { @@ -147,20 +152,26 @@ return Address; }; - const int WordSize = 8; + const int WordSize = Is32Bit ? 4 : 8; int32_t FuncId = 1; uint64_t CurFn = 0; - for (; C != Contents.bytes_end(); C += ELF64SledEntrySize) { + for (; C != Contents.bytes_end(); C += ELFSledEntrySize) { DataExtractor Extractor( - StringRef(reinterpret_cast(C), ELF64SledEntrySize), true, + StringRef(reinterpret_cast(C), ELFSledEntrySize), true, 8); Sleds.push_back({}); auto &Entry = Sleds.back(); uint64_t OffsetPtr = 0; uint64_t AddrOff = OffsetPtr; - Entry.Address = RelocateOrElse(AddrOff, Extractor.getU64(&OffsetPtr)); + if (Is32Bit) + Entry.Address = RelocateOrElse(AddrOff, Extractor.getU32(&OffsetPtr)); + else + Entry.Address = RelocateOrElse(AddrOff, Extractor.getU64(&OffsetPtr)); uint64_t FuncOff = OffsetPtr; - Entry.Function = RelocateOrElse(FuncOff, Extractor.getU64(&OffsetPtr)); + if (Is32Bit) + Entry.Function = RelocateOrElse(FuncOff, Extractor.getU32(&OffsetPtr)); + else + Entry.Function = RelocateOrElse(FuncOff, Extractor.getU64(&OffsetPtr)); auto Kind = Extractor.getU8(&OffsetPtr); static constexpr SledEntry::FunctionKinds Kinds[] = { SledEntry::FunctionKinds::ENTRY, SledEntry::FunctionKinds::EXIT, @@ -240,7 +251,8 @@ if (!ObjectFileOrError) { auto E = ObjectFileOrError.takeError(); // We try to load it as YAML if the ELF load didn't work. - Expected FdOrErr = sys::fs::openNativeFileForRead(Filename); + Expected FdOrErr = + sys::fs::openNativeFileForRead(Filename); if (!FdOrErr) { // Report the ELF load error if YAML failed. consumeError(FdOrErr.takeError()); @@ -262,7 +274,7 @@ Map.FunctionAddresses, Map.FunctionIds)) return std::move(E); } else if (auto E = loadObj(Filename, *ObjectFileOrError, Map.Sleds, - Map.FunctionAddresses, Map.FunctionIds)) { + Map.FunctionAddresses, Map.FunctionIds)) { return std::move(E); } return Map; diff --git a/llvm/test/tools/llvm-xray/ARM/Inputs/elf32-pic.yaml b/llvm/test/tools/llvm-xray/ARM/Inputs/elf32-pic.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-xray/ARM/Inputs/elf32-pic.yaml @@ -0,0 +1,204 @@ +# Generated from the following source: +# __attribute__((xray_always_instrument)) void foo() {} +# __attribute__((xray_always_instrument)) void bar() {} +# __attribute__((xray_always_instrument)) void jar() {} + +# Built with the following arguments: +# -target armv7a-linux-androideabi -nostdlib -fxray-instrument -fPIC -shared + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_ARM + Flags: [ EF_ARM_SOFT_FLOAT, EF_ARM_EABI_VER5 ] + Entry: 0x00000000000012B0 +ProgramHeaders: + - Type: PT_PHDR + Flags: [ PF_R ] + VAddr: 0x0000000000000034 + Align: 0x0000000000000004 + - Type: PT_LOAD + Flags: [ PF_R ] + Sections: + - Section: .dynsym + - Section: .hash + - Section: .dynstr + - Section: .rel.dyn + Align: 0x0000000000001000 + - Type: PT_LOAD + Flags: [ PF_X, PF_R ] + Sections: + - Section: .text + VAddr: 0x00000000000012B0 + Align: 0x0000000000001000 + - Type: PT_LOAD + Flags: [ PF_W, PF_R ] + Sections: + - Section: .dynamic + VAddr: 0x0000000000002364 + Align: 0x0000000000001000 + - Type: PT_LOAD + Flags: [ PF_W, PF_R ] + Sections: + - Section: xray_instr_map + - Section: xray_fn_idx + VAddr: 0x00000000000033CC + Align: 0x0000000000001000 + - Type: PT_DYNAMIC + Flags: [ PF_W, PF_R ] + Sections: + - Section: .dynamic + VAddr: 0x0000000000002364 + Align: 0x0000000000000004 + - Type: PT_GNU_RELRO + Flags: [ PF_R ] + Sections: + - Section: .dynamic + VAddr: 0x0000000000002364 + - Type: PT_GNU_STACK + Flags: [ PF_W, PF_R ] + Align: 0x0000000000000000 +Sections: + - Name: .dynsym + Type: SHT_DYNSYM + Flags: [ SHF_ALLOC ] + Address: 0x0000000000000154 + Link: .dynstr + AddressAlign: 0x0000000000000004 + EntSize: 0x0000000000000010 + - Name: .hash + Type: SHT_HASH + Flags: [ SHF_ALLOC ] + Address: 0x00000000000001BC + Link: .dynsym + AddressAlign: 0x0000000000000004 + EntSize: 0x0000000000000004 + Bucket: [ 0, 0, 3, 0 ] + Chain: [ 0, 0, 1, 2 ] + - Name: .dynstr + Type: SHT_STRTAB + Flags: [ SHF_ALLOC ] + Address: 0x00000000000001E4 + AddressAlign: 0x0000000000000001 + - Name: .rel.dyn + Type: SHT_REL + Flags: [ SHF_ALLOC ] + Address: 0x0000000000000200 + Link: .dynsym + AddressAlign: 0x0000000000000004 + Relocations: + - Offset: 0x00000000000033CC + Type: R_ARM_RELATIVE + - Offset: 0x00000000000033DC + Type: R_ARM_RELATIVE + - Offset: 0x00000000000033EC + Type: R_ARM_RELATIVE + - Offset: 0x00000000000033FC + Type: R_ARM_RELATIVE + - Offset: 0x000000000000340C + Type: R_ARM_RELATIVE + - Offset: 0x000000000000341C + Type: R_ARM_RELATIVE + - Offset: 0x0000000000003430 + Type: R_ARM_RELATIVE + - Offset: 0x0000000000003434 + Type: R_ARM_RELATIVE + - Offset: 0x0000000000003438 + Type: R_ARM_RELATIVE + - Offset: 0x000000000000343C + Type: R_ARM_RELATIVE + - Offset: 0x0000000000003440 + Type: R_ARM_RELATIVE + - Offset: 0x0000000000003444 + Type: R_ARM_RELATIVE + - Offset: 0x00000000000033F0 + Symbol: _Z3barv + Type: R_ARM_ABS32 + - Offset: 0x0000000000003400 + Symbol: _Z3barv + Type: R_ARM_ABS32 + - Offset: 0x00000000000033D0 + Symbol: _Z3foov + Type: R_ARM_ABS32 + - Offset: 0x00000000000033E0 + Symbol: _Z3foov + Type: R_ARM_ABS32 + - Offset: 0x0000000000003410 + Symbol: _Z3jarv + Type: R_ARM_ABS32 + - Offset: 0x0000000000003420 + Symbol: _Z3jarv + Type: R_ARM_ABS32 + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x00000000000012B0 + AddressAlign: 0x0000000000000004 + Content: 050000EA00F020E300F020E300F020E300F020E300F020E300F020E3050000EA00F020E300F020E300F020E300F020E300F020E300F020E31EFF2FE1050000EA00F020E300F020E300F020E300F020E300F020E300F020E3050000EA00F020E300F020E300F020E300F020E300F020E300F020E31EFF2FE1050000EA00F020E300F020E300F020E300F020E300F020E300F020E3050000EA00F020E300F020E300F020E300F020E300F020E300F020E31EFF2FE1 + - Name: .dynamic + Type: SHT_DYNAMIC + Flags: [ SHF_WRITE, SHF_ALLOC ] + Address: 0x0000000000002364 + Link: .dynstr + AddressAlign: 0x0000000000000004 + Entries: + - Tag: DT_FLAGS + Value: 0x0000000000000008 + - Tag: DT_FLAGS_1 + Value: 0x0000000000000001 + - Tag: DT_REL + Value: 0x0000000000000200 + - Tag: DT_RELSZ + Value: 0x0000000000000090 + - Tag: DT_RELENT + Value: 0x0000000000000008 + - Tag: DT_RELCOUNT + Value: 0x000000000000000C + - Tag: DT_SYMTAB + Value: 0x0000000000000154 + - Tag: DT_SYMENT + Value: 0x0000000000000010 + - Tag: DT_STRTAB + Value: 0x00000000000001E4 + - Tag: DT_STRSZ + Value: 0x0000000000000019 + - Tag: DT_HASH + Value: 0x00000000000001BC + - Tag: DT_NULL + Value: 0x0000000000000000 + - Name: xray_instr_map + Type: SHT_PROGBITS + Flags: [ SHF_WRITE, SHF_ALLOC, SHF_LINK_ORDER ] + Address: 0x00000000000033CC + Link: .text + AddressAlign: 0x0000000000000001 + Content: B0120000000000000001000000000000CC120000000000000101000000000000EC120000000000000001000000000000081300000000000001010000000000002813000000000000000100000000000044130000000000000101000000000000 + - Name: xray_fn_idx + Type: SHT_PROGBITS + Flags: [ SHF_WRITE, SHF_ALLOC, SHF_LINK_ORDER ] + Address: 0x0000000000003430 + Link: .text + AddressAlign: 0x0000000000000008 + Content: CC330000EC330000EC3300000C3400000C3400002C340000 +DynamicSymbols: + - Name: _Z3barv + Type: STT_FUNC + Section: .text + Binding: STB_GLOBAL + Value: 0x00000000000012EC + Size: 0x000000000000003C + - Name: _Z3foov + Type: STT_FUNC + Section: .text + Binding: STB_GLOBAL + Value: 0x00000000000012B0 + Size: 0x000000000000003C + - Name: _Z3jarv + Type: STT_FUNC + Section: .text + Binding: STB_GLOBAL + Value: 0x0000000000001328 + Size: 0x000000000000003C +... diff --git a/llvm/test/tools/llvm-xray/ARM/extract-instrmap.test b/llvm/test/tools/llvm-xray/ARM/extract-instrmap.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-xray/ARM/extract-instrmap.test @@ -0,0 +1,25 @@ +## This test makes sure we can extract the instrumentation map from an +## XRay-instrumented PIE file. + +# RUN: yaml2obj %S/Inputs/elf32-pic.yaml -o %t.so +# RUN: llvm-xray extract %t.so -s | FileCheck %s + +# CHECK: --- +# CHECK-NEXT: - { id: 1, address: 0x00000000000012B0, function: 0x00000000000012B0, kind: function-enter, always-instrument: true, function-name: 'foo()' } +# CHECK-NEXT: - { id: 1, address: 0x00000000000012CC, function: 0x00000000000012B0, kind: function-exit, always-instrument: true, function-name: 'foo()' } +# CHECK-NEXT: - { id: 2, address: 0x00000000000012EC, function: 0x00000000000012EC, kind: function-enter, always-instrument: true, function-name: 'bar()' } +# CHECK-NEXT: - { id: 2, address: 0x0000000000001308, function: 0x00000000000012EC, kind: function-exit, always-instrument: true, function-name: 'bar()' } +# CHECK-NEXT: - { id: 3, address: 0x0000000000001328, function: 0x0000000000001328, kind: function-enter, always-instrument: true, function-name: 'jar()' } +# CHECK-NEXT: - { id: 3, address: 0x0000000000001344, function: 0x0000000000001328, kind: function-exit, always-instrument: true, function-name: 'jar()' } +# CHECK-NEXT: ... + +# RUN: llvm-xray extract -s --no-demangle %t.so | FileCheck --check-prefix=MANGLED %s + +# MANGLED: --- +# MANGLED-NEXT: - { id: 1, address: 0x00000000000012B0, function: 0x00000000000012B0, kind: function-enter, always-instrument: true, function-name: _Z3foov } +# MANGLED-NEXT: - { id: 1, address: 0x00000000000012CC, function: 0x00000000000012B0, kind: function-exit, always-instrument: true, function-name: _Z3foov } +# MANGLED-NEXT: - { id: 2, address: 0x00000000000012EC, function: 0x00000000000012EC, kind: function-enter, always-instrument: true, function-name: _Z3barv } +# MANGLED-NEXT: - { id: 2, address: 0x0000000000001308, function: 0x00000000000012EC, kind: function-exit, always-instrument: true, function-name: _Z3barv } +# MANGLED-NEXT: - { id: 3, address: 0x0000000000001328, function: 0x0000000000001328, kind: function-enter, always-instrument: true, function-name: _Z3jarv } +# MANGLED-NEXT: - { id: 3, address: 0x0000000000001344, function: 0x0000000000001328, kind: function-exit, always-instrument: true, function-name: _Z3jarv } +# MANGLED-NEXT: ... diff --git a/llvm/test/tools/llvm-xray/X86/bad-instrmap-sizes.txt b/llvm/test/tools/llvm-xray/X86/bad-instrmap-sizes.txt --- a/llvm/test/tools/llvm-xray/X86/bad-instrmap-sizes.txt +++ b/llvm/test/tools/llvm-xray/X86/bad-instrmap-sizes.txt @@ -1,3 +1,3 @@ ; RUN: not llvm-xray extract %S/Inputs/elf64-badentrysizes.bin 2>&1 | FileCheck %s ; CHECK: llvm-xray: Cannot extract instrumentation map from '{{.*}}elf64-badentrysizes.bin'. -; CHECK-NEXT: Instrumentation map entries not evenly divisible by size of an XRay sled entry in ELF64. +; CHECK-NEXT: Instrumentation map entries not evenly divisible by size of an XRay sled entry. diff --git a/llvm/test/tools/llvm-xray/X86/unsupported-elf32.txt b/llvm/test/tools/llvm-xray/X86/unsupported-elf32.txt --- a/llvm/test/tools/llvm-xray/X86/unsupported-elf32.txt +++ b/llvm/test/tools/llvm-xray/X86/unsupported-elf32.txt @@ -1,3 +1,3 @@ ; RUN: not llvm-xray extract %S/Inputs/elf32-noxray.bin 2>&1 | FileCheck %s ; CHECK: llvm-xray: Cannot extract instrumentation map from '{{.*}}elf32-noxray.bin'. -; CHECK-NEXT: File format not supported (only does ELF and Mach-O little endian 64-bit). +; CHECK-NEXT: File format not supported. Supports: AArch64/ARM/ppc64le/x86-64.