From 4cda6e058b9e8ab0f7118e836794d29409ef4223 Mon Sep 17 00:00:00 2001 From: Jim Ingham Date: Fri, 7 Oct 2011 22:23:45 +0000 Subject: [PATCH] Move the responsibility for translating the various eFunctionNameType lookups to the SymbolFIle (it was done mostly in the BreakpointResolverName resolver before.) Then tailor our searches to the way the indexed maps are laid out. This removes a bunch of test case failures using indexed dSYM's. llvm-svn: 141428 --- .../lldb/Breakpoint/BreakpointResolverName.h | 8 - lldb/include/lldb/Target/CPPLanguageRuntime.h | 9 + .../include/lldb/Target/ObjCLanguageRuntime.h | 20 +- lldb/source/API/SBTarget.cpp | 4 +- .../Breakpoint/BreakpointResolverName.cpp | 110 +---- .../SymbolFile/DWARF/HashedNameToDIE.h | 13 + .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 456 ++++++++++++------ .../SymbolFile/DWARF/SymbolFileDWARF.h | 18 +- lldb/source/Target/CPPLanguageRuntime.cpp | 78 +++ lldb/test/python_api/target/TestTargetAPI.py | 3 + 10 files changed, 445 insertions(+), 274 deletions(-) diff --git a/lldb/include/lldb/Breakpoint/BreakpointResolverName.h b/lldb/include/lldb/Breakpoint/BreakpointResolverName.h index cf69231824ac..2732f4782799 100644 --- a/lldb/include/lldb/Breakpoint/BreakpointResolverName.h +++ b/lldb/include/lldb/Breakpoint/BreakpointResolverName.h @@ -72,14 +72,6 @@ public: protected: ConstString m_func_name; - // "m_basename_filter" is used to filter results after searching for - // "m_func_name" first. This is used when we are asked to set a breakpoint - // at "foo::bar::baz" (C++ function in namespace or in a class). For - // "foo::bar::baz" we will place "baz" into m_func_name and search for all - // matching basename and methods that match "baz", then we will filter the - // results by checking if the demangled name contains "m_basename_filter" - // which would be set to "foo::bar::baz". - std::string m_basename_filter; uint32_t m_func_name_type_mask; // See FunctionNameType ConstString m_class_name; // FIXME: Not used yet. The idea would be to stop on methods of this class. RegularExpression m_regex; diff --git a/lldb/include/lldb/Target/CPPLanguageRuntime.h b/lldb/include/lldb/Target/CPPLanguageRuntime.h index 474b0ba8c06e..e2da738fcbd9 100644 --- a/lldb/include/lldb/Target/CPPLanguageRuntime.h +++ b/lldb/include/lldb/Target/CPPLanguageRuntime.h @@ -42,6 +42,15 @@ public: virtual bool GetObjectDescription (Stream &str, Value &value, ExecutionContextScope *exe_scope); + static bool + IsCPPMangledName(const char *name); + + static bool + IsPossibleCPPCall (const char *name, const char *&base_name_start, const char *&base_name_end); + + static bool + StripNamespacesFromVariableName (const char *name, const char *&base_name_start, const char *&base_name_end); + protected: //------------------------------------------------------------------ // Classes that inherit from CPPLanguageRuntime can see and modify these diff --git a/lldb/include/lldb/Target/ObjCLanguageRuntime.h b/lldb/include/lldb/Target/ObjCLanguageRuntime.h index d1b12cccb220..950740957956 100644 --- a/lldb/include/lldb/Target/ObjCLanguageRuntime.h +++ b/lldb/include/lldb/Target/ObjCLanguageRuntime.h @@ -102,7 +102,25 @@ public: static bool IsPossibleObjCMethodName (const char *name) { - return (name && (name[0] == '+' || name[0] == '-') && name[1] == '['); + if (!name) + return false; + bool starts_right = (name[0] == '+' || name[0] == '-') && name[1] == '['; + bool ends_right = (name[strlen(name) - 1] == ']'); + return (starts_right && ends_right); + } + + static bool + IsPossibleObjCSelector (const char *name) + { + if (!name) + return false; + + if (strchr(name, ':') == NULL) + return true; + else if (name[strlen(name) - 1] == ':') + return true; + else + return false; } protected: diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp index 28bb109108f9..dff700798811 100644 --- a/lldb/source/API/SBTarget.cpp +++ b/lldb/source/API/SBTarget.cpp @@ -588,11 +588,11 @@ SBTarget::BreakpointCreateByName (const char *symbol_name, const char *module_na { FileSpecList module_spec_list; module_spec_list.Append (FileSpec (module_name, false)); - *sb_bp = m_opaque_sp->CreateBreakpoint (&module_spec_list, NULL, symbol_name, eFunctionNameTypeFull | eFunctionNameTypeBase, false); + *sb_bp = m_opaque_sp->CreateBreakpoint (&module_spec_list, NULL, symbol_name, eFunctionNameTypeAuto, false); } else { - *sb_bp = m_opaque_sp->CreateBreakpoint (NULL, NULL, symbol_name, eFunctionNameTypeFull | eFunctionNameTypeBase, false); + *sb_bp = m_opaque_sp->CreateBreakpoint (NULL, NULL, symbol_name, eFunctionNameTypeAuto, false); } } diff --git a/lldb/source/Breakpoint/BreakpointResolverName.cpp b/lldb/source/Breakpoint/BreakpointResolverName.cpp index 42889091a979..9df1dd73334d 100644 --- a/lldb/source/Breakpoint/BreakpointResolverName.cpp +++ b/lldb/source/Breakpoint/BreakpointResolverName.cpp @@ -30,55 +30,14 @@ BreakpointResolverName::BreakpointResolverName bool skip_prologue ) : BreakpointResolver (bkpt, BreakpointResolver::NameResolver), - m_func_name (), - m_basename_filter (), + m_func_name (func_name), m_func_name_type_mask (func_name_type_mask), m_class_name (), m_regex (), m_match_type (type), m_skip_prologue (skip_prologue) { - if (func_name_type_mask == eFunctionNameTypeAuto) - { - if ((::strchr (func_name, '(' ) != NULL) || - (::strstr (func_name, "-[") == func_name) || - (::strstr (func_name, "+[") == func_name)) - { - // We have a name that contains an open parens, or starts with - // "+[" or "-[", so this looks like a complete function prototype - m_func_name_type_mask = eFunctionNameTypeFull; - } - else - { - // We don't have a full function name, but we might have a partial - // function basename with namespaces or classes - if (::strstr (func_name, "::") != NULL) - { - // Keep the full name in "m_basename_filter" - m_basename_filter = func_name; - // Now set "m_func_name" to just the function basename - m_func_name.SetCString(m_basename_filter.c_str() + m_basename_filter.rfind("::") + 2); - // We have a name with a double colon which means we have a - // function name that is a C++ method or a function in a C++ - // namespace - m_func_name_type_mask = eFunctionNameTypeBase | eFunctionNameTypeMethod; - } - else if (::strstr (func_name, ":") != NULL) - { - // Single colon => selector - m_func_name_type_mask = eFunctionNameTypeSelector; - } - else - { - // just a basename by default - m_func_name_type_mask = eFunctionNameTypeBase; - } - } - } - if (!m_func_name) - m_func_name.SetCString(func_name); - if (m_match_type == Breakpoint::Regexp) { if (!m_regex.Compile (m_func_name.AsCString())) @@ -178,7 +137,7 @@ BreakpointResolverName::SearchCallback if (num_functions == 0 && !filter_by_cu) { - if (m_func_name_type_mask & (eFunctionNameTypeBase | eFunctionNameTypeFull)) + if (m_func_name_type_mask & (eFunctionNameTypeBase | eFunctionNameTypeFull | eFunctionNameTypeAuto)) context.module_sp->FindSymbolsWithNameAndType (m_func_name, eSymbolTypeCode, sym_list); } } @@ -217,68 +176,7 @@ BreakpointResolverName::SearchCallback } } } - - - if (!m_basename_filter.empty()) - { - // Filter out any matches whose names don't contain the basename filter - const char *basename_filter = m_basename_filter.c_str(); - if (func_list.GetSize()) - { - bool remove = false; - for (i = 0; i < func_list.GetSize(); remove = false) - { - if (func_list.GetContextAtIndex(i, sc) == false) - remove = true; - else if (sc.function == NULL) - remove = true; - else - { - const InlineFunctionInfo* inlined_info = NULL; - - if (sc.block) - inlined_info = sc.block->GetInlinedFunctionInfo(); - if (inlined_info) - { - if (::strstr (inlined_info->GetName().AsCString(), basename_filter) == NULL) - remove = true; - } - else if (::strstr (sc.function->GetName().AsCString(), basename_filter) == NULL) - remove = true; - } - - if (remove) - { - func_list.RemoveContextAtIndex(i); - continue; - } - i++; - } - } - - if (sym_list.GetSize()) - { - bool remove = false; - for (i = 0; i < sym_list.GetSize(); remove = false) - { - if (sym_list.GetContextAtIndex(i, sc) == false) - remove = true; - else if (sc.symbol == NULL) - remove = true; - else if (::strstr (sc.symbol->GetName().AsCString(), basename_filter) == NULL) - remove = true; - - if (remove) - { - sym_list.RemoveContextAtIndex(i); - continue; - } - i++; - } - } - } - // Remove any duplicates between the funcion list and the symbol list if (func_list.GetSize()) { @@ -395,10 +293,8 @@ BreakpointResolverName::GetDescription (Stream *s) { if (m_match_type == Breakpoint::Regexp) s->Printf("regex = '%s'", m_regex.GetText()); - else if (m_basename_filter.empty()) - s->Printf("name = '%s'", m_func_name.AsCString()); else - s->Printf("name = '%s'", m_basename_filter.c_str()); + s->Printf("name = '%s'", m_func_name.AsCString()); } void diff --git a/lldb/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h b/lldb/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h index 909f6aaeb3e2..81da55a13b2c 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h @@ -652,6 +652,19 @@ struct DWARFMappedHash return die_offsets.size(); } + size_t + FindByName (const char *name, DIEArray &die_offsets) + { + Pair kv_pair; + size_t old_size = die_offsets.size(); + if (Find (name, kv_pair)) + { + die_offsets.swap(kv_pair.value); + return die_offsets.size() - old_size; + } + return 0; + } + protected: const lldb_private::DataExtractor &m_data; const lldb_private::DataExtractor &m_string_table; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index e25acbb28f95..5204d070ff5e 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -43,6 +43,7 @@ #include "lldb/Symbol/VariableList.h" #include "lldb/Target/ObjCLanguageRuntime.h" +#include "lldb/Target/CPPLanguageRuntime.h" #include "DWARFCompileUnit.h" #include "DWARFDebugAbbrev.h" @@ -1655,14 +1656,19 @@ SymbolFileDWARF::GetFunction (DWARFCompileUnit* curr_cu, const DWARFDebugInfoEnt { sc.Clear(); // Check if the symbol vendor already knows about this compile unit? - sc.module_sp = m_obj_file->GetModule(); sc.comp_unit = GetCompUnitForDWARFCompUnit(curr_cu, UINT32_MAX); sc.function = sc.comp_unit->FindFunctionByUID (func_die->GetOffset()).get(); if (sc.function == NULL) sc.function = ParseCompileUnitFunction(sc, curr_cu, func_die); - - return sc.function != NULL; + + if (sc.function) + { + sc.module_sp = sc.function->CalculateSymbolContextModule(); + return true; + } + + return false; } uint32_t @@ -1969,11 +1975,13 @@ SymbolFileDWARF::FindGlobalVariables (const ConstString &name, bool append, uint if (m_apple_names_ap.get()) { const char *name_cstr = name.GetCString(); - DWARFMappedHash::MemoryTable::Pair kv_pair; - if (m_apple_names_ap->Find (name_cstr, kv_pair)) - { - die_offsets.swap(kv_pair.value); - } + const char *base_name_start; + const char *base_name_end = NULL; + + if (!CPPLanguageRuntime::StripNamespacesFromVariableName(name_cstr, base_name_start, base_name_end)) + base_name_start = name_cstr; + + m_apple_names_ap->FindByName (base_name_start, die_offsets); } else { @@ -2080,96 +2088,76 @@ SymbolFileDWARF::FindGlobalVariables(const RegularExpression& regex, bool append return variables.GetSize() - original_size; } - -uint32_t -SymbolFileDWARF::ResolveFunctions (const DIEArray &die_offsets, - SymbolContextList& sc_list, - const ConstString &name, - uint32_t name_type_mask) +bool +SymbolFileDWARF::ResolveFunction (dw_offset_t die_offset, + DWARFCompileUnit *&dwarf_cu, + SymbolContextList& sc_list) { + SymbolContext sc; + DWARFDebugInfo* info = DebugInfo(); + bool resolved_it = false; + if (info == NULL) - return 0; + return resolved_it; + + DWARFDebugInfoEntry *die = info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu); - const uint32_t sc_list_initial_size = sc_list.GetSize(); - SymbolContext sc; - sc.module_sp = m_obj_file->GetModule(); - assert (sc.module_sp); + // If we were passed a die that is not a function, just return false... + if (die->Tag() != DW_TAG_subprogram && die->Tag() != DW_TAG_inlined_subroutine) + return false; - DWARFCompileUnit* dwarf_cu = NULL; - const size_t num_matches = die_offsets.size(); - for (size_t i=0; iTag() == DW_TAG_inlined_subroutine) { - const dw_offset_t die_offset = die_offsets[i]; - const DWARFDebugInfoEntry* die = info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu); + inlined_die = die; - // If we aren't doing full names, - if ((name_type_mask & eFunctionNameTypeFull) == 0) + while ((die = die->GetParent()) != NULL) { - const char *name_cstr = name.GetCString(); - if (ObjCLanguageRuntime::IsPossibleObjCMethodName(name_cstr)) - continue; + if (die->Tag() == DW_TAG_subprogram) + break; + } + } + assert (die->Tag() == DW_TAG_subprogram); + if (GetFunction (dwarf_cu, die, sc)) + { + Address addr; + // Parse all blocks if needed + if (inlined_die) + { + sc.block = sc.function->GetBlock (true).FindBlockByID (inlined_die->GetOffset()); + assert (sc.block != NULL); + if (sc.block->GetStartAddress (addr) == false) + addr.Clear(); + } + else + { + sc.block = NULL; + addr = sc.function->GetAddressRange().GetBaseAddress(); } - - const DWARFDebugInfoEntry* inlined_die = NULL; - if (die->Tag() == DW_TAG_inlined_subroutine) + if (addr.IsValid()) { - // We only are looking for selectors, which disallows anything inlined - if (name_type_mask == eFunctionNameTypeSelector) - continue; - inlined_die = die; - - while ((die = die->GetParent()) != NULL) + // We found the function, so we should find the line table + // and line table entry as well + LineTable *line_table = sc.comp_unit->GetLineTable(); + if (line_table == NULL) { - if (die->Tag() == DW_TAG_subprogram) - break; - } - } - if (die->Tag() == DW_TAG_subprogram) - { - if (GetFunction (dwarf_cu, die, sc)) - { - Address addr; - // Parse all blocks if needed - if (inlined_die) - { - sc.block = sc.function->GetBlock (true).FindBlockByID (inlined_die->GetOffset()); - assert (sc.block != NULL); - if (sc.block->GetStartAddress (addr) == false) - addr.Clear(); - } - else - { - sc.block = NULL; - addr = sc.function->GetAddressRange().GetBaseAddress(); - } - - if (addr.IsValid()) - { - - // We found the function, so we should find the line table - // and line table entry as well - LineTable *line_table = sc.comp_unit->GetLineTable(); - if (line_table == NULL) - { - if (ParseCompileUnitLineTable(sc)) - line_table = sc.comp_unit->GetLineTable(); - } - if (line_table != NULL) - line_table->FindLineEntryByAddress (addr, sc.line_entry); - - sc_list.Append(sc); - } + if (ParseCompileUnitLineTable(sc)) + line_table = sc.comp_unit->GetLineTable(); } + if (line_table != NULL) + line_table->FindLineEntryByAddress (addr, sc.line_entry); + + sc_list.Append(sc); + resolved_it = true; } } - return sc_list.GetSize() - sc_list_initial_size; + + return resolved_it; } - - void SymbolFileDWARF::FindFunctions (const ConstString &name, const NameToDIE &name_to_die, @@ -2216,66 +2204,79 @@ SymbolFileDWARF::ParseFunctions (const DIEArray &die_offsets, if (num_matches) { SymbolContext sc; - sc.module_sp = m_obj_file->GetModule(); DWARFCompileUnit* dwarf_cu = NULL; - const DWARFDebugInfoEntry* die = NULL; - DWARFDebugInfo* debug_info = DebugInfo(); for (size_t i=0; iGetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu); - const DWARFDebugInfoEntry* inlined_die = NULL; - if (die->Tag() == DW_TAG_inlined_subroutine) - { - inlined_die = die; + ResolveFunction (die_offset, dwarf_cu, sc_list); + } + } +} + +bool +SymbolFileDWARF::FunctionDieMatchesPartialName (const DWARFDebugInfoEntry* die, + const DWARFCompileUnit *dwarf_cu, + uint32_t name_type_mask, + const char *partial_name, + const char *base_name_start, + const char *base_name_end) +{ + // If we are looking only for methods, throw away all the ones that aren't in C++ classes: + if (name_type_mask == eFunctionNameTypeMethod + || name_type_mask == eFunctionNameTypeBase) + { + clang::DeclContext *containing_decl_ctx = GetClangDeclContextContainingDIEOffset(die->GetOffset()); + if (!containing_decl_ctx) + return false; - while ((die = die->GetParent()) != NULL) - { - if (die->Tag() == DW_TAG_subprogram) - break; - } - } - assert (die->Tag() == DW_TAG_subprogram); - if (GetFunction (dwarf_cu, die, sc)) + bool is_cxx_method = (containing_decl_ctx->getDeclKind() == clang::Decl::CXXRecord); + + if (!is_cxx_method && name_type_mask == eFunctionNameTypeMethod) + return false; + if (is_cxx_method && name_type_mask == eFunctionNameTypeBase) + return false; + } + + // Now we need to check whether the name we got back for this type matches the extra specifications + // that were in the name we're looking up: + if (base_name_start != partial_name || *base_name_end != '\0') + { + // First see if the stuff to the left matches the full name. To do that let's see if + // we can pull out the mips linkage name attribute: + + Mangled best_name; + + DWARFDebugInfoEntry::Attributes attributes; + die->GetAttributes(this, dwarf_cu, NULL, attributes); + uint32_t idx = attributes.FindAttributeIndex(DW_AT_MIPS_linkage_name); + if (idx != UINT32_MAX) + { + DWARFFormValue form_value; + if (attributes.ExtractFormValueAtIndex(this, idx, form_value)) { - Address addr; - // Parse all blocks if needed - if (inlined_die) - { - sc.block = sc.function->GetBlock (true).FindBlockByID (inlined_die->GetOffset()); - assert (sc.block != NULL); - if (sc.block->GetStartAddress (addr) == false) - addr.Clear(); - } - else - { - sc.block = NULL; - addr = sc.function->GetAddressRange().GetBaseAddress(); - } - - if (addr.IsValid()) + const char *name = form_value.AsCString(&get_debug_str_data()); + best_name.SetValue (name, true); + } + } + if (best_name) + { + const char *demangled = best_name.GetDemangledName().GetCString(); + if (demangled) + { + std::string name_no_parens(partial_name, base_name_end - partial_name); + if (strstr (demangled, name_no_parens.c_str()) == NULL) { - - // We found the function, so we should find the line table - // and line table entry as well - LineTable *line_table = sc.comp_unit->GetLineTable(); - if (line_table == NULL) - { - if (ParseCompileUnitLineTable(sc)) - line_table = sc.comp_unit->GetLineTable(); - } - if (line_table != NULL) - line_table->FindLineEntryByAddress (addr, sc.line_entry); - - sc_list.Append(sc); + printf ("name: \"%s\" didn't match full name: \"%s\".\n", partial_name, demangled); + return false; } } } } + + return true; } - uint32_t SymbolFileDWARF::FindFunctions (const ConstString &name, uint32_t name_type_mask, @@ -2299,18 +2300,134 @@ SymbolFileDWARF::FindFunctions (const ConstString &name, // If we aren't appending the results to this list, then clear the list if (!append) sc_list.Clear(); + + // If name is empty then we won't find anything. + if (name.IsEmpty()) + return 0; // Remember how many sc_list are in the list before we search in case // we are appending the results to a variable list. const uint32_t original_size = sc_list.GetSize(); + const char *name_cstr = name.GetCString(); + uint32_t effective_name_type_mask = eFunctionNameTypeNone; + const char *base_name_start = name_cstr; + const char *base_name_end = name_cstr + strlen(name_cstr); + + if (name_type_mask & eFunctionNameTypeAuto) + { + if (CPPLanguageRuntime::IsCPPMangledName (name_cstr)) + effective_name_type_mask = eFunctionNameTypeFull; + else if (ObjCLanguageRuntime::IsPossibleObjCMethodName (name_cstr)) + effective_name_type_mask = eFunctionNameTypeFull; + else + { + if (ObjCLanguageRuntime::IsPossibleObjCSelector(name_cstr)) + effective_name_type_mask |= eFunctionNameTypeSelector; + + if (CPPLanguageRuntime::IsPossibleCPPCall(name_cstr, base_name_start, base_name_end)) + effective_name_type_mask |= (eFunctionNameTypeMethod | eFunctionNameTypeBase); + } + } + else + { + effective_name_type_mask = name_type_mask; + if (effective_name_type_mask & eFunctionNameTypeMethod || name_type_mask & eFunctionNameTypeBase) + { + // If they've asked for a CPP method or function name and it can't be that, we don't + // even need to search for CPP methods or names. + if (!CPPLanguageRuntime::IsPossibleCPPCall(name_cstr, base_name_start, base_name_end)) + { + effective_name_type_mask &= ~(eFunctionNameTypeMethod | eFunctionNameTypeBase); + if (effective_name_type_mask == eFunctionNameTypeNone) + return 0; + } + } + + if (effective_name_type_mask & eFunctionNameTypeSelector) + { + if (!ObjCLanguageRuntime::IsPossibleObjCSelector(name_cstr)) + { + effective_name_type_mask &= ~(eFunctionNameTypeSelector); + if (effective_name_type_mask == eFunctionNameTypeNone) + return 0; + } + } + } + + DWARFDebugInfo* info = DebugInfo(); + if (info == NULL) + return 0; + if (m_apple_names_ap.get()) { - const char *name_cstr = name.GetCString(); - DWARFMappedHash::MemoryTable::Pair kv_pair; - if (m_apple_names_ap->Find (name_cstr, kv_pair)) - ResolveFunctions (kv_pair.value, sc_list, name, name_type_mask); + DIEArray die_offsets; + + uint32_t num_matches = 0; + + if (effective_name_type_mask & eFunctionNameTypeFull) + { + // If they asked for the full name, match what they typed. At some point we may + // want to canonicalize this (strip double spaces, etc. For now, we just add all the + // dies that we find by exact match. + DWARFCompileUnit *dwarf_cu = NULL; + num_matches = m_apple_names_ap->FindByName (name_cstr, die_offsets); + for (uint32_t i = 0; i < num_matches; i++) + ResolveFunction (die_offsets[i], dwarf_cu, sc_list); + } + else + { + DWARFCompileUnit* dwarf_cu = NULL; + + if (effective_name_type_mask & eFunctionNameTypeSelector) + { + num_matches = m_apple_names_ap->FindByName (name_cstr, die_offsets); + // Now make sure these are actually ObjC methods. In this case we can simply look up the name, + // and if it is an ObjC method name, we're good. + + for (uint32_t i = 0; i < num_matches; i++) + { + const DWARFDebugInfoEntry* die = info->GetDIEPtrWithCompileUnitHint (die_offsets[i], &dwarf_cu); + assert (die); + + const char *die_name = die->GetName(this, dwarf_cu); + if (ObjCLanguageRuntime::IsPossibleObjCMethodName(die_name)) + ResolveFunction (die_offsets[i], dwarf_cu, sc_list); + } + die_offsets.clear(); + } + + if (effective_name_type_mask & eFunctionNameTypeMethod + || effective_name_type_mask & eFunctionNameTypeBase) + { + // The apple_names table stores just the "base name" of C++ methods in the table. So we have to + // extract the base name, look that up, and if there is any other information in the name we were + // passed in we have to post-filter based on that. + + // FIXME: Arrange the logic above so that we don't calculate the base name twice: + std::string base_name(base_name_start, base_name_end - base_name_start); + num_matches = m_apple_names_ap->FindByName (base_name.c_str(), die_offsets); + + for (uint32_t i = 0; i < num_matches; i++) + { + dw_offset_t offset = die_offsets[i]; + const DWARFDebugInfoEntry* die = info->GetDIEPtrWithCompileUnitHint (offset, &dwarf_cu); + assert (die); + if (!FunctionDieMatchesPartialName(die, + dwarf_cu, + effective_name_type_mask, + name_cstr, + base_name_start, + base_name_end)) + continue; + + // If we get to here, the die is good, and we should add it: + ResolveFunction (offset, dwarf_cu, sc_list); + } + die_offsets.clear(); + } + } } else { @@ -2319,24 +2436,73 @@ SymbolFileDWARF::FindFunctions (const ConstString &name, if (!m_indexed) Index (); - if (name_type_mask & eFunctionNameTypeBase) - FindFunctions (name, m_function_basename_index, sc_list); - if (name_type_mask & eFunctionNameTypeFull) FindFunctions (name, m_function_fullname_index, sc_list); + std::string base_name(base_name_start, base_name_end - base_name_start); + ConstString base_name_const(base_name.c_str()); + DIEArray die_offsets; + DWARFCompileUnit *dwarf_cu = NULL; + + if (effective_name_type_mask & eFunctionNameTypeBase) + { + uint32_t num_base = m_function_basename_index.Find(base_name_const, die_offsets); + { + for (uint32_t i = 0; i < num_base; i++) + { + dw_offset_t offset = die_offsets[i]; + const DWARFDebugInfoEntry* die = info->GetDIEPtrWithCompileUnitHint (offset, &dwarf_cu); + assert (die); + if (!FunctionDieMatchesPartialName(die, + dwarf_cu, + effective_name_type_mask, + name_cstr, + base_name_start, + base_name_end)) + continue; + + // If we get to here, the die is good, and we should add it: + ResolveFunction (offset, dwarf_cu, sc_list); + } + } + die_offsets.clear(); + } + if (name_type_mask & eFunctionNameTypeMethod) - FindFunctions (name, m_function_method_index, sc_list); + { + uint32_t num_base = m_function_method_index.Find(base_name_const, die_offsets); + { + for (uint32_t i = 0; i < num_base; i++) + { + dw_offset_t offset = die_offsets[i]; + const DWARFDebugInfoEntry* die = info->GetDIEPtrWithCompileUnitHint (offset, &dwarf_cu); + assert (die); + if (!FunctionDieMatchesPartialName(die, + dwarf_cu, + effective_name_type_mask, + name_cstr, + base_name_start, + base_name_end)) + continue; + + // If we get to here, the die is good, and we should add it: + ResolveFunction (offset, dwarf_cu, sc_list); + } + } + die_offsets.clear(); + } if (name_type_mask & eFunctionNameTypeSelector) + { FindFunctions (name, m_function_selector_index, sc_list); + } + } // Return the number of variable that were appended to the list return sc_list.GetSize() - original_size; } - uint32_t SymbolFileDWARF::FindFunctions(const RegularExpression& regex, bool append, SymbolContextList& sc_list) { @@ -2363,13 +2529,13 @@ SymbolFileDWARF::FindFunctions(const RegularExpression& regex, bool append, Symb // we are appending the results to a variable list. uint32_t original_size = sc_list.GetSize(); - // Index the DWARF if we haven't already if (m_apple_names_ap.get()) { FindFunctions (regex, *m_apple_names_ap, sc_list); } else { + // Index the DWARF if we haven't already if (!m_indexed) Index (); @@ -2442,11 +2608,7 @@ SymbolFileDWARF::FindTypes(const SymbolContext& sc, const ConstString &name, boo if (m_apple_types_ap.get()) { const char *name_cstr = name.GetCString(); - DWARFMappedHash::MemoryTable::Pair kv_pair; - if (m_apple_types_ap->Find (name_cstr, kv_pair)) - { - die_offsets.swap(kv_pair.value); - } + m_apple_types_ap->FindByName (name_cstr, die_offsets); } else { @@ -2518,11 +2680,7 @@ SymbolFileDWARF::FindNamespace (const SymbolContext& sc, if (m_apple_namespaces_ap.get()) { const char *name_cstr = name.GetCString(); - DWARFMappedHash::MemoryTable::Pair kv_pair; - if (m_apple_namespaces_ap->Find (name_cstr, kv_pair)) - { - die_offsets.swap(kv_pair.value); - } + m_apple_namespaces_ap->FindByName (name_cstr, die_offsets); } else { @@ -3192,11 +3350,7 @@ SymbolFileDWARF::FindDefinitionTypeForDIE (DWARFCompileUnit* cu, if (m_apple_types_ap.get()) { const char *name_cstr = type_name.GetCString(); - DWARFMappedHash::MemoryTable::Pair kv_pair; - if (m_apple_types_ap->Find (name_cstr, kv_pair)) - { - die_offsets.swap(kv_pair.value); - } + m_apple_types_ap->FindByName (name_cstr, die_offsets); } else { diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index 0f21e8e6e442..134e734a8779 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -322,11 +322,19 @@ protected: uint32_t& byte_stride, uint32_t& bit_stride); - uint32_t ResolveFunctions ( - const DIEArray &die_offsets, - lldb_private::SymbolContextList& sc_list, - const lldb_private::ConstString &name, - uint32_t name_type_mask); + // Given a die_offset, figure out the symbol context representing that die. + bool ResolveFunction ( + dw_offset_t offset, + DWARFCompileUnit *&dwarf_cu, + lldb_private::SymbolContextList& sc_list); + + bool FunctionDieMatchesPartialName ( + const DWARFDebugInfoEntry* die, + const DWARFCompileUnit *dwarf_cu, + uint32_t name_type_mask, + const char *partial_name, + const char *base_name_start, + const char *base_name_end); void FindFunctions( const lldb_private::ConstString &name, diff --git a/lldb/source/Target/CPPLanguageRuntime.cpp b/lldb/source/Target/CPPLanguageRuntime.cpp index d80ed210440c..22fbd8479b5e 100644 --- a/lldb/source/Target/CPPLanguageRuntime.cpp +++ b/lldb/source/Target/CPPLanguageRuntime.cpp @@ -40,3 +40,81 @@ CPPLanguageRuntime::GetObjectDescription (Stream &str, Value &value, ExecutionCo // C++ has no generic way to do this. return false; } + +bool +CPPLanguageRuntime::IsCPPMangledName (const char *name) +{ + // FIXME, we should really run through all the known C++ Language plugins and ask each one if + // this is a C++ mangled name, but we can put that off till there is actually more than one + // we care about. + + if (name && name[0] == '_' && name[1] == 'Z') + return true; + else + return false; +} + +bool +CPPLanguageRuntime::StripNamespacesFromVariableName (const char *name, const char *&base_name_start, const char *&base_name_end) +{ + if (base_name_end == NULL) + base_name_end = name + strlen (name); + + const char *last_colon = NULL; + for (const char *ptr = base_name_end; ptr != name; ptr--) + { + if (*ptr == ':') + { + last_colon = ptr; + break; + } + } + + if (last_colon == NULL) + { + base_name_start = name; + return true; + } + + // Can't have a C++ name that begins with a single ':', nor contains an internal single ':' + if (last_colon == name) + return false; + else if (last_colon[-1] != ':') + return false; + else + { + // FIXME: should check if there is + base_name_start = last_colon + 1; + return true; + } +} +bool +CPPLanguageRuntime::IsPossibleCPPCall (const char *name, const char *&base_name_start, const char *&base_name_end) +{ + if (!name) + return false; + // For now, I really can't handle taking template names apart, so if you + // have < or > I'll say "could be CPP but leave the base_name empty which + // means I couldn't figure out what to use for that. + // FIXME: Do I need to do more sanity checking here? + + if (strchr(name, '>') != NULL || strchr (name, '>') != NULL) + return true; + + size_t name_len = strlen (name); + + if (name[name_len - 1] == ')') + { + // We've got arguments. + base_name_end = strchr (name, '('); + if (base_name_end == NULL) + return false; + + // FIXME: should check that this parenthesis isn't a template specialized + // on a function type or something gross like that... + } + else + base_name_end = name + strlen (name); + + return StripNamespacesFromVariableName (name, base_name_start, base_name_end); +} diff --git a/lldb/test/python_api/target/TestTargetAPI.py b/lldb/test/python_api/target/TestTargetAPI.py index 81d250b497f2..e0cfa4772382 100644 --- a/lldb/test/python_api/target/TestTargetAPI.py +++ b/lldb/test/python_api/target/TestTargetAPI.py @@ -120,6 +120,9 @@ class TargetAPITestCase(TestBase): # Now launch the process, and do not stop at entry point. process = target.LaunchSimple(None, None, os.getcwd()) self.assertTrue(process, PROCESS_IS_VALID) + # Make sure we hit our breakpoint: + thread_list = lldbutil.get_threads_stopped_at_breakpoint (process, breakpoint) + self.assertTrue (len(thread_list) == 1) value_list = target.FindGlobalVariables('my_global_var_of_char_type', 3) self.assertTrue(value_list.GetSize() == 1) -- GitLab