File indexing completed on 2024-05-12 05:43:27
0001 /* 0002 Copyright (C) 2015 Volker Krause <vkrause@kde.org> 0003 0004 This program is free software; you can redistribute it and/or modify it 0005 under the terms of the GNU Library General Public License as published by 0006 the Free Software Foundation; either version 2 of the License, or (at your 0007 option) any later version. 0008 0009 This program is distributed in the hope that it will be useful, but WITHOUT 0010 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 0011 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 0012 License for more details. 0013 0014 You should have received a copy of the GNU General Public License 0015 along with this program. If not, see <https://www.gnu.org/licenses/>. 0016 */ 0017 0018 #include "dwarfdie.h" 0019 #include "dwarfcudie.h" 0020 #include "dwarfinfo.h" 0021 #include "dwarfexpression.h" 0022 #include "dwarfranges.h" 0023 #include "dwarftypes.h" 0024 0025 #include <QFileInfo> 0026 #include <QString> 0027 0028 #include <dwarf.h> 0029 #include <libdwarf.h> 0030 0031 #include <cassert> 0032 #include <type_traits> 0033 0034 DwarfDie::DwarfDie(Dwarf_Die die, DwarfDie* parent) : 0035 m_die(die) 0036 { 0037 m_parent.parent = parent; 0038 } 0039 0040 DwarfDie::DwarfDie(Dwarf_Die die, DwarfInfo* info) : 0041 m_die(die) 0042 { 0043 m_parent.info = info; 0044 } 0045 0046 DwarfDie::~DwarfDie() 0047 { 0048 qDeleteAll(m_children); 0049 } 0050 0051 DwarfInfo* DwarfDie::dwarfInfo() const 0052 { 0053 if (isCompilationUnit()) 0054 return m_parent.info; 0055 Q_ASSERT(m_parent.parent); 0056 return m_parent.parent->dwarfInfo(); 0057 } 0058 0059 DwarfDie* DwarfDie::parentDie() const 0060 { 0061 if (isCompilationUnit()) 0062 return nullptr; 0063 return m_parent.parent; 0064 } 0065 0066 bool DwarfDie::isCompilationUnit() const 0067 { 0068 const auto tagType = tag(); 0069 return tagType == DW_TAG_compile_unit || tagType == DW_TAG_partial_unit || tagType == DW_TAG_type_unit; 0070 } 0071 0072 QByteArray DwarfDie::name() const 0073 { 0074 Q_ASSERT(m_die); 0075 0076 char* dwarfStr; 0077 const auto res = dwarf_diename(m_die, &dwarfStr, nullptr); 0078 if (res != DW_DLV_OK) { 0079 const auto ref = inheritedFrom(); 0080 if (ref) 0081 return ref->name(); 0082 return {}; 0083 } 0084 const QByteArray s(dwarfStr); 0085 dwarf_dealloc(dwarfHandle(), dwarfStr, DW_DLA_STRING); 0086 return s; 0087 } 0088 0089 Dwarf_Half DwarfDie::tag() const 0090 { 0091 Dwarf_Half tagType; 0092 const auto res = dwarf_tag(m_die, &tagType, nullptr); 0093 if (res != DW_DLV_OK) 0094 return {}; 0095 return tagType; 0096 } 0097 0098 QByteArray DwarfDie::tagName() const 0099 { 0100 const char* tagName; 0101 const auto res = dwarf_get_TAG_name(tag(), &tagName); 0102 if (res != DW_DLV_OK) 0103 return QByteArray("Unknown tag ") + QByteArray::number(tag()); 0104 return QByteArray::fromRawData(tagName, strlen(tagName)); 0105 } 0106 0107 Dwarf_Off DwarfDie::offset() const 0108 { 0109 Dwarf_Off offset; 0110 const auto res = dwarf_dieoffset(m_die, &offset, nullptr); 0111 assert(res == DW_DLV_OK); 0112 return offset; 0113 } 0114 0115 static QVector<int> arrayDimensions(const DwarfDie *die) 0116 { 0117 QVector<int> dims; 0118 foreach (const auto child, die->children()) { 0119 if (child->tag() != DW_TAG_subrange_type) 0120 continue; 0121 const auto attr = child->attribute(DW_AT_upper_bound); 0122 if (attr.isNull()) 0123 dims.push_back(0); 0124 // DW_AT_upper_bound is the highest allowed index, not the size 0125 dims.push_back(attr.toInt() + 1); 0126 } 0127 return dims; 0128 } 0129 0130 static QByteArrayList argumentList(const DwarfDie *die) 0131 { 0132 QByteArrayList args; 0133 foreach (const auto child, die->children()) { 0134 if (child->tag() == DW_TAG_formal_parameter) { 0135 args.push_back(child->typeName()); 0136 } 0137 } 0138 return args; 0139 } 0140 0141 QByteArray DwarfDie::typeName() const 0142 { 0143 const auto n = name(); 0144 if (!n.isEmpty()) 0145 return n; 0146 0147 const auto typeDie = attribute(DW_AT_type).value<DwarfDie*>(); 0148 QByteArray typeName; 0149 if (!typeDie) { 0150 switch (tag()) { 0151 case DW_TAG_class_type: 0152 return "<anon class>"; 0153 case DW_TAG_enumeration_type: 0154 return "<anon enum>"; 0155 case DW_TAG_structure_type: 0156 return "<anon struct>"; 0157 case DW_TAG_union_type: 0158 return "<anon union>"; 0159 case DW_TAG_namespace: 0160 return "(anonymous namespace)"; 0161 case DW_TAG_array_type: 0162 case DW_TAG_base_type: 0163 case DW_TAG_const_type: 0164 case DW_TAG_pointer_type: 0165 case DW_TAG_ptr_to_member_type: 0166 case DW_TAG_reference_type: 0167 case DW_TAG_restrict_type: 0168 case DW_TAG_rvalue_reference_type: 0169 case DW_TAG_subroutine_type: 0170 case DW_TAG_typedef: 0171 typeName = "void"; 0172 break; 0173 default: 0174 return {}; 0175 } 0176 } else { 0177 typeName = typeDie->typeName(); 0178 } 0179 0180 // TODO: function pointers and pointer to members 0181 switch (tag()) { 0182 case DW_TAG_pointer_type: 0183 return typeName + '*'; 0184 case DW_TAG_reference_type: 0185 return typeName + '&'; 0186 case DW_TAG_rvalue_reference_type: 0187 return typeName + "&&"; 0188 case DW_TAG_const_type: 0189 return typeName + " const"; 0190 case DW_TAG_array_type: 0191 { 0192 const auto dims = arrayDimensions(this); 0193 QByteArray n = typeName; 0194 for (int d : dims) 0195 n += '[' + QByteArray::number(d) + ']'; 0196 return n; 0197 } 0198 case DW_TAG_restrict_type: 0199 return typeName + " restrcit"; 0200 case DW_TAG_volatile_type: 0201 return typeName + " volatile"; 0202 case DW_TAG_subroutine_type: 0203 return typeName + " (*)(" + argumentList(this).join(", ") + ')'; 0204 case DW_TAG_ptr_to_member_type: 0205 { 0206 const auto classDie = attribute(DW_AT_containing_type).value<DwarfDie*>(); 0207 QByteArray className; 0208 if (classDie) 0209 className = classDie->typeName(); 0210 return typeName + " (" + className + "::*)(" + argumentList(this).join(", ") + ')'; 0211 } 0212 } 0213 return typeName; 0214 } 0215 0216 int DwarfDie::typeSize() const 0217 { 0218 switch (tag()) { 0219 case DW_TAG_base_type: 0220 case DW_TAG_class_type: 0221 case DW_TAG_enumeration_type: 0222 case DW_TAG_structure_type: 0223 case DW_TAG_union_type: 0224 return attribute(DW_AT_byte_size).toInt(); 0225 case DW_TAG_pointer_type: 0226 case DW_TAG_reference_type: 0227 case DW_TAG_rvalue_reference_type: 0228 return 8; // TODO: support 32bit! 0229 case DW_TAG_const_type: 0230 case DW_TAG_restrict_type: 0231 case DW_TAG_typedef: 0232 case DW_TAG_volatile_type: 0233 { 0234 const auto typeDie = attribute(DW_AT_type).value<DwarfDie*>(); 0235 assert(typeDie); 0236 return typeDie->typeSize(); 0237 } 0238 case DW_TAG_array_type: 0239 { 0240 const auto typeDie = attribute(DW_AT_type).value<DwarfDie*>(); 0241 assert(typeDie); 0242 int s = typeDie->typeSize(); 0243 foreach (auto d, arrayDimensions(this)) 0244 s *= d; 0245 return s; 0246 } 0247 } 0248 0249 return 0; 0250 } 0251 0252 int DwarfDie::typeAlignment() const 0253 { 0254 switch (tag()) { 0255 case DW_TAG_base_type: 0256 case DW_TAG_enumeration_type: 0257 return std::min(typeSize(), 8); // TODO: 32bit support 0258 case DW_TAG_array_type: 0259 case DW_TAG_const_type: 0260 case DW_TAG_restrict_type: 0261 case DW_TAG_typedef: 0262 case DW_TAG_volatile_type: 0263 { 0264 const auto typeDie = attribute(DW_AT_type).value<DwarfDie*>(); 0265 assert(typeDie); 0266 return typeDie->typeAlignment(); 0267 } 0268 case DW_TAG_pointer_type: 0269 case DW_TAG_reference_type: 0270 case DW_TAG_rvalue_reference_type: 0271 return 8; // TODO: 32bit support 0272 case DW_TAG_class_type: 0273 case DW_TAG_structure_type: 0274 case DW_TAG_union_type: 0275 { 0276 int align = 1; 0277 foreach (const auto child, children()) { 0278 if (child->tag() != DW_TAG_member && child->tag() != DW_TAG_inheritance) 0279 continue; 0280 if (child->isStaticMember()) 0281 continue; 0282 const auto typeDie = child->attribute(DW_AT_type).value<DwarfDie*>(); 0283 assert(typeDie); 0284 align = std::max(align, typeDie->typeAlignment()); 0285 } 0286 return align; 0287 } 0288 } 0289 0290 return 0; 0291 } 0292 0293 bool DwarfDie::isStaticMember() const 0294 { 0295 // TODO not entirely sure yet this is correct... 0296 const auto memberLocationAttr = attribute(DW_AT_data_member_location); 0297 if (!memberLocationAttr.isNull()) 0298 return false; 0299 0300 const auto externalAttr = attribute(DW_AT_external).toBool(); 0301 const auto declAttr = attribute(DW_AT_declaration).toBool(); 0302 return externalAttr || declAttr; 0303 } 0304 0305 QString DwarfDie::displayName() const 0306 { 0307 QString n = name(); 0308 0309 if (n.isEmpty()) 0310 n = typeName(); 0311 0312 if (n.isEmpty()) { 0313 n = tagName(); 0314 n += QLatin1String(" (offset "); 0315 } else { 0316 n += QLatin1String(" ("); 0317 n += tagName(); 0318 n += QLatin1String(", offset "); 0319 } 0320 n += QString::number(offset()); 0321 n += QLatin1Char(')'); 0322 return n; 0323 } 0324 0325 QByteArray DwarfDie::fullyQualifiedName() const 0326 { 0327 QByteArray baseName; 0328 auto parent = parentDie(); 0329 if (parent->tag() == DW_TAG_class_type || parent->tag() == DW_TAG_structure_type || parent->tag() == DW_TAG_namespace) 0330 baseName = parent->fullyQualifiedName() + "::"; 0331 return baseName + typeName(); 0332 } 0333 0334 QString DwarfDie::sourceFilePath() const 0335 { 0336 auto filePath = attribute(DW_AT_decl_file).toString(); 0337 if (filePath.isEmpty()) 0338 return filePath; 0339 QFileInfo fi(filePath); 0340 if (fi.isRelative()) { 0341 QString cuPath; 0342 DwarfDie const* parentDie = this; 0343 while (parentDie && parentDie->tag() != DW_TAG_compile_unit) 0344 parentDie = parentDie->parentDie(); 0345 if (parentDie) 0346 fi.setFile(parentDie->attribute(DW_AT_comp_dir).toString() + QLatin1Char('/') + filePath); 0347 } 0348 if (fi.exists()) 0349 filePath = fi.canonicalFilePath(); 0350 0351 return filePath; 0352 } 0353 0354 QString DwarfDie::sourceLocation() const 0355 { 0356 return sourceFilePath() + QLatin1Char(':') + QString::number(attribute(DW_AT_decl_line).toInt()); 0357 } 0358 0359 static void stringifyEnum(QVariant &value, int (*get_name)(unsigned int, const char**)) 0360 { 0361 const auto i = value.value<Dwarf_Unsigned>(); 0362 const char* str; 0363 const auto res = get_name(i, &str); 0364 if (res != DW_DLV_OK) 0365 return; 0366 value = QString::fromLocal8Bit(str); 0367 } 0368 0369 QVector< Dwarf_Half > DwarfDie::attributes() const 0370 { 0371 Dwarf_Attribute* attrList; 0372 Dwarf_Signed attrCount; 0373 auto res = dwarf_attrlist(m_die, &attrList, &attrCount, nullptr); 0374 if (res != DW_DLV_OK) 0375 return {}; 0376 0377 QVector<Dwarf_Half> attrs; 0378 attrs.reserve(attrCount); 0379 for (int i = 0; i < attrCount; ++i) { 0380 Dwarf_Half attrType; 0381 res = dwarf_whatattr(attrList[i], &attrType, nullptr); 0382 if (res != DW_DLV_OK) 0383 continue; 0384 attrs.push_back(attrType); 0385 } 0386 0387 dwarf_dealloc(dwarfHandle(), attrList, DW_DLA_LIST); 0388 0389 if (const auto die = inheritedFrom()) { 0390 auto inheritedAttrs = die->attributes(); 0391 // remove attributes that must not be inherited 0392 inheritedAttrs.erase( 0393 std::remove_if(inheritedAttrs.begin(), inheritedAttrs.end(), [](Dwarf_Half at) { 0394 return at == DW_AT_declaration || at == DW_AT_sibling; 0395 }), inheritedAttrs.end()); 0396 0397 attrs += inheritedAttrs; 0398 std::sort(attrs.begin(), attrs.end()); 0399 attrs.erase(std::unique(attrs.begin(), attrs.end()), attrs.end()); 0400 } 0401 0402 return attrs; 0403 } 0404 0405 QByteArray DwarfDie::attributeName(Dwarf_Half attributeType) 0406 { 0407 const char* attrName; 0408 const auto res = dwarf_get_AT_name(attributeType, &attrName); 0409 if (res != DW_DLV_OK) 0410 return QByteArray("Unknown attribute ") + QByteArray::number(attributeType); 0411 return QByteArray::fromRawData(attrName, strlen(attrName)); 0412 } 0413 0414 QVariant DwarfDie::attribute(Dwarf_Half attributeType) const 0415 { 0416 const QVariant localAttr = attributeLocal(attributeType); 0417 if (localAttr.isValid()) 0418 return localAttr; 0419 0420 switch (attributeType) { 0421 case DW_AT_sibling: 0422 case DW_AT_declaration: 0423 return {}; // never inherit these 0424 } 0425 0426 const auto ref = inheritedFrom(); 0427 if (!ref) 0428 return {}; 0429 return ref->attribute(attributeType); 0430 } 0431 0432 QVariant DwarfDie::attributeLocal(Dwarf_Half attributeType) const 0433 { 0434 Dwarf_Attribute attr; 0435 auto res = dwarf_attr(m_die, attributeType, &attr, nullptr); 0436 if (res != DW_DLV_OK) 0437 return {}; 0438 0439 Dwarf_Half formType; 0440 res = dwarf_whatform(attr, &formType, nullptr); 0441 if (res != DW_DLV_OK) 0442 return {}; 0443 0444 QVariant value; 0445 switch (formType) { 0446 case DW_FORM_data1: 0447 case DW_FORM_data2: 0448 case DW_FORM_data4: 0449 case DW_FORM_data8: 0450 case DW_FORM_udata: 0451 { 0452 static_assert( std::is_convertible<Dwarf_Unsigned, qulonglong>::value, "Incompatible DWARFs" ); 0453 Dwarf_Unsigned n; 0454 res = dwarf_formudata(attr, &n, nullptr); 0455 value = static_cast<qulonglong>(n); 0456 break; 0457 } 0458 case DW_FORM_sdata: 0459 { 0460 static_assert( std::is_convertible<Dwarf_Signed, qlonglong>::value, "Incompatible DWARFs" ); 0461 Dwarf_Signed n; 0462 res = dwarf_formsdata(attr, &n, nullptr); 0463 value = static_cast<qlonglong>(n); 0464 break; 0465 } 0466 case DW_FORM_string: 0467 case DW_FORM_strp: 0468 { 0469 char *str; 0470 res = dwarf_formstring(attr, &str, nullptr); 0471 value = QByteArray(str); 0472 break; 0473 } 0474 case DW_FORM_flag: 0475 case DW_FORM_flag_present: 0476 { 0477 Dwarf_Bool b; 0478 res = dwarf_formflag(attr, &b, nullptr); 0479 value = b ? true : false; 0480 break; 0481 } 0482 case DW_FORM_ref1: 0483 case DW_FORM_ref2: 0484 case DW_FORM_ref4: 0485 case DW_FORM_ref8: 0486 { 0487 Dwarf_Off offset; 0488 res = dwarf_global_formref(attr, &offset, nullptr); 0489 value = QVariant::fromValue(dwarfInfo()->dieAtOffset(offset)); 0490 break; 0491 } 0492 case DW_FORM_sec_offset: 0493 { 0494 static_assert( std::is_convertible<Dwarf_Off, qulonglong>::value, "Incompatible DWARFs" ); 0495 Dwarf_Off offset; 0496 res = dwarf_global_formref(attr, &offset, nullptr); 0497 value = static_cast<qulonglong>(offset); 0498 break; 0499 } 0500 case DW_FORM_addr: 0501 { 0502 static_assert( std::is_convertible<Dwarf_Addr, qulonglong>::value, "Incompatible DWARFs" ); 0503 Dwarf_Addr addr; 0504 res = dwarf_formaddr(attr, &addr, nullptr); 0505 value = static_cast<qulonglong>(addr); 0506 break; 0507 } 0508 case DW_FORM_exprloc: 0509 { 0510 Dwarf_Unsigned len; 0511 Dwarf_Ptr block; 0512 res = dwarf_formexprloc(attr, &len, &block, nullptr); 0513 value = QVariant::fromValue(DwarfExpression(block, len, dwarfInfo()->elfFile()->addressSize())); 0514 break; 0515 } 0516 default: 0517 { 0518 const char* formName; 0519 res = dwarf_get_FORM_name(formType, &formName); 0520 if (res != DW_DLV_OK) 0521 return {}; 0522 value = QLatin1String("TODO: ") + QString::fromLocal8Bit(formName); 0523 break; 0524 } 0525 } 0526 0527 // post-process some well-known types 0528 switch (attributeType) { 0529 case DW_AT_decl_file: 0530 case DW_AT_call_file: 0531 { 0532 const auto fileIndex = value.value<Dwarf_Unsigned>(); 0533 // index 0 means not present, TODO handle that 0534 value = compilationUnit()->sourceFileForIndex(fileIndex -1); 0535 break; 0536 } 0537 case DW_AT_ranges: 0538 value = QVariant::fromValue(DwarfRanges(this, value.toLongLong())); 0539 break; 0540 case DW_AT_accessibility: 0541 stringifyEnum(value, &dwarf_get_ACCESS_name); 0542 break; 0543 case DW_AT_language: 0544 stringifyEnum(value, &dwarf_get_LANG_name); 0545 break; 0546 case DW_AT_virtuality: 0547 value = QVariant::fromValue(static_cast<DwarfVirtuality>(value.toInt())); 0548 break; 0549 case DW_AT_visibility: 0550 stringifyEnum(value, &dwarf_get_VIS_name); 0551 break; 0552 case DW_AT_identifier_case: 0553 stringifyEnum(value, &dwarf_get_ID_name); 0554 break; 0555 case DW_AT_inline: 0556 stringifyEnum(value, &dwarf_get_INL_name); 0557 break; 0558 case DW_AT_encoding: 0559 stringifyEnum(value, &dwarf_get_ATE_name); 0560 break; 0561 case DW_AT_ordering: 0562 stringifyEnum(value, &dwarf_get_ORD_name); 0563 break; 0564 case DW_AT_calling_convention: 0565 stringifyEnum(value, &dwarf_get_CC_name); 0566 break; 0567 case DW_AT_discr_list: 0568 stringifyEnum(value, &dwarf_get_DSC_name); 0569 break; 0570 default: 0571 break; 0572 } 0573 0574 return value; 0575 } 0576 0577 QVector< DwarfDie* > DwarfDie::children() const 0578 { 0579 if (!m_childrenScanned) 0580 scanChildren(); 0581 return m_children; 0582 } 0583 0584 DwarfDie* DwarfDie::dieAtOffset(Dwarf_Off offset) const 0585 { 0586 const auto cus = children(); 0587 auto it = std::lower_bound(cus.begin(), cus.end(), offset, [](DwarfDie* lhs, Dwarf_Off rhs) { return lhs->offset() < rhs; }); 0588 0589 if (it != cus.end() && (*it)->offset() == offset) 0590 return *it; 0591 0592 Q_ASSERT(it != cus.begin()); 0593 --it; 0594 return (*it)->dieAtOffset(offset); 0595 } 0596 0597 DwarfDie* DwarfDie::inheritedFrom() const 0598 { 0599 auto ref = attributeLocal(DW_AT_abstract_origin); 0600 if (ref.isNull()) 0601 ref = attributeLocal(DW_AT_specification); 0602 if (ref.isNull()) 0603 return nullptr; 0604 return ref.value<DwarfDie*>(); 0605 } 0606 0607 void DwarfDie::scanChildren() const 0608 { 0609 m_childrenScanned = true; 0610 0611 Dwarf_Die childDie; 0612 auto res = dwarf_child(m_die, &childDie, nullptr); 0613 if (res != DW_DLV_OK) 0614 return; 0615 0616 const auto handle = dwarfHandle(); 0617 forever { 0618 m_children.push_back(new DwarfDie(childDie, const_cast<DwarfDie*>(this))); 0619 0620 Dwarf_Die siblingDie; 0621 res = dwarf_siblingof_b(handle, childDie, true, &siblingDie, nullptr); 0622 if (res != DW_DLV_OK) 0623 return; 0624 0625 childDie = siblingDie; 0626 } 0627 } 0628 0629 Dwarf_Debug DwarfDie::dwarfHandle() const 0630 { 0631 return dwarfInfo()->dwarfHandle(); 0632 } 0633 0634 Dwarf_Die DwarfDie::dieHandle() const 0635 { 0636 return m_die; 0637 } 0638 0639 const DwarfCuDie* DwarfDie::compilationUnit() const 0640 { 0641 if (isCompilationUnit()) 0642 return static_cast<const DwarfCuDie*>(this); 0643 assert(m_parent.parent); 0644 return m_parent.parent->compilationUnit(); 0645 }