diff --git a/lldb/include/lldb/Breakpoint/BreakpointResolverName.h b/lldb/include/lldb/Breakpoint/BreakpointResolverName.h index cf69231824ac4dcc24b23ca695c8a921d6e31a40..2732f4782799ccd31822befc158a951b63441114 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 474b0ba8c06e91869f3db12c4e670bfd7e0b9de2..e2da738fcbd9a7d74b2674609382ba56552b8830 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 d1b12cccb220cda33a52a578927b89d75a723780..950740957956cbbc5900ed5f9f5bcfdacb7273c8 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 28bb109108f90f21b8bdecc9c45eb3bca5e81858..dff70079881130f4b67782bc78dc4782b815315b 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 42889091a979949cc1d1cebd6d3d25c80cd4dd22..9df1dd73334d5df6e1e026003e9e4340949a19ae 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 909f6aaeb3e2f925c0e494f4e48d2168718ec3b6..81da55a13b2c32c63137f5157f8f97adc8754b9a 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 e25acbb28f95592df66a15a7204ed0eb3f0fc1d3..5204d070ff5e46a68a2d7845ae2aa2b1f9912b50 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 0f21e8e6e442a8b522fabdc9a1da68f38d6b06e2..134e734a87799f08f96b74b665663953f0591a46 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 d80ed210440c474fd37327853ed0aff960b209e5..22fbd8479b5e56d7ad9e2f55326e2caa8f910888 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 81d250b497f2ce9f865e5fbd8fc2ff18292b645b..e0cfa47723827ecad3e95e70e46df2cd39f3b41a 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)