| //===-- DWARFDebugPubnames.cpp ----------------------------------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "DWARFDebugPubnames.h" |
| |
| #include "lldb/Core/Stream.h" |
| #include "lldb/Core/Timer.h" |
| |
| #include "DWARFDebugInfo.h" |
| #include "DWARFDIECollection.h" |
| #include "DWARFFormValue.h" |
| #include "DWARFCompileUnit.h" |
| #include "LogChannelDWARF.h" |
| #include "SymbolFileDWARF.h" |
| |
| |
| using namespace lldb_private; |
| |
| DWARFDebugPubnames::DWARFDebugPubnames() : |
| m_sets() |
| { |
| } |
| |
| bool |
| DWARFDebugPubnames::Extract(const DataExtractor& data) |
| { |
| Timer scoped_timer (__PRETTY_FUNCTION__, |
| "DWARFDebugPubnames::Extract (byte_size = %zu)", |
| data.GetByteSize()); |
| Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_PUBNAMES); |
| if (log) |
| log->Printf("DWARFDebugPubnames::Extract (byte_size = %zu)", data.GetByteSize()); |
| |
| if (data.ValidOffset(0)) |
| { |
| uint32_t offset = 0; |
| |
| DWARFDebugPubnamesSet set; |
| while (data.ValidOffset(offset)) |
| { |
| if (set.Extract(data, &offset)) |
| { |
| m_sets.push_back(set); |
| offset = set.GetOffsetOfNextEntry(); |
| } |
| else |
| break; |
| } |
| if (log) |
| Dump (log); |
| return true; |
| } |
| return false; |
| } |
| |
| |
| bool |
| DWARFDebugPubnames::GeneratePubnames(SymbolFileDWARF* dwarf2Data) |
| { |
| Timer scoped_timer (__PRETTY_FUNCTION__, |
| "DWARFDebugPubnames::GeneratePubnames (data = %p)", |
| dwarf2Data); |
| |
| Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_PUBNAMES); |
| if (log) |
| log->Printf("DWARFDebugPubnames::GeneratePubnames (data = %p)", dwarf2Data); |
| |
| m_sets.clear(); |
| DWARFDebugInfo* debug_info = dwarf2Data->DebugInfo(); |
| if (debug_info) |
| { |
| |
| const DataExtractor* debug_str = &dwarf2Data->get_debug_str_data(); |
| |
| uint32_t cu_idx = 0; |
| const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits(); |
| for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) |
| { |
| |
| DWARFCompileUnit* cu = debug_info->GetCompileUnitAtIndex(cu_idx); |
| |
| bool clear_dies = cu->ExtractDIEsIfNeeded (false) > 1; |
| |
| DWARFDIECollection dies; |
| const size_t die_count = cu->AppendDIEsWithTag (DW_TAG_subprogram, dies) + |
| cu->AppendDIEsWithTag (DW_TAG_variable, dies); |
| |
| dw_offset_t cu_offset = cu->GetOffset(); |
| DWARFDebugPubnamesSet pubnames_set(DW_INVALID_OFFSET, cu_offset, cu->GetNextCompileUnitOffset() - cu_offset); |
| |
| size_t die_idx; |
| for (die_idx = 0; die_idx < die_count; ++die_idx) |
| { |
| const DWARFDebugInfoEntry *die = dies.GetDIEPtrAtIndex(die_idx); |
| DWARFDebugInfoEntry::Attributes attributes; |
| const char *name = NULL; |
| const char *mangled = NULL; |
| bool add_die = false; |
| bool is_variable = false; |
| const size_t num_attributes = die->GetAttributes(dwarf2Data, cu, attributes); |
| if (num_attributes > 0) |
| { |
| uint32_t i; |
| |
| dw_tag_t tag = die->Tag(); |
| |
| is_variable = tag == DW_TAG_variable; |
| |
| for (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(dwarf2Data, i, form_value)) |
| name = form_value.AsCString(debug_str); |
| break; |
| |
| case DW_AT_MIPS_linkage_name: |
| if (attributes.ExtractFormValueAtIndex(dwarf2Data, i, form_value)) |
| mangled = form_value.AsCString(debug_str); |
| break; |
| |
| case DW_AT_low_pc: |
| case DW_AT_ranges: |
| case DW_AT_entry_pc: |
| if (tag == DW_TAG_subprogram) |
| add_die = true; |
| break; |
| |
| case DW_AT_location: |
| 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 dont want the performance |
| // penalty of that right now. |
| add_die = false; |
| // if (attributes.ExtractFormValueAtIndex(dwarf2Data, i, form_value)) |
| // { |
| // // If we have valid block data, then we have location expression bytes |
| // // that 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: |
| add_die = true; |
| parent_die = NULL; // Terminate the while loop. |
| break; |
| |
| default: |
| parent_die = parent_die->GetParent(); // Keep going in the while loop. |
| break; |
| } |
| } |
| } |
| break; |
| } |
| } |
| } |
| |
| if (add_die && (name || mangled)) |
| { |
| if (is_variable) |
| cu->AddGlobal(die); |
| pubnames_set.AddDescriptor(die->GetOffset() - cu_offset, mangled ? mangled : name); |
| } |
| } |
| |
| if (pubnames_set.NumDescriptors() > 0) |
| { |
| m_sets.push_back(pubnames_set); |
| } |
| |
| // Keep memory down by clearing DIEs if this generate function |
| // caused them to be parsed |
| if (clear_dies) |
| cu->ClearDIEs (true); |
| } |
| } |
| if (m_sets.empty()) |
| return false; |
| if (log) |
| Dump (log); |
| return true; |
| } |
| |
| bool |
| DWARFDebugPubnames::GeneratePubBaseTypes(SymbolFileDWARF* dwarf2Data) |
| { |
| m_sets.clear(); |
| DWARFDebugInfo* debug_info = dwarf2Data->DebugInfo(); |
| if (debug_info) |
| { |
| uint32_t cu_idx = 0; |
| const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits(); |
| for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) |
| { |
| DWARFCompileUnit* cu = debug_info->GetCompileUnitAtIndex(cu_idx); |
| DWARFDIECollection dies; |
| const size_t die_count = cu->AppendDIEsWithTag (DW_TAG_base_type, dies); |
| dw_offset_t cu_offset = cu->GetOffset(); |
| DWARFDebugPubnamesSet pubnames_set(DW_INVALID_OFFSET, cu_offset, cu->GetNextCompileUnitOffset() - cu_offset); |
| |
| size_t die_idx; |
| for (die_idx = 0; die_idx < die_count; ++die_idx) |
| { |
| const DWARFDebugInfoEntry *die = dies.GetDIEPtrAtIndex(die_idx); |
| const char *name = die->GetAttributeValueAsString(dwarf2Data, cu, DW_AT_name, NULL); |
| |
| if (name) |
| { |
| pubnames_set.AddDescriptor(die->GetOffset() - cu_offset, name); |
| } |
| } |
| |
| if (pubnames_set.NumDescriptors() > 0) |
| { |
| m_sets.push_back(pubnames_set); |
| } |
| } |
| } |
| return !m_sets.empty(); |
| } |
| |
| void |
| DWARFDebugPubnames::Dump(Log *s) const |
| { |
| if (m_sets.empty()) |
| s->PutCString("< EMPTY >\n"); |
| else |
| { |
| const_iterator pos; |
| const_iterator end = m_sets.end(); |
| |
| for (pos = m_sets.begin(); pos != end; ++pos) |
| (*pos).Dump(s); |
| } |
| } |
| |
| bool |
| DWARFDebugPubnames::Find(const char* name, bool ignore_case, std::vector<dw_offset_t>& die_offsets) const |
| { |
| const_iterator pos; |
| const_iterator end = m_sets.end(); |
| |
| die_offsets.clear(); |
| |
| for (pos = m_sets.begin(); pos != end; ++pos) |
| { |
| (*pos).Find(name, ignore_case, die_offsets); |
| } |
| |
| return !die_offsets.empty(); |
| } |
| |
| bool |
| DWARFDebugPubnames::Find(const RegularExpression& regex, std::vector<dw_offset_t>& die_offsets) const |
| { |
| const_iterator pos; |
| const_iterator end = m_sets.end(); |
| |
| die_offsets.clear(); |
| |
| for (pos = m_sets.begin(); pos != end; ++pos) |
| { |
| (*pos).Find(regex, die_offsets); |
| } |
| |
| return !die_offsets.empty(); |
| } |