Skip to content

Commit

Permalink
DWARF: Move indexing code from DWARFUnit to ManualDWARFIndex
Browse files Browse the repository at this point in the history
Summary:
I think this makes sense for several reasons:
- better separation of concerns: DWARFUnit's job should be to provide a
  nice interface to its users to access the unit contents.
  ManualDWARFIndex can then use this interface to build an index and
  provide it to its users.
- closer alignment with llvm parsers: there is no indexing equivalent in
  llvm, and there probably never will be, as the index is very centered
  around how lldb wants to access debug info. If we ever switch to
  llvm's parser, this will allow us swap out DWARFUnit implementations
  and keep indexing as-is.
- closer proximity of the indexing code to AppleDWARFIndex will make it
  easier to keep the two in sync (e.g. right now the two use very
  different algorithms to determine whether a DW_TAG_subroutine
  represents a "method"). This is my primary motivation for making this
  change now, but I am leaving this work to a separate patch.

The only interface change to DWARFUnit I needed to make was to add an
efficient way to iterate over the list of all DIEs. Adding this also
aligns us closer to the llvm parser.

Reviewers: JDevlieghere, clayborg, aprantl

Subscribers: lldb-commits

Differential Revision: https://reviews.llvm.org/D47253

llvm-svn: 333178
  • Loading branch information
labath committed May 24, 2018
1 parent 93d7b13 commit b7b2424
Show file tree
Hide file tree
Showing 4 changed files with 346 additions and 346 deletions.
330 changes: 1 addition & 329 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
Expand Up @@ -9,20 +9,18 @@

#include "DWARFUnit.h"

#include "Plugins/Language/ObjC/ObjCLanguage.h"
#include "lldb/Core/Module.h"
#include "lldb/Host/StringConvert.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/LineTable.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Utility/StreamString.h"
#include "lldb/Utility/Timer.h"

#include "DWARFDIECollection.h"
#include "DWARFDebugAbbrev.h"
#include "DWARFDebugAranges.h"
#include "DWARFDebugInfo.h"
#include "LogChannelDWARF.h"
#include "NameToDIE.h"
#include "SymbolFileDWARFDebugMap.h"
#include "SymbolFileDWARFDwo.h"

Expand Down Expand Up @@ -627,332 +625,6 @@ SymbolFileDWARFDwo *DWARFUnit::GetDwoSymbolFile() const {

dw_offset_t DWARFUnit::GetBaseObjOffset() const { return m_base_obj_offset; }

void DWARFUnit::Index(NameToDIE &func_basenames, NameToDIE &func_fullnames,
NameToDIE &func_methods, NameToDIE &func_selectors,
NameToDIE &objc_class_selectors, NameToDIE &globals,
NameToDIE &types, NameToDIE &namespaces) {
assert(!m_dwarf->GetBaseCompileUnit() &&
"DWARFUnit associated with .dwo or .dwp "
"should not be indexed directly");

Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS));

if (log) {
m_dwarf->GetObjectFile()->GetModule()->LogMessage(
log, "DWARFUnit::Index() for compile unit at .debug_info[0x%8.8x]",
GetOffset());
}

const LanguageType cu_language = GetLanguageType();
DWARFFormValue::FixedFormSizes fixed_form_sizes =
DWARFFormValue::GetFixedFormSizesForAddressSize(GetAddressByteSize(),
IsDWARF64());

IndexPrivate(this, cu_language, fixed_form_sizes, GetOffset(), func_basenames,
func_fullnames, func_methods, func_selectors,
objc_class_selectors, globals, types, namespaces);

SymbolFileDWARFDwo *dwo_symbol_file = GetDwoSymbolFile();
if (dwo_symbol_file) {
IndexPrivate(
dwo_symbol_file->GetCompileUnit(), cu_language, fixed_form_sizes,
GetOffset(), func_basenames, func_fullnames, func_methods,
func_selectors, objc_class_selectors, globals, types, namespaces);
}
}

void DWARFUnit::IndexPrivate(
DWARFUnit *dwarf_cu, const LanguageType cu_language,
const DWARFFormValue::FixedFormSizes &fixed_form_sizes,
const dw_offset_t cu_offset, NameToDIE &func_basenames,
NameToDIE &func_fullnames, NameToDIE &func_methods,
NameToDIE &func_selectors, NameToDIE &objc_class_selectors,
NameToDIE &globals, NameToDIE &types, NameToDIE &namespaces) {
DWARFDebugInfoEntry::const_iterator pos;
DWARFDebugInfoEntry::const_iterator begin = dwarf_cu->m_die_array.begin();
DWARFDebugInfoEntry::const_iterator end = dwarf_cu->m_die_array.end();
for (pos = begin; pos != end; ++pos) {
const DWARFDebugInfoEntry &die = *pos;

const dw_tag_t tag = die.Tag();

switch (tag) {
case DW_TAG_array_type:
case DW_TAG_base_type:
case DW_TAG_class_type:
case DW_TAG_constant:
case DW_TAG_enumeration_type:
case DW_TAG_inlined_subroutine:
case DW_TAG_namespace:
case DW_TAG_string_type:
case DW_TAG_structure_type:
case DW_TAG_subprogram:
case DW_TAG_subroutine_type:
case DW_TAG_typedef:
case DW_TAG_union_type:
case DW_TAG_unspecified_type:
case DW_TAG_variable:
break;

default:
continue;
}

DWARFAttributes attributes;
const char *name = NULL;
const char *mangled_cstr = NULL;
bool is_declaration = false;
// bool is_artificial = false;
bool has_address = false;
bool has_location_or_const_value = false;
bool is_global_or_static_variable = false;

DWARFFormValue specification_die_form;
const size_t num_attributes =
die.GetAttributes(dwarf_cu, fixed_form_sizes, attributes);
if (num_attributes > 0) {
for (uint32_t i = 0; i < num_attributes; ++i) {
dw_attr_t attr = attributes.AttributeAtIndex(i);
DWARFFormValue form_value;
switch (attr) {
case DW_AT_name:
if (attributes.ExtractFormValueAtIndex(i, form_value))
name = form_value.AsCString();
break;

case DW_AT_declaration:
if (attributes.ExtractFormValueAtIndex(i, form_value))
is_declaration = form_value.Unsigned() != 0;
break;

// case DW_AT_artificial:
// if (attributes.ExtractFormValueAtIndex(i,
// form_value))
// is_artificial = form_value.Unsigned() != 0;
// break;

case DW_AT_MIPS_linkage_name:
case DW_AT_linkage_name:
if (attributes.ExtractFormValueAtIndex(i, form_value))
mangled_cstr = form_value.AsCString();
break;

case DW_AT_low_pc:
case DW_AT_high_pc:
case DW_AT_ranges:
has_address = true;
break;

case DW_AT_entry_pc:
has_address = true;
break;

case DW_AT_location:
case DW_AT_const_value:
has_location_or_const_value = true;
if (tag == DW_TAG_variable) {
const DWARFDebugInfoEntry *parent_die = die.GetParent();
while (parent_die != NULL) {
switch (parent_die->Tag()) {
case DW_TAG_subprogram:
case DW_TAG_lexical_block:
case DW_TAG_inlined_subroutine:
// Even if this is a function level static, we don't add it. We
// could theoretically add these if we wanted to by
// introspecting into the DW_AT_location and seeing if the
// location describes a hard coded address, but we don't want
// the performance penalty of that right now.
is_global_or_static_variable = false;
// if (attributes.ExtractFormValueAtIndex(dwarf, i,
// form_value)) {
// // If we have valid block data, then we have location
// // expression bytesthat are fixed (not a location list).
// const uint8_t *block_data = form_value.BlockData();
// if (block_data) {
// uint32_t block_length = form_value.Unsigned();
// if (block_length == 1 +
// attributes.CompileUnitAtIndex(i)->GetAddressByteSize()) {
// if (block_data[0] == DW_OP_addr)
// add_die = true;
// }
// }
// }
parent_die = NULL; // Terminate the while loop.
break;

case DW_TAG_compile_unit:
case DW_TAG_partial_unit:
is_global_or_static_variable = true;
parent_die = NULL; // Terminate the while loop.
break;

default:
parent_die =
parent_die->GetParent(); // Keep going in the while loop.
break;
}
}
}
break;

case DW_AT_specification:
if (attributes.ExtractFormValueAtIndex(i, form_value))
specification_die_form = form_value;
break;
}
}
}

switch (tag) {
case DW_TAG_subprogram:
if (has_address) {
if (name) {
ObjCLanguage::MethodName objc_method(name, true);
if (objc_method.IsValid(true)) {
ConstString objc_class_name_with_category(
objc_method.GetClassNameWithCategory());
ConstString objc_selector_name(objc_method.GetSelector());
ConstString objc_fullname_no_category_name(
objc_method.GetFullNameWithoutCategory(true));
ConstString objc_class_name_no_category(objc_method.GetClassName());
func_fullnames.Insert(ConstString(name),
DIERef(cu_offset, die.GetOffset()));
if (objc_class_name_with_category)
objc_class_selectors.Insert(objc_class_name_with_category,
DIERef(cu_offset, die.GetOffset()));
if (objc_class_name_no_category &&
objc_class_name_no_category != objc_class_name_with_category)
objc_class_selectors.Insert(objc_class_name_no_category,
DIERef(cu_offset, die.GetOffset()));
if (objc_selector_name)
func_selectors.Insert(objc_selector_name,
DIERef(cu_offset, die.GetOffset()));
if (objc_fullname_no_category_name)
func_fullnames.Insert(objc_fullname_no_category_name,
DIERef(cu_offset, die.GetOffset()));
}
// If we have a mangled name, then the DW_AT_name attribute is
// usually the method name without the class or any parameters
const DWARFDebugInfoEntry *parent = die.GetParent();
bool is_method = false;
if (parent) {
dw_tag_t parent_tag = parent->Tag();
if (parent_tag == DW_TAG_class_type ||
parent_tag == DW_TAG_structure_type) {
is_method = true;
} else {
if (specification_die_form.IsValid()) {
DWARFDIE specification_die =
dwarf_cu->GetSymbolFileDWARF()->DebugInfo()->GetDIE(
DIERef(specification_die_form));
if (specification_die.GetParent().IsStructOrClass())
is_method = true;
}
}
}

if (is_method)
func_methods.Insert(ConstString(name),
DIERef(cu_offset, die.GetOffset()));
else
func_basenames.Insert(ConstString(name),
DIERef(cu_offset, die.GetOffset()));

if (!is_method && !mangled_cstr && !objc_method.IsValid(true))
func_fullnames.Insert(ConstString(name),
DIERef(cu_offset, die.GetOffset()));
}
if (mangled_cstr) {
// Make sure our mangled name isn't the same string table entry as
// our name. If it starts with '_', then it is ok, else compare the
// string to make sure it isn't the same and we don't end up with
// duplicate entries
if (name && name != mangled_cstr &&
((mangled_cstr[0] == '_') ||
(::strcmp(name, mangled_cstr) != 0))) {
func_fullnames.Insert(ConstString(mangled_cstr),
DIERef(cu_offset, die.GetOffset()));
}
}
}
break;

case DW_TAG_inlined_subroutine:
if (has_address) {
if (name)
func_basenames.Insert(ConstString(name),
DIERef(cu_offset, die.GetOffset()));
if (mangled_cstr) {
// Make sure our mangled name isn't the same string table entry as
// our name. If it starts with '_', then it is ok, else compare the
// string to make sure it isn't the same and we don't end up with
// duplicate entries
if (name && name != mangled_cstr &&
((mangled_cstr[0] == '_') ||
(::strcmp(name, mangled_cstr) != 0))) {
func_fullnames.Insert(ConstString(mangled_cstr),
DIERef(cu_offset, die.GetOffset()));
}
} else
func_fullnames.Insert(ConstString(name),
DIERef(cu_offset, die.GetOffset()));
}
break;

case DW_TAG_array_type:
case DW_TAG_base_type:
case DW_TAG_class_type:
case DW_TAG_constant:
case DW_TAG_enumeration_type:
case DW_TAG_string_type:
case DW_TAG_structure_type:
case DW_TAG_subroutine_type:
case DW_TAG_typedef:
case DW_TAG_union_type:
case DW_TAG_unspecified_type:
if (name && !is_declaration)
types.Insert(ConstString(name), DIERef(cu_offset, die.GetOffset()));
if (mangled_cstr && !is_declaration)
types.Insert(ConstString(mangled_cstr),
DIERef(cu_offset, die.GetOffset()));
break;

case DW_TAG_namespace:
if (name)
namespaces.Insert(ConstString(name),
DIERef(cu_offset, die.GetOffset()));
break;

case DW_TAG_variable:
if (name && has_location_or_const_value && is_global_or_static_variable) {
globals.Insert(ConstString(name), DIERef(cu_offset, die.GetOffset()));
// Be sure to include variables by their mangled and demangled names if
// they have any since a variable can have a basename "i", a mangled
// named "_ZN12_GLOBAL__N_11iE" and a demangled mangled name
// "(anonymous namespace)::i"...

// Make sure our mangled name isn't the same string table entry as our
// name. If it starts with '_', then it is ok, else compare the string
// to make sure it isn't the same and we don't end up with duplicate
// entries
if (mangled_cstr && name != mangled_cstr &&
((mangled_cstr[0] == '_') || (::strcmp(name, mangled_cstr) != 0))) {
Mangled mangled(ConstString(mangled_cstr), true);
globals.Insert(mangled.GetMangledName(),
DIERef(cu_offset, die.GetOffset()));
ConstString demangled = mangled.GetDemangledName(cu_language);
if (demangled)
globals.Insert(demangled, DIERef(cu_offset, die.GetOffset()));
}
}
break;

default:
continue;
}
}
}

const DWARFDebugAranges &DWARFUnit::GetFunctionAranges() {
if (m_func_aranges_ap.get() == NULL) {
m_func_aranges_ap.reset(new DWARFDebugAranges());
Expand Down

0 comments on commit b7b2424

Please sign in to comment.