File indexing completed on 2024-05-12 05:43:32

0001 /*
0002     Copyright (C) 2013-2014 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 "datavisitor.h"
0019 #include "elfmodel.h"
0020 
0021 #include <elf/elffile.h>
0022 #include <elf/elfnoteentry.h>
0023 #include <elf/elfgnusymbolversiontable.h>
0024 #include <elf/elfgnusymbolversiondefinitionssection.h>
0025 #include <elf/elfgnusymbolversiondefinitionauxiliaryentry.h>
0026 #include <elf/elfgnusymbolversionrequirement.h>
0027 #include <elf/elfgnusymbolversionrequirementauxiliaryentry.h>
0028 #include <elf/elfsegmentheader.h>
0029 #include <elf.h>
0030 
0031 #if HAVE_DWARF
0032 #include <dwarf/dwarfaddressranges.h>
0033 #endif
0034 
0035 #include <disassmbler/disassembler.h>
0036 #include <demangle/demangler.h>
0037 #include <checks/structurepackingcheck.h>
0038 #include <navigator/codenavigatorprinter.h>
0039 
0040 #include <printers/dwarfprinter.h>
0041 #include <printers/dynamicsectionprinter.h>
0042 #include <printers/elfprinter.h>
0043 #include <printers/gnuversionprinter.h>
0044 #include <printers/notesectionprinter.h>
0045 #include <printers/relocationprinter.h>
0046 #include <printers/symbolprinter.h>
0047 
0048 #include <QIcon>
0049 #include <QUrl>
0050 
0051 #include <cassert>
0052 
0053 class NavigatingDisassembler : public Disassembler
0054 {
0055 public:
0056     NavigatingDisassembler(const DataVisitor *v) : m_v(v) {}
0057 
0058     QString printSymbol(ElfSymbolTableEntry* entry) const override
0059     {
0060         return m_v->printSymbolName(entry);
0061     }
0062 
0063     QString printGotEntry(ElfGotEntry* entry) const override
0064     {
0065         QString s;
0066         s += QLatin1String("<a href=\"");
0067         s += m_v->m_model->indexForNode(entry).data(ElfModel::NodeUrl).toUrl().toEncoded();
0068         s += QLatin1String("\">");
0069         s += Disassembler::printGotEntry(entry);
0070         s += QLatin1String("</a>");
0071         return s;
0072     }
0073 
0074     QString printPltEntry(ElfPltEntry* entry) const override
0075     {
0076         QString s;
0077         s += QLatin1String("<a href=\"");
0078         s += m_v->m_model->indexForNode(entry).data(ElfModel::NodeUrl).toUrl().toEncoded();
0079         s += QLatin1String("\">");
0080         s += Disassembler::printPltEntry(entry);
0081         s += QLatin1String("</a>");
0082         return s;
0083     }
0084 
0085 private:
0086     const DataVisitor* const m_v;
0087 };
0088 
0089 DataVisitor::DataVisitor(const ElfModel* model, int column) :
0090     m_model(model),
0091     m_column(column)
0092 {
0093 }
0094 
0095 QVariant DataVisitor::doVisit(ElfFile* file, int arg) const
0096 {
0097     switch (arg) {
0098         case Qt::DisplayRole:
0099             return file->displayName();
0100         case Qt::ToolTipRole:
0101             return file->fileName();
0102         case ElfModel::SizeRole:
0103             return QVariant::fromValue<uint64_t>(file->size());
0104         case ElfModel::DetailRole:
0105         {
0106             QString s;
0107             s += "File name: " + file->fileName() + "<br/>";
0108             s += QLatin1String("Address size: ") + (file->type() == ELFCLASS32 ? "32 bit" : "64 bit") + "<br/>";
0109             s += QLatin1String("Byte order: ") + (file->byteOrder() == ELFDATA2LSB ? "little endian" : "big endian") + "<br/>";
0110             s += QLatin1String("File type: ") + ElfPrinter::fileType(file->header()->type()) + "<br/>";
0111             s += QLatin1String("Machine: ") + ElfPrinter::machine(file->header()->machine()) + "<br/>";
0112             s += QLatin1String("OS ABI: ") + ElfPrinter::osAbi(file->osAbi()) + "<br/>";
0113             s += "Flags: " + QString::number(file->header()->flags()) + "<br/>";
0114             s += QLatin1String("Entry point: 0x") + QString::number(file->header()->entryPoint(), 16);
0115             if (file->header()->entryPoint() && file->symbolTable()) {
0116                 const auto entry = file->symbolTable()->entryWithValue(file->header()->entryPoint());
0117                 if (entry)
0118                     s += " (" + printSymbolName(entry) + ')';
0119             }
0120             if (file->separateDebugFile())
0121                 s += "<br/>Separate debug file: " + file->separateDebugFile()->fileName();
0122             s += QLatin1String("<br/><br/>");
0123 
0124             s += QLatin1String("<b>Segments</b></br>");
0125             s += QLatin1String("<table border=\"1\" border-style=\"solid\" cellspacing=\"0\">");
0126             s += QLatin1String("<tr><th>Type</th><th>Flags</th><th>Offset</th><th>Virtual Address</th>");
0127             s += QLatin1String("<th>Physical Address</th><th>File Size</th><th>Memory Size</th><th>Alignment</th></tr>");
0128             foreach (auto phdr, file->segmentHeaders()) {
0129                 s += QLatin1String("<tr>");
0130                 s += "<td>" + ElfPrinter::segmentType(phdr->type()) + "</td>";
0131                 s += "<td>" + ElfPrinter::segmentFlags(phdr->flags()) + "</td>";
0132                 s += "<td>0x" + QString::number(phdr->offset(), 16) + "</td>";
0133                 s += "<td>0x" + QString::number(phdr->virtualAddress(), 16) + "</td>";
0134                 s += "<td>0x" + QString::number(phdr->physicalAddress(), 16) + "</td>";
0135                 s += "<td>" + QString::number(phdr->fileSize()) + "</td>";
0136                 s += "<td>" + QString::number(phdr->memorySize()) + "</td>";
0137                 s += "<td>0x" + QString::number(phdr->alignment(), 16) + "</td>";
0138                 s += QLatin1String("</tr>");
0139             }
0140             s += QLatin1String("</table");
0141             return s;
0142         }
0143         case ElfModel::FileRole:
0144             return QVariant::fromValue(file);
0145     }
0146     return QVariant();
0147 }
0148 
0149 QVariant DataVisitor::doVisit(ElfSection* section, int arg) const
0150 {
0151     switch (arg) {
0152         case Qt::DisplayRole:
0153             if (*section->header()->name() == 0)
0154                 return QObject::tr("<null>");
0155             return section->header()->name();
0156         case Qt::DecorationRole:
0157             if (m_column == 0 && section->file()->isSeparateDebugFile())
0158                 return QIcon::fromTheme(QStringLiteral("package_development_debugger"));
0159             return {};
0160         case ElfModel::SizeRole:
0161             return QVariant::fromValue<uint64_t>(section->size());
0162         case ElfModel::DetailRole:
0163         {
0164             QString s(QStringLiteral("<b>Section</b><br/>"));
0165             s += QLatin1String("Name: ") + section->header()->name() + "<br/>";
0166             s += QLatin1String("Size: ") + QString::number(section->header()->size()) + " bytes<br/>";
0167             s += QLatin1String("Flags: ") + ElfPrinter::sectionFlags(section->header()->flags()) + "<br/>";
0168             s += QLatin1String("Offset: 0x") + QString::number(section->header()->sectionOffset(), 16) + "<br/>";
0169             s += QLatin1String("Virtual Address: 0x") + QString::number(section->header()->virtualAddress(), 16) + "<br/>";
0170             s += QLatin1String("Type: ") + ElfPrinter::sectionType(section->header()->type()) + "<br/>";
0171             if (section->header()->link())
0172                 s += "Linked section: " + printSectionName(section->linkedSection<ElfSection>()) + "<br/>";
0173             if (section->header()->flags() & SHF_INFO_LINK)
0174                 s += "Referenced section: " + printSectionName(section->file()->section<ElfSection>(section->header()->info())) + "<br/>";
0175             if (section->header()->entrySize()) {
0176                 s += QLatin1String("Entries: ") + QString::number(section->header()->entryCount())
0177                   + " x " + QString::number(section->header()->entrySize()) + " byte<br/>";
0178             }
0179             if (section->header()->flags() & SHF_STRINGS && section->size() < 100000) { // QTextBrowser fails on too large input
0180                 s += QLatin1String("Strings:<br/>");
0181                 uint prevIndex = 0, index = 0;
0182                 do {
0183                     if (section->rawData()[index] == 0) {
0184                         if (index - prevIndex > 0) {
0185                             const auto b = QByteArray::fromRawData(reinterpret_cast<const char*>(section->rawData() + prevIndex), index - prevIndex);
0186                             s += QString::number(prevIndex) + ": " + b + "<br/>";
0187                         }
0188                         prevIndex = index + 1;
0189                     }
0190                     ++index;
0191                 } while (index < section->size());
0192             }
0193             if (strcmp(section->header()->name(), ".init") == 0 || strcmp(section->header()->name(), ".fini") == 0) {
0194                 NavigatingDisassembler da(this);
0195                 s += "Code:<br/><tt>" + da.disassemble(section) + "</tt>";
0196             }
0197             if (section->header()->type() == SHT_INIT_ARRAY || section->header()->type() == SHT_FINI_ARRAY) {
0198                 const auto addrSize = section->file()->addressSize();
0199                 s += QLatin1String("Content:<br/>");
0200                 for (uint i = 0; i < section->header()->size() / addrSize; ++i) {
0201                     uint64_t value = 0;
0202                     memcpy(&value, section->rawData() + i * addrSize, addrSize);
0203                     s += QString::number(i) + ": 0x" + QString::number(value, 16);
0204                     if (value) {
0205                         const auto ref = section->file()->symbolTable()->entryWithValue(value);
0206                         if (ref)
0207                             s += QLatin1Char(' ') + printSymbolName(ref);
0208                     } else { // check for relocation
0209                         const auto relocEntry = section->file()->reverseRelocator()->find(section->header()->virtualAddress() + i * addrSize);
0210                         if (relocEntry) {
0211                             const auto sym = section->file()->symbolTable()->entryContainingValue(relocEntry->relocationTarget());
0212                             if (sym)
0213                                 s += " relocated to: " + printSymbolName(sym);
0214                         }
0215                     }
0216 
0217                     s += QLatin1String("<br/>");
0218                 }
0219             }
0220             return s;
0221         }
0222         case ElfModel::SectionRole:
0223             return QVariant::fromValue(section);
0224     }
0225 
0226     return QVariant();
0227 }
0228 
0229 QVariant DataVisitor::doVisit(ElfSymbolTableSection* symtab, int arg) const
0230 {
0231     const auto base = doVisit(static_cast<ElfSection*>(symtab), arg);
0232     if (arg != ElfModel::DetailRole)
0233         return base;
0234     QString s = base.toString();
0235     s += QLatin1String("<br/><b>Symbol Table</b>");
0236     s += "<br/>Exported symbols: " + QString::number(symtab->exportCount());
0237     s += "<br/>Imported symbols: " + QString::number(symtab->importCount());
0238     s += QLatin1String("<br/>");
0239     return s;
0240 }
0241 
0242 static uint64_t virtualTableEntry(ElfSymbolTableEntry *entry, int index)
0243 {
0244     const auto addrSize = entry->symbolTable()->file()->addressSize();
0245     assert(entry->size() % addrSize == 0);
0246 
0247     // TODO this assumes endianess equalness
0248     if (addrSize == 8)
0249         return *reinterpret_cast<const uint64_t*>(entry->data() + index * addrSize);
0250     if (addrSize == 4)
0251         return *reinterpret_cast<const uint32_t*>(entry->data() + index * addrSize);
0252 
0253     Q_UNREACHABLE();
0254 }
0255 
0256 static QString printVerSymInfo(ElfSymbolTableEntry *entry)
0257 {
0258     if (entry->symbolTable()->header()->type() != SHT_DYNSYM)
0259         return {};
0260     const ElfFile *file = entry->symbolTable()->file();
0261     const auto verSymIdx = file->indexOfSection(SHT_GNU_versym);
0262     if (verSymIdx < 0)
0263         return {};
0264     const auto verSymTab = file->section<ElfGNUSymbolVersionTable>(verSymIdx);
0265     const auto versionIndex = verSymTab->versionIndex(entry->index());
0266 
0267     QString s(QStringLiteral("GNU version: "));
0268     switch (versionIndex) {
0269         case VER_NDX_LOCAL:
0270             s += QLatin1String("&lt;local&gt;");
0271             break;
0272         case VER_NDX_GLOBAL:
0273             s += QLatin1String("&lt;global&gt;");
0274             break;
0275         default:
0276         {
0277             auto f = entry->symbolTable()->file();
0278             if (entry->hasValidSection()) { // definition
0279                 const auto verDefIdx = f->indexOfSection(SHT_GNU_verdef);
0280                 if (verDefIdx <= 0) {
0281                     s += QString::number(versionIndex);
0282                 } else {
0283                     auto verDefSection = f->section<ElfGNUSymbolVersionDefinitionsSection>(verDefIdx);
0284                     assert(verDefSection);
0285                     s += verDefSection->definitionForVersionIndex(versionIndex)->auxiliaryEntry(0)->name();
0286                 }
0287                 break;
0288             } else { // requirement
0289                 const auto verReqIdx = f->indexOfSection(SHT_GNU_verneed);
0290                 auto verReqSection = f->section<ElfGNUSymbolVersionRequirementsSection>(verReqIdx);
0291                 assert(verReqSection);
0292                 s += verReqSection->requirementForVersionIndex(versionIndex)->name();
0293                 break;
0294             }
0295             s += QString::number(versionIndex);
0296         }
0297     };
0298     if (verSymTab->isHidden(entry->index()))
0299         s += QLatin1String(" (hidden)");
0300     s += QLatin1String("<br/>");
0301     return s;
0302 }
0303 
0304 #if HAVE_DWARF
0305 static DwarfDie* findDwarfDie(ElfSymbolTableEntry *entry)
0306 {
0307     auto *dwarf = entry->symbolTable()->file()->dwarfInfo();
0308     if (!dwarf || entry->value() == 0)
0309         return nullptr;
0310 
0311     DwarfDie* res = nullptr;
0312     if (dwarf->addressRanges()->isValid())
0313        res = dwarf->addressRanges()->dieForAddress(entry->value());
0314     if (!res)
0315         res = dwarf->dieForMangledSymbol(entry->name());
0316     return res;
0317 }
0318 #endif
0319 
0320 QVariant DataVisitor::doVisit(ElfSymbolTableEntry* entry, int arg) const
0321 {
0322     switch (arg) {
0323         case Qt::DisplayRole:
0324             if (*entry->name() == 0)
0325                 return QObject::tr("<null>");
0326             return entry->name();
0327         case ElfModel::SizeRole:
0328             return QVariant::fromValue<uint64_t>(entry->size());
0329         case ElfModel::DetailRole:
0330         {
0331             QString s(QStringLiteral("<b>Symbol</b><br/>"));
0332             s += QLatin1String("Mangled name: ") + entry->name() + "<br/>";
0333             Demangler demangler;
0334             s += QLatin1String("Demangled name: ") + QString(demangler.demangleFull(entry->name())).toHtmlEscaped() + "<br/>";
0335             s += QLatin1String("Size: ") + QString::number(entry->size()) + "<br/>";
0336             s += QLatin1String("Value: 0x") + QString::number(entry->value(), 16) + "<br/>";
0337             s += QLatin1String("Bind type: ") + SymbolPrinter::bindType(entry->bindType()) + "<br/>";
0338             s += QLatin1String("Symbol type: ") + SymbolPrinter::symbolType(entry->type()) + "<br/>";
0339             s += QLatin1String("Visibility: ") + SymbolPrinter::visibility(entry->visibility()) + "<br/>";
0340             s += printVerSymInfo(entry);
0341 
0342             const auto hasValidSectionIndex = entry->hasValidSection();
0343             if (hasValidSectionIndex) {
0344                 s += "Section: " + printSectionName(entry->section()) + "<br/>";
0345             }
0346 
0347             if (hasValidSectionIndex && entry->sectionHeader()->type() == SHT_NOBITS) {
0348                 // .bss, i.e. no content to display
0349             } else if (entry->type() == STT_FUNC && entry->size() > 0) {
0350                 NavigatingDisassembler da(this);
0351                 s += QLatin1String("Code:<br/><tt>") + da.disassemble(entry) + "</tt>";
0352             } else if (entry->type() == STT_OBJECT && entry->size() > 0) {
0353                 const auto addrSize = entry->symbolTable()->file()->addressSize();
0354                 const auto symbolType = Demangler::symbolType(entry->name());
0355                 switch (symbolType) {
0356                     case Demangler::SymbolType::VTable:
0357                     case Demangler::SymbolType::ConstructionVTable:
0358                     {
0359                         s += symbolType == Demangler::SymbolType::ConstructionVTable ? QObject::tr("Construction VTable") : QObject::tr("VTable");
0360                         s += QLatin1String(":<br/><tt>");
0361                         for (uint i = 0; i < entry->size() / addrSize; ++i) {
0362                             const uint64_t v = virtualTableEntry(entry, i);
0363                             s += QString::number(i) + ": 0x" + QString::number(v, 16);
0364                             const auto ref = entry->symbolTable()->entryWithValue(v);
0365                             if (ref) {
0366                                 s += QLatin1Char(' ') + printSymbolName(ref) + QLatin1String(" (") + Demangler::demangleFull(ref->name()) + QLatin1Char(')');
0367                             } else {
0368                                 auto reloc = entry->symbolTable()->file()->reverseRelocator()->find(entry->value() + i * addrSize);
0369                                 if (reloc) {
0370                                     const auto relocSym = reloc->symbol();
0371                                     if (relocSym)
0372                                         s += QLatin1String(" relocation: ") + printSymbolName(relocSym);
0373                                 }
0374                             }
0375                             s += QLatin1String("<br/>");
0376                         }
0377                         s += QLatin1String("</tt><br/>");
0378                         break;
0379                     }
0380                     case Demangler::SymbolType::VTT:
0381                     {
0382                         s += QLatin1String("VTT:<br/><tt>");
0383                         for (uint i = 0; i < entry->size() / addrSize; ++i) {
0384                             const uint64_t v = virtualTableEntry(entry, i);
0385                             s += QString::number(i) + ": 0x" + QString::number(v, 16);
0386                             // vptrs point to one after the RTTI entry, which is the first virtual method, unless there is none in that
0387                             // case we would point past the vtable here, and thus we wont find it, so better look for the RTTI spot.
0388                             const auto ref = entry->symbolTable()->entryContainingValue(v - addrSize);
0389                             if (ref) {
0390                                 const auto offset = v - ref->value();
0391                                 s += QLatin1String(" entry ") + QString::number(offset / addrSize) + QLatin1String(" in ") + printSymbolName(ref);
0392                                 s += QLatin1String(" (") + Demangler::demangleFull(ref->name()) + QLatin1Char(')');
0393                             }
0394                             s += QLatin1String("<br/>");
0395                         }
0396                         s += QLatin1String("</tt><br/>");
0397                         break;
0398                     }
0399                     case Demangler::SymbolType::TypeInfoName:
0400                         s += "Type info name: " + QByteArray((const char*)entry->data()) + "<br/>";
0401                         break;
0402                     // TODO: add other symbol types
0403                     default:
0404                         s += QStringLiteral("Data:<br/><tt>");
0405                         const unsigned char* data = entry->data();
0406                         s += QByteArray::fromRawData((const char*)data, entry->size()).toHex();
0407                         s += QLatin1String("</tt><br/>");
0408                 }
0409             }
0410 
0411 #if HAVE_DWARF
0412             const auto die = findDwarfDie(entry);
0413             if (die) {
0414                 s += CodeNavigatorPrinter::sourceLocationRichText(die);
0415                 s += QLatin1String("<br/><b>DWARF DIE</b><br/>");
0416                 s += printDwarfDie(die);
0417             }
0418 #endif
0419             return s;
0420         }
0421     }
0422 
0423     return QVariant();
0424 }
0425 
0426 QVariant DataVisitor::doVisit(ElfGnuDebugLinkSection* section, int role) const
0427 {
0428     auto baseData = doVisit(static_cast<ElfSection*>(section), role);
0429     if (role == ElfModel::DetailRole) {
0430         QString s = baseData.toString();
0431         s += QLatin1String("<br/><b>Debug Link</b>");
0432         s += "<br/>File name: " + section->fileName();
0433         s += "<br/>CRC: 0x" + QString::number(section->crc(), 16);
0434         return s;
0435     }
0436     return baseData;
0437 }
0438 
0439 QVariant DataVisitor::doVisit(ElfDynamicEntry *entry, int arg) const
0440 {
0441     switch (arg) {
0442         case Qt::DisplayRole:
0443             return entry->tagName();
0444         case ElfModel::DetailRole:
0445         {
0446             QString s;
0447             s += QLatin1String("Tag name: ") + entry->tagName() + "<br/>";
0448             s += QStringLiteral("Value: ");
0449             switch (entry->tag()) {
0450                 case DT_FLAGS:
0451                     s += DynamicSectionPrinter::flagsToDescriptions(entry->value());
0452                     break;
0453                 case DT_FLAGS_1:
0454                     s += DynamicSectionPrinter::flags1ToDescriptions(entry->value());
0455                     break;
0456                 case DT_PLTREL:
0457                     s += RelocationPrinter::label(entry->dynamicSection()->file()->header()->machine(), entry->value());
0458                     break;
0459                 default:
0460                     if (entry->isStringValue()) {
0461                         s+= entry->stringValue();
0462                     } else if (entry->isAddress()) {
0463                         s += QLatin1String("0x") + QString::number(entry->pointer(), 16);
0464                         const auto secIdx = entry->dynamicSection()->file()->indexOfSectionWithVirtualAddress(entry->pointer());
0465                         if (secIdx >= 0) {
0466                             const auto section = entry->dynamicSection()->file()->section<ElfSection>(secIdx);
0467                             assert(section);
0468                             s += " (" + printSectionName(section);
0469                             if (section->header()->virtualAddress() < entry->pointer())
0470                                 s += " + 0x" + QString::number(entry->pointer() - section->header()->virtualAddress(), 16);
0471                             s += ')';
0472                         }
0473                     } else {
0474                         s += QString::number(entry->value());
0475                     }
0476             }
0477             s += QLatin1String("<br/>");
0478             return s;
0479         }
0480     }
0481 
0482     return QVariant();
0483 }
0484 
0485 QVariant DataVisitor::doVisit(ElfHashSection* section, int role) const
0486 {
0487     const auto base = doVisit(static_cast<ElfSection*>(section), role);
0488     if (role == ElfModel::DetailRole) {
0489         QString s = base.toString();
0490         s += QLatin1String("<br/><b>Hash Table</b><br/>");
0491         s += "Buckets: " + QString::number(section->bucketCount()) + "<br/>";
0492         s += "Chains: " + QString::number(section->chainCount()) + "<br/>";
0493         if (ElfGnuHashSection *gnuHash = dynamic_cast<ElfGnuHashSection*>(section)) {
0494             s += "Symbol table index: " + QString::number(gnuHash->symbolIndex()) + "<br/>";
0495             s += "Mask word count: " + QString::number(gnuHash->maskWordsCount()) + "<br/>";
0496             s += "Shift count: " + QString::number(gnuHash->shift2()) + "<br/>";
0497         }
0498 
0499         s += QLatin1String("Chain length histogram<br/>");
0500         const auto hist = section->histogram();
0501         for (int i = 0; i < hist.size(); ++i) {
0502             s += "&nbsp;&nbsp;" + QString::number(i) + ": " + QString::number(hist.at(i)) + "<br/>";
0503         }
0504         s += "Average collision common prefix length: " + QString::number(section->averagePrefixLength()) + "<br/>";
0505         return s;
0506     }
0507     return base;
0508 }
0509 
0510 QVariant DataVisitor::doVisit(ElfGNUSymbolVersionDefinition* verDef, int role) const
0511 {
0512     switch (role) {
0513         case Qt::DisplayRole:
0514             return "version definition";
0515         case ElfModel::SizeRole:
0516             return verDef->size();
0517         case ElfModel::DetailRole:
0518         {
0519             QString s;
0520             s += "Flags: " + GnuVersionPrinter::versionFlags(verDef->flags()) + "<br/>";
0521             s += "Index: " + QString::number(verDef->versionIndex()) + "<br/>";
0522             s += "Aux count: " + QString::number(verDef->auxiliarySize()) + "<br/>";
0523             s += "Hash: " + QString::number(verDef->hash()) + "<br/>";
0524             s += "Aux offset: " + QString::number(verDef->auxiliaryOffset()) + "<br/>";
0525             s += "Next offset: " + QString::number(verDef->nextOffset()) + "<br/>";
0526             return s;
0527         }
0528     }
0529     return {};
0530 }
0531 
0532 QVariant DataVisitor::doVisit(ElfGNUSymbolVersionDefinitionAuxiliaryEntry* auxEntry, int role) const
0533 {
0534     switch (role) {
0535         case Qt::DisplayRole:
0536             return auxEntry->name();
0537         case ElfModel::SizeRole:
0538             return (int)sizeof(Elf64_Verdaux);
0539         case ElfModel::DetailRole:
0540         {
0541             QString s;
0542             s += QLatin1String("Name: ") + auxEntry->name() + "<br/>";
0543             s += "Next: " + QString::number(auxEntry->nextAuxiliaryEntryOffset()) + "<br/>";
0544             return s;
0545         }
0546     }
0547     return {};
0548 }
0549 
0550 QVariant DataVisitor::doVisit(ElfGNUSymbolVersionRequirement *verNeed, int role) const
0551 {
0552     switch (role) {
0553         case Qt::DisplayRole:
0554             return verNeed->fileName();
0555         case ElfModel::SizeRole:
0556             return verNeed->size();
0557         case ElfModel::DetailRole:
0558         {
0559             QString s;
0560             s += "File: " + QString(verNeed->fileName()) + "<br/>";
0561             s += "Aux count: " + QString::number(verNeed->auxiliarySize()) + "<br/>";
0562             s += "Aux offset: " + QString::number(verNeed->auxiliaryOffset()) + "<br/>";
0563             s += "Next offset: " + QString::number(verNeed->nextOffset()) + "<br/>";
0564             return s;
0565         }
0566     }
0567     return {};
0568 }
0569 
0570 QVariant DataVisitor::doVisit(ElfGNUSymbolVersionRequirementAuxiliaryEntry* auxEntry, int role) const
0571 {
0572     switch (role) {
0573         case Qt::DisplayRole:
0574             return auxEntry->name();
0575         case ElfModel::SizeRole:
0576             return (int)sizeof(Elf64_Vernaux);
0577         case ElfModel::DetailRole:
0578         {
0579             QString s;
0580             s += QLatin1String("Name: ") + auxEntry->name() + "<br/>";
0581             s += "Hash: " + QString::number(auxEntry->hash()) + "<br/>";
0582             s += "Flags: " + QString::number(auxEntry->flags()) + "<br/>";
0583             s += "Other: " + QString::number(auxEntry->other()) + "<br/>";
0584             s += "Next: " + QString::number(auxEntry->nextAuxiliaryEntryOffset()) + "<br/>";
0585             return s;
0586         }
0587     }
0588     return {};
0589 }
0590 
0591 QVariant DataVisitor::doVisit(ElfGotEntry* entry, int role) const
0592 {
0593     switch (role) {
0594         case Qt::DisplayRole:
0595         {
0596             const auto reloc = entry->relocation();
0597             const auto sym = reloc ? reloc->symbol() : nullptr;
0598             if (sym)
0599                 return sym->name() + QStringLiteral("@got");
0600             return "GOT entry " + QString::number(entry->index());
0601         }
0602         case ElfModel::SizeRole:
0603             return entry->section()->file()->addressSize();
0604         case ElfModel::DetailRole:
0605         {
0606             QString s;
0607             s += QLatin1String("<b>GOT entry</b><br/>");
0608             s += "Address: 0x" + QString::number(entry->address(), 16) + "<br/><br/>";
0609             const auto reloc = entry->relocation();
0610             s += printRelocation(reloc);
0611             return s;
0612         }
0613     }
0614     return {};
0615 }
0616 
0617 QVariant DataVisitor::doVisit(ElfNoteEntry* entry, int role) const
0618 {
0619     switch (role) {
0620         case Qt::DisplayRole:
0621             return NoteSectionPrinter::typeDisplayString(entry);
0622         case ElfModel::SizeRole:
0623             return QVariant::fromValue<quint64>(entry->size());
0624         case ElfModel::DetailRole:
0625         {
0626             QString s(QStringLiteral("Name: "));
0627             s += entry->name() + QStringLiteral("<br/>Description: ");
0628             if (entry->isGNUVendorNote() && entry->type() == NT_GNU_ABI_TAG) {
0629                 s += NoteSectionPrinter::abi(entry);
0630             } else if (entry->isGNUVendorNote() && entry->type() == NT_GNU_GOLD_VERSION) {
0631                 s += QByteArray(entry->descriptionData(), entry->descriptionSize());
0632             } else {
0633                 s += QByteArray(entry->descriptionData(), entry->descriptionSize()).toHex();
0634             }
0635             return s;
0636         }
0637     }
0638 
0639     return QVariant();
0640 }
0641 
0642 QVariant DataVisitor::doVisit(ElfPltEntry* entry, int role) const
0643 {
0644     switch (role) {
0645         case Qt::DisplayRole:
0646         {
0647             const auto gotEntry = entry->gotEntry();
0648             const auto reloc = gotEntry ? gotEntry->relocation() : nullptr;
0649             const auto sym = reloc ? reloc->symbol() : nullptr;
0650             if (sym)
0651                 return sym->name() + QStringLiteral("@plt");
0652             return "PLT entry " + QString::number(entry->index());
0653         }
0654         case ElfModel::SizeRole:
0655             return QVariant::fromValue<quint64>(entry->size());
0656         case ElfModel::DetailRole:
0657         {
0658             QString s(QStringLiteral("<b>PLT Entry</b><br/>Virtual address: 0x"));
0659             s += QString::number(entry->section()->header()->virtualAddress() + entry->index() * entry->size(), 16);
0660             s += QLatin1String("<br/>Code:<br/><tt>");
0661             NavigatingDisassembler da(this);
0662             s += da.disassemble(entry);
0663             s += QLatin1String("</tt><br/>");
0664 
0665             const auto got = entry->gotEntry();
0666             if (got) {
0667                 // TODO add navigation link
0668                 s += QLatin1String("<b>Corresponding GOT entry</b><br/>");
0669                 s += "Address: 0x" + QString::number(got->address(), 16) + "<br/><br/>";
0670                 const auto reloc = got->relocation();
0671                 s += printRelocation(reloc);
0672             }
0673 
0674             return s;
0675         }
0676     }
0677 
0678     return {};
0679 }
0680 
0681 QVariant DataVisitor::doVisit(ElfRelocationEntry *entry, int arg) const
0682 {
0683     switch (arg) {
0684         case Qt::DisplayRole:
0685             return RelocationPrinter::label(entry) + " 0x" + QString::number(entry->offset(), 16);
0686             break;
0687         case ElfModel::DetailRole:
0688             return printRelocation(entry);
0689     }
0690 
0691     return {};
0692 }
0693 
0694 #if HAVE_DWARF
0695 QVariant DataVisitor::doVisit(DwarfInfo* info, int arg) const
0696 {
0697     const auto sectionIndex = info->elfFile()->indexOfSection(".debug_info");
0698     const auto section = info->elfFile()->section<ElfSection>(sectionIndex);
0699     return doVisit(section, arg);
0700 }
0701 
0702 QVariant DataVisitor::doVisit(DwarfDie* die, int arg) const
0703 {
0704     switch (arg) {
0705         case Qt::DisplayRole:
0706             return die->displayName();
0707         case ElfModel::DetailRole:
0708         {
0709             QString s = printDwarfDie(die);
0710             s += CodeNavigatorPrinter::sourceLocationRichText(die);
0711 
0712             if ((die->tag() == DW_TAG_structure_type || die->tag() == DW_TAG_class_type) && die->typeSize() > 0) {
0713                 s += QLatin1String("<tt><pre>");
0714                 StructurePackingCheck check;
0715                 check.setElfFileSet(m_model->fileSet());
0716                 s += check.checkOneStructure(die).toHtmlEscaped();
0717                 s += QLatin1String("</pre></tt><br/>");
0718             }
0719 
0720             return s;
0721         }
0722     }
0723     return {};
0724 }
0725 #endif
0726 
0727 QString DataVisitor::printSectionName(ElfSection* section) const
0728 {
0729     const auto idx = m_model->indexForNode(section);
0730     const auto url = idx.data(ElfModel::NodeUrl).toUrl();
0731 
0732     QString s(QStringLiteral("<a href=\""));
0733     s += url.toEncoded();
0734     s += QLatin1String("\">");
0735     s += section->header()->name();
0736     s += QLatin1String("</a>");
0737 
0738     return s;
0739 }
0740 
0741 QString DataVisitor::printSymbolName(ElfSymbolTableEntry* symbol) const
0742 {
0743     const auto idx = m_model->indexForNode(symbol);
0744     const auto url = idx.data(ElfModel::NodeUrl).toUrl();
0745 
0746     QString s(QStringLiteral("<a href=\""));
0747     s += url.toEncoded();
0748     s += QLatin1String("\">");
0749     s += symbol->name();
0750     s += QLatin1String("</a>");
0751 
0752     return s;
0753 }
0754 
0755 QString DataVisitor::printRelocation(ElfRelocationEntry* entry) const
0756 {
0757     QString s;
0758     if (!entry)
0759         return s;
0760 
0761     s += QLatin1String("<b>Relocation</b><br/>");
0762     s += "Offset: 0x" + QString::number(entry->offset(), 16);
0763     const auto sym = entry->relocationTable()->file()->symbolTable()->entryContainingValue(entry->offset());
0764     if (sym) {
0765         s += QLatin1String(" (") + printSymbolName(sym) + " + 0x" + QString::number(entry->offset() - sym->value(), 16) + ')';
0766     } else {
0767         foreach (const auto shdr, entry->relocationTable()->file()->sectionHeaders()) {
0768             if (shdr->virtualAddress() <= entry->offset() && entry->offset() < shdr->virtualAddress() + shdr->size()) {
0769                 s += QLatin1String(" (") + shdr->name() + " + 0x" + QString::number(entry->offset() - shdr->virtualAddress(), 16) + ')';
0770                 break;
0771             }
0772         }
0773     }
0774     s += QLatin1String("<br/>");
0775     s += "Type: " + RelocationPrinter::description(entry) + " (" + RelocationPrinter::label(entry) + ")<br/>";
0776     const auto sourceSym = entry->symbol();
0777     if (sourceSym) {
0778         s += QLatin1String("Symbol: ") + printSymbolName(sourceSym) + "<br/>";
0779         s += QLatin1String("Demangled symbol: ") + QString(Demangler::demangleFull(sourceSym->name())).toHtmlEscaped() + "<br/>";
0780     } else {
0781         s += QStringLiteral("Symbol: &lt;none&gt;<br/>");
0782     }
0783     s += "Addend: 0x" + QString::number(entry->addend(), 16);
0784     return s;
0785 }
0786 
0787 #if HAVE_DWARF
0788 QString DataVisitor::printDwarfDie(DwarfDie* die) const
0789 {
0790     assert(die);
0791     QString s;
0792     s += "TAG: " + QLatin1String(die->tagName()) + "<br/>";
0793     s += "Name: " + QString::fromUtf8(die->name()).toHtmlEscaped() + "<br/>";
0794     s += "Offset: " + QString::number(die->offset()) + "<br/>";
0795     foreach (const auto attrType, die->attributes()) {
0796         const QVariant attrValue = die->attribute(attrType);
0797         QString attrValueStr;
0798         if (DwarfDie *die = attrValue.value<DwarfDie*>())
0799             attrValueStr = printDwarfDieName(die);
0800         else
0801             attrValueStr = attrValue.toString().toHtmlEscaped();
0802         s += QLatin1String(die->attributeName(attrType)) + ": " + attrValueStr + "<br/>";
0803     }
0804     return s;
0805 }
0806 
0807 QString DataVisitor::printDwarfDieName(DwarfDie* die) const
0808 {
0809     const auto idx = m_model->indexForNode(die);
0810     const auto url = idx.data(ElfModel::NodeUrl).toUrl();
0811 
0812     QString s(QStringLiteral("<a href=\""));
0813     s += url.toEncoded();
0814     s += QLatin1String("\">");
0815     s += die->displayName().toHtmlEscaped();
0816     s += QLatin1String("</a>");
0817 
0818     return s;
0819 }
0820 #endif