1//===-- DWARFDebugPubnames.cpp ----------------------------------*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9 10#include "DWARFDebugPubnames.h" 11 12#include "lldb/Core/Stream.h" 13#include "lldb/Core/Timer.h" 14 15#include "DWARFDebugInfo.h" 16#include "DWARFDIECollection.h" 17#include "DWARFFormValue.h" 18#include "DWARFCompileUnit.h" 19#include "LogChannelDWARF.h" 20#include "SymbolFileDWARF.h" 21 22 23using namespace lldb; 24using namespace lldb_private; 25 26DWARFDebugPubnames::DWARFDebugPubnames() : 27 m_sets() 28{ 29} 30 31bool 32DWARFDebugPubnames::Extract(const DataExtractor& data) 33{ 34 Timer scoped_timer (__PRETTY_FUNCTION__, 35 "DWARFDebugPubnames::Extract (byte_size = %" PRIu64 ")", 36 (uint64_t)data.GetByteSize()); 37 Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_PUBNAMES)); 38 if (log) 39 log->Printf("DWARFDebugPubnames::Extract (byte_size = %" PRIu64 ")", (uint64_t)data.GetByteSize()); 40 41 if (data.ValidOffset(0)) 42 { 43 lldb::offset_t offset = 0; 44 45 DWARFDebugPubnamesSet set; 46 while (data.ValidOffset(offset)) 47 { 48 if (set.Extract(data, &offset)) 49 { 50 m_sets.push_back(set); 51 offset = set.GetOffsetOfNextEntry(); 52 } 53 else 54 break; 55 } 56 if (log) 57 Dump (log); 58 return true; 59 } 60 return false; 61} 62 63 64bool 65DWARFDebugPubnames::GeneratePubnames(SymbolFileDWARF* dwarf2Data) 66{ 67 Timer scoped_timer (__PRETTY_FUNCTION__, 68 "DWARFDebugPubnames::GeneratePubnames (data = %p)", 69 dwarf2Data); 70 71 Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_PUBNAMES)); 72 if (log) 73 log->Printf("DWARFDebugPubnames::GeneratePubnames (data = %p)", dwarf2Data); 74 75 m_sets.clear(); 76 DWARFDebugInfo* debug_info = dwarf2Data->DebugInfo(); 77 if (debug_info) 78 { 79 80 const DataExtractor* debug_str = &dwarf2Data->get_debug_str_data(); 81 82 uint32_t cu_idx = 0; 83 const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits(); 84 for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) 85 { 86 87 DWARFCompileUnit* cu = debug_info->GetCompileUnitAtIndex(cu_idx); 88 89 const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (cu->GetAddressByteSize()); 90 91 bool clear_dies = cu->ExtractDIEsIfNeeded (false) > 1; 92 93 DWARFDIECollection dies; 94 const size_t die_count = cu->AppendDIEsWithTag (DW_TAG_subprogram, dies) + 95 cu->AppendDIEsWithTag (DW_TAG_variable, dies); 96 97 dw_offset_t cu_offset = cu->GetOffset(); 98 DWARFDebugPubnamesSet pubnames_set(DW_INVALID_OFFSET, cu_offset, cu->GetNextCompileUnitOffset() - cu_offset); 99 100 size_t die_idx; 101 for (die_idx = 0; die_idx < die_count; ++die_idx) 102 { 103 const DWARFDebugInfoEntry *die = dies.GetDIEPtrAtIndex(die_idx); 104 DWARFDebugInfoEntry::Attributes attributes; 105 const char *name = NULL; 106 const char *mangled = NULL; 107 bool add_die = false; 108 const size_t num_attributes = die->GetAttributes(dwarf2Data, cu, fixed_form_sizes, attributes); 109 if (num_attributes > 0) 110 { 111 uint32_t i; 112 113 dw_tag_t tag = die->Tag(); 114 115 for (i=0; i<num_attributes; ++i) 116 { 117 dw_attr_t attr = attributes.AttributeAtIndex(i); 118 DWARFFormValue form_value; 119 switch (attr) 120 { 121 case DW_AT_name: 122 if (attributes.ExtractFormValueAtIndex(dwarf2Data, i, form_value)) 123 name = form_value.AsCString(debug_str); 124 break; 125 126 case DW_AT_MIPS_linkage_name: 127 case DW_AT_linkage_name: 128 if (attributes.ExtractFormValueAtIndex(dwarf2Data, i, form_value)) 129 mangled = form_value.AsCString(debug_str); 130 break; 131 132 case DW_AT_low_pc: 133 case DW_AT_ranges: 134 case DW_AT_entry_pc: 135 if (tag == DW_TAG_subprogram) 136 add_die = true; 137 break; 138 139 case DW_AT_location: 140 if (tag == DW_TAG_variable) 141 { 142 const DWARFDebugInfoEntry* parent_die = die->GetParent(); 143 while ( parent_die != NULL ) 144 { 145 switch (parent_die->Tag()) 146 { 147 case DW_TAG_subprogram: 148 case DW_TAG_lexical_block: 149 case DW_TAG_inlined_subroutine: 150 // Even if this is a function level static, we don't add it. We could theoretically 151 // add these if we wanted to by introspecting into the DW_AT_location and seeing 152 // if the location describes a hard coded address, but we don't want the performance 153 // penalty of that right now. 154 add_die = false; 155// if (attributes.ExtractFormValueAtIndex(dwarf2Data, i, form_value)) 156// { 157// // If we have valid block data, then we have location expression bytes 158// // that are fixed (not a location list). 159// const uint8_t *block_data = form_value.BlockData(); 160// if (block_data) 161// { 162// uint32_t block_length = form_value.Unsigned(); 163// if (block_length == 1 + attributes.CompileUnitAtIndex(i)->GetAddressByteSize()) 164// { 165// if (block_data[0] == DW_OP_addr) 166// add_die = true; 167// } 168// } 169// } 170 parent_die = NULL; // Terminate the while loop. 171 break; 172 173 case DW_TAG_compile_unit: 174 add_die = true; 175 parent_die = NULL; // Terminate the while loop. 176 break; 177 178 default: 179 parent_die = parent_die->GetParent(); // Keep going in the while loop. 180 break; 181 } 182 } 183 } 184 break; 185 } 186 } 187 } 188 189 if (add_die && (name || mangled)) 190 { 191 pubnames_set.AddDescriptor(die->GetOffset() - cu_offset, mangled ? mangled : name); 192 } 193 } 194 195 if (pubnames_set.NumDescriptors() > 0) 196 { 197 m_sets.push_back(pubnames_set); 198 } 199 200 // Keep memory down by clearing DIEs if this generate function 201 // caused them to be parsed 202 if (clear_dies) 203 cu->ClearDIEs (true); 204 } 205 } 206 if (m_sets.empty()) 207 return false; 208 if (log) 209 Dump (log); 210 return true; 211} 212 213bool 214DWARFDebugPubnames::GeneratePubBaseTypes(SymbolFileDWARF* dwarf2Data) 215{ 216 m_sets.clear(); 217 DWARFDebugInfo* debug_info = dwarf2Data->DebugInfo(); 218 if (debug_info) 219 { 220 uint32_t cu_idx = 0; 221 const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits(); 222 for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) 223 { 224 DWARFCompileUnit* cu = debug_info->GetCompileUnitAtIndex(cu_idx); 225 DWARFDIECollection dies; 226 const size_t die_count = cu->AppendDIEsWithTag (DW_TAG_base_type, dies); 227 dw_offset_t cu_offset = cu->GetOffset(); 228 DWARFDebugPubnamesSet pubnames_set(DW_INVALID_OFFSET, cu_offset, cu->GetNextCompileUnitOffset() - cu_offset); 229 230 size_t die_idx; 231 for (die_idx = 0; die_idx < die_count; ++die_idx) 232 { 233 const DWARFDebugInfoEntry *die = dies.GetDIEPtrAtIndex(die_idx); 234 const char *name = die->GetAttributeValueAsString(dwarf2Data, cu, DW_AT_name, NULL); 235 236 if (name) 237 { 238 pubnames_set.AddDescriptor(die->GetOffset() - cu_offset, name); 239 } 240 } 241 242 if (pubnames_set.NumDescriptors() > 0) 243 { 244 m_sets.push_back(pubnames_set); 245 } 246 } 247 } 248 return !m_sets.empty(); 249} 250 251void 252DWARFDebugPubnames::Dump(Log *s) const 253{ 254 if (m_sets.empty()) 255 s->PutCString("< EMPTY >\n"); 256 else 257 { 258 const_iterator pos; 259 const_iterator end = m_sets.end(); 260 261 for (pos = m_sets.begin(); pos != end; ++pos) 262 (*pos).Dump(s); 263 } 264} 265 266bool 267DWARFDebugPubnames::Find(const char* name, bool ignore_case, std::vector<dw_offset_t>& die_offsets) const 268{ 269 const_iterator pos; 270 const_iterator end = m_sets.end(); 271 272 die_offsets.clear(); 273 274 for (pos = m_sets.begin(); pos != end; ++pos) 275 { 276 (*pos).Find(name, ignore_case, die_offsets); 277 } 278 279 return !die_offsets.empty(); 280} 281 282bool 283DWARFDebugPubnames::Find(const RegularExpression& regex, std::vector<dw_offset_t>& die_offsets) const 284{ 285 const_iterator pos; 286 const_iterator end = m_sets.end(); 287 288 die_offsets.clear(); 289 290 for (pos = m_sets.begin(); pos != end; ++pos) 291 { 292 (*pos).Find(regex, die_offsets); 293 } 294 295 return !die_offsets.empty(); 296} 297