DWARFDIE.cpp revision 355940
1//===-- DWARFDIE.cpp --------------------------------------------*- C++ -*-===// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8 9#include "DWARFDIE.h" 10 11#include "DWARFASTParser.h" 12#include "DWARFDebugInfo.h" 13#include "DWARFDebugInfoEntry.h" 14#include "DWARFDeclContext.h" 15#include "DWARFUnit.h" 16 17using namespace lldb_private; 18 19namespace { 20 21/// Iterate through all DIEs elaborating (i.e. reachable by a chain of 22/// DW_AT_specification and DW_AT_abstract_origin attributes) a given DIE. For 23/// convenience, the starting die is included in the sequence as the first 24/// item. 25class ElaboratingDIEIterator 26 : public std::iterator<std::input_iterator_tag, DWARFDIE> { 27 28 // The operating invariant is: top of m_worklist contains the "current" item 29 // and the rest of the list are items yet to be visited. An empty worklist 30 // means we've reached the end. 31 // Infinite recursion is prevented by maintaining a list of seen DIEs. 32 // Container sizes are optimized for the case of following DW_AT_specification 33 // and DW_AT_abstract_origin just once. 34 llvm::SmallVector<DWARFDIE, 2> m_worklist; 35 llvm::SmallSet<lldb::user_id_t, 3> m_seen; 36 37 void Next() { 38 assert(!m_worklist.empty() && "Incrementing end iterator?"); 39 40 // Pop the current item from the list. 41 DWARFDIE die = m_worklist.back(); 42 m_worklist.pop_back(); 43 44 // And add back any items that elaborate it. 45 for (dw_attr_t attr : {DW_AT_specification, DW_AT_abstract_origin}) { 46 if (DWARFDIE d = die.GetReferencedDIE(attr)) 47 if (m_seen.insert(die.GetID()).second) 48 m_worklist.push_back(d); 49 } 50 } 51 52public: 53 /// An iterator starting at die d. 54 explicit ElaboratingDIEIterator(DWARFDIE d) : m_worklist(1, d) {} 55 56 /// End marker 57 ElaboratingDIEIterator() {} 58 59 const DWARFDIE &operator*() const { return m_worklist.back(); } 60 ElaboratingDIEIterator &operator++() { 61 Next(); 62 return *this; 63 } 64 ElaboratingDIEIterator operator++(int) { 65 ElaboratingDIEIterator I = *this; 66 Next(); 67 return I; 68 } 69 70 friend bool operator==(const ElaboratingDIEIterator &a, 71 const ElaboratingDIEIterator &b) { 72 if (a.m_worklist.empty() || b.m_worklist.empty()) 73 return a.m_worklist.empty() == b.m_worklist.empty(); 74 return a.m_worklist.back() == b.m_worklist.back(); 75 } 76 friend bool operator!=(const ElaboratingDIEIterator &a, 77 const ElaboratingDIEIterator &b) { 78 return !(a == b); 79 } 80}; 81 82llvm::iterator_range<ElaboratingDIEIterator> 83elaborating_dies(const DWARFDIE &die) { 84 return llvm::make_range(ElaboratingDIEIterator(die), 85 ElaboratingDIEIterator()); 86} 87} // namespace 88 89DWARFDIE 90DWARFDIE::GetParent() const { 91 if (IsValid()) 92 return DWARFDIE(m_cu, m_die->GetParent()); 93 else 94 return DWARFDIE(); 95} 96 97DWARFDIE 98DWARFDIE::GetFirstChild() const { 99 if (IsValid()) 100 return DWARFDIE(m_cu, m_die->GetFirstChild()); 101 else 102 return DWARFDIE(); 103} 104 105DWARFDIE 106DWARFDIE::GetSibling() const { 107 if (IsValid()) 108 return DWARFDIE(m_cu, m_die->GetSibling()); 109 else 110 return DWARFDIE(); 111} 112 113DWARFDIE 114DWARFDIE::GetReferencedDIE(const dw_attr_t attr) const { 115 if (IsValid()) 116 return m_die->GetAttributeValueAsReference(GetCU(), attr); 117 else 118 return {}; 119} 120 121DWARFDIE 122DWARFDIE::GetDIE(dw_offset_t die_offset) const { 123 if (IsValid()) 124 return m_cu->GetDIE(die_offset); 125 else 126 return DWARFDIE(); 127} 128 129DWARFDIE 130DWARFDIE::GetAttributeValueAsReferenceDIE(const dw_attr_t attr) const { 131 if (IsValid()) { 132 DWARFUnit *cu = GetCU(); 133 const bool check_specification_or_abstract_origin = true; 134 DWARFFormValue form_value; 135 if (m_die->GetAttributeValue(cu, attr, form_value, nullptr, 136 check_specification_or_abstract_origin)) 137 return form_value.Reference(); 138 } 139 return DWARFDIE(); 140} 141 142DWARFDIE 143DWARFDIE::LookupDeepestBlock(lldb::addr_t file_addr) const { 144 if (IsValid()) { 145 SymbolFileDWARF *dwarf = GetDWARF(); 146 DWARFUnit *cu = GetCU(); 147 DWARFDebugInfoEntry *function_die = nullptr; 148 DWARFDebugInfoEntry *block_die = nullptr; 149 if (m_die->LookupAddress(file_addr, cu, &function_die, &block_die)) { 150 if (block_die && block_die != function_die) { 151 if (cu->ContainsDIEOffset(block_die->GetOffset())) 152 return DWARFDIE(cu, block_die); 153 else 154 return DWARFDIE(dwarf->DebugInfo()->GetUnit(DIERef( 155 cu->GetSymbolFileDWARF().GetDwoNum(), 156 cu->GetDebugSection(), block_die->GetOffset())), 157 block_die); 158 } 159 } 160 } 161 return DWARFDIE(); 162} 163 164const char *DWARFDIE::GetMangledName() const { 165 if (IsValid()) 166 return m_die->GetMangledName(m_cu); 167 else 168 return nullptr; 169} 170 171const char *DWARFDIE::GetPubname() const { 172 if (IsValid()) 173 return m_die->GetPubname(m_cu); 174 else 175 return nullptr; 176} 177 178const char *DWARFDIE::GetQualifiedName(std::string &storage) const { 179 if (IsValid()) 180 return m_die->GetQualifiedName(m_cu, storage); 181 else 182 return nullptr; 183} 184 185// GetName 186// 187// Get value of the DW_AT_name attribute and place that value into the supplied 188// stream object. If the DIE is a NULL object "NULL" is placed into the stream, 189// and if no DW_AT_name attribute exists for the DIE then nothing is printed. 190void DWARFDIE::GetName(Stream &s) const { 191 if (!IsValid()) 192 return; 193 if (GetDIE()->IsNULL()) { 194 s.PutCString("NULL"); 195 return; 196 } 197 const char *name = GetDIE()->GetAttributeValueAsString(GetCU(), DW_AT_name, nullptr, true); 198 if (!name) 199 return; 200 s.PutCString(name); 201} 202 203// AppendTypeName 204// 205// Follows the type name definition down through all needed tags to end up with 206// a fully qualified type name and dump the results to the supplied stream. 207// This is used to show the name of types given a type identifier. 208void DWARFDIE::AppendTypeName(Stream &s) const { 209 if (!IsValid()) 210 return; 211 if (GetDIE()->IsNULL()) { 212 s.PutCString("NULL"); 213 return; 214 } 215 if (const char *name = GetPubname()) { 216 s.PutCString(name); 217 return; 218 } 219 switch (Tag()) { 220 case DW_TAG_array_type: 221 break; // print out a "[]" after printing the full type of the element 222 // below 223 case DW_TAG_base_type: 224 s.PutCString("base "); 225 break; 226 case DW_TAG_class_type: 227 s.PutCString("class "); 228 break; 229 case DW_TAG_const_type: 230 s.PutCString("const "); 231 break; 232 case DW_TAG_enumeration_type: 233 s.PutCString("enum "); 234 break; 235 case DW_TAG_file_type: 236 s.PutCString("file "); 237 break; 238 case DW_TAG_interface_type: 239 s.PutCString("interface "); 240 break; 241 case DW_TAG_packed_type: 242 s.PutCString("packed "); 243 break; 244 case DW_TAG_pointer_type: 245 break; // print out a '*' after printing the full type below 246 case DW_TAG_ptr_to_member_type: 247 break; // print out a '*' after printing the full type below 248 case DW_TAG_reference_type: 249 break; // print out a '&' after printing the full type below 250 case DW_TAG_restrict_type: 251 s.PutCString("restrict "); 252 break; 253 case DW_TAG_set_type: 254 s.PutCString("set "); 255 break; 256 case DW_TAG_shared_type: 257 s.PutCString("shared "); 258 break; 259 case DW_TAG_string_type: 260 s.PutCString("string "); 261 break; 262 case DW_TAG_structure_type: 263 s.PutCString("struct "); 264 break; 265 case DW_TAG_subrange_type: 266 s.PutCString("subrange "); 267 break; 268 case DW_TAG_subroutine_type: 269 s.PutCString("function "); 270 break; 271 case DW_TAG_thrown_type: 272 s.PutCString("thrown "); 273 break; 274 case DW_TAG_union_type: 275 s.PutCString("union "); 276 break; 277 case DW_TAG_unspecified_type: 278 s.PutCString("unspecified "); 279 break; 280 case DW_TAG_volatile_type: 281 s.PutCString("volatile "); 282 break; 283 default: 284 return; 285 } 286 287 // Follow the DW_AT_type if possible 288 if (DWARFDIE next_die = GetAttributeValueAsReferenceDIE(DW_AT_type)) 289 next_die.AppendTypeName(s); 290 291 switch (Tag()) { 292 case DW_TAG_array_type: 293 s.PutCString("[]"); 294 break; 295 case DW_TAG_pointer_type: 296 s.PutChar('*'); 297 break; 298 case DW_TAG_ptr_to_member_type: 299 s.PutChar('*'); 300 break; 301 case DW_TAG_reference_type: 302 s.PutChar('&'); 303 break; 304 default: 305 break; 306 } 307} 308 309lldb_private::Type *DWARFDIE::ResolveType() const { 310 if (IsValid()) 311 return GetDWARF()->ResolveType(*this, true); 312 else 313 return nullptr; 314} 315 316lldb_private::Type *DWARFDIE::ResolveTypeUID(const DWARFDIE &die) const { 317 if (SymbolFileDWARF *dwarf = GetDWARF()) 318 return dwarf->ResolveTypeUID(die, true); 319 return nullptr; 320} 321 322std::vector<DWARFDIE> DWARFDIE::GetDeclContextDIEs() const { 323 if (!IsValid()) 324 return {}; 325 326 std::vector<DWARFDIE> result; 327 DWARFDIE parent = GetParentDeclContextDIE(); 328 while (parent.IsValid() && parent.GetDIE() != GetDIE()) { 329 result.push_back(std::move(parent)); 330 parent = parent.GetParentDeclContextDIE(); 331 } 332 333 return result; 334} 335 336void DWARFDIE::GetDWARFDeclContext(DWARFDeclContext &dwarf_decl_ctx) const { 337 if (IsValid()) { 338 dwarf_decl_ctx.SetLanguage(GetLanguage()); 339 m_die->GetDWARFDeclContext(GetCU(), dwarf_decl_ctx); 340 } else { 341 dwarf_decl_ctx.Clear(); 342 } 343} 344 345void DWARFDIE::GetDeclContext(std::vector<CompilerContext> &context) const { 346 const dw_tag_t tag = Tag(); 347 if (tag == DW_TAG_compile_unit || tag == DW_TAG_partial_unit) 348 return; 349 DWARFDIE parent = GetParent(); 350 if (parent) 351 parent.GetDeclContext(context); 352 switch (tag) { 353 case DW_TAG_module: 354 context.push_back( 355 CompilerContext(CompilerContextKind::Module, ConstString(GetName()))); 356 break; 357 case DW_TAG_namespace: 358 context.push_back(CompilerContext(CompilerContextKind::Namespace, 359 ConstString(GetName()))); 360 break; 361 case DW_TAG_structure_type: 362 context.push_back(CompilerContext(CompilerContextKind::Structure, 363 ConstString(GetName()))); 364 break; 365 case DW_TAG_union_type: 366 context.push_back( 367 CompilerContext(CompilerContextKind::Union, ConstString(GetName()))); 368 break; 369 case DW_TAG_class_type: 370 context.push_back( 371 CompilerContext(CompilerContextKind::Class, ConstString(GetName()))); 372 break; 373 case DW_TAG_enumeration_type: 374 context.push_back(CompilerContext(CompilerContextKind::Enumeration, 375 ConstString(GetName()))); 376 break; 377 case DW_TAG_subprogram: 378 context.push_back(CompilerContext(CompilerContextKind::Function, 379 ConstString(GetPubname()))); 380 break; 381 case DW_TAG_variable: 382 context.push_back(CompilerContext(CompilerContextKind::Variable, 383 ConstString(GetPubname()))); 384 break; 385 case DW_TAG_typedef: 386 context.push_back( 387 CompilerContext(CompilerContextKind::Typedef, ConstString(GetName()))); 388 break; 389 default: 390 break; 391 } 392} 393 394DWARFDIE 395DWARFDIE::GetParentDeclContextDIE() const { 396 if (IsValid()) 397 return m_die->GetParentDeclContextDIE(m_cu); 398 else 399 return DWARFDIE(); 400} 401 402bool DWARFDIE::IsStructUnionOrClass() const { 403 const dw_tag_t tag = Tag(); 404 return tag == DW_TAG_class_type || tag == DW_TAG_structure_type || 405 tag == DW_TAG_union_type; 406} 407 408bool DWARFDIE::IsMethod() const { 409 for (DWARFDIE d : elaborating_dies(*this)) 410 if (d.GetParent().IsStructUnionOrClass()) 411 return true; 412 return false; 413} 414 415DWARFDIE 416DWARFDIE::GetContainingDWOModuleDIE() const { 417 if (IsValid()) { 418 DWARFDIE top_module_die; 419 // Now make sure this DIE is scoped in a DW_TAG_module tag and return true 420 // if so 421 for (DWARFDIE parent = GetParent(); parent.IsValid(); 422 parent = parent.GetParent()) { 423 const dw_tag_t tag = parent.Tag(); 424 if (tag == DW_TAG_module) 425 top_module_die = parent; 426 else if (tag == DW_TAG_compile_unit || tag == DW_TAG_partial_unit) 427 break; 428 } 429 430 return top_module_die; 431 } 432 return DWARFDIE(); 433} 434 435lldb::ModuleSP DWARFDIE::GetContainingDWOModule() const { 436 if (IsValid()) { 437 DWARFDIE dwo_module_die = GetContainingDWOModuleDIE(); 438 439 if (dwo_module_die) { 440 const char *module_name = dwo_module_die.GetName(); 441 if (module_name) 442 return GetDWARF()->GetDWOModule(lldb_private::ConstString(module_name)); 443 } 444 } 445 return lldb::ModuleSP(); 446} 447 448bool DWARFDIE::GetDIENamesAndRanges( 449 const char *&name, const char *&mangled, DWARFRangeList &ranges, 450 int &decl_file, int &decl_line, int &decl_column, int &call_file, 451 int &call_line, int &call_column, 452 lldb_private::DWARFExpression *frame_base) const { 453 if (IsValid()) { 454 return m_die->GetDIENamesAndRanges( 455 GetCU(), name, mangled, ranges, decl_file, decl_line, decl_column, 456 call_file, call_line, call_column, frame_base); 457 } else 458 return false; 459} 460 461CompilerDecl DWARFDIE::GetDecl() const { 462 DWARFASTParser *dwarf_ast = GetDWARFParser(); 463 if (dwarf_ast) 464 return dwarf_ast->GetDeclForUIDFromDWARF(*this); 465 else 466 return CompilerDecl(); 467} 468 469CompilerDeclContext DWARFDIE::GetDeclContext() const { 470 DWARFASTParser *dwarf_ast = GetDWARFParser(); 471 if (dwarf_ast) 472 return dwarf_ast->GetDeclContextForUIDFromDWARF(*this); 473 else 474 return CompilerDeclContext(); 475} 476 477CompilerDeclContext DWARFDIE::GetContainingDeclContext() const { 478 DWARFASTParser *dwarf_ast = GetDWARFParser(); 479 if (dwarf_ast) 480 return dwarf_ast->GetDeclContextContainingUIDFromDWARF(*this); 481 else 482 return CompilerDeclContext(); 483} 484