//===-- ObjCLanguage.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 // //===----------------------------------------------------------------------===// #include #include "ObjCLanguage.h" #include "Plugins/ExpressionParser/Clang/ClangUtil.h" #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/ValueObject.h" #include "lldb/DataFormatters/DataVisualization.h" #include "lldb/DataFormatters/FormattersHelpers.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Target/Target.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/StreamString.h" #include "llvm/Support/Threading.h" #include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h" #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" #include "CF.h" #include "Cocoa.h" #include "CoreMedia.h" #include "NSDictionary.h" #include "NSSet.h" #include "NSString.h" using namespace lldb; using namespace lldb_private; using namespace lldb_private::formatters; LLDB_PLUGIN_DEFINE(ObjCLanguage) void ObjCLanguage::Initialize() { PluginManager::RegisterPlugin(GetPluginNameStatic(), "Objective-C Language", CreateInstance); } void ObjCLanguage::Terminate() { PluginManager::UnregisterPlugin(CreateInstance); } // Static Functions Language *ObjCLanguage::CreateInstance(lldb::LanguageType language) { switch (language) { case lldb::eLanguageTypeObjC: return new ObjCLanguage(); default: return nullptr; } } std::optional ObjCLanguage::MethodName::Create(llvm::StringRef name, bool strict) { if (name.empty()) return std::nullopt; // Objective-C method minimum requirements: // - If `strict` is true, must start with '-' or '+' (1 char) // - Must be followed by '[' (1 char) // - Must have at least one character for class name (1 char) // - Must have a space between class name and method name (1 char) // - Must have at least one character for method name (1 char) // - Must be end with ']' (1 char) // This means that the minimum size is 5 characters (6 if `strict`) // e.g. [a a] (-[a a] or +[a a] if `strict`) // We can check length and ending invariants first if (name.size() < (5 + (strict ? 1 : 0)) || name.back() != ']') return std::nullopt; // Figure out type Type type = eTypeUnspecified; if (name.starts_with("+[")) type = eTypeClassMethod; else if (name.starts_with("-[")) type = eTypeInstanceMethod; // If there's no type and it's strict, this is invalid if (strict && type == eTypeUnspecified) return std::nullopt; // If not strict and type unspecified, make sure we start with '[' if (type == eTypeUnspecified && name.front() != '[') return std::nullopt; // If we've gotten here, we're confident that this looks enough like an // Objective-C method to treat it like one. ObjCLanguage::MethodName method_name(name, type); return method_name; } llvm::StringRef ObjCLanguage::MethodName::GetClassName() const { llvm::StringRef full = m_full; const size_t class_start_pos = (full.front() == '[' ? 1 : 2); const size_t paren_pos = full.find('(', class_start_pos); // If there's a category we want to stop there if (paren_pos != llvm::StringRef::npos) return full.substr(class_start_pos, paren_pos - class_start_pos); // Otherwise we find the space separating the class and method const size_t space_pos = full.find(' ', class_start_pos); return full.substr(class_start_pos, space_pos - class_start_pos); } llvm::StringRef ObjCLanguage::MethodName::GetClassNameWithCategory() const { llvm::StringRef full = m_full; const size_t class_start_pos = (full.front() == '[' ? 1 : 2); const size_t space_pos = full.find(' ', class_start_pos); return full.substr(class_start_pos, space_pos - class_start_pos); } llvm::StringRef ObjCLanguage::MethodName::GetSelector() const { llvm::StringRef full = m_full; const size_t space_pos = full.find(' '); if (space_pos == llvm::StringRef::npos) return llvm::StringRef(); const size_t closing_bracket = full.find(']', space_pos); return full.substr(space_pos + 1, closing_bracket - space_pos - 1); } llvm::StringRef ObjCLanguage::MethodName::GetCategory() const { llvm::StringRef full = m_full; const size_t open_paren_pos = full.find('('); const size_t close_paren_pos = full.find(')'); if (open_paren_pos == llvm::StringRef::npos || close_paren_pos == llvm::StringRef::npos) return llvm::StringRef(); return full.substr(open_paren_pos + 1, close_paren_pos - (open_paren_pos + 1)); } std::string ObjCLanguage::MethodName::GetFullNameWithoutCategory() const { llvm::StringRef full = m_full; const size_t open_paren_pos = full.find('('); const size_t close_paren_pos = full.find(')'); if (open_paren_pos == llvm::StringRef::npos || close_paren_pos == llvm::StringRef::npos) return std::string(); llvm::StringRef class_name = GetClassName(); llvm::StringRef selector_name = GetSelector(); // Compute the total size to avoid reallocations // class name + selector name + '[' + ' ' + ']' size_t total_size = class_name.size() + selector_name.size() + 3; if (m_type != eTypeUnspecified) total_size++; // For + or - std::string name_sans_category; name_sans_category.reserve(total_size); if (m_type == eTypeClassMethod) name_sans_category += '+'; else if (m_type == eTypeInstanceMethod) name_sans_category += '-'; name_sans_category += '['; name_sans_category.append(class_name.data(), class_name.size()); name_sans_category += ' '; name_sans_category.append(selector_name.data(), selector_name.size()); name_sans_category += ']'; return name_sans_category; } std::vector ObjCLanguage::GetMethodNameVariants(ConstString method_name) const { std::vector variant_names; std::optional objc_method = ObjCLanguage::MethodName::Create(method_name.GetStringRef(), false); if (!objc_method) return variant_names; variant_names.emplace_back(ConstString(objc_method->GetSelector()), lldb::eFunctionNameTypeSelector); const std::string name_sans_category = objc_method->GetFullNameWithoutCategory(); if (objc_method->IsClassMethod() || objc_method->IsInstanceMethod()) { if (!name_sans_category.empty()) variant_names.emplace_back(ConstString(name_sans_category.c_str()), lldb::eFunctionNameTypeFull); } else { StreamString strm; strm.Printf("+%s", objc_method->GetFullName().c_str()); variant_names.emplace_back(ConstString(strm.GetString()), lldb::eFunctionNameTypeFull); strm.Clear(); strm.Printf("-%s", objc_method->GetFullName().c_str()); variant_names.emplace_back(ConstString(strm.GetString()), lldb::eFunctionNameTypeFull); strm.Clear(); if (!name_sans_category.empty()) { strm.Printf("+%s", name_sans_category.c_str()); variant_names.emplace_back(ConstString(strm.GetString()), lldb::eFunctionNameTypeFull); strm.Clear(); strm.Printf("-%s", name_sans_category.c_str()); variant_names.emplace_back(ConstString(strm.GetString()), lldb::eFunctionNameTypeFull); } } return variant_names; } bool ObjCLanguage::SymbolNameFitsToLanguage(Mangled mangled) const { ConstString demangled_name = mangled.GetDemangledName(); if (!demangled_name) return false; return ObjCLanguage::IsPossibleObjCMethodName(demangled_name.GetCString()); } static void LoadObjCFormatters(TypeCategoryImplSP objc_category_sp) { if (!objc_category_sp) return; TypeSummaryImpl::Flags objc_flags; objc_flags.SetCascades(false) .SetSkipPointers(true) .SetSkipReferences(true) .SetDontShowChildren(true) .SetDontShowValue(true) .SetShowMembersOneLiner(false) .SetHideItemNames(false); lldb::TypeSummaryImplSP ObjC_BOOL_summary(new CXXFunctionSummaryFormat( objc_flags, lldb_private::formatters::ObjCBOOLSummaryProvider, "")); objc_category_sp->AddTypeSummary("BOOL", eFormatterMatchExact, ObjC_BOOL_summary); objc_category_sp->AddTypeSummary("BOOL &", eFormatterMatchExact, ObjC_BOOL_summary); objc_category_sp->AddTypeSummary("BOOL *", eFormatterMatchExact, ObjC_BOOL_summary); // we need to skip pointers here since we are special casing a SEL* when // retrieving its value objc_flags.SetSkipPointers(true); AddCXXSummary(objc_category_sp, lldb_private::formatters::ObjCSELSummaryProvider, "SEL summary provider", "SEL", objc_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::ObjCSELSummaryProvider, "SEL summary provider", "struct objc_selector", objc_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::ObjCSELSummaryProvider, "SEL summary provider", "objc_selector", objc_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::ObjCSELSummaryProvider, "SEL summary provider", "objc_selector *", objc_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::ObjCSELSummaryProvider, "SEL summary provider", "SEL *", objc_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::ObjCClassSummaryProvider, "Class summary provider", "Class", objc_flags); SyntheticChildren::Flags class_synth_flags; class_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences( false); AddCXXSynthetic(objc_category_sp, lldb_private::formatters::ObjCClassSyntheticFrontEndCreator, "Class synthetic children", "Class", class_synth_flags); objc_flags.SetSkipPointers(false); objc_flags.SetCascades(true); objc_flags.SetSkipReferences(false); AddStringSummary(objc_category_sp, "${var.__FuncPtr%A}", "__block_literal_generic", objc_flags); AddStringSummary(objc_category_sp, "${var.years} years, ${var.months} " "months, ${var.days} days, ${var.hours} " "hours, ${var.minutes} minutes " "${var.seconds} seconds", "CFGregorianUnits", objc_flags); AddStringSummary(objc_category_sp, "location=${var.location} length=${var.length}", "CFRange", objc_flags); AddStringSummary(objc_category_sp, "location=${var.location}, length=${var.length}", "NSRange", objc_flags); AddStringSummary(objc_category_sp, "(${var.origin}, ${var.size}), ...", "NSRectArray", objc_flags); AddOneLineSummary(objc_category_sp, "NSPoint", objc_flags); AddOneLineSummary(objc_category_sp, "NSSize", objc_flags); AddOneLineSummary(objc_category_sp, "NSRect", objc_flags); AddOneLineSummary(objc_category_sp, "CGSize", objc_flags); AddOneLineSummary(objc_category_sp, "CGPoint", objc_flags); AddOneLineSummary(objc_category_sp, "CGRect", objc_flags); AddStringSummary(objc_category_sp, "red=${var.red} green=${var.green} blue=${var.blue}", "RGBColor", objc_flags); AddStringSummary( objc_category_sp, "(t=${var.top}, l=${var.left}, b=${var.bottom}, r=${var.right})", "Rect", objc_flags); AddStringSummary(objc_category_sp, "{(v=${var.v}, h=${var.h})}", "Point", objc_flags); AddStringSummary(objc_category_sp, "${var.month}/${var.day}/${var.year} ${var.hour} " ":${var.minute} :${var.second} dayOfWeek:${var.dayOfWeek}", "DateTimeRect *", objc_flags); AddStringSummary(objc_category_sp, "${var.ld.month}/${var.ld.day}/" "${var.ld.year} ${var.ld.hour} " ":${var.ld.minute} :${var.ld.second} " "dayOfWeek:${var.ld.dayOfWeek}", "LongDateRect", objc_flags); AddStringSummary(objc_category_sp, "(x=${var.x}, y=${var.y})", "HIPoint", objc_flags); AddStringSummary(objc_category_sp, "origin=${var.origin} size=${var.size}", "HIRect", objc_flags); TypeSummaryImpl::Flags appkit_flags; appkit_flags.SetCascades(true) .SetSkipPointers(false) .SetSkipReferences(false) .SetDontShowChildren(true) .SetDontShowValue(false) .SetShowMembersOneLiner(false) .SetHideItemNames(false); appkit_flags.SetDontShowChildren(false); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSArraySummaryProvider, "NSArray summary provider", "NSArray", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSArraySummaryProvider, "NSArray summary provider", "NSConstantArray", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSArraySummaryProvider, "NSArray summary provider", "NSMutableArray", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSArraySummaryProvider, "NSArray summary provider", "__NSArrayI", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSArraySummaryProvider, "NSArray summary provider", "__NSArray0", appkit_flags); AddCXXSummary( objc_category_sp, lldb_private::formatters::NSArraySummaryProvider, "NSArray summary provider", "__NSSingleObjectArrayI", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSArraySummaryProvider, "NSArray summary provider", "__NSArrayM", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSArraySummaryProvider, "NSArray summary provider", "__NSCFArray", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSArraySummaryProvider, "NSArray summary provider", "_NSCallStackArray", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSArraySummaryProvider, "NSArray summary provider", "CFArrayRef", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSArraySummaryProvider, "NSArray summary provider", "CFMutableArrayRef", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSDictionarySummaryProvider, "NSDictionary summary provider", "NSDictionary", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSDictionarySummaryProvider, "NSDictionary summary provider", "NSConstantDictionary", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSDictionarySummaryProvider, "NSDictionary summary provider", "NSMutableDictionary", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSDictionarySummaryProvider, "NSDictionary summary provider", "__NSCFDictionary", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSDictionarySummaryProvider, "NSDictionary summary provider", "__NSDictionaryI", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSDictionarySummaryProvider, "NSDictionary summary provider", "__NSSingleEntryDictionaryI", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSDictionarySummaryProvider, "NSDictionary summary provider", "__NSDictionaryM", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSDictionarySummaryProvider, "NSDictionary summary provider", "CFDictionaryRef", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSDictionarySummaryProvider, "NSDictionary summary provider", "__CFDictionary", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSDictionarySummaryProvider, "NSDictionary summary provider", "CFMutableDictionaryRef", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSSetSummaryProvider, "NSSet summary", "NSSet", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSSetSummaryProvider, "NSMutableSet summary", "NSMutableSet", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSSetSummaryProvider, "CFSetRef summary", "CFSetRef", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSSetSummaryProvider, "CFMutableSetRef summary", "CFMutableSetRef", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSSetSummaryProvider, "__NSCFSet summary", "__NSCFSet", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSSetSummaryProvider, "__CFSet summary", "__CFSet", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSSetSummaryProvider, "__NSSetI summary", "__NSSetI", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSSetSummaryProvider, "__NSSetM summary", "__NSSetM", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSSetSummaryProvider, "NSCountedSet summary", "NSCountedSet", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSSetSummaryProvider, "NSMutableSet summary", "NSMutableSet", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSSetSummaryProvider, "NSOrderedSet summary", "NSOrderedSet", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSSetSummaryProvider, "__NSOrderedSetI summary", "__NSOrderedSetI", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSSetSummaryProvider, "__NSOrderedSetM summary", "__NSOrderedSetM", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSError_SummaryProvider, "NSError summary provider", "NSError", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSException_SummaryProvider, "NSException summary provider", "NSException", appkit_flags); // AddSummary(appkit_category_sp, "${var.key%@} -> ${var.value%@}", // ConstString("$_lldb_typegen_nspair"), appkit_flags); appkit_flags.SetDontShowChildren(true); AddCXXSynthetic(objc_category_sp, lldb_private::formatters::NSArraySyntheticFrontEndCreator, "NSArray synthetic children", "__NSArrayM", ScriptedSyntheticChildren::Flags()); AddCXXSynthetic(objc_category_sp, lldb_private::formatters::NSArraySyntheticFrontEndCreator, "NSArray synthetic children", "__NSArrayI", ScriptedSyntheticChildren::Flags()); AddCXXSynthetic(objc_category_sp, lldb_private::formatters::NSArraySyntheticFrontEndCreator, "NSArray synthetic children", "__NSArray0", ScriptedSyntheticChildren::Flags()); AddCXXSynthetic(objc_category_sp, lldb_private::formatters::NSArraySyntheticFrontEndCreator, "NSArray synthetic children", "__NSSingleObjectArrayI", ScriptedSyntheticChildren::Flags()); AddCXXSynthetic(objc_category_sp, lldb_private::formatters::NSArraySyntheticFrontEndCreator, "NSArray synthetic children", "NSArray", ScriptedSyntheticChildren::Flags()); AddCXXSynthetic(objc_category_sp, lldb_private::formatters::NSArraySyntheticFrontEndCreator, "NSArray synthetic children", "NSConstantArray", ScriptedSyntheticChildren::Flags()); AddCXXSynthetic(objc_category_sp, lldb_private::formatters::NSArraySyntheticFrontEndCreator, "NSArray synthetic children", "NSMutableArray", ScriptedSyntheticChildren::Flags()); AddCXXSynthetic(objc_category_sp, lldb_private::formatters::NSArraySyntheticFrontEndCreator, "NSArray synthetic children", "__NSCFArray", ScriptedSyntheticChildren::Flags()); AddCXXSynthetic(objc_category_sp, lldb_private::formatters::NSArraySyntheticFrontEndCreator, "NSArray synthetic children", "_NSCallStackArray", ScriptedSyntheticChildren::Flags()); AddCXXSynthetic(objc_category_sp, lldb_private::formatters::NSArraySyntheticFrontEndCreator, "NSArray synthetic children", "CFMutableArrayRef", ScriptedSyntheticChildren::Flags()); AddCXXSynthetic(objc_category_sp, lldb_private::formatters::NSArraySyntheticFrontEndCreator, "NSArray synthetic children", "CFArrayRef", ScriptedSyntheticChildren::Flags()); AddCXXSynthetic( objc_category_sp, lldb_private::formatters::NSDictionarySyntheticFrontEndCreator, "NSDictionary synthetic children", "__NSDictionaryM", ScriptedSyntheticChildren::Flags()); AddCXXSynthetic( objc_category_sp, lldb_private::formatters::NSDictionarySyntheticFrontEndCreator, "NSDictionary synthetic children", "NSConstantDictionary", ScriptedSyntheticChildren::Flags()); AddCXXSynthetic( objc_category_sp, lldb_private::formatters::NSDictionarySyntheticFrontEndCreator, "NSDictionary synthetic children", "__NSDictionaryI", ScriptedSyntheticChildren::Flags()); AddCXXSynthetic( objc_category_sp, lldb_private::formatters::NSDictionarySyntheticFrontEndCreator, "NSDictionary synthetic children", "__NSSingleEntryDictionaryI", ScriptedSyntheticChildren::Flags()); AddCXXSynthetic( objc_category_sp, lldb_private::formatters::NSDictionarySyntheticFrontEndCreator, "NSDictionary synthetic children", "__NSCFDictionary", ScriptedSyntheticChildren::Flags()); AddCXXSynthetic( objc_category_sp, lldb_private::formatters::NSDictionarySyntheticFrontEndCreator, "NSDictionary synthetic children", "NSDictionary", ScriptedSyntheticChildren::Flags()); AddCXXSynthetic( objc_category_sp, lldb_private::formatters::NSDictionarySyntheticFrontEndCreator, "NSDictionary synthetic children", "NSMutableDictionary", ScriptedSyntheticChildren::Flags()); AddCXXSynthetic( objc_category_sp, lldb_private::formatters::NSDictionarySyntheticFrontEndCreator, "NSDictionary synthetic children", "CFDictionaryRef", ScriptedSyntheticChildren::Flags()); AddCXXSynthetic( objc_category_sp, lldb_private::formatters::NSDictionarySyntheticFrontEndCreator, "NSDictionary synthetic children", "CFMutableDictionaryRef", ScriptedSyntheticChildren::Flags()); AddCXXSynthetic( objc_category_sp, lldb_private::formatters::NSDictionarySyntheticFrontEndCreator, "NSDictionary synthetic children", "__CFDictionary", ScriptedSyntheticChildren::Flags()); AddCXXSynthetic(objc_category_sp, lldb_private::formatters::NSErrorSyntheticFrontEndCreator, "NSError synthetic children", "NSError", ScriptedSyntheticChildren::Flags()); AddCXXSynthetic(objc_category_sp, lldb_private::formatters::NSExceptionSyntheticFrontEndCreator, "NSException synthetic children", "NSException", ScriptedSyntheticChildren::Flags()); AddCXXSynthetic( objc_category_sp, lldb_private::formatters::NSSetSyntheticFrontEndCreator, "NSSet synthetic children", "NSSet", ScriptedSyntheticChildren::Flags()); AddCXXSynthetic(objc_category_sp, lldb_private::formatters::NSSetSyntheticFrontEndCreator, "__NSSetI synthetic children", "__NSSetI", ScriptedSyntheticChildren::Flags()); AddCXXSynthetic(objc_category_sp, lldb_private::formatters::NSSetSyntheticFrontEndCreator, "__NSSetM synthetic children", "__NSSetM", ScriptedSyntheticChildren::Flags()); AddCXXSynthetic(objc_category_sp, lldb_private::formatters::NSSetSyntheticFrontEndCreator, "__NSCFSet synthetic children", "__NSCFSet", ScriptedSyntheticChildren::Flags()); AddCXXSynthetic(objc_category_sp, lldb_private::formatters::NSSetSyntheticFrontEndCreator, "CFSetRef synthetic children", "CFSetRef", ScriptedSyntheticChildren::Flags()); AddCXXSynthetic(objc_category_sp, lldb_private::formatters::NSSetSyntheticFrontEndCreator, "NSMutableSet synthetic children", "NSMutableSet", ScriptedSyntheticChildren::Flags()); AddCXXSynthetic(objc_category_sp, lldb_private::formatters::NSSetSyntheticFrontEndCreator, "NSOrderedSet synthetic children", "NSOrderedSet", ScriptedSyntheticChildren::Flags()); AddCXXSynthetic(objc_category_sp, lldb_private::formatters::NSSetSyntheticFrontEndCreator, "__NSOrderedSetI synthetic children", "__NSOrderedSetI", ScriptedSyntheticChildren::Flags()); AddCXXSynthetic(objc_category_sp, lldb_private::formatters::NSSetSyntheticFrontEndCreator, "__NSOrderedSetM synthetic children", "__NSOrderedSetM", ScriptedSyntheticChildren::Flags()); AddCXXSynthetic(objc_category_sp, lldb_private::formatters::NSSetSyntheticFrontEndCreator, "__CFSet synthetic children", "__CFSet", ScriptedSyntheticChildren::Flags()); AddCXXSynthetic(objc_category_sp, lldb_private::formatters::NSIndexPathSyntheticFrontEndCreator, "NSIndexPath synthetic children", "NSIndexPath", ScriptedSyntheticChildren::Flags()); AddCXXSummary(objc_category_sp, lldb_private::formatters::CFBagSummaryProvider, "CFBag summary provider", "CFBagRef", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::CFBagSummaryProvider, "CFBag summary provider", "__CFBag", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::CFBagSummaryProvider, "CFBag summary provider", "const struct __CFBag", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::CFBagSummaryProvider, "CFBag summary provider", "CFMutableBagRef", appkit_flags); AddCXXSummary( objc_category_sp, lldb_private::formatters::CFBinaryHeapSummaryProvider, "CFBinaryHeap summary provider", "CFBinaryHeapRef", appkit_flags); AddCXXSummary( objc_category_sp, lldb_private::formatters::CFBinaryHeapSummaryProvider, "CFBinaryHeap summary provider", "__CFBinaryHeap", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSStringSummaryProvider, "NSString summary provider", "NSString", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSStringSummaryProvider, "NSString summary provider", "CFStringRef", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSStringSummaryProvider, "NSString summary provider", "__CFString", appkit_flags); AddCXXSummary( objc_category_sp, lldb_private::formatters::NSStringSummaryProvider, "NSString summary provider", "CFMutableStringRef", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSStringSummaryProvider, "NSString summary provider", "NSMutableString", appkit_flags); AddCXXSummary( objc_category_sp, lldb_private::formatters::NSStringSummaryProvider, "NSString summary provider", "__NSCFConstantString", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSStringSummaryProvider, "NSString summary provider", "__NSCFString", appkit_flags); AddCXXSummary( objc_category_sp, lldb_private::formatters::NSStringSummaryProvider, "NSString summary provider", "NSCFConstantString", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSStringSummaryProvider, "NSString summary provider", "NSCFString", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSStringSummaryProvider, "NSString summary provider", "NSPathStore2", appkit_flags); AddCXXSummary( objc_category_sp, lldb_private::formatters::NSStringSummaryProvider, "NSString summary provider", "NSTaggedPointerString", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSAttributedStringSummaryProvider, "NSAttributedString summary provider", "NSAttributedString", appkit_flags); AddCXXSummary( objc_category_sp, lldb_private::formatters::NSMutableAttributedStringSummaryProvider, "NSMutableAttributedString summary provider", "NSMutableAttributedString", appkit_flags); AddCXXSummary( objc_category_sp, lldb_private::formatters::NSMutableAttributedStringSummaryProvider, "NSMutableAttributedString summary provider", "NSConcreteMutableAttributedString", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSBundleSummaryProvider, "NSBundle summary provider", "NSBundle", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSDataSummaryProvider, "NSData summary provider", "NSData", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSDataSummaryProvider, "NSData summary provider", "_NSInlineData", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSDataSummaryProvider, "NSData summary provider", "NSConcreteData", appkit_flags); AddCXXSummary( objc_category_sp, lldb_private::formatters::NSDataSummaryProvider, "NSData summary provider", "NSConcreteMutableData", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSDataSummaryProvider, "NSData summary provider", "NSMutableData", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSDataSummaryProvider, "NSData summary provider", "__NSCFData", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSDataSummaryProvider, "NSData summary provider", "CFDataRef", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSDataSummaryProvider, "NSData summary provider", "CFMutableDataRef", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSMachPortSummaryProvider, "NSMachPort summary provider", "NSMachPort", appkit_flags); AddCXXSummary( objc_category_sp, lldb_private::formatters::NSNotificationSummaryProvider, "NSNotification summary provider", "NSNotification", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSNotificationSummaryProvider, "NSNotification summary provider", "NSConcreteNotification", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSNumberSummaryProvider, "NSNumber summary provider", "NSNumber", appkit_flags); AddCXXSummary( objc_category_sp, lldb_private::formatters::NSNumberSummaryProvider, "NSNumber summary provider", "NSConstantIntegerNumber", appkit_flags); AddCXXSummary( objc_category_sp, lldb_private::formatters::NSNumberSummaryProvider, "NSNumber summary provider", "NSConstantDoubleNumber", appkit_flags); AddCXXSummary( objc_category_sp, lldb_private::formatters::NSNumberSummaryProvider, "NSNumber summary provider", "NSConstantFloatNumber", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSNumberSummaryProvider, "CFNumberRef summary provider", "CFNumberRef", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSNumberSummaryProvider, "NSNumber summary provider", "__NSCFBoolean", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSNumberSummaryProvider, "NSNumber summary provider", "__NSCFNumber", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSNumberSummaryProvider, "NSNumber summary provider", "NSCFBoolean", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSNumberSummaryProvider, "NSNumber summary provider", "NSCFNumber", appkit_flags); AddCXXSummary( objc_category_sp, lldb_private::formatters::NSNumberSummaryProvider, "NSDecimalNumber summary provider", "NSDecimalNumber", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSURLSummaryProvider, "NSURL summary provider", "NSURL", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSURLSummaryProvider, "NSURL summary provider", "CFURLRef", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSDateSummaryProvider, "NSDate summary provider", "NSDate", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSDateSummaryProvider, "NSDate summary provider", "__NSDate", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSDateSummaryProvider, "NSDate summary provider", "__NSTaggedDate", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSDateSummaryProvider, "NSDate summary provider", "NSCalendarDate", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSTimeZoneSummaryProvider, "NSTimeZone summary provider", "NSTimeZone", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSTimeZoneSummaryProvider, "NSTimeZone summary provider", "CFTimeZoneRef", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSTimeZoneSummaryProvider, "NSTimeZone summary provider", "__NSTimeZone", appkit_flags); // CFAbsoluteTime is actually a double rather than a pointer to an object we // do not care about the numeric value, since it is probably meaningless to // users appkit_flags.SetDontShowValue(true); AddCXXSummary( objc_category_sp, lldb_private::formatters::CFAbsoluteTimeSummaryProvider, "CFAbsoluteTime summary provider", "CFAbsoluteTime", appkit_flags); appkit_flags.SetDontShowValue(false); AddCXXSummary(objc_category_sp, lldb_private::formatters::NSIndexSetSummaryProvider, "NSIndexSet summary provider", "NSIndexSet", appkit_flags); AddCXXSummary( objc_category_sp, lldb_private::formatters::NSIndexSetSummaryProvider, "NSIndexSet summary provider", "NSMutableIndexSet", appkit_flags); AddStringSummary(objc_category_sp, "@\"${var.month%d}/${var.day%d}/${var.year%d} " "${var.hour%d}:${var.minute%d}:${var.second}\"", "CFGregorianDate", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::CFBitVectorSummaryProvider, "CFBitVector summary provider", "CFBitVectorRef", appkit_flags); AddCXXSummary( objc_category_sp, lldb_private::formatters::CFBitVectorSummaryProvider, "CFBitVector summary provider", "CFMutableBitVectorRef", appkit_flags); AddCXXSummary(objc_category_sp, lldb_private::formatters::CFBitVectorSummaryProvider, "CFBitVector summary provider", "__CFBitVector", appkit_flags); AddCXXSummary( objc_category_sp, lldb_private::formatters::CFBitVectorSummaryProvider, "CFBitVector summary provider", "__CFMutableBitVector", appkit_flags); } static void LoadCoreMediaFormatters(TypeCategoryImplSP objc_category_sp) { if (!objc_category_sp) return; TypeSummaryImpl::Flags cm_flags; cm_flags.SetCascades(true) .SetDontShowChildren(false) .SetDontShowValue(false) .SetHideItemNames(false) .SetShowMembersOneLiner(false) .SetSkipPointers(false) .SetSkipReferences(false); AddCXXSummary(objc_category_sp, lldb_private::formatters::CMTimeSummaryProvider, "CMTime summary provider", "CMTime", cm_flags); } lldb::TypeCategoryImplSP ObjCLanguage::GetFormatters() { static llvm::once_flag g_initialize; static TypeCategoryImplSP g_category; llvm::call_once(g_initialize, [this]() -> void { DataVisualization::Categories::GetCategory(ConstString(GetPluginName()), g_category); if (g_category) { LoadCoreMediaFormatters(g_category); LoadObjCFormatters(g_category); } }); return g_category; } std::vector ObjCLanguage::GetPossibleFormattersMatches(ValueObject &valobj, lldb::DynamicValueType use_dynamic) { std::vector result; if (use_dynamic == lldb::eNoDynamicValues) return result; CompilerType compiler_type(valobj.GetCompilerType()); const bool check_cpp = false; const bool check_objc = true; bool canBeObjCDynamic = compiler_type.IsPossibleDynamicType(nullptr, check_cpp, check_objc); if (canBeObjCDynamic && ClangUtil::IsClangType(compiler_type)) { do { lldb::ProcessSP process_sp = valobj.GetProcessSP(); if (!process_sp) break; ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp); if (runtime == nullptr) break; ObjCLanguageRuntime::ClassDescriptorSP objc_class_sp( runtime->GetClassDescriptor(valobj)); if (!objc_class_sp) break; if (ConstString name = objc_class_sp->GetClassName()) result.push_back( {name, valobj.GetTargetSP()->GetDebugger().GetScriptInterpreter(), TypeImpl(objc_class_sp->GetType()), FormattersMatchCandidate::Flags{}}); } while (false); } return result; } std::unique_ptr ObjCLanguage::GetTypeScavenger() { class ObjCScavengerResult : public Language::TypeScavenger::Result { public: ObjCScavengerResult(CompilerType type) : Language::TypeScavenger::Result(), m_compiler_type(type) {} bool IsValid() override { return m_compiler_type.IsValid(); } bool DumpToStream(Stream &stream, bool print_help_if_available) override { if (IsValid()) { m_compiler_type.DumpTypeDescription(&stream); stream.EOL(); return true; } return false; } private: CompilerType m_compiler_type; }; class ObjCRuntimeScavenger : public Language::TypeScavenger { protected: bool Find_Impl(ExecutionContextScope *exe_scope, const char *key, ResultSet &results) override { bool result = false; if (auto *process = exe_scope->CalculateProcess().get()) { if (auto *objc_runtime = ObjCLanguageRuntime::Get(*process)) { if (auto *decl_vendor = objc_runtime->GetDeclVendor()) { ConstString name(key); for (const CompilerType &type : decl_vendor->FindTypes(name, /*max_matches*/ UINT32_MAX)) { result = true; std::unique_ptr result( new ObjCScavengerResult(type)); results.insert(std::move(result)); } } } } return result; } friend class lldb_private::ObjCLanguage; }; class ObjCModulesScavenger : public Language::TypeScavenger { protected: bool Find_Impl(ExecutionContextScope *exe_scope, const char *key, ResultSet &results) override { bool result = false; if (auto *target = exe_scope->CalculateTarget().get()) { auto *persistent_vars = llvm::cast( target->GetPersistentExpressionStateForLanguage( lldb::eLanguageTypeC)); if (std::shared_ptr clang_modules_decl_vendor = persistent_vars->GetClangModulesDeclVendor()) { ConstString key_cs(key); auto types = clang_modules_decl_vendor->FindTypes( key_cs, /*max_matches*/ UINT32_MAX); if (!types.empty()) { result = true; std::unique_ptr result( new ObjCScavengerResult(types.front())); results.insert(std::move(result)); } } } return result; } friend class lldb_private::ObjCLanguage; }; class ObjCDebugInfoScavenger : public Language::ImageListTypeScavenger { public: CompilerType AdjustForInclusion(CompilerType &candidate) override { LanguageType lang_type(candidate.GetMinimumLanguage()); if (!Language::LanguageIsObjC(lang_type)) return CompilerType(); if (candidate.IsTypedefType()) return candidate.GetTypedefedType(); return candidate; } }; return std::unique_ptr( new Language::EitherTypeScavenger()); } std::pair ObjCLanguage::GetFormatterPrefixSuffix(llvm::StringRef type_hint) { static constexpr llvm::StringRef empty; static const llvm::StringMap< std::pair> g_affix_map = { {"CFBag", {"@", empty}}, {"CFBinaryHeap", {"@", empty}}, {"NSString", {"@", empty}}, {"NSString*", {"@", empty}}, {"NSNumber:char", {"(char)", empty}}, {"NSNumber:short", {"(short)", empty}}, {"NSNumber:int", {"(int)", empty}}, {"NSNumber:long", {"(long)", empty}}, {"NSNumber:int128_t", {"(int128_t)", empty}}, {"NSNumber:float", {"(float)", empty}}, {"NSNumber:double", {"(double)", empty}}, {"NSData", {"@\"", "\""}}, {"NSArray", {"@\"", "\""}}, }; return g_affix_map.lookup(type_hint); } bool ObjCLanguage::IsNilReference(ValueObject &valobj) { const uint32_t mask = eTypeIsObjC | eTypeIsPointer; bool isObjCpointer = (((valobj.GetCompilerType().GetTypeInfo(nullptr)) & mask) == mask); if (!isObjCpointer) return false; bool canReadValue = true; bool isZero = valobj.GetValueAsUnsigned(0, &canReadValue) == 0; return canReadValue && isZero; } bool ObjCLanguage::IsSourceFile(llvm::StringRef file_path) const { const auto suffixes = {".h", ".m", ".M"}; for (auto suffix : suffixes) { if (file_path.ends_with_insensitive(suffix)) return true; } return false; }