diff --git a/llvm/docs/CommandGuide/dsymutil.rst b/llvm/docs/CommandGuide/dsymutil.rst index 02243e227a24d..df621a429bb5c 100644 --- a/llvm/docs/CommandGuide/dsymutil.rst +++ b/llvm/docs/CommandGuide/dsymutil.rst @@ -32,11 +32,26 @@ OPTIONS architectures will be linked by default and any architectures that can't be properly linked will cause :program:`dsymutil` to return an error. +.. option:: --build-variant-suffix + + Specify the build variant suffix used to build the executabe file. + There can be multiple variants for the binary of a product, each built + slightly differently. The most common build variants are 'debug' and + 'profile'. Setting the DYLD_IMAGE_SUFFIX environment variable will + cause dyld to load the specified variant at runtime. + .. option:: --dump-debug-map Dump the *executable*'s debug-map (the list of the object files containing the debug information) in YAML format and exit. No DWARF link will take place. + .. option:: -D + + Specify a directory that contain dSYM files to search for. + This is used for mergeable libraries, so dsymutil knows where to look + for dSYM files with debug information about symbols present in those + libraries. + .. option:: --fat64 Use a 64-bit header when emitting universal binaries. diff --git a/llvm/include/llvm/BinaryFormat/Dwarf.def b/llvm/include/llvm/BinaryFormat/Dwarf.def index fb328a0257732..d1abb1f361d3e 100644 --- a/llvm/include/llvm/BinaryFormat/Dwarf.def +++ b/llvm/include/llvm/BinaryFormat/Dwarf.def @@ -629,6 +629,7 @@ HANDLE_DW_AT(0x3fec, APPLE_objc_complete_type, 0, APPLE) HANDLE_DW_AT(0x3fed, APPLE_property, 0, APPLE) HANDLE_DW_AT(0x3fee, APPLE_objc_direct, 0, APPLE) HANDLE_DW_AT(0x3fef, APPLE_sdk, 0, APPLE) +HANDLE_DW_AT(0x3ff0, APPLE_origin, 0, APPLE) // Attribute form encodings. HANDLE_DW_FORM(0x01, addr, 2, DWARF) diff --git a/llvm/include/llvm/BinaryFormat/MachO.h b/llvm/include/llvm/BinaryFormat/MachO.h index 49991ebe7bfaf..bef70f869520b 100644 --- a/llvm/include/llvm/BinaryFormat/MachO.h +++ b/llvm/include/llvm/BinaryFormat/MachO.h @@ -373,6 +373,7 @@ enum StabType { N_SSYM = 0x60u, N_SO = 0x64u, N_OSO = 0x66u, + N_LIB = 0x68u, N_LSYM = 0x80u, N_BINCL = 0x82u, N_SOL = 0x84u, diff --git a/llvm/include/llvm/DWARFLinker/DWARFLinker.h b/llvm/include/llvm/DWARFLinker/DWARFLinker.h index e5797514165a2..a5721184a6a2f 100644 --- a/llvm/include/llvm/DWARFLinker/DWARFLinker.h +++ b/llvm/include/llvm/DWARFLinker/DWARFLinker.h @@ -62,6 +62,9 @@ class AddressesMap { virtual std::optional getSubprogramRelocAdjustment(const DWARFDie &DIE) = 0; + /// Returns the file name associated to the AddessesMap + virtual std::optional getLibraryInstallName() = 0; + /// Apply the valid relocations to the buffer \p Data, taking into /// account that Data is at \p BaseOffset in the .debug_info section. /// @@ -69,6 +72,23 @@ class AddressesMap { virtual bool applyValidRelocs(MutableArrayRef Data, uint64_t BaseOffset, bool IsLittleEndian) = 0; + /// Check if the linker needs to gather and save relocation info. + virtual bool needToSaveValidRelocs() = 0; + + /// Update and save original relocations located in between StartOffset and + /// EndOffset. LinkedOffset is the value which should be added to the original + /// relocation offset to get new relocation offset in linked binary. + virtual void updateAndSaveValidRelocs(bool IsDWARF5, + uint64_t OriginalUnitOffset, + int64_t LinkedOffset, + uint64_t StartOffset, + uint64_t EndOffset) = 0; + + /// Update the valid relocations that used OriginalUnitOffset as the compile + /// unit offset, and update their values to reflect OutputUnitOffset. + virtual void updateRelocationsWithUnitOffset(uint64_t OriginalUnitOffset, + uint64_t OutputUnitOffset) = 0; + /// Erases all data. virtual void clear() = 0; }; @@ -752,6 +772,9 @@ class DWARFLinker { /// Is there a DW_AT_str_offsets_base in the CU? bool AttrStrOffsetBaseSeen = false; + /// Is there a DW_AT_APPLE_origin in the CU? + bool HasAppleOrigin = false; + AttributesInfo() = default; }; diff --git a/llvm/include/llvm/DWARFLinkerParallel/AddressesMap.h b/llvm/include/llvm/DWARFLinkerParallel/AddressesMap.h index 22fbec20d7d37..b451fee4e0b72 100644 --- a/llvm/include/llvm/DWARFLinkerParallel/AddressesMap.h +++ b/llvm/include/llvm/DWARFLinkerParallel/AddressesMap.h @@ -55,6 +55,9 @@ class AddressesMap { virtual std::optional getSubprogramRelocAdjustment(const DWARFDie &DIE) = 0; + // Returns the library install name associated to the AddessesMap. + virtual std::optional getLibraryInstallName() = 0; + /// Apply the valid relocations to the buffer \p Data, taking into /// account that Data is at \p BaseOffset in the .debug_info section. /// @@ -62,6 +65,21 @@ class AddressesMap { virtual bool applyValidRelocs(MutableArrayRef Data, uint64_t BaseOffset, bool IsLittleEndian) = 0; + /// Check if the linker needs to gather and save relocation info. + virtual bool needToSaveValidRelocs() = 0; + + /// Update and save relocation values to be serialized + virtual void updateAndSaveValidRelocs(bool IsDWARF5, + uint64_t OriginalUnitOffset, + int64_t LinkedOffset, + uint64_t StartOffset, + uint64_t EndOffset) = 0; + + /// Update the valid relocations that used OriginalUnitOffset as the compile + /// unit offset, and update their values to reflect OutputUnitOffset. + virtual void updateRelocationsWithUnitOffset(uint64_t OriginalUnitOffset, + uint64_t OutputUnitOffset) = 0; + /// Erases all data. virtual void clear() = 0; diff --git a/llvm/include/llvm/TargetParser/Triple.h b/llvm/include/llvm/TargetParser/Triple.h index 53cef0abbe0e1..0f56ac68c851f 100644 --- a/llvm/include/llvm/TargetParser/Triple.h +++ b/llvm/include/llvm/TargetParser/Triple.h @@ -418,9 +418,6 @@ class Triple { /// Get the architecture (first) component of the triple. StringRef getArchName() const; - /// Get the architecture name based on Kind and SubArch. - StringRef getArchName(ArchType Kind, SubArchType SubArch = NoSubArch) const; - /// Get the vendor (second) component of the triple. StringRef getVendorName() const; @@ -1118,6 +1115,9 @@ class Triple { /// Get the canonical name for the \p Kind architecture. static StringRef getArchTypeName(ArchType Kind); + /// Get the architecture name based on \p Kind and \p SubArch. + static StringRef getArchName(ArchType Kind, SubArchType SubArch = NoSubArch); + /// Get the "prefix" canonical name for the \p Kind architecture. This is the /// prefix used by the architecture specific builtins, and is suitable for /// passing to \see Intrinsic::getIntrinsicForClangBuiltin(). diff --git a/llvm/lib/DWARFLinker/DWARFLinker.cpp b/llvm/lib/DWARFLinker/DWARFLinker.cpp index 2d8360f100c11..80a4e2adefa6c 100644 --- a/llvm/lib/DWARFLinker/DWARFLinker.cpp +++ b/llvm/lib/DWARFLinker/DWARFLinker.cpp @@ -1026,6 +1026,15 @@ unsigned DWARFLinker::DIECloner::cloneStringAttribute(DIE &Die, StringEntry = DebugLineStrPool.getEntry(*String); } else { StringEntry = DebugStrPool.getEntry(*String); + + if (AttrSpec.Attr == dwarf::DW_AT_APPLE_origin) { + Info.HasAppleOrigin = true; + if (std::optional FileName = + ObjFile.Addresses->getLibraryInstallName()) { + StringEntry = DebugStrPool.getEntry(*FileName); + } + } + // Update attributes info. if (AttrSpec.Attr == dwarf::DW_AT_name) Info.Name = StringEntry; @@ -1637,6 +1646,12 @@ shouldSkipAttribute(bool Update, } } +struct AttributeLinkedOffsetFixup { + int64_t LinkedOffsetFixupVal; + uint64_t InputAttrStartOffset; + uint64_t InputAttrEndOffset; +}; + DIE *DWARFLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE, const DWARFFile &File, CompileUnit &Unit, int64_t PCOffset, uint32_t OutOffset, @@ -1720,6 +1735,9 @@ DIE *DWARFLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE, Flags |= TF_SkipPC; } + std::optional LibraryInstallName = + ObjFile.Addresses->getLibraryInstallName(); + SmallVector AttributesFixups; for (const auto &AttrSpec : Abbrev->attributes()) { if (shouldSkipAttribute(Update, AttrSpec, Flags & TF_SkipPC)) { DWARFFormValue::skipValue(AttrSpec.Form, Data, &Offset, @@ -1727,17 +1745,41 @@ DIE *DWARFLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE, continue; } + AttributeLinkedOffsetFixup CurAttrFixup; + CurAttrFixup.InputAttrStartOffset = InputDIE.getOffset() + Offset; + CurAttrFixup.LinkedOffsetFixupVal = + Unit.getStartOffset() + OutOffset - CurAttrFixup.InputAttrStartOffset; + DWARFFormValue Val = AttrSpec.getFormValue(); uint64_t AttrSize = Offset; Val.extractValue(Data, &Offset, U.getFormParams(), &U); + CurAttrFixup.InputAttrEndOffset = InputDIE.getOffset() + Offset; AttrSize = Offset - AttrSize; - OutOffset += cloneAttribute(*Die, InputDIE, File, Unit, Val, AttrSpec, - AttrSize, AttrInfo, IsLittleEndian); + uint64_t FinalAttrSize = + cloneAttribute(*Die, InputDIE, File, Unit, Val, AttrSpec, AttrSize, + AttrInfo, IsLittleEndian); + if (FinalAttrSize != 0 && ObjFile.Addresses->needToSaveValidRelocs()) + AttributesFixups.push_back(CurAttrFixup); + + OutOffset += FinalAttrSize; } - // Look for accelerator entries. uint16_t Tag = InputDIE.getTag(); + // Add the DW_AT_APPLE_origin attribute to Compile Unit die if we have + // an install name and the DWARF doesn't have the attribute yet. + const bool NeedsAppleOrigin = (Tag == dwarf::DW_TAG_compile_unit) && + LibraryInstallName.has_value() && + !AttrInfo.HasAppleOrigin; + if (NeedsAppleOrigin) { + auto StringEntry = DebugStrPool.getEntry(LibraryInstallName.value()); + Die->addValue(DIEAlloc, dwarf::Attribute(dwarf::DW_AT_APPLE_origin), + dwarf::DW_FORM_strp, DIEInteger(StringEntry.getOffset())); + AttrInfo.Name = StringEntry; + OutOffset += 4; + } + + // Look for accelerator entries. // FIXME: This is slightly wrong. An inline_subroutine without a // low_pc, but with AT_ranges might be interesting to get into the // accelerator tables too. For now stick with dsymutil's behavior. @@ -1806,8 +1848,19 @@ DIE *DWARFLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE, Linker.assignAbbrev(NewAbbrev); Die->setAbbrevNumber(NewAbbrev.getNumber()); + uint64_t AbbrevNumberSize = getULEB128Size(Die->getAbbrevNumber()); + // Add the size of the abbreviation number to the output offset. - OutOffset += getULEB128Size(Die->getAbbrevNumber()); + OutOffset += AbbrevNumberSize; + + // Update fixups with the size of the abbreviation number + for (AttributeLinkedOffsetFixup &F : AttributesFixups) + F.LinkedOffsetFixupVal += AbbrevNumberSize; + + for (AttributeLinkedOffsetFixup &F : AttributesFixups) + ObjFile.Addresses->updateAndSaveValidRelocs( + Unit.getOrigUnit().getVersion() >= 5, Unit.getOrigUnit().getOffset(), + F.LinkedOffsetFixupVal, F.InputAttrStartOffset, F.InputAttrEndOffset); if (!HasChildren) { // Update our size. diff --git a/llvm/lib/TargetParser/Triple.cpp b/llvm/lib/TargetParser/Triple.cpp index b9fab469f7476..5d4eb79675f89 100644 --- a/llvm/lib/TargetParser/Triple.cpp +++ b/llvm/lib/TargetParser/Triple.cpp @@ -90,6 +90,36 @@ StringRef Triple::getArchTypeName(ArchType Kind) { llvm_unreachable("Invalid ArchType!"); } +StringRef Triple::getArchName(ArchType Kind, SubArchType SubArch) { + switch (Kind) { + case Triple::mips: + if (SubArch == MipsSubArch_r6) + return "mipsisa32r6"; + break; + case Triple::mipsel: + if (SubArch == MipsSubArch_r6) + return "mipsisa32r6el"; + break; + case Triple::mips64: + if (SubArch == MipsSubArch_r6) + return "mipsisa64r6"; + break; + case Triple::mips64el: + if (SubArch == MipsSubArch_r6) + return "mipsisa64r6el"; + break; + case Triple::aarch64: + if (SubArch == AArch64SubArch_arm64ec) + return "arm64ec"; + if (SubArch == AArch64SubArch_arm64e) + return "arm64e"; + break; + default: + break; + } + return getArchTypeName(Kind); +} + StringRef Triple::getArchTypePrefix(ArchType Kind) { switch (Kind) { default: @@ -1143,34 +1173,6 @@ StringRef Triple::getArchName() const { return StringRef(Data).split('-').first; // Isolate first component } -StringRef Triple::getArchName(ArchType Kind, SubArchType SubArch) const { - switch (Kind) { - case Triple::mips: - if (SubArch == MipsSubArch_r6) - return "mipsisa32r6"; - break; - case Triple::mipsel: - if (SubArch == MipsSubArch_r6) - return "mipsisa32r6el"; - break; - case Triple::mips64: - if (SubArch == MipsSubArch_r6) - return "mipsisa64r6"; - break; - case Triple::mips64el: - if (SubArch == MipsSubArch_r6) - return "mipsisa64r6el"; - break; - case Triple::aarch64: - if (SubArch == AArch64SubArch_arm64ec) - return "arm64ec"; - break; - default: - break; - } - return getArchTypeName(Kind); -} - StringRef Triple::getVendorName() const { StringRef Tmp = StringRef(Data).split('-').second; // Strip first component return Tmp.split('-').first; // Isolate second component diff --git a/llvm/test/tools/dsymutil/Inputs/bar-relink-variant.dylib.dSYM/Contents/Info.plist b/llvm/test/tools/dsymutil/Inputs/bar-relink-variant.dylib.dSYM/Contents/Info.plist new file mode 100644 index 0000000000000..14d6272d3f8d9 --- /dev/null +++ b/llvm/test/tools/dsymutil/Inputs/bar-relink-variant.dylib.dSYM/Contents/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleIdentifier + com.apple.xcode.dsym.bar-relink-variant.dylib + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + dSYM + CFBundleSignature + ???? + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/llvm/test/tools/dsymutil/Inputs/bar-relink-variant.dylib.dSYM/Contents/Resources/Relocations/aarch64/bar-relink-variant.dylib.yml b/llvm/test/tools/dsymutil/Inputs/bar-relink-variant.dylib.dSYM/Contents/Resources/Relocations/aarch64/bar-relink-variant.dylib.yml new file mode 100644 index 0000000000000..68fd250cdf2a8 --- /dev/null +++ b/llvm/test/tools/dsymutil/Inputs/bar-relink-variant.dylib.dSYM/Contents/Resources/Relocations/aarch64/bar-relink-variant.dylib.yml @@ -0,0 +1,8 @@ +--- +triple: 'arm64-apple-darwin' +binary-path: bar-relink-variant.dylib +relocations: + - { offset: 0x26, size: 0x8, addend: 0x0, symName: _bar, symObjAddr: 0x0, symBinAddr: 0x3FA0, symSize: 0x8 } + - { offset: 0x3F, size: 0x8, addend: 0x0, symName: _baz, symObjAddr: 0x8, symBinAddr: 0x4000, symSize: 0x0 } + - { offset: 0x4F, size: 0x8, addend: 0x0, symName: _bar, symObjAddr: 0x0, symBinAddr: 0x3FA0, symSize: 0x8 } +... diff --git a/llvm/test/tools/dsymutil/Inputs/bar-relink.dylib.dSYM/Contents/Info.plist b/llvm/test/tools/dsymutil/Inputs/bar-relink.dylib.dSYM/Contents/Info.plist new file mode 100644 index 0000000000000..37c2a8aebe4c6 --- /dev/null +++ b/llvm/test/tools/dsymutil/Inputs/bar-relink.dylib.dSYM/Contents/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleIdentifier + com.apple.xcode.dsym.bar-relink.dylib + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + dSYM + CFBundleSignature + ???? + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/llvm/test/tools/dsymutil/Inputs/bar-relink.dylib.dSYM/Contents/Resources/Relocations/aarch64/bar-relink.dylib.yml b/llvm/test/tools/dsymutil/Inputs/bar-relink.dylib.dSYM/Contents/Resources/Relocations/aarch64/bar-relink.dylib.yml new file mode 100644 index 0000000000000..d47e5f9e2e8d2 --- /dev/null +++ b/llvm/test/tools/dsymutil/Inputs/bar-relink.dylib.dSYM/Contents/Resources/Relocations/aarch64/bar-relink.dylib.yml @@ -0,0 +1,8 @@ +--- +triple: 'arm64-apple-darwin' +binary-path: bar-relink.dylib +relocations: + - { offset: 0x26, size: 0x8, addend: 0x0, symName: _bar, symObjAddr: 0x0, symBinAddr: 0x3FA0, symSize: 0x8 } + - { offset: 0x3F, size: 0x8, addend: 0x0, symName: _baz, symObjAddr: 0x8, symBinAddr: 0x4000, symSize: 0x0 } + - { offset: 0x4F, size: 0x8, addend: 0x0, symName: _bar, symObjAddr: 0x0, symBinAddr: 0x3FA0, symSize: 0x8 } +... diff --git a/llvm/test/tools/dsymutil/Inputs/foo-relink-variant.dylib.dSYM/Contents/Info.plist b/llvm/test/tools/dsymutil/Inputs/foo-relink-variant.dylib.dSYM/Contents/Info.plist new file mode 100644 index 0000000000000..7e84e95bd3f48 --- /dev/null +++ b/llvm/test/tools/dsymutil/Inputs/foo-relink-variant.dylib.dSYM/Contents/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleIdentifier + com.apple.xcode.dsym.foo-relink-variant.dylib + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + dSYM + CFBundleSignature + ???? + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/llvm/test/tools/dsymutil/Inputs/foo-relink-variant.dylib.dSYM/Contents/Resources/Relocations/aarch64/foo-relink-variant.dylib.yml b/llvm/test/tools/dsymutil/Inputs/foo-relink-variant.dylib.dSYM/Contents/Resources/Relocations/aarch64/foo-relink-variant.dylib.yml new file mode 100644 index 0000000000000..0bc06e9a9e857 --- /dev/null +++ b/llvm/test/tools/dsymutil/Inputs/foo-relink-variant.dylib.dSYM/Contents/Resources/Relocations/aarch64/foo-relink-variant.dylib.yml @@ -0,0 +1,9 @@ +--- +triple: 'arm64-apple-darwin' +binary-path: foo-relink-variant.dylib +relocations: + - { offset: 0x26, size: 0x8, addend: 0x0, symName: _foo, symObjAddr: 0x0, symBinAddr: 0x3F64, symSize: 0x20 } + - { offset: 0x33, size: 0x8, addend: 0x0, symName: _foo, symObjAddr: 0x0, symBinAddr: 0x3F64, symSize: 0x20 } + - { offset: 0x88, size: 0x8, addend: 0x0, symName: _altfoo, symObjAddr: 0x0, symBinAddr: 0x3F84, symSize: 0x24 } + - { offset: 0x95, size: 0x8, addend: 0x0, symName: _altfoo, symObjAddr: 0x0, symBinAddr: 0x3F84, symSize: 0x24 } +... diff --git a/llvm/test/tools/dsymutil/Inputs/foo-relink.dylib.dSYM/Contents/Info.plist b/llvm/test/tools/dsymutil/Inputs/foo-relink.dylib.dSYM/Contents/Info.plist new file mode 100644 index 0000000000000..e919260131558 --- /dev/null +++ b/llvm/test/tools/dsymutil/Inputs/foo-relink.dylib.dSYM/Contents/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleIdentifier + com.apple.xcode.dsym.foo-relink.dylib + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + dSYM + CFBundleSignature + ???? + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/llvm/test/tools/dsymutil/Inputs/foo-relink.dylib.dSYM/Contents/Resources/Relocations/aarch64/foo-relink.dylib.yml b/llvm/test/tools/dsymutil/Inputs/foo-relink.dylib.dSYM/Contents/Resources/Relocations/aarch64/foo-relink.dylib.yml new file mode 100644 index 0000000000000..0db1b30e9d126 --- /dev/null +++ b/llvm/test/tools/dsymutil/Inputs/foo-relink.dylib.dSYM/Contents/Resources/Relocations/aarch64/foo-relink.dylib.yml @@ -0,0 +1,10 @@ +--- +triple: 'arm64-apple-darwin' +binary-path: foo-relink.dylib +relocations: + - { offset: 0x26, size: 0x8, addend: 0x0, symName: _foo, symObjAddr: 0x0, symBinAddr: 0x3F54, symSize: 0x20 } + - { offset: 0x33, size: 0x8, addend: 0x0, symName: _foo, symObjAddr: 0x0, symBinAddr: 0x3F54, symSize: 0x20 } + - { offset: 0x5B, size: 0x8, addend: 0x0, symName: _foo_unused, symObjAddr: 0x20, symBinAddr: 0x3F74, symSize: 0x8 } + - { offset: 0xA1, size: 0x8, addend: 0x0, symName: _altfoo, symObjAddr: 0x0, symBinAddr: 0x3F7C, symSize: 0x24 } + - { offset: 0xAE, size: 0x8, addend: 0x0, symName: _altfoo, symObjAddr: 0x0, symBinAddr: 0x3F7C, symSize: 0x24 } +... diff --git a/llvm/test/tools/dsymutil/Inputs/proxy-relink.dylib.dSYM/Contents/Info.plist b/llvm/test/tools/dsymutil/Inputs/proxy-relink.dylib.dSYM/Contents/Info.plist new file mode 100644 index 0000000000000..425df2f6c841d --- /dev/null +++ b/llvm/test/tools/dsymutil/Inputs/proxy-relink.dylib.dSYM/Contents/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleIdentifier + com.apple.xcode.dsym.proxy-relink.dylib + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + dSYM + CFBundleSignature + ???? + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/llvm/test/tools/dsymutil/Inputs/proxy-relink.dylib.dSYM/Contents/Resources/Relocations/aarch64/proxy-relink.dylib.yml b/llvm/test/tools/dsymutil/Inputs/proxy-relink.dylib.dSYM/Contents/Resources/Relocations/aarch64/proxy-relink.dylib.yml new file mode 100644 index 0000000000000..44dd0a2342da8 --- /dev/null +++ b/llvm/test/tools/dsymutil/Inputs/proxy-relink.dylib.dSYM/Contents/Resources/Relocations/aarch64/proxy-relink.dylib.yml @@ -0,0 +1,14 @@ +--- +triple: 'arm64-apple-darwin' +binary-path: proxy-relink.dylib +relocations: + - { offset: 0x26, size: 0x8, addend: 0x0, symName: _display, symObjAddr: 0x0, symBinAddr: 0x3F1C, symSize: 0x1C } + - { offset: 0x41, size: 0x8, addend: 0x0, symName: _display, symObjAddr: 0x0, symBinAddr: 0x3F1C, symSize: 0x1C } + - { offset: 0x7C, size: 0x8, addend: 0x0, symName: _bar, symObjAddr: 0x3FA0, symBinAddr: 0x3F38, symSize: 0x8 } + - { offset: 0x99, size: 0x8, addend: 0x0, symName: _baz, symObjAddr: 0x4000, symBinAddr: 0x8000, symSize: 0x0 } + - { offset: 0xA9, size: 0x8, addend: 0x0, symName: _bar, symObjAddr: 0x3FA0, symBinAddr: 0x3F38, symSize: 0x8 } + - { offset: 0xE8, size: 0x8, addend: 0x0, symName: _foo, symObjAddr: 0x3F60, symBinAddr: 0x3F40, symSize: 0x24 } + - { offset: 0xF9, size: 0x8, addend: 0x0, symName: _foo, symObjAddr: 0x3F60, symBinAddr: 0x3F40, symSize: 0x24 } + - { offset: 0x14E, size: 0x8, addend: 0x0, symName: _altfoo, symObjAddr: 0x3F84, symBinAddr: 0x3F64, symSize: 0x24 } + - { offset: 0x15F, size: 0x8, addend: 0x0, symName: _altfoo, symObjAddr: 0x3F84, symBinAddr: 0x3F64, symSize: 0x24 } +... diff --git a/llvm/test/tools/dsymutil/basic-linking.test b/llvm/test/tools/dsymutil/basic-linking.test index cc521430b0c87..88cd3293efa24 100644 --- a/llvm/test/tools/dsymutil/basic-linking.test +++ b/llvm/test/tools/dsymutil/basic-linking.test @@ -2,6 +2,9 @@ RUN: dsymutil -no-output -verbose -oso-prepend-path=%p %p/Inputs/basic.macho.x86 RUN: dsymutil -no-output -verbose -oso-prepend-path=%p %p/Inputs/basic-lto.macho.x86_64 | FileCheck %s --check-prefix=CHECK-LTO RUN: dsymutil -no-output -verbose -oso-prepend-path=%p %p/Inputs/basic-archive.macho.x86_64 | FileCheck %s --check-prefix=CHECK-ARCHIVE RUN: dsymutil -no-output -verbose -oso-prepend-path=%p %p/Inputs/basic.macho.x86_64 %p/Inputs/basic-lto.macho.x86_64 %p/Inputs/basic-archive.macho.x86_64 | FileCheck %s --check-prefixes=CHECK,CHECK-LTO,CHECK-ARCHIVE +RUN: dsymutil -no-output -verbose -oso-prepend-path=%p -D %p/Inputs %p/Inputs/basic-relink.macho.arm64.dylib | FileCheck %s --check-prefix=CHECK-RELINK +RUN: dsymutil -no-output -verbose -oso-prepend-path=%p -D %p/Inputs %p/Inputs/two-level-relink.macho.arm64.dylib | FileCheck %s --check-prefix=CHECK-RELINK-TWO +RUN: dsymutil -no-output -verbose -oso-prepend-path=%p -build-variant-suffix=_debug -D WrongPath -D %p/Inputs %p/Inputs/variant-relink.macho.arm64.dylib | FileCheck %s --check-prefix=CHECK-RELINK-VARIANT This test check the basic Dwarf linking process through the debug dumps. @@ -175,3 +178,122 @@ CHECK-ARCHIVE: Found valid debug map entry: _inc 0x0000000000000070 => 0x0000000 CHECK-ARCHIVE-NEXT: Keeping subprogram DIE: CHECK-ARCHIVE-NEXT: DW_TAG_subprogram CHECK-ARCHIVE-NEXT: DW_AT_name {{.*}}"inc") + + +================================= Simple relink ================================ +CHECK-RELINK: DEBUG MAP OBJECT: {{.*}}basic-relink.macho.arm64.o +CHECK-RELINK: Input compilation unit: +CHECK-RELINK-NEXT: TAG_compile_unit +CHECK-RELINK-NOT: TAG +CHECK-RELINK: AT_name {{.*}}basic-relink.macho.arm64.c + +CHECK-RELINK: DEBUG MAP OBJECT: {{.*}}foo-relink.dylib +CHECK-RELINK: Input compilation unit: +CHECK-RELINK-NEXT: TAG_compile_unit +CHECK-RELINK-NOT: TAG +CHECK-RELINK: AT_name {{.*}}foo-relink.c + +CHECK-RELINK: Input compilation unit: +CHECK-RELINK-NEXT: TAG_compile_unit +CHECK-RELINK-NOT: TAG +CHECK-RELINK: AT_name {{.*}}altfoo-relink.c + +CHECK-RELINK: DEBUG MAP OBJECT: {{.*}}bar-relink.dylib +CHECK-RELINK: Input compilation unit: +CHECK-RELINK-NEXT: TAG_compile_unit +CHECK-RELINK-NOT: TAG +CHECK-RELINK: AT_name {{.*}}bar-relink.c + +CHECK-RELINK-NOT: Found valid debug map entry +CHECK-RELINK: Found valid debug map entry: _display 0x0000000000000000 => 0x0000000000003f10 +CHECK-RELINK-NEXT: Keeping subprogram DIE: +CHECK-RELINK-NEXT: DW_TAG_subprogram +CHECK-RELINK: DW_AT_name{{.*}}"display" + +CHECK-RELINK: Found valid debug map entry: _foo 0x0000000000003f54 => 0x0000000000003f2c +CHECK-RELINK-NEXT: Keeping subprogram DIE: +CHECK-RELINK-NEXT: DW_TAG_subprogram +CHECK-RELINK: DW_AT_name {{.*}}"foo" + +CHECK-RELINK-NOT: Found valid debug map entry +CHECK-RELINK: Found valid debug map entry: _foo_unused 0x0000000000003f74 => 0x0000000000003f4c +CHECK-RELINK-NEXT: Keeping subprogram DIE: +CHECK-RELINK-NEXT: DW_TAG_subprogram +CHECK-RELINK: DW_AT_name {{.*}}"foo_unused" + +CHECK-RELINK-NOT: Found valid debug map entry +CHECK-RELINK: Found valid debug map entry: _altfoo 0x0000000000003f7c => 0x0000000000003f54 +CHECK-RELINK-NEXT: Keeping subprogram DIE: +CHECK-RELINK-NEXT: DW_TAG_subprogram +CHECK-RELINK: DW_AT_name {{.*}}"altfoo" + +CHECK-RELINK-NOT: Found valid debug map entry +CHECK-RELINK: Found valid debug map entry: _baz 0x0000000000004000 => 0x0000000000008000 +CHECK-RELINK-NEXT: Keeping variable DIE: +CHECK-RELINK-NEXT: DW_TAG_variable +CHECK-RELINK-NEXT: DW_AT_name {{.*}}"baz" + +CHECK-RELINK-NOT: Found valid debug map entry +CHECK-RELINK: Found valid debug map entry: _bar 0x0000000000003fa0 => 0x0000000000003f78 +CHECK-RELINK-NEXT: Keeping subprogram DIE: +CHECK-RELINK-NEXT: DW_TAG_subprogram +CHECK-RELINK: DW_AT_name {{.*}}"bar" + +================================= Two level relink ================================ +CHECK-RELINK-TWO: DEBUG MAP OBJECT: {{.*}}proxy-relink.dylib +CHECK-RELINK-TWO: Input compilation unit: +CHECK-RELINK-TWO-NEXT: TAG_compile_unit +CHECK-RELINK-TWO-NOT: TAG +CHECK-RELINK-TWO: AT_name {{.*}}two-level-relink.macho.arm64.c + +CHECK-RELINK-TWO: Input compilation unit: +CHECK-RELINK-TWO-NEXT: TAG_compile_unit +CHECK-RELINK-TWO-NOT: TAG +CHECK-RELINK-TWO: AT_name {{.*}}bar-relink.c +CHECK-RELINK-TWO: DW_AT_APPLE_origin {{.*}}/path/to/bar-relink.dylib + +CHECK-RELINK-TWO: Input compilation unit: +CHECK-RELINK-TWO-NEXT: TAG_compile_unit +CHECK-RELINK-TWO-NOT: TAG +CHECK-RELINK-TWO: AT_name {{.*}}foo-relink.c +CHECK-RELINK-TWO: DW_AT_APPLE_origin {{.*}}/path/to/foo-relink.dylib + +CHECK-RELINK-TWO: Input compilation unit: +CHECK-RELINK-TWO-NEXT: TAG_compile_unit +CHECK-RELINK-TWO-NOT: TAG +CHECK-RELINK-TWO: AT_name {{.*}}altfoo-relink.c +CHECK-RELINK-TWO: DW_AT_APPLE_origin {{.*}}/path/to/foo-relink.dylib + +CHECK-RELINK-TWO-NOT: Found valid debug map entry +CHECK-RELINK-TWO: Found valid debug map entry: _display 0x0000000000003f1c => 0x0000000000003f1c +CHECK-RELINK-TWO-NEXT: Keeping subprogram DIE: +CHECK-RELINK-TWO-NEXT: DW_TAG_subprogram +CHECK-RELINK-TWO: DW_AT_name{{.*}}"display" + +CHECK-RELINK-TWO-NOT: Found valid debug map entry +CHECK-RELINK-TWO: Found valid debug map entry: _baz 0x0000000000008000 => 0x0000000000008000 +CHECK-RELINK-TWO-NEXT: Keeping variable DIE: +CHECK-RELINK-TWO-NEXT: DW_TAG_variable +CHECK-RELINK-TWO-NEXT: DW_AT_name {{.*}}"baz" + +CHECK-RELINK-TWO-NOT: Found valid debug map entry +CHECK-RELINK-TWO: Found valid debug map entry: _bar 0x0000000000003f38 => 0x0000000000003f38 +CHECK-RELINK-TWO-NEXT: Keeping subprogram DIE: +CHECK-RELINK-TWO-NEXT: DW_TAG_subprogram +CHECK-RELINK-TWO: DW_AT_name {{.*}}"bar" + +CHECK-RELINK-TWO: Found valid debug map entry: _foo 0x0000000000003f40 => 0x0000000000003f40 +CHECK-RELINK-TWO-NEXT: Keeping subprogram DIE: +CHECK-RELINK-TWO-NEXT: DW_TAG_subprogram +CHECK-RELINK-TWO: DW_AT_name {{.*}}"foo" + +CHECK-RELINK-TWO-NOT: Found valid debug map entry +CHECK-RELINK-TWO: Found valid debug map entry: _altfoo 0x0000000000003f64 => 0x0000000000003f64 +CHECK-RELINK-TWO-NEXT: Keeping subprogram DIE: +CHECK-RELINK-TWO-NEXT: DW_TAG_subprogram +CHECK-RELINK-TWO: DW_AT_name {{.*}}"altfoo" + +================================= Build variants relink ================================ +CHECK-RELINK-VARIANT: DEBUG MAP OBJECT: {{.*}}basic-relink.macho.arm64.o +CHECK-RELINK-VARIANT: DEBUG MAP OBJECT: {{.*}}foo-relink-variant_debug.dylib +CHECK-RELINK-VARIANT: DEBUG MAP OBJECT: {{.*}}bar-relink-variant.dylib diff --git a/llvm/test/tools/dsymutil/cmdline.test b/llvm/test/tools/dsymutil/cmdline.test index 2317852f3c489..36cf3f542695c 100644 --- a/llvm/test/tools/dsymutil/cmdline.test +++ b/llvm/test/tools/dsymutil/cmdline.test @@ -7,7 +7,9 @@ HELP-NOT: -reverse-iterate HELP: Dsymutil Options: CHECK: -accelerator CHECK: -arch +CHECK: -build-variant-suffix CHECK: -dump-debug-map +CHECK: -D CHECK: -fat64 CHECK: -flat CHECK: -gen-reproducer diff --git a/llvm/tools/dsymutil/CMakeLists.txt b/llvm/tools/dsymutil/CMakeLists.txt index 3cb7594d2fd92..c612bfd9150c4 100644 --- a/llvm/tools/dsymutil/CMakeLists.txt +++ b/llvm/tools/dsymutil/CMakeLists.txt @@ -30,6 +30,7 @@ add_llvm_tool(dsymutil MachODebugMapParser.cpp MachOUtils.cpp Reproducer.cpp + RelocationMap.cpp SymbolMap.cpp DEPENDS diff --git a/llvm/tools/dsymutil/DebugMap.cpp b/llvm/tools/dsymutil/DebugMap.cpp index d4e2c2b2cfac7..1950258ce7227 100644 --- a/llvm/tools/dsymutil/DebugMap.cpp +++ b/llvm/tools/dsymutil/DebugMap.cpp @@ -45,6 +45,11 @@ DebugMapObject::DebugMapObject(StringRef ObjectFilename, bool DebugMapObject::addSymbol(StringRef Name, std::optional ObjectAddress, uint64_t LinkedAddress, uint32_t Size) { + if (Symbols.count(Name)) { + // Symbol was previously added. + return true; + } + auto InsertResult = Symbols.insert( std::make_pair(Name, SymbolMapping(ObjectAddress, LinkedAddress, Size))); @@ -53,6 +58,12 @@ bool DebugMapObject::addSymbol(StringRef Name, return InsertResult.second; } +void DebugMapObject::setRelocationMap(dsymutil::RelocationMap &RM) { + RelocationMap.emplace(RM); +} + +void DebugMapObject::setInstallName(StringRef IN) { InstallName.emplace(IN); } + void DebugMapObject::print(raw_ostream &OS) const { OS << getObjectFilename() << ":\n"; // Sort the symbols in alphabetical order, like llvm-nm (and to get @@ -158,8 +169,8 @@ struct MappingTraits::YamlDMO { std::vector Entries; }; -void MappingTraits>:: - mapping(IO &io, std::pair &s) { +void MappingTraits>::mapping( + IO &io, std::pair &s) { io.mapRequired("sym", s.first); io.mapOptional("objAddr", s.second.ObjectAddress); io.mapRequired("binAddr", s.second.BinaryAddress); @@ -275,7 +286,13 @@ MappingTraits::YamlDMO::denormalize(IO &IO) { } } - dsymutil::DebugMapObject Res(Path, sys::toTimePoint(Timestamp), MachO::N_OSO); + uint8_t Type = MachO::N_OSO; + if (Path.endswith(".dylib")) { + // FIXME: find a more resilient way + Type = MachO::N_LIB; + } + dsymutil::DebugMapObject Res(Path, sys::toTimePoint(Timestamp), Type); + for (auto &Entry : Entries) { auto &Mapping = Entry.second; std::optional ObjAddress; diff --git a/llvm/tools/dsymutil/DebugMap.h b/llvm/tools/dsymutil/DebugMap.h index 86cb88d32492d..0b2f760dc17a3 100644 --- a/llvm/tools/dsymutil/DebugMap.h +++ b/llvm/tools/dsymutil/DebugMap.h @@ -21,6 +21,7 @@ #ifndef LLVM_TOOLS_DSYMUTIL_DEBUGMAP_H #define LLVM_TOOLS_DSYMUTIL_DEBUGMAP_H +#include "RelocationMap.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" @@ -134,22 +135,6 @@ class DebugMap { /// linked binary for all the linked atoms in this object file. class DebugMapObject { public: - struct SymbolMapping { - std::optional ObjectAddress; - yaml::Hex64 BinaryAddress; - yaml::Hex32 Size; - - SymbolMapping(std::optional ObjectAddr, uint64_t BinaryAddress, - uint32_t Size) - : BinaryAddress(BinaryAddress), Size(Size) { - if (ObjectAddr) - ObjectAddress = *ObjectAddr; - } - - /// For YAML IO support - SymbolMapping() = default; - }; - using YAMLSymbolMapping = std::pair; using DebugMapEntry = StringMapEntry; @@ -182,6 +167,16 @@ class DebugMapObject { } const std::vector &getWarnings() const { return Warnings; } + const std::optional &getRelocationMap() const { + return RelocationMap; + } + void setRelocationMap(dsymutil::RelocationMap &RM); + + const std::optional &getInstallName() const { + return InstallName; + } + void setInstallName(StringRef IN); + void print(raw_ostream &OS) const; #ifndef NDEBUG void dump() const; @@ -200,6 +195,9 @@ class DebugMapObject { DenseMap AddressToMapping; uint8_t Type; + std::optional RelocationMap; + std::optional InstallName; + std::vector Warnings; /// For YAMLIO support. @@ -225,10 +223,8 @@ namespace yaml { using namespace llvm::dsymutil; -template <> -struct MappingTraits> { - static void mapping(IO &io, - std::pair &s); +template <> struct MappingTraits> { + static void mapping(IO &io, std::pair &s); static const bool flow = true; }; @@ -237,12 +233,6 @@ template <> struct MappingTraits { static void mapping(IO &io, dsymutil::DebugMapObject &DMO); }; -template <> struct ScalarTraits { - static void output(const Triple &val, void *, raw_ostream &out); - static StringRef input(StringRef scalar, void *, Triple &value); - static QuotingType mustQuote(StringRef) { return QuotingType::Single; } -}; - template <> struct SequenceTraits>> { static size_t diff --git a/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp b/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp index 39776ae5a9200..a8fea1e271227 100644 --- a/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp +++ b/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp @@ -189,6 +189,44 @@ static Error remarksErrorHandler(const DebugMapObject &DMO, return createFileError(FE->getFileName(), std::move(NewE)); } +template +Error DwarfLinkerForBinary::emitRelocations( + const DebugMap &DM, + std::vector> &ObjectsForLinking) { + // Return early if the "Resources" directory is not being written to. + if (!Options.ResourceDir) + return Error::success(); + + RelocationMap RM(DM.getTriple(), DM.getBinaryPath()); + for (auto &Obj : ObjectsForLinking) { + if (!Obj.OutRelocs->isInitialized()) + continue; + Obj.OutRelocs->addValidRelocs(RM); + } + + SmallString<128> InputPath; + SmallString<128> Path; + // Create the "Relocations" directory in the "Resources" directory, and + // create an architecture-specific directory in the "Relocations" directory. + StringRef ArchName = Triple::getArchName(RM.getTriple().getArch(), + RM.getTriple().getSubArch()); + sys::path::append(Path, *Options.ResourceDir, "Relocations", ArchName); + if (std::error_code EC = sys::fs::create_directories(Path.str(), true, + sys::fs::perms::all_all)) + return errorCodeToError(EC); + + // Append the file name. + sys::path::append(Path, sys::path::filename(DM.getBinaryPath())); + Path.append(".yml"); + + std::error_code EC; + raw_fd_ostream OS(Path.str(), EC, sys::fs::OF_Text); + if (EC) + return errorCodeToError(EC); + + RM.print(OS); + return Error::success(); +} static Error emitRemarks(const LinkOptions &Options, StringRef BinaryPath, StringRef ArchName, const remarks::RemarkLinker &RL) { @@ -229,30 +267,31 @@ static Error emitRemarks(const LinkOptions &Options, StringRef BinaryPath, } template -ErrorOr> -DwarfLinkerForBinary::loadObject(const DebugMapObject &Obj, - const DebugMap &DebugMap, - remarks::RemarkLinker &RL) { +ErrorOr> DwarfLinkerForBinary::loadObject( + const DebugMapObject &Obj, const DebugMap &DebugMap, + remarks::RemarkLinker &RL, + std::shared_ptr DLBRM) { auto ErrorOrObj = loadObject(Obj, DebugMap.getTriple()); std::unique_ptr Res; if (ErrorOrObj) { + auto Context = DWARFContext::create( + *ErrorOrObj, DWARFContext::ProcessDebugRelocations::Process, nullptr, + "", + [&](Error Err) { + handleAllErrors(std::move(Err), [&](ErrorInfoBase &Info) { + reportError(Info.message()); + }); + }, + [&](Error Warning) { + handleAllErrors(std::move(Warning), [&](ErrorInfoBase &Info) { + reportWarning(Info.message()); + }); + }); + DLBRM->init(*Context); Res = std::make_unique( - Obj.getObjectFilename(), - DWARFContext::create( - *ErrorOrObj, DWARFContext::ProcessDebugRelocations::Process, - nullptr, "", - [&](Error Err) { - handleAllErrors(std::move(Err), [&](ErrorInfoBase &Info) { - reportError(Info.message()); - }); - }, - [&](Error Warning) { - handleAllErrors(std::move(Warning), [&](ErrorInfoBase &Info) { - reportWarning(Info.message()); - }); - }), - std::make_unique(*this, *ErrorOrObj, Obj), + Obj.getObjectFilename(), std::move(Context), + std::make_unique(*this, *ErrorOrObj, Obj, DLBRM), [&](StringRef FileName) { BinHolder.eraseObjectEntry(FileName); }); Error E = RL.link(*ErrorOrObj); @@ -614,7 +653,7 @@ template bool DwarfLinkerForBinary::linkImpl( const DebugMap &Map, typename Linker::OutputFileType ObjectType) { - std::vector> ObjectsForLinking; + std::vector> ObjectsForLinking; DebugMap DebugMap(Map.getTriple(), Map.getBinaryPath()); @@ -668,10 +707,12 @@ bool DwarfLinkerForBinary::linkImpl( auto &Obj = DebugMap.addDebugMapObject( Path, sys::TimePoint(), MachO::N_OSO); + auto DLBRelocMap = std::make_shared(); if (ErrorOr> ErrorOrObj = - loadObject(Obj, DebugMap, RL)) { - ObjectsForLinking.emplace_back(std::move(*ErrorOrObj)); - return *ObjectsForLinking.back(); + loadObject(Obj, DebugMap, RL, + DLBRelocMap)) { + ObjectsForLinking.emplace_back(std::move(*ErrorOrObj), DLBRelocMap); + return *ObjectsForLinking.back().Object; } else { // Try and emit more helpful warnings by applying some heuristics. StringRef ObjFile = ContainerName; @@ -782,15 +823,18 @@ bool DwarfLinkerForBinary::linkImpl( continue; } + auto DLBRelocMap = std::make_shared(); if (ErrorOr> ErrorOrObj = - loadObject(*Obj, Map, RL)) { - ObjectsForLinking.emplace_back(std::move(*ErrorOrObj)); - GeneralLinker->addObjectFile(*ObjectsForLinking.back(), Loader, + loadObject(*Obj, Map, RL, DLBRelocMap)) { + ObjectsForLinking.emplace_back(std::move(*ErrorOrObj), DLBRelocMap); + GeneralLinker->addObjectFile(*ObjectsForLinking.back().Object, Loader, OnCUDieLoaded); } else { - ObjectsForLinking.push_back(std::make_unique( - Obj->getObjectFilename(), nullptr, nullptr)); - GeneralLinker->addObjectFile(*ObjectsForLinking.back()); + ObjectsForLinking.push_back( + {std::make_unique(Obj->getObjectFilename(), nullptr, + nullptr), + DLBRelocMap}); + GeneralLinker->addObjectFile(*ObjectsForLinking.back().Object); } } @@ -815,6 +859,10 @@ bool DwarfLinkerForBinary::linkImpl( if (Options.NoOutput) return true; + if (Error E = + emitRelocations(Map, ObjectsForLinking)) + return error(toString(std::move(E))); + if (Options.ResourceDir && !ParseableSwiftInterfaces.empty()) { StringRef ArchName = Triple::getArchTypeName(Map.getTriple().getArch()); if (auto E = copySwiftInterfaces(ArchName)) @@ -903,12 +951,14 @@ void DwarfLinkerForBinary::AddressManager:: continue; } if (const auto *Mapping = DMO.lookupSymbol(*SymbolName)) - ValidRelocs.emplace_back(Offset64, RelocSize, Addend, Mapping); + ValidRelocs.emplace_back(Offset64, RelocSize, Addend, Mapping->getKey(), + Mapping->getValue()); } else if (const auto *Mapping = DMO.lookupObjectAddress(SymAddress)) { // Do not store the addend. The addend was the address of the symbol in // the object file, the address in the binary that is stored in the debug // map doesn't need to be offset. - ValidRelocs.emplace_back(Offset64, RelocSize, SymOffset, Mapping); + ValidRelocs.emplace_back(Offset64, RelocSize, SymOffset, + Mapping->getKey(), Mapping->getValue()); } } } @@ -966,20 +1016,17 @@ bool DwarfLinkerForBinary::AddressManager:: } template -std::vector< - typename DwarfLinkerForBinary::AddressManager::ValidReloc> +std::vector DwarfLinkerForBinary::AddressManager::getRelocations( const std::vector &Relocs, uint64_t StartPos, uint64_t EndPos) { - std::vector< - DwarfLinkerForBinary::AddressManager::ValidReloc> - Res; + std::vector Res; auto CurReloc = partition_point(Relocs, [StartPos](const ValidReloc &Reloc) { - return Reloc.Offset < StartPos; + return (uint64_t)Reloc.Offset < StartPos; }); while (CurReloc != Relocs.end() && CurReloc->Offset >= StartPos && - CurReloc->Offset < EndPos) { + (uint64_t)CurReloc->Offset < EndPos) { Res.push_back(*CurReloc); CurReloc++; } @@ -990,12 +1037,12 @@ DwarfLinkerForBinary::AddressManager::getRelocations( template void DwarfLinkerForBinary::AddressManager::printReloc( const ValidReloc &Reloc) { - const auto &Mapping = Reloc.Mapping->getValue(); + const auto &Mapping = Reloc.SymbolMapping; const uint64_t ObjectAddress = Mapping.ObjectAddress ? uint64_t(*Mapping.ObjectAddress) : std::numeric_limits::max(); - outs() << "Found valid debug map entry: " << Reloc.Mapping->getKey() << "\t" + outs() << "Found valid debug map entry: " << Reloc.SymbolName << "\t" << format("0x%016" PRIx64 " => 0x%016" PRIx64 "\n", ObjectAddress, uint64_t(Mapping.BinaryAddress)); } @@ -1004,8 +1051,8 @@ template int64_t DwarfLinkerForBinary::AddressManager::getRelocValue( const ValidReloc &Reloc) { int64_t AddrAdjust = relocate(Reloc); - if (Reloc.Mapping->getValue().ObjectAddress) - AddrAdjust -= uint64_t(*Reloc.Mapping->getValue().ObjectAddress); + if (Reloc.SymbolMapping.ObjectAddress) + AddrAdjust -= uint64_t(*Reloc.SymbolMapping.ObjectAddress); return AddrAdjust; } @@ -1116,12 +1163,40 @@ std::optional DwarfLinkerForBinary::AddressManager< } } +template +std::optional DwarfLinkerForBinary::AddressManager< + AddressesMapBase>::getLibraryInstallName() { + return LibInstallName; +} + template uint64_t DwarfLinkerForBinary::AddressManager::relocate( const ValidReloc &Reloc) const { - return Reloc.Mapping->getValue().BinaryAddress + Reloc.Addend; + return Reloc.SymbolMapping.BinaryAddress + Reloc.Addend; +} + +template +void DwarfLinkerForBinary::AddressManager< + AddressesMapBase>::updateAndSaveValidRelocs(bool IsDWARF5, + uint64_t OriginalUnitOffset, + int64_t LinkedOffset, + uint64_t StartOffset, + uint64_t EndOffset) { + std::vector InRelocs = + getRelocations(ValidDebugInfoRelocs, StartOffset, EndOffset); + if (IsDWARF5) + InRelocs = getRelocations(ValidDebugAddrRelocs, StartOffset, EndOffset); + DwarfLinkerRelocMap->updateAndSaveValidRelocs( + IsDWARF5, InRelocs, OriginalUnitOffset, LinkedOffset); } +template +void DwarfLinkerForBinary::AddressManager:: + updateRelocationsWithUnitOffset(uint64_t OriginalUnitOffset, + uint64_t OutputUnitOffset) { + DwarfLinkerRelocMap->updateRelocationsWithUnitOffset(OriginalUnitOffset, + OutputUnitOffset); +} /// Apply the valid relocations found by findValidRelocs() to /// the buffer \p Data, taking into account that Data is at \p BaseOffset /// in the debug_info section. @@ -1133,6 +1208,7 @@ uint64_t DwarfLinkerForBinary::AddressManager::relocate( template bool DwarfLinkerForBinary::AddressManager::applyValidRelocs( MutableArrayRef Data, uint64_t BaseOffset, bool IsLittleEndian) { + std::vector Relocs = getRelocations( ValidDebugInfoRelocs, BaseOffset, BaseOffset + Data.size()); @@ -1148,9 +1224,47 @@ bool DwarfLinkerForBinary::AddressManager::applyValidRelocs( assert(CurReloc.Size <= sizeof(Buf)); memcpy(&Data[CurReloc.Offset - BaseOffset], Buf, CurReloc.Size); } - return Relocs.size() > 0; } +void DwarfLinkerForBinaryRelocationMap::init(DWARFContext &Context) { + for (const std::unique_ptr &CU : Context.compile_units()) + StoredValidDebugInfoRelocsMap.insert( + std::make_pair(CU->getOffset(), std::vector())); + // FIXME: Support relocations debug_addr (DWARF5). +} + +void DwarfLinkerForBinaryRelocationMap::addValidRelocs(RelocationMap &RM) { + for (const auto &DebugInfoRelocs : StoredValidDebugInfoRelocsMap) { + for (const auto &InfoReloc : DebugInfoRelocs.second) + RM.addRelocationMapEntry(InfoReloc); + } + // FIXME: Support relocations debug_addr (DWARF5). +} + +void DwarfLinkerForBinaryRelocationMap::updateRelocationsWithUnitOffset( + uint64_t OriginalUnitOffset, uint64_t OutputUnitOffset) { + std::vector &StoredValidDebugInfoRelocs = + StoredValidDebugInfoRelocsMap[OriginalUnitOffset]; + for (ValidReloc &R : StoredValidDebugInfoRelocs) { + R.Offset = (uint64_t)R.Offset + OutputUnitOffset; + } + // FIXME: Support relocations debug_addr (DWARF5). +} + +void DwarfLinkerForBinaryRelocationMap::updateAndSaveValidRelocs( + bool IsDWARF5, std::vector &InRelocs, uint64_t UnitOffset, + int64_t LinkedOffset) { + std::vector &OutRelocs = + StoredValidDebugInfoRelocsMap[UnitOffset]; + if (IsDWARF5) + OutRelocs = StoredValidDebugAddrRelocsMap[UnitOffset]; + + for (ValidReloc &R : InRelocs) { + OutRelocs.emplace_back(R.Offset + LinkedOffset, R.Size, R.Addend, + R.SymbolName, R.SymbolMapping); + } +} + } // namespace dsymutil } // namespace llvm diff --git a/llvm/tools/dsymutil/DwarfLinkerForBinary.h b/llvm/tools/dsymutil/DwarfLinkerForBinary.h index 230f569a6988c..328cd9197d0d1 100644 --- a/llvm/tools/dsymutil/DwarfLinkerForBinary.h +++ b/llvm/tools/dsymutil/DwarfLinkerForBinary.h @@ -13,6 +13,7 @@ #include "DebugMap.h" #include "LinkUtils.h" #include "MachOUtils.h" +#include "RelocationMap.h" #include "llvm/DWARFLinker/DWARFLinker.h" #include "llvm/DWARFLinker/DWARFLinkerCompileUnit.h" #include "llvm/DWARFLinker/DWARFLinkerDeclContext.h" @@ -21,10 +22,48 @@ #include "llvm/Remarks/RemarkFormat.h" #include "llvm/Remarks/RemarkLinker.h" #include +#include namespace llvm { namespace dsymutil { +/// DwarfLinkerForBinaryRelocationMap contains the logic to handle the +/// relocations and to store them inside an associated RelocationMap. +class DwarfLinkerForBinaryRelocationMap { +public: + void init(DWARFContext &Context); + + bool isInitialized() { + return StoredValidDebugInfoRelocsMap.getMemorySize() != 0; + } + + void addValidRelocs(RelocationMap &RM); + + void updateAndSaveValidRelocs(bool IsDWARF5, + std::vector &InRelocs, + uint64_t UnitOffset, int64_t LinkedOffset); + + void updateRelocationsWithUnitOffset(uint64_t OriginalUnitOffset, + uint64_t OutputUnitOffset); + + /// Map compilation unit offset to the valid relocations to store + /// @{ + DenseMap> StoredValidDebugInfoRelocsMap; + DenseMap> StoredValidDebugAddrRelocsMap; + /// @} + + DwarfLinkerForBinaryRelocationMap() = default; +}; + +template struct ObjectWithRelocMap { + ObjectWithRelocMap( + std::unique_ptr Object, + std::shared_ptr OutRelocs) + : Object(std::move(Object)), OutRelocs(OutRelocs) {} + std::unique_ptr Object; + std::shared_ptr OutRelocs; +}; + /// The core of the Dsymutil Dwarf linking logic. /// /// The link of the dwarf information from the object files will be @@ -67,26 +106,11 @@ class DwarfLinkerForBinary { /// Keeps track of relocations. template class AddressManager : public AddressesMapBase { - struct ValidReloc { - uint64_t Offset; - uint32_t Size; - uint64_t Addend; - const DebugMapObject::DebugMapEntry *Mapping; - - ValidReloc(uint64_t Offset, uint32_t Size, uint64_t Addend, - const DebugMapObject::DebugMapEntry *Mapping) - : Offset(Offset), Size(Size), Addend(Addend), Mapping(Mapping) {} - - bool operator<(const ValidReloc &RHS) const { - return Offset < RHS.Offset; - } - bool operator<(uint64_t RHS) const { return Offset < RHS; } - }; const DwarfLinkerForBinary &Linker; /// The valid relocations for the current DebugMapObject. - /// This vector is sorted by relocation offset. + /// These vectors are sorted by relocation offset. /// { std::vector ValidDebugInfoRelocs; std::vector ValidDebugAddrRelocs; @@ -94,6 +118,12 @@ class DwarfLinkerForBinary { StringRef SrcFileName; + uint8_t DebugMapObjectType; + + std::shared_ptr DwarfLinkerRelocMap; + + std::optional LibInstallName; + /// Returns list of valid relocations from \p Relocs, /// between \p StartOffset and \p NextOffset. /// @@ -115,9 +145,29 @@ class DwarfLinkerForBinary { public: AddressManager(DwarfLinkerForBinary &Linker, const object::ObjectFile &Obj, - const DebugMapObject &DMO) - : Linker(Linker), SrcFileName(DMO.getObjectFilename()) { - findValidRelocsInDebugSections(Obj, DMO); + const DebugMapObject &DMO, + std::shared_ptr DLBRM) + : Linker(Linker), SrcFileName(DMO.getObjectFilename()), + DebugMapObjectType(MachO::N_OSO), DwarfLinkerRelocMap(DLBRM) { + if (DMO.getRelocationMap().has_value()) { + DebugMapObjectType = MachO::N_LIB; + LibInstallName.emplace(DMO.getInstallName().value()); + const RelocationMap &RM = DMO.getRelocationMap().value(); + for (const auto &Reloc : RM.relocations()) { + const auto *DebugMapEntry = DMO.lookupSymbol(Reloc.SymbolName); + if (!DebugMapEntry) + continue; + std::optional ObjAddress; + ObjAddress.emplace(DebugMapEntry->getValue().ObjectAddress.value()); + ValidDebugInfoRelocs.emplace_back( + Reloc.Offset, Reloc.Size, Reloc.Addend, Reloc.SymbolName, + SymbolMapping(ObjAddress, DebugMapEntry->getValue().BinaryAddress, + DebugMapEntry->getValue().Size)); + // FIXME: Support relocations debug_addr. + } + } else { + findValidRelocsInDebugSections(Obj, DMO); + } } ~AddressManager() override { clear(); } @@ -158,9 +208,20 @@ class DwarfLinkerForBinary { std::optional getSubprogramRelocAdjustment(const DWARFDie &DIE) override; + std::optional getLibraryInstallName() override; + bool applyValidRelocs(MutableArrayRef Data, uint64_t BaseOffset, bool IsLittleEndian) override; + bool needToSaveValidRelocs() override { return true; } + + void updateAndSaveValidRelocs(bool IsDWARF5, uint64_t OriginalUnitOffset, + int64_t LinkedOffset, uint64_t StartOffset, + uint64_t EndOffset) override; + + void updateRelocationsWithUnitOffset(uint64_t OriginalUnitOffset, + uint64_t OutputUnitOffset) override; + void clear() override { ValidDebugInfoRelocs.clear(); ValidDebugAddrRelocs.clear(); @@ -180,11 +241,11 @@ class DwarfLinkerForBinary { /// Attempt to load a debug object from disk. ErrorOr loadObject(const DebugMapObject &Obj, const Triple &triple); - template - ErrorOr> loadObject(const DebugMapObject &Obj, - const DebugMap &DebugMap, - remarks::RemarkLinker &RL); + ErrorOr> + loadObject(const DebugMapObject &Obj, const DebugMap &DebugMap, + remarks::RemarkLinker &RL, + std::shared_ptr DLBRM); void collectRelocationsToApplyToSwiftReflectionSections( const object::SectionRef &Section, StringRef &Contents, @@ -207,6 +268,11 @@ class DwarfLinkerForBinary { bool linkImpl(const DebugMap &Map, typename Linker::OutputFileType ObjectType); + template + Error emitRelocations( + const DebugMap &DM, + std::vector> &ObjectsForLinking); + raw_fd_ostream &OutFile; BinaryHolder &BinHolder; LinkOptions Options; diff --git a/llvm/tools/dsymutil/LinkUtils.h b/llvm/tools/dsymutil/LinkUtils.h index 88c17d5036899..0bf6d9aac1a3f 100644 --- a/llvm/tools/dsymutil/LinkUtils.h +++ b/llvm/tools/dsymutil/LinkUtils.h @@ -93,6 +93,12 @@ struct LinkOptions { llvm::IntrusiveRefCntPtr VFS = vfs::getRealFileSystem(); + /// -build-variant-suffix. + std::string BuildVariantSuffix; + + /// Paths where to search for the .dSYM files of merged libraries. + std::vector DSYMSearchPaths; + /// Fields used for linking and placing remarks into the .dSYM bundle. /// @{ diff --git a/llvm/tools/dsymutil/MachODebugMapParser.cpp b/llvm/tools/dsymutil/MachODebugMapParser.cpp index d9bf2301e21e5..9623b71714582 100644 --- a/llvm/tools/dsymutil/MachODebugMapParser.cpp +++ b/llvm/tools/dsymutil/MachODebugMapParser.cpp @@ -9,6 +9,7 @@ #include "BinaryHolder.h" #include "DebugMap.h" #include "MachOUtils.h" +#include "RelocationMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallSet.h" #include "llvm/Object/MachO.h" @@ -28,9 +29,13 @@ class MachODebugMapParser { public: MachODebugMapParser(llvm::IntrusiveRefCntPtr VFS, StringRef BinaryPath, ArrayRef Archs, - StringRef PathPrefix = "", bool Verbose = false) + ArrayRef DSYMSearchPaths, + StringRef PathPrefix = "", StringRef VariantSuffix = "", + bool Verbose = false) : BinaryPath(std::string(BinaryPath)), Archs(Archs.begin(), Archs.end()), - PathPrefix(std::string(PathPrefix)), BinHolder(VFS, Verbose), + DSYMSearchPaths(DSYMSearchPaths.begin(), DSYMSearchPaths.end()), + PathPrefix(std::string(PathPrefix)), + VariantSuffix(std::string(VariantSuffix)), BinHolder(VFS, Verbose), CurrentDebugMapObject(nullptr), SkipDebugMapObject(false) {} /// Parses and returns the DebugMaps of the input binary. The binary contains @@ -47,7 +52,9 @@ class MachODebugMapParser { private: std::string BinaryPath; SmallVector Archs; + SmallVector DSYMSearchPaths; std::string PathPrefix; + std::string VariantSuffix; /// Owns the MemoryBuffer for the main binary. BinaryHolder BinHolder; @@ -87,6 +94,9 @@ class MachODebugMapParser { void switchToNewDebugMapObject(StringRef Filename, sys::TimePoint Timestamp); + void + switchToNewLibDebugMapObject(StringRef Filename, + sys::TimePoint Timestamp); void resetParserState(); uint64_t getMainBinarySymbolAddress(StringRef Name); std::vector getMainBinarySymbolNames(uint64_t Value); @@ -176,8 +186,6 @@ void MachODebugMapParser::addCommonSymbols() { /// everything up to add symbols to the new one. void MachODebugMapParser::switchToNewDebugMapObject( StringRef Filename, sys::TimePoint Timestamp) { - addCommonSymbols(); - resetParserState(); SmallString<80> Path(PathPrefix); sys::path::append(Path, Filename); @@ -198,11 +206,138 @@ void MachODebugMapParser::switchToNewDebugMapObject( return; } + addCommonSymbols(); + resetParserState(); + CurrentDebugMapObject = &Result->addDebugMapObject(Path, Timestamp, MachO::N_OSO); + loadCurrentObjectFileSymbols(*Object); } +/// Create a new DebugMapObject of type MachO::N_LIB. +/// This function resets the state of the parser that was +/// referring to the last object file and sets everything +/// up to add symbols to the new one. +void MachODebugMapParser::switchToNewLibDebugMapObject( + StringRef Filename, sys::TimePoint Timestamp) { + + if (DSYMSearchPaths.empty()) { + Warning("no dSYM search path was specified"); + return; + } + + StringRef LeafName = sys::path::filename(Filename); + SmallString<128> VariantLeafName; + SmallString<128> ProductName(LeafName); + + // For Framework.framework/Framework and -build-variant-suffix=_debug, + // look in the following order: + // 1) Framework.framework.dSYM/Contents/Resources/DWARF/Framework_debug + // 2) Framework.framework.dSYM/Contents/Resources/DWARF/Framework + // + // For libName.dylib and -build-variant-suffix=_debug, + // look in the following order: + // 1) libName.dylib.dSYM/Contents/Resources/DWARF/libName_debug.dylib + // 2) libName.dylib.dSYM/Contents/Resources/DWARF/libName.dylib + + size_t libExt = LeafName.rfind(".dylib"); + if (libExt != StringRef::npos) { + if (!VariantSuffix.empty()) { + VariantLeafName.append(LeafName.substr(0, libExt)); + VariantLeafName.append(VariantSuffix); + VariantLeafName.append(".dylib"); + } + } else { + // Expected to be a framework + ProductName.append(".framework"); + if (!VariantSuffix.empty()) { + VariantLeafName.append(LeafName); + VariantLeafName.append(VariantSuffix); + } + } + + for (auto DSYMSearchPath : DSYMSearchPaths) { + SmallString<256> Path(DSYMSearchPath); + SmallString<256> FallbackPath(Path); + + SmallString<256> DSYMPath(ProductName); + DSYMPath.append(".dSYM"); + sys::path::append(DSYMPath, "Contents", "Resources", "DWARF"); + + if (!VariantSuffix.empty()) { + sys::path::append(Path, DSYMPath, VariantLeafName); + sys::path::append(FallbackPath, DSYMPath, LeafName); + } else { + sys::path::append(Path, DSYMPath, LeafName); + } + + auto ObjectEntry = BinHolder.getObjectEntry(Path, Timestamp); + if (!ObjectEntry) { + auto Err = ObjectEntry.takeError(); + Warning("unable to open object file: " + toString(std::move(Err)), + Path.str()); + if (!VariantSuffix.empty()) { + ObjectEntry = BinHolder.getObjectEntry(FallbackPath, Timestamp); + if (!ObjectEntry) { + auto Err = ObjectEntry.takeError(); + Warning("unable to open object file: " + toString(std::move(Err)), + FallbackPath.str()); + continue; + } + Path.assign(FallbackPath); + } else { + continue; + } + } + + auto Object = + ObjectEntry->getObjectAs(Result->getTriple()); + if (!Object) { + auto Err = Object.takeError(); + Warning("unable to open object file: " + toString(std::move(Err)), + Path.str()); + continue; + } + + if (CurrentDebugMapObject && + CurrentDebugMapObject->getType() == MachO::N_LIB && + CurrentDebugMapObject->getObjectFilename().compare(Path.str()) == 0) { + return; + } + + addCommonSymbols(); + resetParserState(); + + CurrentDebugMapObject = + &Result->addDebugMapObject(Path, Timestamp, MachO::N_LIB); + + CurrentDebugMapObject->setInstallName(Filename); + + SmallString<256> RMPath(DSYMSearchPath); + sys::path::append(RMPath, ProductName); + RMPath.append(".dSYM"); + StringRef ArchName = Triple::getArchName(Result->getTriple().getArch(), + Result->getTriple().getSubArch()); + sys::path::append(RMPath, "Contents", "Resources", "Relocations", ArchName); + sys::path::append(RMPath, LeafName); + RMPath.append(".yml"); + const auto &RelocMapPtrOrErr = + RelocationMap::parseYAMLRelocationMap(RMPath, PathPrefix); + if (auto EC = RelocMapPtrOrErr.getError()) { + Warning("cannot parse relocation map file: " + EC.message(), + RMPath.str()); + return; + } + CurrentDebugMapObject->setRelocationMap(*RelocMapPtrOrErr->get()); + + loadCurrentObjectFileSymbols(*Object); + + // Found and loaded new dSYM file + return; + } +} + static std::string getArchName(const object::MachOObjectFile &Obj) { Triple T = Obj.getArchTriple(); return std::string(T.getArchName()); @@ -275,23 +410,39 @@ struct DarwinStabName { const char *Name; }; -const struct DarwinStabName DarwinStabNames[] = { - {MachO::N_GSYM, "N_GSYM"}, {MachO::N_FNAME, "N_FNAME"}, - {MachO::N_FUN, "N_FUN"}, {MachO::N_STSYM, "N_STSYM"}, - {MachO::N_LCSYM, "N_LCSYM"}, {MachO::N_BNSYM, "N_BNSYM"}, - {MachO::N_PC, "N_PC"}, {MachO::N_AST, "N_AST"}, - {MachO::N_OPT, "N_OPT"}, {MachO::N_RSYM, "N_RSYM"}, - {MachO::N_SLINE, "N_SLINE"}, {MachO::N_ENSYM, "N_ENSYM"}, - {MachO::N_SSYM, "N_SSYM"}, {MachO::N_SO, "N_SO"}, - {MachO::N_OSO, "N_OSO"}, {MachO::N_LSYM, "N_LSYM"}, - {MachO::N_BINCL, "N_BINCL"}, {MachO::N_SOL, "N_SOL"}, - {MachO::N_PARAMS, "N_PARAM"}, {MachO::N_VERSION, "N_VERS"}, - {MachO::N_OLEVEL, "N_OLEV"}, {MachO::N_PSYM, "N_PSYM"}, - {MachO::N_EINCL, "N_EINCL"}, {MachO::N_ENTRY, "N_ENTRY"}, - {MachO::N_LBRAC, "N_LBRAC"}, {MachO::N_EXCL, "N_EXCL"}, - {MachO::N_RBRAC, "N_RBRAC"}, {MachO::N_BCOMM, "N_BCOMM"}, - {MachO::N_ECOMM, "N_ECOMM"}, {MachO::N_ECOML, "N_ECOML"}, - {MachO::N_LENG, "N_LENG"}, {0, nullptr}}; +const struct DarwinStabName DarwinStabNames[] = {{MachO::N_GSYM, "N_GSYM"}, + {MachO::N_FNAME, "N_FNAME"}, + {MachO::N_FUN, "N_FUN"}, + {MachO::N_STSYM, "N_STSYM"}, + {MachO::N_LCSYM, "N_LCSYM"}, + {MachO::N_BNSYM, "N_BNSYM"}, + {MachO::N_PC, "N_PC"}, + {MachO::N_AST, "N_AST"}, + {MachO::N_OPT, "N_OPT"}, + {MachO::N_RSYM, "N_RSYM"}, + {MachO::N_SLINE, "N_SLINE"}, + {MachO::N_ENSYM, "N_ENSYM"}, + {MachO::N_SSYM, "N_SSYM"}, + {MachO::N_SO, "N_SO"}, + {MachO::N_OSO, "N_OSO"}, + {MachO::N_LIB, "N_LIB"}, + {MachO::N_LSYM, "N_LSYM"}, + {MachO::N_BINCL, "N_BINCL"}, + {MachO::N_SOL, "N_SOL"}, + {MachO::N_PARAMS, "N_PARAM"}, + {MachO::N_VERSION, "N_VERS"}, + {MachO::N_OLEVEL, "N_OLEV"}, + {MachO::N_PSYM, "N_PSYM"}, + {MachO::N_EINCL, "N_EINCL"}, + {MachO::N_ENTRY, "N_ENTRY"}, + {MachO::N_LBRAC, "N_LBRAC"}, + {MachO::N_EXCL, "N_EXCL"}, + {MachO::N_RBRAC, "N_RBRAC"}, + {MachO::N_BCOMM, "N_BCOMM"}, + {MachO::N_ECOMM, "N_ECOMM"}, + {MachO::N_ECOML, "N_ECOML"}, + {MachO::N_LENG, "N_LENG"}, + {0, nullptr}}; static const char *getDarwinStabString(uint8_t NType) { for (unsigned i = 0; DarwinStabNames[i].Name; i++) { @@ -477,13 +628,25 @@ void MachODebugMapParser::handleStabSymbolTableEntry( const char *Name = &MainBinaryStrings.data()[StringIndex]; + // An N_LIB entry represents the start of a new library file description. + if (Type == MachO::N_LIB) { + switchToNewLibDebugMapObject(Name, sys::toTimePoint(Value)); + return; + } + // An N_OSO entry represents the start of a new object file description. + // If an N_LIB entry was present, this is parsed only if the library + // dSYM file could not be found. if (Type == MachO::N_OSO) { - if (Duplicates.count(OSO(Name, Value))) { - SkipDebugMapObject = true; - return; + if (!CurrentDebugMapObject || + CurrentDebugMapObject->getType() != MachO::N_LIB) { + if (Duplicates.count(OSO(Name, Value))) { + SkipDebugMapObject = true; + return; + } + switchToNewDebugMapObject(Name, sys::toTimePoint(Value)); } - return switchToNewDebugMapObject(Name, sys::toTimePoint(Value)); + return; } if (SkipDebugMapObject) @@ -694,18 +857,23 @@ namespace dsymutil { llvm::ErrorOr>> parseDebugMap(llvm::IntrusiveRefCntPtr VFS, StringRef InputFile, ArrayRef Archs, - StringRef PrependPath, bool Verbose, bool InputIsYAML) { + ArrayRef DSYMSearchPaths, StringRef PrependPath, + StringRef VariantSuffix, bool Verbose, bool InputIsYAML) { if (InputIsYAML) return DebugMap::parseYAMLDebugMap(InputFile, PrependPath, Verbose); - MachODebugMapParser Parser(VFS, InputFile, Archs, PrependPath, Verbose); + MachODebugMapParser Parser(VFS, InputFile, Archs, DSYMSearchPaths, + PrependPath, VariantSuffix, Verbose); + return Parser.parse(); } bool dumpStab(llvm::IntrusiveRefCntPtr VFS, StringRef InputFile, ArrayRef Archs, - StringRef PrependPath) { - MachODebugMapParser Parser(VFS, InputFile, Archs, PrependPath, false); + ArrayRef DSYMSearchPaths, StringRef PrependPath, + StringRef VariantSuffix) { + MachODebugMapParser Parser(VFS, InputFile, Archs, DSYMSearchPaths, + PrependPath, VariantSuffix, false); return Parser.dumpStab(); } } // namespace dsymutil diff --git a/llvm/tools/dsymutil/Options.td b/llvm/tools/dsymutil/Options.td index 79f04fdfb0360..da071341cc01f 100644 --- a/llvm/tools/dsymutil/Options.td +++ b/llvm/tools/dsymutil/Options.td @@ -201,3 +201,14 @@ def linker: Separate<["--", "-"], "linker">, HelpText<"Specify the desired type of DWARF linker. Defaults to 'apple'">, Group; def: Joined<["--", "-"], "linker=">, Alias; + +def build_variant_suffix: Separate<["--", "-"], "build-variant-suffix">, + MetaVarName<"">, + HelpText<"Specify the build variant suffix used to build the executabe file.">, + Group; +def: Joined<["--", "-"], "build-variant-suffix=">, Alias; + +def dsym_search_path: Separate<["-", "--"], "D">, + MetaVarName<"">, + HelpText<"Specify a directory that contain dSYM files to search for.">, + Group; diff --git a/llvm/tools/dsymutil/RelocationMap.cpp b/llvm/tools/dsymutil/RelocationMap.cpp new file mode 100644 index 0000000000000..5921e7c9c2495 --- /dev/null +++ b/llvm/tools/dsymutil/RelocationMap.cpp @@ -0,0 +1,92 @@ +//===- tools/dsymutil/RelocationMap.cpp - Relocation map representation---===// +// +// 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 "RelocationMap.h" + +namespace llvm { + +namespace dsymutil { + +void RelocationMap::print(raw_ostream &OS) const { + yaml::Output yout(OS, /* Ctxt = */ nullptr, /* WrapColumn = */ 0); + yout << const_cast(*this); +} + +#ifndef NDEBUG +void RelocationMap::dump() const { print(errs()); } +#endif + +void RelocationMap::addRelocationMapEntry(const ValidReloc &Relocation) { + Relocations.push_back(Relocation); +} + +namespace { + +struct YAMLContext { + StringRef PrependPath; + Triple BinaryTriple; +}; + +} // end anonymous namespace + +ErrorOr> +RelocationMap::parseYAMLRelocationMap(StringRef InputFile, + StringRef PrependPath) { + auto ErrOrFile = MemoryBuffer::getFileOrSTDIN(InputFile); + if (auto Err = ErrOrFile.getError()) + return Err; + + YAMLContext Ctxt; + + Ctxt.PrependPath = PrependPath; + + std::unique_ptr Result; + yaml::Input yin((*ErrOrFile)->getBuffer(), &Ctxt); + yin >> Result; + + if (auto EC = yin.error()) + return EC; + return std::move(Result); +} + +} // end namespace dsymutil + +namespace yaml { + +void MappingTraits::mapping(IO &io, + dsymutil::ValidReloc &VR) { + io.mapRequired("offset", VR.Offset); + io.mapRequired("size", VR.Size); + io.mapRequired("addend", VR.Addend); + io.mapRequired("symName", VR.SymbolName); + io.mapOptional("symObjAddr", VR.SymbolMapping.ObjectAddress); + io.mapRequired("symBinAddr", VR.SymbolMapping.BinaryAddress); + io.mapRequired("symSize", VR.SymbolMapping.Size); +} + +void MappingTraits::mapping( + IO &io, dsymutil::RelocationMap &RM) { + io.mapRequired("triple", RM.BinaryTriple); + io.mapRequired("binary-path", RM.BinaryPath); + if (void *Ctxt = io.getContext()) + reinterpret_cast(Ctxt)->BinaryTriple = RM.BinaryTriple; + io.mapRequired("relocations", RM.Relocations); +} + +void MappingTraits>::mapping( + IO &io, std::unique_ptr &RM) { + if (!RM) + RM.reset(new RelocationMap()); + io.mapRequired("triple", RM->BinaryTriple); + io.mapRequired("binary-path", RM->BinaryPath); + if (void *Ctxt = io.getContext()) + reinterpret_cast(Ctxt)->BinaryTriple = RM->BinaryTriple; + io.mapRequired("relocations", RM->Relocations); +} +} // end namespace yaml +} // end namespace llvm diff --git a/llvm/tools/dsymutil/RelocationMap.h b/llvm/tools/dsymutil/RelocationMap.h new file mode 100644 index 0000000000000..a7d8ce3b122a6 --- /dev/null +++ b/llvm/tools/dsymutil/RelocationMap.h @@ -0,0 +1,160 @@ +//===- tools/dsymutil/RelocationMap.h -------------------------- *- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +/// \file +/// +/// This file contains the class declaration of the RelocationMap +/// entity. RelocationMap lists all the relocations of all the +/// atoms used in the object files linked together to +/// produce an executable. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_DSYMUTIL_RELOCATIONMAP_H +#define LLVM_TOOLS_DSYMUTIL_RELOCATIONMAP_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/YAMLTraits.h" +#include "llvm/TargetParser/Triple.h" + +#include +#include +#include + +namespace llvm { + +class raw_ostream; + +namespace dsymutil { + +struct SymbolMapping { + std::optional ObjectAddress; + yaml::Hex64 BinaryAddress; + yaml::Hex32 Size; + + SymbolMapping(std::optional ObjectAddr, uint64_t BinaryAddress, + uint32_t Size) + : BinaryAddress(BinaryAddress), Size(Size) { + if (ObjectAddr) + ObjectAddress = *ObjectAddr; + } + + /// For YAML IO support + SymbolMapping() = default; +}; + +/// ValidReloc represents one relocation entry described by the RelocationMap. +/// It contains a list of DWARF relocations to apply to a linked binary. +class ValidReloc { +public: + yaml::Hex64 Offset; + yaml::Hex32 Size; + yaml::Hex64 Addend; + std::string SymbolName; + SymbolMapping SymbolMapping; + + struct SymbolMapping getSymbolMapping() const { return SymbolMapping; } + + ValidReloc(uint64_t Offset, uint32_t Size, uint64_t Addend, + StringRef SymbolName, struct SymbolMapping SymbolMapping) + : Offset(Offset), Size(Size), Addend(Addend), SymbolName(SymbolName), + SymbolMapping(SymbolMapping) {} + + bool operator<(const ValidReloc &RHS) const { return Offset < RHS.Offset; } + + /// For YAMLIO support. + ValidReloc() = default; +}; + +/// The RelocationMap object stores the list of relocation entries for a binary +class RelocationMap { + Triple BinaryTriple; + std::string BinaryPath; + using RelocContainer = std::vector; + + RelocContainer Relocations; + + /// For YAML IO support. + ///@{ + friend yaml::MappingTraits>; + friend yaml::MappingTraits; + + RelocationMap() = default; + ///@} + +public: + RelocationMap(const Triple &BinaryTriple, StringRef BinaryPath) + : BinaryTriple(BinaryTriple), BinaryPath(std::string(BinaryPath)) {} + + using const_iterator = RelocContainer::const_iterator; + + iterator_range relocations() const { + return make_range(begin(), end()); + } + + const_iterator begin() const { return Relocations.begin(); } + + const_iterator end() const { return Relocations.end(); } + + size_t getNumberOfEntries() const { return Relocations.size(); } + + /// This function adds a ValidReloc to the list owned by this + /// relocation map. + void addRelocationMapEntry(const ValidReloc &Relocation); + + const Triple &getTriple() const { return BinaryTriple; } + + StringRef getBinaryPath() const { return BinaryPath; } + + void print(raw_ostream &OS) const; + +#ifndef NDEBUG + void dump() const; +#endif + + /// Read a relocation map from \a InputFile. + static ErrorOr> + parseYAMLRelocationMap(StringRef InputFile, StringRef PrependPath); +}; + +} // end namespace dsymutil +} // end namespace llvm + +LLVM_YAML_IS_SEQUENCE_VECTOR(dsymutil::ValidReloc) + +namespace llvm { +namespace yaml { + +using namespace llvm::dsymutil; + +template <> struct MappingTraits { + static void mapping(IO &io, dsymutil::ValidReloc &VR); + static const bool flow = true; +}; + +template <> struct MappingTraits { + struct YamlRM; + static void mapping(IO &io, dsymutil::RelocationMap &RM); +}; + +template <> struct MappingTraits> { + struct YamlRM; + static void mapping(IO &io, std::unique_ptr &RM); +}; + +template <> struct ScalarTraits { + static void output(const Triple &val, void *, raw_ostream &out); + static StringRef input(StringRef scalar, void *, Triple &value); + static QuotingType mustQuote(StringRef) { return QuotingType::Single; } +}; + +} // end namespace yaml +} // end namespace llvm + +#endif // LLVM_TOOLS_DSYMUTIL_RELOCATIONMAP_H diff --git a/llvm/tools/dsymutil/dsymutil.cpp b/llvm/tools/dsymutil/dsymutil.cpp index 104895b1a90bd..2dd123318e00b 100644 --- a/llvm/tools/dsymutil/dsymutil.cpp +++ b/llvm/tools/dsymutil/dsymutil.cpp @@ -398,6 +398,12 @@ static Expected getOptions(opt::InputArgList &Args) { Options.LinkOpts.RemarksKeepAll = !Args.hasArg(OPT_remarks_drop_without_debug); + if (opt::Arg *BuildVariantSuffix = Args.getLastArg(OPT_build_variant_suffix)) + Options.LinkOpts.BuildVariantSuffix = BuildVariantSuffix->getValue(); + + for (auto *SearchPath : Args.filtered(OPT_dsym_search_path)) + Options.LinkOpts.DSYMSearchPaths.push_back(SearchPath->getValue()); + if (Error E = verifyOptions(Options)) return std::move(E); return Options; @@ -670,15 +676,18 @@ int dsymutil_main(int argc, char **argv, const llvm::ToolContext &) { // Dump the symbol table for each input file and requested arch if (Options.DumpStab) { if (!dumpStab(Options.LinkOpts.VFS, InputFile, Options.Archs, - Options.LinkOpts.PrependPath)) + Options.LinkOpts.DSYMSearchPaths, + Options.LinkOpts.PrependPath, + Options.LinkOpts.BuildVariantSuffix)) return EXIT_FAILURE; continue; } - auto DebugMapPtrsOrErr = - parseDebugMap(Options.LinkOpts.VFS, InputFile, Options.Archs, - Options.LinkOpts.PrependPath, Options.LinkOpts.Verbose, - Options.InputIsYAMLDebugMap); + auto DebugMapPtrsOrErr = parseDebugMap( + Options.LinkOpts.VFS, InputFile, Options.Archs, + Options.LinkOpts.DSYMSearchPaths, Options.LinkOpts.PrependPath, + Options.LinkOpts.BuildVariantSuffix, Options.LinkOpts.Verbose, + Options.InputIsYAMLDebugMap); if (auto EC = DebugMapPtrsOrErr.getError()) { WithColor::error() << "cannot parse the debug map for '" << InputFile diff --git a/llvm/tools/dsymutil/dsymutil.h b/llvm/tools/dsymutil/dsymutil.h index ddecd8a76c7fc..5504dd57c7e55 100644 --- a/llvm/tools/dsymutil/dsymutil.h +++ b/llvm/tools/dsymutil/dsymutil.h @@ -35,12 +35,14 @@ namespace dsymutil { ErrorOr>> parseDebugMap(llvm::IntrusiveRefCntPtr VFS, StringRef InputFile, ArrayRef Archs, - StringRef PrependPath, bool Verbose, bool InputIsYAML); + ArrayRef DSYMSearchPaths, StringRef PrependPath, + StringRef VariantSuffix, bool Verbose, bool InputIsYAML); /// Dump the symbol table. bool dumpStab(llvm::IntrusiveRefCntPtr VFS, StringRef InputFile, ArrayRef Archs, - StringRef PrependPath = ""); + ArrayRef DSYMSearchPaths, StringRef PrependPath = "", + StringRef VariantSuffix = ""); } // end namespace dsymutil } // end namespace llvm diff --git a/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp b/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp index d97dd7392b0df..02a94596ec764 100644 --- a/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp +++ b/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp @@ -132,11 +132,23 @@ class ObjFileAddressMap : public AddressMapBase { return std::nullopt; } + std::optional getLibraryInstallName() override { + return std::nullopt; + } + bool applyValidRelocs(MutableArrayRef, uint64_t, bool) override { // no need to apply relocations to the linked binary. return false; } + bool needToSaveValidRelocs() override { return false; } + + void updateAndSaveValidRelocs(bool, uint64_t, int64_t, uint64_t, + uint64_t) override {} + + void updateRelocationsWithUnitOffset(uint64_t OriginalUnitOffset, + uint64_t OutputUnitOffset) override {} + void clear() override {} protected: diff --git a/llvm/tools/llvm-nm/llvm-nm.cpp b/llvm/tools/llvm-nm/llvm-nm.cpp index e32aa8ab8f5bf..fede89e9c1167 100644 --- a/llvm/tools/llvm-nm/llvm-nm.cpp +++ b/llvm/tools/llvm-nm/llvm-nm.cpp @@ -561,37 +561,22 @@ struct DarwinStabName { const char *Name; }; const struct DarwinStabName DarwinStabNames[] = { - {MachO::N_GSYM, "GSYM"}, - {MachO::N_FNAME, "FNAME"}, - {MachO::N_FUN, "FUN"}, - {MachO::N_STSYM, "STSYM"}, - {MachO::N_LCSYM, "LCSYM"}, - {MachO::N_BNSYM, "BNSYM"}, - {MachO::N_PC, "PC"}, - {MachO::N_AST, "AST"}, - {MachO::N_OPT, "OPT"}, - {MachO::N_RSYM, "RSYM"}, - {MachO::N_SLINE, "SLINE"}, - {MachO::N_ENSYM, "ENSYM"}, - {MachO::N_SSYM, "SSYM"}, - {MachO::N_SO, "SO"}, - {MachO::N_OSO, "OSO"}, - {MachO::N_LSYM, "LSYM"}, - {MachO::N_BINCL, "BINCL"}, - {MachO::N_SOL, "SOL"}, - {MachO::N_PARAMS, "PARAM"}, - {MachO::N_VERSION, "VERS"}, - {MachO::N_OLEVEL, "OLEV"}, - {MachO::N_PSYM, "PSYM"}, - {MachO::N_EINCL, "EINCL"}, - {MachO::N_ENTRY, "ENTRY"}, - {MachO::N_LBRAC, "LBRAC"}, - {MachO::N_EXCL, "EXCL"}, - {MachO::N_RBRAC, "RBRAC"}, - {MachO::N_BCOMM, "BCOMM"}, - {MachO::N_ECOMM, "ECOMM"}, - {MachO::N_ECOML, "ECOML"}, - {MachO::N_LENG, "LENG"}, + {MachO::N_GSYM, "GSYM"}, {MachO::N_FNAME, "FNAME"}, + {MachO::N_FUN, "FUN"}, {MachO::N_STSYM, "STSYM"}, + {MachO::N_LCSYM, "LCSYM"}, {MachO::N_BNSYM, "BNSYM"}, + {MachO::N_PC, "PC"}, {MachO::N_AST, "AST"}, + {MachO::N_OPT, "OPT"}, {MachO::N_RSYM, "RSYM"}, + {MachO::N_SLINE, "SLINE"}, {MachO::N_ENSYM, "ENSYM"}, + {MachO::N_SSYM, "SSYM"}, {MachO::N_SO, "SO"}, + {MachO::N_OSO, "OSO"}, {MachO::N_LIB, "LIB"}, + {MachO::N_LSYM, "LSYM"}, {MachO::N_BINCL, "BINCL"}, + {MachO::N_SOL, "SOL"}, {MachO::N_PARAMS, "PARAM"}, + {MachO::N_VERSION, "VERS"}, {MachO::N_OLEVEL, "OLEV"}, + {MachO::N_PSYM, "PSYM"}, {MachO::N_EINCL, "EINCL"}, + {MachO::N_ENTRY, "ENTRY"}, {MachO::N_LBRAC, "LBRAC"}, + {MachO::N_EXCL, "EXCL"}, {MachO::N_RBRAC, "RBRAC"}, + {MachO::N_BCOMM, "BCOMM"}, {MachO::N_ECOMM, "ECOMM"}, + {MachO::N_ECOML, "ECOML"}, {MachO::N_LENG, "LENG"}, }; static const char *getDarwinStabString(uint8_t NType) {