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 }