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("<local>"); 0271 break; 0272 case VER_NDX_GLOBAL: 0273 s += QLatin1String("<global>"); 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 += " " + 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: <none><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