| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,185 @@ | ||
| //===- bolt/Core/GDBIndex.cpp - GDB Index support ------------------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "bolt/Core/GDBIndex.h" | ||
|
|
||
| using namespace llvm::bolt; | ||
| using namespace llvm::support::endian; | ||
|
|
||
| void GDBIndex::addGDBTypeUnitEntry(const GDBIndexTUEntry &&Entry) { | ||
| std::lock_guard<std::mutex> Lock(GDBIndexMutex); | ||
| if (!BC.getGdbIndexSection()) | ||
| return; | ||
| GDBIndexTUEntryVector.emplace_back(Entry); | ||
| } | ||
|
|
||
| void GDBIndex::updateGdbIndexSection( | ||
| const CUOffsetMap &CUMap, const uint32_t NumCUs, | ||
| DebugARangesSectionWriter &ARangesSectionWriter) { | ||
| if (!BC.getGdbIndexSection()) | ||
| return; | ||
|
|
||
| // See https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html | ||
| // for .gdb_index section format. | ||
|
|
||
| StringRef GdbIndexContents = BC.getGdbIndexSection()->getContents(); | ||
|
|
||
| const char *Data = GdbIndexContents.data(); | ||
|
|
||
| // Parse the header. | ||
| const uint32_t Version = read32le(Data); | ||
| if (Version != 7 && Version != 8) { | ||
| errs() << "BOLT-ERROR: can only process .gdb_index versions 7 and 8\n"; | ||
| exit(1); | ||
| } | ||
|
|
||
| // Some .gdb_index generators use file offsets while others use section | ||
| // offsets. Hence we can only rely on offsets relative to each other, | ||
| // and ignore their absolute values. | ||
| const uint32_t CUListOffset = read32le(Data + 4); | ||
| const uint32_t CUTypesOffset = read32le(Data + 8); | ||
| const uint32_t AddressTableOffset = read32le(Data + 12); | ||
| const uint32_t SymbolTableOffset = read32le(Data + 16); | ||
| const uint32_t ConstantPoolOffset = read32le(Data + 20); | ||
| Data += 24; | ||
|
|
||
| // Map CUs offsets to indices and verify existing index table. | ||
| std::map<uint32_t, uint32_t> OffsetToIndexMap; | ||
| const uint32_t CUListSize = CUTypesOffset - CUListOffset; | ||
| const uint32_t TUListSize = AddressTableOffset - CUTypesOffset; | ||
| const unsigned NUmCUsEncoded = CUListSize / 16; | ||
| unsigned MaxDWARFVersion = BC.DwCtx->getMaxVersion(); | ||
| unsigned NumDWARF5TUs = | ||
| getGDBIndexTUEntryVector().size() - BC.DwCtx->getNumTypeUnits(); | ||
| bool SkipTypeUnits = false; | ||
| // For DWARF5 Types are in .debug_info. | ||
| // LLD doesn't generate Types CU List, and in CU list offset | ||
| // only includes CUs. | ||
| // GDB 11+ includes only CUs in CU list and generates Types | ||
| // list. | ||
| // GDB 9 includes CUs and TUs in CU list and generates TYpes | ||
| // list. The NumCUs is CUs + TUs, so need to modify the check. | ||
| // For split-dwarf | ||
| // GDB-11, DWARF5: TU units from dwo are not included. | ||
| // GDB-11, DWARF4: TU units from dwo are included. | ||
| if (MaxDWARFVersion >= 5) | ||
| SkipTypeUnits = !TUListSize ? true | ||
| : ((NUmCUsEncoded + NumDWARF5TUs) == | ||
| BC.DwCtx->getNumCompileUnits()); | ||
|
|
||
| if (!((CUListSize == NumCUs * 16) || | ||
| (CUListSize == (NumCUs + NumDWARF5TUs) * 16))) { | ||
| errs() << "BOLT-ERROR: .gdb_index: CU count mismatch\n"; | ||
| exit(1); | ||
| } | ||
| DenseSet<uint64_t> OriginalOffsets; | ||
| for (unsigned Index = 0, Units = BC.DwCtx->getNumCompileUnits(); | ||
| Index < Units; ++Index) { | ||
| const DWARFUnit *CU = BC.DwCtx->getUnitAtIndex(Index); | ||
| if (SkipTypeUnits && CU->isTypeUnit()) | ||
| continue; | ||
| const uint64_t Offset = read64le(Data); | ||
| Data += 16; | ||
| if (CU->getOffset() != Offset) { | ||
| errs() << "BOLT-ERROR: .gdb_index CU offset mismatch\n"; | ||
| exit(1); | ||
| } | ||
|
|
||
| OriginalOffsets.insert(Offset); | ||
| OffsetToIndexMap[Offset] = Index; | ||
| } | ||
|
|
||
| // Ignore old address table. | ||
| const uint32_t OldAddressTableSize = SymbolTableOffset - AddressTableOffset; | ||
| // Move Data to the beginning of symbol table. | ||
| Data += SymbolTableOffset - CUTypesOffset; | ||
|
|
||
| // Calculate the size of the new address table. | ||
| uint32_t NewAddressTableSize = 0; | ||
| for (const auto &CURangesPair : ARangesSectionWriter.getCUAddressRanges()) { | ||
| const SmallVector<DebugAddressRange, 2> &Ranges = CURangesPair.second; | ||
| NewAddressTableSize += Ranges.size() * 20; | ||
| } | ||
|
|
||
| // Difference between old and new table (and section) sizes. | ||
| // Could be negative. | ||
| int32_t Delta = NewAddressTableSize - OldAddressTableSize; | ||
|
|
||
| size_t NewGdbIndexSize = GdbIndexContents.size() + Delta; | ||
|
|
||
| // Free'd by ExecutableFileMemoryManager. | ||
| auto *NewGdbIndexContents = new uint8_t[NewGdbIndexSize]; | ||
| uint8_t *Buffer = NewGdbIndexContents; | ||
|
|
||
| write32le(Buffer, Version); | ||
| write32le(Buffer + 4, CUListOffset); | ||
| write32le(Buffer + 8, CUTypesOffset); | ||
| write32le(Buffer + 12, AddressTableOffset); | ||
| write32le(Buffer + 16, SymbolTableOffset + Delta); | ||
| write32le(Buffer + 20, ConstantPoolOffset + Delta); | ||
| Buffer += 24; | ||
|
|
||
| using MapEntry = std::pair<uint32_t, CUInfo>; | ||
| std::vector<MapEntry> CUVector(CUMap.begin(), CUMap.end()); | ||
| // Need to sort since we write out all of TUs in .debug_info before CUs. | ||
| std::sort(CUVector.begin(), CUVector.end(), | ||
| [](const MapEntry &E1, const MapEntry &E2) -> bool { | ||
| return E1.second.Offset < E2.second.Offset; | ||
| }); | ||
| // Writing out CU List <Offset, Size> | ||
| for (auto &CUInfo : CUVector) { | ||
| // Skipping TU for DWARF5 when they are not included in CU list. | ||
| if (!OriginalOffsets.count(CUInfo.first)) | ||
| continue; | ||
| write64le(Buffer, CUInfo.second.Offset); | ||
| // Length encoded in CU doesn't contain first 4 bytes that encode length. | ||
| write64le(Buffer + 8, CUInfo.second.Length + 4); | ||
| Buffer += 16; | ||
| } | ||
|
|
||
| // Rewrite TU CU List, since abbrevs can be different. | ||
| // Entry example: | ||
| // 0: offset = 0x00000000, type_offset = 0x0000001e, type_signature = | ||
| // 0x418503b8111e9a7b Spec says " triplet, the first value is the CU offset, | ||
| // the second value is the type offset in the CU, and the third value is the | ||
| // type signature" Looking at what is being generated by gdb-add-index. The | ||
| // first entry is TU offset, second entry is offset from it, and third entry | ||
| // is the type signature. | ||
| if (TUListSize) | ||
| for (const GDBIndexTUEntry &Entry : getGDBIndexTUEntryVector()) { | ||
| write64le(Buffer, Entry.UnitOffset); | ||
| write64le(Buffer + 8, Entry.TypeDIERelativeOffset); | ||
| write64le(Buffer + 16, Entry.TypeHash); | ||
| Buffer += sizeof(GDBIndexTUEntry); | ||
| } | ||
|
|
||
| // Generate new address table. | ||
| for (const std::pair<const uint64_t, DebugAddressRangesVector> &CURangesPair : | ||
| ARangesSectionWriter.getCUAddressRanges()) { | ||
| const uint32_t CUIndex = OffsetToIndexMap[CURangesPair.first]; | ||
| const DebugAddressRangesVector &Ranges = CURangesPair.second; | ||
| for (const DebugAddressRange &Range : Ranges) { | ||
| write64le(Buffer, Range.LowPC); | ||
| write64le(Buffer + 8, Range.HighPC); | ||
| write32le(Buffer + 16, CUIndex); | ||
| Buffer += 20; | ||
| } | ||
| } | ||
|
|
||
| const size_t TrailingSize = | ||
| GdbIndexContents.data() + GdbIndexContents.size() - Data; | ||
| assert(Buffer + TrailingSize == NewGdbIndexContents + NewGdbIndexSize && | ||
| "size calculation error"); | ||
|
|
||
| // Copy over the rest of the original data. | ||
| memcpy(Buffer, Data, TrailingSize); | ||
|
|
||
| // Register the new section. | ||
| BC.registerOrUpdateNoteSection(".gdb_index", NewGdbIndexContents, | ||
| NewGdbIndexSize); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| //===- bolt/Rewrite/BuildIDRewriter.cpp -----------------------------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // Read and update build ID stored in ELF note section. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "bolt/Rewrite/MetadataRewriter.h" | ||
| #include "bolt/Rewrite/MetadataRewriters.h" | ||
| #include "llvm/Support/Errc.h" | ||
|
|
||
| using namespace llvm; | ||
| using namespace bolt; | ||
|
|
||
| namespace { | ||
|
|
||
| /// The build-id is typically a stream of 20 bytes. Return these bytes in | ||
| /// printable hexadecimal form. | ||
| std::string getPrintableBuildID(StringRef BuildID) { | ||
| std::string Str; | ||
| raw_string_ostream OS(Str); | ||
| for (const char &Char : BuildID) | ||
| OS << format("%.2x", static_cast<unsigned char>(Char)); | ||
|
|
||
| return OS.str(); | ||
| } | ||
|
|
||
| class BuildIDRewriter final : public MetadataRewriter { | ||
|
|
||
| /// Information about binary build ID. | ||
| ErrorOr<BinarySection &> BuildIDSection{std::errc::bad_address}; | ||
| StringRef BuildID; | ||
| std::optional<uint64_t> BuildIDOffset; | ||
| std::optional<uint64_t> BuildIDSize; | ||
|
|
||
| public: | ||
| BuildIDRewriter(StringRef Name, BinaryContext &BC) | ||
| : MetadataRewriter(Name, BC) {} | ||
|
|
||
| Error sectionInitializer() override; | ||
|
|
||
| Error postEmitFinalizer() override; | ||
| }; | ||
|
|
||
| Error BuildIDRewriter::sectionInitializer() { | ||
| // Typically, build ID will reside in .note.gnu.build-id section. Howerver, | ||
| // a linker script can change the section name and such is the case with | ||
| // the Linux kernel. Hence, we iterate over all note sections. | ||
| for (BinarySection &NoteSection : BC.sections()) { | ||
| if (!NoteSection.isNote()) | ||
| continue; | ||
|
|
||
| StringRef Buf = NoteSection.getContents(); | ||
| DataExtractor DE = DataExtractor(Buf, BC.AsmInfo->isLittleEndian(), | ||
| BC.AsmInfo->getCodePointerSize()); | ||
| DataExtractor::Cursor Cursor(0); | ||
| while (Cursor && !DE.eof(Cursor)) { | ||
| const uint32_t NameSz = DE.getU32(Cursor); | ||
| const uint32_t DescSz = DE.getU32(Cursor); | ||
| const uint32_t Type = DE.getU32(Cursor); | ||
|
|
||
| StringRef Name = | ||
| NameSz ? Buf.slice(Cursor.tell(), Cursor.tell() + NameSz) : "<empty>"; | ||
| Cursor.seek(alignTo(Cursor.tell() + NameSz, 4)); | ||
|
|
||
| const uint64_t DescOffset = Cursor.tell(); | ||
| StringRef Desc = | ||
| DescSz ? Buf.slice(DescOffset, DescOffset + DescSz) : "<empty>"; | ||
| Cursor.seek(alignTo(DescOffset + DescSz, 4)); | ||
|
|
||
| if (!Cursor) | ||
| return createStringError(errc::executable_format_error, | ||
| "out of bounds while reading note section: %s", | ||
| toString(Cursor.takeError()).c_str()); | ||
|
|
||
| if (Type == ELF::NT_GNU_BUILD_ID && Name.substr(0, 3) == "GNU" && | ||
| DescSz) { | ||
| BuildIDSection = NoteSection; | ||
| BuildID = Desc; | ||
| BC.setFileBuildID(getPrintableBuildID(Desc)); | ||
| BuildIDOffset = DescOffset; | ||
| BuildIDSize = DescSz; | ||
|
|
||
| return Error::success(); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return Error::success(); | ||
| } | ||
|
|
||
| Error BuildIDRewriter::postEmitFinalizer() { | ||
| if (!BuildIDSection || !BuildIDOffset) | ||
| return Error::success(); | ||
|
|
||
| const uint8_t LastByte = BuildID[BuildID.size() - 1]; | ||
| SmallVector<char, 1> Patch = {static_cast<char>(LastByte ^ 1)}; | ||
| BuildIDSection->addPatch(*BuildIDOffset + BuildID.size() - 1, Patch); | ||
| BC.outs() << "BOLT-INFO: patched build-id (flipped last bit)\n"; | ||
|
|
||
| return Error::success(); | ||
| } | ||
| } // namespace | ||
|
|
||
| std::unique_ptr<MetadataRewriter> | ||
| llvm::bolt::createBuildIDRewriter(BinaryContext &BC) { | ||
| return std::make_unique<BuildIDRewriter>("build-id-rewriter", BC); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| ; RUN: rm -rf %t | ||
| ; RUN: mkdir %t | ||
| ; RUN: cd %t | ||
| ; RUN: llvm-mc -dwarf-version=4 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf4-df-input-lowpc-ranges-main.s \ | ||
| ; RUN: -split-dwarf-file=main.dwo -o main.o | ||
| ; RUN: llvm-mc -dwarf-version=4 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf4-df-input-lowpc-ranges-other.s \ | ||
| ; RUN: -split-dwarf-file=mainOther.dwo -o other.o | ||
| ; RUN: %clang %cflags -gdwarf-4 -gsplit-dwarf=split main.o other.o -o main.exe | ||
| ; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections | ||
| ; RUN: llvm-dwarfdump --show-form --verbose --debug-ranges main.exe.bolt &> %t/foo.txt | ||
| ; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.exe.bolt >> %t/foo.txt | ||
| ; RUN: cat %t/foo.txt | FileCheck -check-prefix=BOLT %s | ||
| ; RUN: not llvm-dwarfdump --show-form --verbose --debug-info main.dwo.dwo mainOther.dwo.dwo &> %t/mainddwodwo.txt | ||
| ; RUN: cat %t/mainddwodwo.txt | FileCheck -check-prefix=BOLT-DWO-MAIN %s | ||
|
|
||
| ;; Tests that BOLT correctly handles Skeleton CU which has DW_AT_low_pc/DW_AT_ranges as input and handles multiple CUs with ranges. | ||
|
|
||
| ; BOLT: .debug_ranges | ||
| ; BOLT-NEXT: 00000000 <End of list> | ||
| ; BOLT-NEXT: 00000010 | ||
| ; BOLT-NEXT: 00000010 | ||
| ; BOLT-NEXT: 00000010 | ||
| ; BOLT-NEXT: 00000010 <End of list> | ||
| ; BOLT-NEXT: 00000050 | ||
| ; BOLT-NEXT: 00000050 | ||
| ; BOLT-NEXT: 00000050 | ||
| ; BOLT-NEXT: 00000050 <End of list> | ||
| ; BOLT-NEXT: 00000090 [[#%.16x,ADDR1:]] [[#%.16x,ADDRB1:]] | ||
| ; BOLT-NEXT: 00000090 [[#%.16x,ADDR2:]] [[#%.16x,ADDRB2:]] | ||
| ; BOLT-NEXT: 00000090 [[#%.16x,ADDR3:]] [[#%.16x,ADDRB3:]] | ||
| ; BOLT-NEXT: 00000090 [[#%.16x,ADDR4:]] [[#%.16x,ADDRB4:]] | ||
| ; BOLT-NEXT: 00000090 [[#%.16x,ADDR5:]] [[#%.16x,ADDRB5:]] | ||
| ; BOLT-NEXT: 00000090 [[#%.16x,ADDR6:]] [[#%.16x,ADDRB6:]] | ||
| ; BOLT-NEXT: 00000090 [[#%.16x,ADDR7:]] [[#%.16x,ADDRB7:]] | ||
| ; BOLT-NEXT: 00000090 <End of list> | ||
| ; BOLT-NEXT: 00000110 | ||
| ; BOLT-NEXT: 00000110 | ||
| ; BOLT-NEXT: 00000110 | ||
| ; BOLT-NEXT: 00000110 <End of list> | ||
| ; BOLT-NEXT: 00000150 | ||
| ; BOLT-NEXT: 00000150 | ||
| ; BOLT-NEXT: 00000150 | ||
| ; BOLT-NEXT: 00000150 <End of list> | ||
| ; BOLT-NEXT: 00000190 [[#%.16x,ADDR8:]] [[#%.16x,ADDRB8:]] | ||
| ; BOLT-NEXT: 00000190 [[#%.16x,ADDR9:]] [[#%.16x,ADDRB9:]] | ||
| ; BOLT-NEXT: 00000190 [[#%.16x,ADDR10:]] [[#%.16x,ADDRB10:]] | ||
| ; BOLT-NEXT: 00000190 [[#%.16x,ADDR11:]] [[#%.16x,ADDRB11:]] | ||
| ; BOLT-NEXT: 00000190 [[#%.16x,ADDR12:]] [[#%.16x,ADDRB12:]] | ||
| ; BOLT-NEXT: 00000190 [[#%.16x,ADDR13:]] [[#%.16x,ADDRB13:]] | ||
| ; BOLT-NEXT: 00000190 [[#%.16x,ADDR14:]] [[#%.16x,ADDRB14:]] | ||
| ; BOLT-NEXT: 00000190 <End of list> | ||
|
|
||
| ; BOLT: DW_TAG_compile_unit | ||
| ; BOLT: DW_AT_GNU_dwo_name [DW_FORM_strp] ( .debug_str[0x{{[0-9a-fA-F]+}}] = "main.dwo.dwo") | ||
| ; BOLT-NEXT: DW_AT_GNU_dwo_id | ||
| ; BOLT-NEXT: DW_AT_GNU_ranges_base [DW_FORM_sec_offset] (0x00000010) | ||
| ; BOLT-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) | ||
| ; BOLT-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000090 | ||
| ; BOLT-NEXT: [0x[[#ADDR1]], 0x[[#ADDRB1]]) | ||
| ; BOLT-NEXT: [0x[[#ADDR2]], 0x[[#ADDRB2]]) | ||
| ; BOLT-NEXT: [0x[[#ADDR3]], 0x[[#ADDRB3]]) | ||
| ; BOLT-NEXT: [0x[[#ADDR4]], 0x[[#ADDRB4]]) | ||
| ; BOLT-NEXT: [0x[[#ADDR5]], 0x[[#ADDRB5]]) | ||
| ; BOLT-NEXT: [0x[[#ADDR6]], 0x[[#ADDRB6]]) | ||
| ; BOLT-NEXT: [0x[[#ADDR7]], 0x[[#ADDRB7]]) | ||
| ; BOLT-NEXT: DW_AT_GNU_addr_base [DW_FORM_sec_offset] (0x00000000) | ||
|
|
||
| ; BOLT: DW_TAG_compile_unit | ||
| ; BOLT: DW_AT_GNU_dwo_name [DW_FORM_strp] ( .debug_str[0x{{[0-9a-fA-F]+}}] = "mainOther.dwo.dwo") | ||
| ; BOLT-NEXT: DW_AT_GNU_dwo_id | ||
| ; BOLT-NEXT: DW_AT_GNU_ranges_base [DW_FORM_sec_offset] (0x00000110) | ||
| ; BOLT-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) | ||
| ; BOLT-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000190 | ||
| ; BOLT-NEXT: [0x[[#ADDR8]], 0x[[#ADDRB8]]) | ||
| ; BOLT-NEXT: [0x[[#ADDR9]], 0x[[#ADDRB9]]) | ||
| ; BOLT-NEXT: [0x[[#ADDR10]], 0x[[#ADDRB10]]) | ||
| ; BOLT-NEXT: [0x[[#ADDR11]], 0x[[#ADDRB11]]) | ||
| ; BOLT-NEXT: [0x[[#ADDR12]], 0x[[#ADDRB12]]) | ||
| ; BOLT-NEXT: [0x[[#ADDR13]], 0x[[#ADDRB13]]) | ||
| ; BOLT-NEXT: [0x[[#ADDR14]], 0x[[#ADDRB14]]) | ||
| ; BOLT-NEXT: DW_AT_GNU_addr_base [DW_FORM_sec_offset] (0x00000018) | ||
|
|
||
| ; BOLT-DWO-MAIN: DW_TAG_subprogram | ||
| ; BOLT-DWO-MAIN-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000000 | ||
| ; BOLT-DWO-MAIN: DW_TAG_subprogram | ||
| ; BOLT-DWO-MAIN: DW_TAG_subprogram | ||
| ; BOLT-DWO-MAIN: DW_TAG_subprogram | ||
| ; BOLT-DWO-MAIN: DW_TAG_subprogram | ||
| ; BOLT-DWO-MAIN-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000040 | ||
|
|
||
| ; BOLT-DWO-MAIN: DW_TAG_subprogram | ||
| ; BOLT-DWO-MAIN-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000000 | ||
| ; BOLT-DWO-MAIN: DW_TAG_subprogram | ||
| ; BOLT-DWO-MAIN: DW_TAG_subprogram | ||
| ; BOLT-DWO-MAIN: DW_TAG_subprogram | ||
| ; BOLT-DWO-MAIN: DW_TAG_subprogram | ||
| ; BOLT-DWO-MAIN-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000040 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| ; RUN: rm -rf %t | ||
| ; RUN: mkdir %t | ||
| ; RUN: cd %t | ||
| ; RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf5-df-input-lowpc-ranges-main.s \ | ||
| ; RUN: -split-dwarf-file=main.dwo -o main.o | ||
| ; RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf5-df-input-lowpc-ranges-other.s \ | ||
| ; RUN: -split-dwarf-file=mainOther.dwo -o other.o | ||
| ; RUN: %clang %cflags main.o other.o -o main.exe | ||
| ; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections | ||
| ; RUN: llvm-dwarfdump --show-form --verbose --debug-rnglists main.exe.bolt &> %t/foo.txt | ||
| ; RUN: llvm-dwarfdump --show-form --verbose --debug-addr main.exe.bolt >> %t/foo.txt | ||
| ; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.exe.bolt >> %t/foo.txt | ||
| ; RUN: cat %t/foo.txt | FileCheck -check-prefix=BOLT %s | ||
| ; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.dwo.dwo mainOther.dwo.dwo &> %t/mainddwodwo.txt | ||
| ; RUN: cat %t/mainddwodwo.txt | FileCheck -check-prefix=BOLT-DWO-MAIN %s | ||
|
|
||
| ;; Tests that BOLT correctly handles Skeleton CU which has DW_AT_low_pc/DW_AT_ranges as input and handles multiple CUs with ranges. | ||
|
|
||
| ; BOLT: Addrs: [ | ||
| ; BOLT-NEXT: 0x[[#%.16x,ADDR1:]] | ||
| ; BOLT-NEXT: 0x[[#%.16x,ADDR2:]] | ||
| ; BOLT-NEXT: 0x[[#%.16x,ADDR3:]] | ||
| ; BOLT-NEXT: 0x[[#%.16x,ADDR4:]] | ||
| ; BOLT-NEXT: 0x[[#%.16x,ADDR5:]] | ||
|
|
||
| ; BOLT: Addrs: [ | ||
| ; BOLT-NEXT: 0x[[#%.16x,ADDR6:]] | ||
| ; BOLT-NEXT: 0x[[#%.16x,ADDR7:]] | ||
| ; BOLT-NEXT: 0x[[#%.16x,ADDR8:]] | ||
| ; BOLT-NEXT: 0x[[#%.16x,ADDR9:]] | ||
| ; BOLT-NEXT: 0x[[#%.16x,ADDR10:]] | ||
|
|
||
| ; BOLT: DW_TAG_skeleton_unit | ||
| ; BOLT: DW_AT_dwo_name [DW_FORM_strx1] (indexed (00000001) string = "main.dwo.dwo") | ||
| ; BOLT-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) | ||
| ; BOLT-NEXT: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x0) rangelist = 0x00000010 | ||
| ; BOLT-NEXT: [0x[[#ADDR1]], 0x[[#ADDR1 + 0x16]]) | ||
| ; BOLT-NEXT: [0x[[#ADDR1 + 0x16]], 0x[[#ADDR1 + 0x24]]) | ||
| ; BOLT-NEXT: [0x[[#ADDR1 + 0x24]], 0x[[#ADDR1 + 0x29]]) | ||
| ; BOLT-NEXT: [0x[[#ADDR1 + 0x30]], 0x[[#ADDR1 + 0x46]]) | ||
| ; BOLT-NEXT: [0x[[#ADDR1 + 0x50]], 0x[[#ADDR1 + 0x77]]) | ||
| ; BOLT-NEXT: [0x[[#ADDR1 + 0x77]], 0x[[#ADDR1 + 0x85]]) | ||
| ; BOLT-NEXT: [0x[[#ADDR1 + 0x85]], 0x[[#ADDR1 + 0x9f]]) | ||
| ; BOLT-NEXT: DW_AT_addr_base [DW_FORM_sec_offset] (0x00000008) | ||
| ; BOLT-NEXT: DW_AT_rnglists_base [DW_FORM_sec_offset] (0x0000000c) | ||
|
|
||
| ; BOLT: DW_TAG_skeleton_unit | ||
| ; BOLT: DW_AT_dwo_name [DW_FORM_strx1] (indexed (00000001) string = "mainOther.dwo.dwo") | ||
| ; BOLT-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) | ||
| ; BOLT-NEXT: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x0) rangelist = 0x0000003b | ||
| ; BOLT-NEXT: [0x[[#ADDR6]], 0x[[#ADDR6 + 0x16]]) | ||
| ; BOLT-NEXT: [0x[[#ADDR6 + 0x16]], 0x[[#ADDR6 + 0x24]]) | ||
| ; BOLT-NEXT: [0x[[#ADDR6 + 0x24]], 0x[[#ADDR6 + 0x29]]) | ||
| ; BOLT-NEXT: [0x[[#ADDR6 + 0x30]], 0x[[#ADDR6 + 0x46]]) | ||
| ; BOLT-NEXT: [0x[[#ADDR6 + 0x50]], 0x[[#ADDR6 + 0x70]]) | ||
| ; BOLT-NEXT: [0x[[#ADDR6 + 0x70]], 0x[[#ADDR6 + 0x7e]]) | ||
| ; BOLT-NEXT: [0x[[#ADDR6 + 0x7e]], 0x[[#ADDR6 + 0x98]]) | ||
| ; BOLT-NEXT: DW_AT_addr_base [DW_FORM_sec_offset] (0x00000038) | ||
| ; BOLT-NEXT: DW_AT_rnglists_base [DW_FORM_sec_offset] (0x00000037) | ||
|
|
||
| ; BOLT-DWO-MAIN: DW_TAG_subprogram | ||
| ; BOLT-DWO-MAIN-NEXT: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x0) rangelist = 0x00000014 | ||
| ; BOLT-DWO-MAIN-NEXT: [0x0000000000000000, 0x0000000000000016) | ||
| ; BOLT-DWO-MAIN-NEXT: [0x0000000000000016, 0x0000000000000024) | ||
| ; BOLT-DWO-MAIN-NEXT: [0x0000000000000024, 0x0000000000000029)) | ||
| ; BOLT-DWO-MAIN: DW_TAG_subprogram | ||
| ; BOLT-DWO-MAIN: DW_TAG_subprogram | ||
| ; BOLT-DWO-MAIN: DW_TAG_subprogram | ||
| ; BOLT-DWO-MAIN: DW_TAG_subprogram | ||
| ; BOLT-DWO-MAIN-NEXT: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x1) rangelist = 0x00000020 | ||
| ; BOLT-DWO-MAIN-NEXT: [0x0000000000000002, 0x0000000000000029) | ||
| ; BOLT-DWO-MAIN-NEXT: [0x0000000000000029, 0x0000000000000037) | ||
| ; BOLT-DWO-MAIN-NEXT: [0x0000000000000037, 0x0000000000000051)) | ||
|
|
||
| ; BOLT-DWO-MAIN: DW_TAG_subprogram | ||
| ; BOLT-DWO-MAIN-NEXT: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x0) rangelist = 0x00000014 | ||
| ; BOLT-DWO-MAIN-NEXT: [0x0000000000000000, 0x0000000000000016) | ||
| ; BOLT-DWO-MAIN-NEXT: [0x0000000000000016, 0x0000000000000024) | ||
| ; BOLT-DWO-MAIN-NEXT: [0x0000000000000024, 0x0000000000000029)) | ||
| ; BOLT-DWO-MAIN: DW_TAG_subprogram | ||
| ; BOLT-DWO-MAIN: DW_TAG_subprogram | ||
| ; BOLT-DWO-MAIN: DW_TAG_subprogram | ||
| ; BOLT-DWO-MAIN: DW_TAG_subprogram | ||
| ; BOLT-DWO-MAIN-NEXT: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x1) rangelist = 0x00000020 | ||
| ; BOLT-DWO-MAIN-NEXT: [0x0000000000000002, 0x0000000000000022) | ||
| ; BOLT-DWO-MAIN-NEXT: [0x0000000000000022, 0x0000000000000030) | ||
| ; BOLT-DWO-MAIN-NEXT: [0x0000000000000030, 0x000000000000004a)) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| ## If the operand references a symbol that differs from the jump table label, | ||
| ## no reference updating is required even if its target address resides within | ||
| ## the jump table's range. | ||
| ## In this test case, consider the second instruction within the main function, | ||
| ## where the address resulting from 'c + 17' corresponds to one byte beyond the | ||
| ## address of the .LJTI2_0 jump table label. However, this operand represents | ||
| ## an offset calculation related to the global variable 'c' and should remain | ||
| ## unaffected by the jump table. | ||
|
|
||
| # REQUIRES: system-linux | ||
|
|
||
| # RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o | ||
| # RUN: %clang -no-pie %t.o -o %t.exe -Wl,-q | ||
| # RUN: llvm-bolt --funcs=main,foo/1 %t.exe -o %t.exe.bolt --print-normalized \ | ||
| # RUN: 2>&1 | FileCheck %s | ||
|
|
||
| .text | ||
| .globl main | ||
| .type main,@function | ||
| main: | ||
| # CHECK: Binary Function "main" | ||
| pushq %rbp | ||
| movq %rsp, %rbp | ||
| movq $-16, %rax | ||
| movl c+17(%rax), %edx | ||
| # CHECK: movl c+17(%rax), %edx | ||
| cmpl $255, %edx | ||
| je .LCorrect | ||
| movl $1, %eax | ||
| popq %rbp | ||
| ret | ||
| .LCorrect: | ||
| movl $0, %eax | ||
| popq %rbp | ||
| ret | ||
|
|
||
| .p2align 4, 0x90 | ||
| .type foo,@function | ||
| foo: | ||
| # CHECK: Binary Function "foo | ||
| movq $0, %rax | ||
| jmpq *.LJTI2_0(,%rax,8) | ||
| # CHECK: jmpq *{{.*}} # JUMPTABLE | ||
| addl $-36, %eax | ||
| .LBB2_2: | ||
| addl $-16, %eax | ||
| retq | ||
| .section .rodata,"a",@progbits | ||
| .type c,@object | ||
| .data | ||
| .globl c | ||
| .p2align 4, 0x0 | ||
| c: | ||
| .byte 1 | ||
| .byte 0xff | ||
| .zero 14 | ||
| .size c, 16 | ||
| .LJTI2_0: | ||
| .quad .LBB2_2 | ||
| .quad .LBB2_2 | ||
| .quad .LBB2_2 | ||
| .quad .LBB2_2 | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| // RUN: not clang-tidy %s -checks='-*,misc-header-include-cycle' | ||
|
|
||
| #include "header-include-cycle.self.cpp" |