diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h @@ -749,6 +749,22 @@ /// E.g.: StripTemplateParameters("foo") = "foo". std::optional StripTemplateParameters(StringRef Name); +struct ObjCSelectorNames { + /// For "-[A(Category) method:]", this would be "method:" + StringRef Selector; + /// For "-[A(Category) method:]", this would be "A(category)" + StringRef ClassName; + /// For "-[A(Category) method:]", this would be "A" + std::optional ClassNameNoCategory; + /// For "-[A(Category) method:]", this would be "A method:" + std::optional MethodNameNoCategory; +}; + +/// If `Name` is the AT_name of a DIE which refers to an Objective-C selector, +/// returns an instance of ObjCSelectorNames. The Selector and ClassName fields +/// are guaranteed to be non-empty in the result. +std::optional getObjCNamesIfSelector(StringRef Name); + } // end namespace llvm #endif // LLVM_DEBUGINFO_DWARF_DWARFACCELERATORTABLE_H diff --git a/llvm/lib/DWARFLinker/DWARFLinker.cpp b/llvm/lib/DWARFLinker/DWARFLinker.cpp --- a/llvm/lib/DWARFLinker/DWARFLinker.cpp +++ b/llvm/lib/DWARFLinker/DWARFLinker.cpp @@ -1587,51 +1587,25 @@ return 0; } -static bool isObjCSelector(StringRef Name) { - return Name.size() > 2 && (Name[0] == '-' || Name[0] == '+') && - (Name[1] == '['); -} - void DWARFLinker::DIECloner::addObjCAccelerator(CompileUnit &Unit, const DIE *Die, DwarfStringPoolEntryRef Name, OffsetsStringPool &StringPool, bool SkipPubSection) { - assert(isObjCSelector(Name.getString()) && "not an objc selector"); - // Objective C method or class function. - // "- [Class(Category) selector :withArg ...]" - StringRef ClassNameStart(Name.getString().drop_front(2)); - size_t FirstSpace = ClassNameStart.find(' '); - if (FirstSpace == StringRef::npos) - return; - - StringRef SelectorStart(ClassNameStart.data() + FirstSpace + 1); - if (!SelectorStart.size()) + std::optional Names = + getObjCNamesIfSelector(Name.getString()); + if (!Names) return; - - StringRef Selector(SelectorStart.data(), SelectorStart.size() - 1); - Unit.addNameAccelerator(Die, StringPool.getEntry(Selector), SkipPubSection); - - // Add an entry for the class name that points to this - // method/class function. - StringRef ClassName(ClassNameStart.data(), FirstSpace); - Unit.addObjCAccelerator(Die, StringPool.getEntry(ClassName), SkipPubSection); - - if (ClassName[ClassName.size() - 1] == ')') { - size_t OpenParens = ClassName.find('('); - if (OpenParens != StringRef::npos) { - StringRef ClassNameNoCategory(ClassName.data(), OpenParens); - Unit.addObjCAccelerator(Die, StringPool.getEntry(ClassNameNoCategory), - SkipPubSection); - - std::string MethodNameNoCategory(Name.getString().data(), OpenParens + 2); - // FIXME: The missing space here may be a bug, but - // dsymutil-classic also does it this way. - MethodNameNoCategory.append(std::string(SelectorStart)); - Unit.addNameAccelerator(Die, StringPool.getEntry(MethodNameNoCategory), - SkipPubSection); - } - } + Unit.addNameAccelerator(Die, StringPool.getEntry(Names->Selector), + SkipPubSection); + Unit.addObjCAccelerator(Die, StringPool.getEntry(Names->ClassName), + SkipPubSection); + if (Names->ClassNameNoCategory) + Unit.addObjCAccelerator( + Die, StringPool.getEntry(*Names->ClassNameNoCategory), SkipPubSection); + if (Names->MethodNameNoCategory) + Unit.addNameAccelerator( + Die, StringPool.getEntry(*Names->MethodNameNoCategory), SkipPubSection); } static bool @@ -1781,7 +1755,7 @@ Unit.addNameAccelerator(Die, AttrInfo.Name, Tag == dwarf::DW_TAG_inlined_subroutine); } - if (AttrInfo.Name && isObjCSelector(AttrInfo.Name.getString())) + if (AttrInfo.Name) addObjCAccelerator(Unit, Die, AttrInfo.Name, DebugStrPool, /* SkipPubSection =*/true); diff --git a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp @@ -970,6 +970,43 @@ return CUToNameIndex.lookup(CUOffset); } +static bool isObjCSelector(StringRef Name) { + return Name.size() > 2 && (Name[0] == '-' || Name[0] == '+') && + (Name[1] == '['); +} + +std::optional llvm::getObjCNamesIfSelector(StringRef Name) { + if (!isObjCSelector(Name)) + return std::nullopt; + // "-[Atom setMass:]" + StringRef ClassNameStart(Name.drop_front(2)); + size_t FirstSpace = ClassNameStart.find(' '); + if (FirstSpace == StringRef::npos) + return std::nullopt; + + StringRef SelectorStart = ClassNameStart.drop_front(FirstSpace + 1); + if (!SelectorStart.size()) + return std::nullopt; + + ObjCSelectorNames Ans; + Ans.ClassName = ClassNameStart.take_front(FirstSpace); + Ans.Selector = SelectorStart.drop_back(); // drop ']'; + + // "-[Class(Category) selector :withArg ...]" + if (Ans.ClassName.back() == ')') { + size_t OpenParens = Ans.ClassName.find('('); + if (OpenParens != StringRef::npos) { + Ans.ClassNameNoCategory = Ans.ClassName.take_front(OpenParens); + + Ans.MethodNameNoCategory = Name.take_front(OpenParens + 2); + // FIXME: The missing space here may be a bug, but dsymutil-classic also + // does it this way. + append_range(*Ans.MethodNameNoCategory, SelectorStart); + } + } + return Ans; +} + std::optional llvm::StripTemplateParameters(StringRef Name) { // We are looking for template parameters to strip from Name. e.g. // diff --git a/llvm/test/tools/dsymutil/X86/objc.test b/llvm/test/tools/dsymutil/X86/objc.test --- a/llvm/test/tools/dsymutil/X86/objc.test +++ b/llvm/test/tools/dsymutil/X86/objc.test @@ -1,5 +1,5 @@ -RUN: dsymutil -f -oso-prepend-path=%p/.. %p/../Inputs/objc.macho.x86_64 -o - \ -RUN: | llvm-dwarfdump -apple-types -apple-objc - | FileCheck %s +RUN: dsymutil --verify-dwarf=output -f -oso-prepend-path=%p/.. %p/../Inputs/objc.macho.x86_64 -o %t.d4 +RUN: llvm-dwarfdump -apple-types -apple-objc %t.d4 | FileCheck %s CHECK: .apple_types contents: CHECK: String: 0x00000066 "A"