1 /*
2     Copyright (C) 2013-2014 Volker Krause <vkrause@kde.org>
3 
4     This program is free software; you can redistribute it and/or modify it
5     under the terms of the GNU Library General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or (at your
7     option) any later version.
8 
9     This program is distributed in the hope that it will be useful, but WITHOUT
10     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
12     License for more details.
13 
14     You should have received a copy of the GNU General Public License
15     along with this program.  If not, see <https://www.gnu.org/licenses/>.
16 */
17 
18 #include "elfdefinitions.h" // must come first before <elf.h>
19 #define _ELF_H_
20 #include "datavisitor.h"
21 #include "elfmodel.h"
22 
23 #include <elf/elffile.h>
24 #include <elf/elfnoteentry.h>
25 #include <elf/elfgnusymbolversiontable.h>
26 #include <elf/elfgnusymbolversiondefinitionssection.h>
27 #include <elf/elfgnusymbolversiondefinitionauxiliaryentry.h>
28 #include <elf/elfgnusymbolversionrequirement.h>
29 #include <elf/elfgnusymbolversionrequirementauxiliaryentry.h>
30 #include <elf/elfsegmentheader.h>
31 #include <elf.h>
32 
33 #include <dwarf/dwarfaddressranges.h>
34 
35 #include <disassmbler/disassembler.h>
36 #include <demangle/demangler.h>
37 #include <checks/structurepackingcheck.h>
38 #include <navigator/codenavigatorprinter.h>
39 
40 #include <printers/dwarfprinter.h>
41 #include <printers/dynamicsectionprinter.h>
42 #include <printers/elfprinter.h>
43 #include <printers/gnuversionprinter.h>
44 #include <printers/notesectionprinter.h>
45 #include <printers/relocationprinter.h>
46 #include <printers/symbolprinter.h>
47 
48 #include <QIcon>
49 #include <QUrl>
50 
51 #include <cassert>
52 
53 class NavigatingDisassembler : public Disassembler
54 {
55 public:
NavigatingDisassembler(const DataVisitor * v)56     NavigatingDisassembler(const DataVisitor *v) : m_v(v) {}
57 
printSymbol(ElfSymbolTableEntry * entry) const58     QString printSymbol(ElfSymbolTableEntry* entry) const override
59     {
60         return m_v->printSymbolName(entry);
61     }
62 
printGotEntry(ElfGotEntry * entry) const63     QString printGotEntry(ElfGotEntry* entry) const override
64     {
65         QString s;
66         s += QLatin1String("<a href=\"");
67         s += m_v->m_model->indexForNode(entry).data(ElfModel::NodeUrl).toUrl().toEncoded();
68         s += QLatin1String("\">");
69         s += Disassembler::printGotEntry(entry);
70         s += QLatin1String("</a>");
71         return s;
72     }
73 
printPltEntry(ElfPltEntry * entry) const74     QString printPltEntry(ElfPltEntry* entry) const override
75     {
76         QString s;
77         s += QLatin1String("<a href=\"");
78         s += m_v->m_model->indexForNode(entry).data(ElfModel::NodeUrl).toUrl().toEncoded();
79         s += QLatin1String("\">");
80         s += Disassembler::printPltEntry(entry);
81         s += QLatin1String("</a>");
82         return s;
83     }
84 
85 private:
86     const DataVisitor* const m_v;
87 };
88 
DataVisitor(const ElfModel * model,int column)89 DataVisitor::DataVisitor(const ElfModel* model, int column) :
90     m_model(model),
91     m_column(column)
92 {
93 }
94 
doVisit(ElfFile * file,int arg) const95 QVariant DataVisitor::doVisit(ElfFile* file, int arg) const
96 {
97     switch (arg) {
98         case Qt::DisplayRole:
99             return file->displayName();
100         case Qt::ToolTipRole:
101             return file->fileName();
102         case ElfModel::SizeRole:
103             return QVariant::fromValue<uint64_t>(file->size());
104         case ElfModel::DetailRole:
105         {
106             QString s;
107             s += "File name: " + file->fileName() + "<br/>";
108             s += QLatin1String("Address size: ") + (file->type() == ELFCLASS32 ? "32 bit" : "64 bit") + "<br/>";
109             s += QLatin1String("Byte order: ") + (file->byteOrder() == ELFDATA2LSB ? "little endian" : "big endian") + "<br/>";
110             s += QLatin1String("File type: ") + ElfPrinter::fileType(file->header()->type()) + "<br/>";
111             s += QLatin1String("Machine: ") + ElfPrinter::machine(file->header()->machine()) + "<br/>";
112             s += QLatin1String("OS ABI: ") + ElfPrinter::osAbi(file->osAbi()) + "<br/>";
113             s += "Flags: " + QString::number(file->header()->flags()) + "<br/>";
114             s += QLatin1String("Entry point: 0x") + QString::number(file->header()->entryPoint(), 16);
115             if (file->header()->entryPoint() && file->symbolTable()) {
116                 const auto entry = file->symbolTable()->entryWithValue(file->header()->entryPoint());
117                 if (entry)
118                     s += " (" + printSymbolName(entry) + ')';
119             }
120             if (file->separateDebugFile())
121                 s += "<br/>Separate debug file: " + file->separateDebugFile()->fileName();
122             s += QLatin1String("<br/><br/>");
123 
124             s += QLatin1String("<b>Segments</b></br>");
125             s += QLatin1String("<table border=\"1\" border-style=\"solid\" cellspacing=\"0\">");
126             s += QLatin1String("<tr><th>Type</th><th>Flags</th><th>Offset</th><th>Virtual Address</th>");
127             s += QLatin1String("<th>Physical Address</th><th>File Size</th><th>Memory Size</th><th>Alignment</th></tr>");
128             foreach (auto phdr, file->segmentHeaders()) {
129                 s += QLatin1String("<tr>");
130                 s += "<td>" + ElfPrinter::segmentType(phdr->type()) + "</td>";
131                 s += "<td>" + ElfPrinter::segmentFlags(phdr->flags()) + "</td>";
132                 s += "<td>0x" + QString::number(phdr->offset(), 16) + "</td>";
133                 s += "<td>0x" + QString::number(phdr->virtualAddress(), 16) + "</td>";
134                 s += "<td>0x" + QString::number(phdr->physicalAddress(), 16) + "</td>";
135                 s += "<td>" + QString::number(phdr->fileSize()) + "</td>";
136                 s += "<td>" + QString::number(phdr->memorySize()) + "</td>";
137                 s += "<td>0x" + QString::number(phdr->alignment(), 16) + "</td>";
138                 s += QLatin1String("</tr>");
139             }
140             s += QLatin1String("</table");
141             return s;
142         }
143         case ElfModel::FileRole:
144             return QVariant::fromValue(file);
145     }
146     return QVariant();
147 }
148 
doVisit(ElfSection * section,int arg) const149 QVariant DataVisitor::doVisit(ElfSection* section, int arg) const
150 {
151     switch (arg) {
152         case Qt::DisplayRole:
153             if (*section->header()->name() == 0)
154                 return QObject::tr("<null>");
155             return section->header()->name();
156         case Qt::DecorationRole:
157             if (m_column == 0 && section->file()->isSeparateDebugFile())
158                 return QIcon::fromTheme(QStringLiteral("package_development_debugger"));
159             return {};
160         case ElfModel::SizeRole:
161             return QVariant::fromValue<uint64_t>(section->size());
162         case ElfModel::DetailRole:
163         {
164             QString s(QStringLiteral("<b>Section</b><br/>"));
165             s += QLatin1String("Name: ") + section->header()->name() + "<br/>";
166             s += QLatin1String("Size: ") + QString::number(section->header()->size()) + " bytes<br/>";
167             s += QLatin1String("Flags: ") + ElfPrinter::sectionFlags(section->header()->flags()) + "<br/>";
168             s += QLatin1String("Offset: 0x") + QString::number(section->header()->sectionOffset(), 16) + "<br/>";
169             s += QLatin1String("Virtual Address: 0x") + QString::number(section->header()->virtualAddress(), 16) + "<br/>";
170             s += QLatin1String("Type: ") + ElfPrinter::sectionType(section->header()->type()) + "<br/>";
171             if (section->header()->link())
172                 s += "Linked section: " + printSectionName(section->linkedSection<ElfSection>()) + "<br/>";
173             if (section->header()->flags() & SHF_INFO_LINK)
174                 s += "Referenced section: " + printSectionName(section->file()->section<ElfSection>(section->header()->info())) + "<br/>";
175             if (section->header()->entrySize()) {
176                 s += QLatin1String("Entries: ") + QString::number(section->header()->entryCount())
177                   + " x " + QString::number(section->header()->entrySize()) + " byte<br/>";
178             }
179             if (section->header()->flags() & SHF_STRINGS && section->size() < 100000) { // QTextBrowser fails on too large input
180                 s += QLatin1String("Strings:<br/>");
181                 uint prevIndex = 0, index = 0;
182                 do {
183                     if (section->rawData()[index] == 0) {
184                         if (index - prevIndex > 0) {
185                             const auto b = QByteArray::fromRawData(reinterpret_cast<const char*>(section->rawData() + prevIndex), index - prevIndex);
186                             s += QString::number(prevIndex) + ": " + b + "<br/>";
187                         }
188                         prevIndex = index + 1;
189                     }
190                     ++index;
191                 } while (index < section->size());
192             }
193             if (strcmp(section->header()->name(), ".init") == 0 || strcmp(section->header()->name(), ".fini") == 0) {
194                 NavigatingDisassembler da(this);
195                 s += "Code:<br/><tt>" + da.disassemble(section) + "</tt>";
196             }
197             if (section->header()->type() == SHT_INIT_ARRAY || section->header()->type() == SHT_FINI_ARRAY) {
198                 const auto addrSize = section->file()->addressSize();
199                 s += QLatin1String("Content:<br/>");
200                 for (uint i = 0; i < section->header()->size() / addrSize; ++i) {
201                     uint64_t value = 0;
202                     memcpy(&value, section->rawData() + i * addrSize, addrSize);
203                     s += QString::number(i) + ": 0x" + QString::number(value, 16);
204                     if (value) {
205                         const auto ref = section->file()->symbolTable()->entryWithValue(value);
206                         if (ref)
207                             s += QLatin1Char(' ') + printSymbolName(ref);
208                     } else { // check for relocation
209                         const auto relocEntry = section->file()->reverseRelocator()->find(section->header()->virtualAddress() + i * addrSize);
210                         if (relocEntry) {
211                             const auto sym = section->file()->symbolTable()->entryContainingValue(relocEntry->relocationTarget());
212                             if (sym)
213                                 s += " relocated to: " + printSymbolName(sym);
214                         }
215                     }
216 
217                     s += QLatin1String("<br/>");
218                 }
219             }
220             return s;
221         }
222         case ElfModel::SectionRole:
223             return QVariant::fromValue(section);
224     }
225 
226     return QVariant();
227 }
228 
doVisit(ElfSymbolTableSection * symtab,int arg) const229 QVariant DataVisitor::doVisit(ElfSymbolTableSection* symtab, int arg) const
230 {
231     const auto base = doVisit(static_cast<ElfSection*>(symtab), arg);
232     if (arg != ElfModel::DetailRole)
233         return base;
234     QString s = base.toString();
235     s += QLatin1String("<br/><b>Symbol Table</b>");
236     s += "<br/>Exported symbols: " + QString::number(symtab->exportCount());
237     s += "<br/>Imported symbols: " + QString::number(symtab->importCount());
238     s += QLatin1String("<br/>");
239     return s;
240 }
241 
virtualTableEntry(ElfSymbolTableEntry * entry,int index)242 static uint64_t virtualTableEntry(ElfSymbolTableEntry *entry, int index)
243 {
244     const auto addrSize = entry->symbolTable()->file()->addressSize();
245     assert(entry->size() % addrSize == 0);
246 
247     // TODO this assumes endianess equalness
248     if (addrSize == 8)
249         return *reinterpret_cast<const uint64_t*>(entry->data() + index * addrSize);
250     if (addrSize == 4)
251         return *reinterpret_cast<const uint32_t*>(entry->data() + index * addrSize);
252 
253     Q_UNREACHABLE();
254 }
255 
printVerSymInfo(ElfSymbolTableEntry * entry)256 static QString printVerSymInfo(ElfSymbolTableEntry *entry)
257 {
258     if (entry->symbolTable()->header()->type() != SHT_DYNSYM)
259         return {};
260     const ElfFile *file = entry->symbolTable()->file();
261     const auto verSymIdx = file->indexOfSection(SHT_GNU_versym);
262     if (verSymIdx < 0)
263         return {};
264     const auto verSymTab = file->section<ElfGNUSymbolVersionTable>(verSymIdx);
265     const auto versionIndex = verSymTab->versionIndex(entry->index());
266 
267     QString s(QStringLiteral("GNU version: "));
268     switch (versionIndex) {
269         case VER_NDX_LOCAL:
270             s += QLatin1String("&lt;local&gt;");
271             break;
272         case VER_NDX_GLOBAL:
273             s += QLatin1String("&lt;global&gt;");
274             break;
275         default:
276         {
277             auto f = entry->symbolTable()->file();
278             if (entry->hasValidSection()) { // definition
279                 const auto verDefIdx = f->indexOfSection(SHT_GNU_verdef);
280                 if (verDefIdx <= 0) {
281                     s += QString::number(versionIndex);
282                 } else {
283                     auto verDefSection = f->section<ElfGNUSymbolVersionDefinitionsSection>(verDefIdx);
284                     assert(verDefSection);
285                     s += verDefSection->definitionForVersionIndex(versionIndex)->auxiliaryEntry(0)->name();
286                 }
287                 break;
288             } else { // requirement
289                 const auto verReqIdx = f->indexOfSection(SHT_GNU_verneed);
290                 auto verReqSection = f->section<ElfGNUSymbolVersionRequirementsSection>(verReqIdx);
291                 assert(verReqSection);
292                 s += verReqSection->requirementForVersionIndex(versionIndex)->name();
293                 break;
294             }
295             s += QString::number(versionIndex);
296         }
297     };
298     if (verSymTab->isHidden(entry->index()))
299         s += QLatin1String(" (hidden)");
300     s += QLatin1String("<br/>");
301     return s;
302 }
303 
findDwarfDie(ElfSymbolTableEntry * entry)304 static DwarfDie* findDwarfDie(ElfSymbolTableEntry *entry)
305 {
306     auto *dwarf = entry->symbolTable()->file()->dwarfInfo();
307     if (!dwarf || entry->value() == 0)
308         return nullptr;
309 
310     DwarfDie* res = nullptr;
311     if (dwarf->addressRanges()->isValid())
312        res = dwarf->addressRanges()->dieForAddress(entry->value());
313     if (!res)
314         res = dwarf->dieForMangledSymbol(entry->name());
315     return res;
316 }
317 
doVisit(ElfSymbolTableEntry * entry,int arg) const318 QVariant DataVisitor::doVisit(ElfSymbolTableEntry* entry, int arg) const
319 {
320     switch (arg) {
321         case Qt::DisplayRole:
322             if (*entry->name() == 0)
323                 return QObject::tr("<null>");
324             return entry->name();
325         case ElfModel::SizeRole:
326             return QVariant::fromValue<uint64_t>(entry->size());
327         case ElfModel::DetailRole:
328         {
329             QString s(QStringLiteral("<b>Symbol</b><br/>"));
330             s += QLatin1String("Mangled name: ") + entry->name() + "<br/>";
331             Demangler demangler;
332             s += QLatin1String("Demangled name: ") + QString(demangler.demangleFull(entry->name())).toHtmlEscaped() + "<br/>";
333             s += QLatin1String("Size: ") + QString::number(entry->size()) + "<br/>";
334             s += QLatin1String("Value: 0x") + QString::number(entry->value(), 16) + "<br/>";
335             s += QLatin1String("Bind type: ") + SymbolPrinter::bindType(entry->bindType()) + "<br/>";
336             s += QLatin1String("Symbol type: ") + SymbolPrinter::symbolType(entry->type()) + "<br/>";
337             s += QLatin1String("Visibility: ") + SymbolPrinter::visibility(entry->visibility()) + "<br/>";
338             s += printVerSymInfo(entry);
339 
340             const auto hasValidSectionIndex = entry->hasValidSection();
341             if (hasValidSectionIndex) {
342                 s += "Section: " + printSectionName(entry->section()) + "<br/>";
343             }
344 
345             if (hasValidSectionIndex && entry->sectionHeader()->type() == SHT_NOBITS) {
346                 // .bss, i.e. no content to display
347             } else if (entry->type() == STT_FUNC && entry->size() > 0) {
348                 NavigatingDisassembler da(this);
349                 s += QLatin1String("Code:<br/><tt>") + da.disassemble(entry) + "</tt>";
350             } else if (entry->type() == STT_OBJECT && entry->size() > 0) {
351                 const auto addrSize = entry->symbolTable()->file()->addressSize();
352                 const auto symbolType = Demangler::symbolType(entry->name());
353                 switch (symbolType) {
354                     case Demangler::SymbolType::VTable:
355                     case Demangler::SymbolType::ConstructionVTable:
356                     {
357                         s += symbolType == Demangler::SymbolType::ConstructionVTable ? QObject::tr("Construction VTable") : QObject::tr("VTable");
358                         s += QLatin1String(":<br/><tt>");
359                         for (uint i = 0; i < entry->size() / addrSize; ++i) {
360                             const uint64_t v = virtualTableEntry(entry, i);
361                             s += QString::number(i) + ": 0x" + QString::number(v, 16);
362                             const auto ref = entry->symbolTable()->entryWithValue(v);
363                             if (ref) {
364                                 s += QLatin1Char(' ') + printSymbolName(ref) + QLatin1String(" (") + Demangler::demangleFull(ref->name()) + QLatin1Char(')');
365                             } else {
366                                 auto reloc = entry->symbolTable()->file()->reverseRelocator()->find(entry->value() + i * addrSize);
367                                 if (reloc) {
368                                     const auto relocSym = reloc->symbol();
369                                     if (relocSym)
370                                         s += QLatin1String(" relocation: ") + printSymbolName(relocSym);
371                                 }
372                             }
373                             s += QLatin1String("<br/>");
374                         }
375                         s += QLatin1String("</tt><br/>");
376                         break;
377                     }
378                     case Demangler::SymbolType::VTT:
379                     {
380                         s += QLatin1String("VTT:<br/><tt>");
381                         for (uint i = 0; i < entry->size() / addrSize; ++i) {
382                             const uint64_t v = virtualTableEntry(entry, i);
383                             s += QString::number(i) + ": 0x" + QString::number(v, 16);
384                             // vptrs point to one after the RTTI entry, which is the first virtual method, unless there is none in that
385                             // case we would point past the vtable here, and thus we wont find it, so better look for the RTTI spot.
386                             const auto ref = entry->symbolTable()->entryContainingValue(v - addrSize);
387                             if (ref) {
388                                 const auto offset = v - ref->value();
389                                 s += QLatin1String(" entry ") + QString::number(offset / addrSize) + QLatin1String(" in ") + printSymbolName(ref);
390                                 s += QLatin1String(" (") + Demangler::demangleFull(ref->name()) + QLatin1Char(')');
391                             }
392                             s += QLatin1String("<br/>");
393                         }
394                         s += QLatin1String("</tt><br/>");
395                         break;
396                     }
397                     case Demangler::SymbolType::TypeInfoName:
398                         s += "Type info name: " + QByteArray((const char*)entry->data()) + "<br/>";
399                         break;
400                     // TODO: add other symbol types
401                     default:
402                         s += QStringLiteral("Data:<br/><tt>");
403                         const unsigned char* data = entry->data();
404                         s += QByteArray::fromRawData((const char*)data, entry->size()).toHex();
405                         s += QLatin1String("</tt><br/>");
406                 }
407             }
408 
409             const auto die = findDwarfDie(entry);
410             if (die) {
411                 s += CodeNavigatorPrinter::sourceLocationRichText(die);
412                 s += QLatin1String("<br/><b>DWARF DIE</b><br/>");
413                 s += printDwarfDie(die);
414             }
415             return s;
416         }
417     }
418 
419     return QVariant();
420 }
421 
doVisit(ElfGnuDebugLinkSection * section,int role) const422 QVariant DataVisitor::doVisit(ElfGnuDebugLinkSection* section, int role) const
423 {
424     auto baseData = doVisit(static_cast<ElfSection*>(section), role);
425     if (role == ElfModel::DetailRole) {
426         QString s = baseData.toString();
427         s += QLatin1String("<br/><b>Debug Link</b>");
428         s += "<br/>File name: " + section->fileName();
429         s += "<br/>CRC: 0x" + QString::number(section->crc(), 16);
430         return s;
431     }
432     return baseData;
433 }
434 
doVisit(ElfDynamicEntry * entry,int arg) const435 QVariant DataVisitor::doVisit(ElfDynamicEntry *entry, int arg) const
436 {
437     switch (arg) {
438         case Qt::DisplayRole:
439             return entry->tagName();
440         case ElfModel::DetailRole:
441         {
442             QString s;
443             s += QLatin1String("Tag name: ") + entry->tagName() + "<br/>";
444             s += QStringLiteral("Value: ");
445             switch (entry->tag()) {
446                 case DT_FLAGS:
447                     s += DynamicSectionPrinter::flagsToDescriptions(entry->value());
448                     break;
449                 case DT_FLAGS_1:
450                     s += DynamicSectionPrinter::flags1ToDescriptions(entry->value());
451                     break;
452                 case DT_PLTREL:
453                     s += RelocationPrinter::label(entry->dynamicSection()->file()->header()->machine(), entry->value());
454                     break;
455                 default:
456                     if (entry->isStringValue()) {
457                         s+= entry->stringValue();
458                     } else if (entry->isAddress()) {
459                         s += QLatin1String("0x") + QString::number(entry->pointer(), 16);
460                         const auto secIdx = entry->dynamicSection()->file()->indexOfSectionWithVirtualAddress(entry->pointer());
461                         if (secIdx >= 0) {
462                             const auto section = entry->dynamicSection()->file()->section<ElfSection>(secIdx);
463                             assert(section);
464                             s += " (" + printSectionName(section);
465                             if (section->header()->virtualAddress() < entry->pointer())
466                                 s += " + 0x" + QString::number(entry->pointer() - section->header()->virtualAddress(), 16);
467                             s += ')';
468                         }
469                     } else {
470                         s += QString::number(entry->value());
471                     }
472             }
473             s += QLatin1String("<br/>");
474             return s;
475         }
476     }
477 
478     return QVariant();
479 }
480 
doVisit(ElfHashSection * section,int role) const481 QVariant DataVisitor::doVisit(ElfHashSection* section, int role) const
482 {
483     const auto base = doVisit(static_cast<ElfSection*>(section), role);
484     if (role == ElfModel::DetailRole) {
485         QString s = base.toString();
486         s += QLatin1String("<br/><b>Hash Table</b><br/>");
487         s += "Buckets: " + QString::number(section->bucketCount()) + "<br/>";
488         s += "Chains: " + QString::number(section->chainCount()) + "<br/>";
489         if (ElfGnuHashSection *gnuHash = dynamic_cast<ElfGnuHashSection*>(section)) {
490             s += "Symbol table index: " + QString::number(gnuHash->symbolIndex()) + "<br/>";
491             s += "Mask word count: " + QString::number(gnuHash->maskWordsCount()) + "<br/>";
492             s += "Shift count: " + QString::number(gnuHash->shift2()) + "<br/>";
493         }
494 
495         s += QLatin1String("Chain length histogram<br/>");
496         const auto hist = section->histogram();
497         for (int i = 0; i < hist.size(); ++i) {
498             s += "&nbsp;&nbsp;" + QString::number(i) + ": " + QString::number(hist.at(i)) + "<br/>";
499         }
500         s += "Average collision common prefix length: " + QString::number(section->averagePrefixLength()) + "<br/>";
501         return s;
502     }
503     return base;
504 }
505 
doVisit(ElfGNUSymbolVersionDefinition * verDef,int role) const506 QVariant DataVisitor::doVisit(ElfGNUSymbolVersionDefinition* verDef, int role) const
507 {
508     switch (role) {
509         case Qt::DisplayRole:
510             return "version definition";
511         case ElfModel::SizeRole:
512             return verDef->size();
513         case ElfModel::DetailRole:
514         {
515             QString s;
516             s += "Flags: " + GnuVersionPrinter::versionFlags(verDef->flags()) + "<br/>";
517             s += "Index: " + QString::number(verDef->versionIndex()) + "<br/>";
518             s += "Aux count: " + QString::number(verDef->auxiliarySize()) + "<br/>";
519             s += "Hash: " + QString::number(verDef->hash()) + "<br/>";
520             s += "Aux offset: " + QString::number(verDef->auxiliaryOffset()) + "<br/>";
521             s += "Next offset: " + QString::number(verDef->nextOffset()) + "<br/>";
522             return s;
523         }
524     }
525     return {};
526 }
527 
doVisit(ElfGNUSymbolVersionDefinitionAuxiliaryEntry * auxEntry,int role) const528 QVariant DataVisitor::doVisit(ElfGNUSymbolVersionDefinitionAuxiliaryEntry* auxEntry, int role) const
529 {
530     switch (role) {
531         case Qt::DisplayRole:
532             return auxEntry->name();
533         case ElfModel::SizeRole:
534             return (int)sizeof(Elf64_Verdaux);
535         case ElfModel::DetailRole:
536         {
537             QString s;
538             s += QLatin1String("Name: ") + auxEntry->name() + "<br/>";
539             s += "Next: " + QString::number(auxEntry->nextAuxiliaryEntryOffset()) + "<br/>";
540             return s;
541         }
542     }
543     return {};
544 }
545 
doVisit(ElfGNUSymbolVersionRequirement * verNeed,int role) const546 QVariant DataVisitor::doVisit(ElfGNUSymbolVersionRequirement *verNeed, int role) const
547 {
548     switch (role) {
549         case Qt::DisplayRole:
550             return verNeed->fileName();
551         case ElfModel::SizeRole:
552             return verNeed->size();
553         case ElfModel::DetailRole:
554         {
555             QString s;
556             s += "File: " + QString(verNeed->fileName()) + "<br/>";
557             s += "Aux count: " + QString::number(verNeed->auxiliarySize()) + "<br/>";
558             s += "Aux offset: " + QString::number(verNeed->auxiliaryOffset()) + "<br/>";
559             s += "Next offset: " + QString::number(verNeed->nextOffset()) + "<br/>";
560             return s;
561         }
562     }
563     return {};
564 }
565 
doVisit(ElfGNUSymbolVersionRequirementAuxiliaryEntry * auxEntry,int role) const566 QVariant DataVisitor::doVisit(ElfGNUSymbolVersionRequirementAuxiliaryEntry* auxEntry, int role) const
567 {
568     switch (role) {
569         case Qt::DisplayRole:
570             return auxEntry->name();
571         case ElfModel::SizeRole:
572             return (int)sizeof(Elf64_Vernaux);
573         case ElfModel::DetailRole:
574         {
575             QString s;
576             s += QLatin1String("Name: ") + auxEntry->name() + "<br/>";
577             s += "Hash: " + QString::number(auxEntry->hash()) + "<br/>";
578             s += "Flags: " + QString::number(auxEntry->flags()) + "<br/>";
579             s += "Other: " + QString::number(auxEntry->other()) + "<br/>";
580             s += "Next: " + QString::number(auxEntry->nextAuxiliaryEntryOffset()) + "<br/>";
581             return s;
582         }
583     }
584     return {};
585 }
586 
doVisit(ElfGotEntry * entry,int role) const587 QVariant DataVisitor::doVisit(ElfGotEntry* entry, int role) const
588 {
589     switch (role) {
590         case Qt::DisplayRole:
591         {
592             const auto reloc = entry->relocation();
593             const auto sym = reloc ? reloc->symbol() : nullptr;
594             if (sym)
595                 return sym->name() + QStringLiteral("@got");
596             return "GOT entry " + QString::number(entry->index());
597         }
598         case ElfModel::SizeRole:
599             return entry->section()->file()->addressSize();
600         case ElfModel::DetailRole:
601         {
602             QString s;
603             s += QLatin1String("<b>GOT entry</b><br/>");
604             s += "Address: 0x" + QString::number(entry->address(), 16) + "<br/><br/>";
605             const auto reloc = entry->relocation();
606             s += printRelocation(reloc);
607             return s;
608         }
609     }
610     return {};
611 }
612 
doVisit(ElfNoteEntry * entry,int role) const613 QVariant DataVisitor::doVisit(ElfNoteEntry* entry, int role) const
614 {
615     switch (role) {
616         case Qt::DisplayRole:
617             return NoteSectionPrinter::typeDisplayString(entry);
618         case ElfModel::SizeRole:
619             return QVariant::fromValue<quint64>(entry->size());
620         case ElfModel::DetailRole:
621         {
622             QString s(QStringLiteral("Name: "));
623             s += entry->name() + QStringLiteral("<br/>Description: ");
624             if (entry->isGNUVendorNote() && entry->type() == NT_GNU_ABI_TAG) {
625                 s += NoteSectionPrinter::abi(entry);
626             } else if (entry->isGNUVendorNote() && entry->type() == NT_GNU_GOLD_VERSION) {
627                 s += QByteArray(entry->descriptionData(), entry->descriptionSize());
628             } else {
629                 s += QByteArray(entry->descriptionData(), entry->descriptionSize()).toHex();
630             }
631             return s;
632         }
633     }
634 
635     return QVariant();
636 }
637 
doVisit(ElfPltEntry * entry,int role) const638 QVariant DataVisitor::doVisit(ElfPltEntry* entry, int role) const
639 {
640     switch (role) {
641         case Qt::DisplayRole:
642         {
643             const auto gotEntry = entry->gotEntry();
644             const auto reloc = gotEntry ? gotEntry->relocation() : nullptr;
645             const auto sym = reloc ? reloc->symbol() : nullptr;
646             if (sym)
647                 return sym->name() + QStringLiteral("@plt");
648             return "PLT entry " + QString::number(entry->index());
649         }
650         case ElfModel::SizeRole:
651             return QVariant::fromValue<quint64>(entry->size());
652         case ElfModel::DetailRole:
653         {
654             QString s(QStringLiteral("<b>PLT Entry</b><br/>Virtual address: 0x"));
655             s += QString::number(entry->section()->header()->virtualAddress() + entry->index() * entry->size(), 16);
656             s += QLatin1String("<br/>Code:<br/><tt>");
657             NavigatingDisassembler da(this);
658             s += da.disassemble(entry);
659             s += QLatin1String("</tt><br/>");
660 
661             const auto got = entry->gotEntry();
662             if (got) {
663                 // TODO add navigation link
664                 s += QLatin1String("<b>Corresponding GOT entry</b><br/>");
665                 s += "Address: 0x" + QString::number(got->address(), 16) + "<br/><br/>";
666                 const auto reloc = got->relocation();
667                 s += printRelocation(reloc);
668             }
669 
670             return s;
671         }
672     }
673 
674     return {};
675 }
676 
doVisit(ElfRelocationEntry * entry,int arg) const677 QVariant DataVisitor::doVisit(ElfRelocationEntry *entry, int arg) const
678 {
679     switch (arg) {
680         case Qt::DisplayRole:
681             return RelocationPrinter::label(entry) + " 0x" + QString::number(entry->offset(), 16);
682             break;
683         case ElfModel::DetailRole:
684             return printRelocation(entry);
685     }
686 
687     return {};
688 }
689 
doVisit(DwarfInfo * info,int arg) const690 QVariant DataVisitor::doVisit(DwarfInfo* info, int arg) const
691 {
692     const auto sectionIndex = info->elfFile()->indexOfSection(".debug_info");
693     const auto section = info->elfFile()->section<ElfSection>(sectionIndex);
694     return doVisit(section, arg);
695 }
696 
doVisit(DwarfDie * die,int arg) const697 QVariant DataVisitor::doVisit(DwarfDie* die, int arg) const
698 {
699     switch (arg) {
700         case Qt::DisplayRole:
701             return die->displayName();
702         case ElfModel::DetailRole:
703         {
704             QString s = printDwarfDie(die);
705             s += CodeNavigatorPrinter::sourceLocationRichText(die);
706 
707             if ((die->tag() == DW_TAG_structure_type || die->tag() == DW_TAG_class_type) && die->typeSize() > 0) {
708                 s += QLatin1String("<tt><pre>");
709                 StructurePackingCheck check;
710                 check.setElfFileSet(m_model->fileSet());
711                 s += check.checkOneStructure(die).toHtmlEscaped();
712                 s += QLatin1String("</pre></tt><br/>");
713             }
714 
715             return s;
716         }
717     }
718     return {};
719 }
720 
printSectionName(ElfSection * section) const721 QString DataVisitor::printSectionName(ElfSection* section) const
722 {
723     const auto idx = m_model->indexForNode(section);
724     const auto url = idx.data(ElfModel::NodeUrl).toUrl();
725 
726     QString s(QStringLiteral("<a href=\""));
727     s += url.toEncoded();
728     s += QLatin1String("\">");
729     s += section->header()->name();
730     s += QLatin1String("</a>");
731 
732     return s;
733 }
734 
printSymbolName(ElfSymbolTableEntry * symbol) const735 QString DataVisitor::printSymbolName(ElfSymbolTableEntry* symbol) const
736 {
737     const auto idx = m_model->indexForNode(symbol);
738     const auto url = idx.data(ElfModel::NodeUrl).toUrl();
739 
740     QString s(QStringLiteral("<a href=\""));
741     s += url.toEncoded();
742     s += QLatin1String("\">");
743     s += symbol->name();
744     s += QLatin1String("</a>");
745 
746     return s;
747 }
748 
printRelocation(ElfRelocationEntry * entry) const749 QString DataVisitor::printRelocation(ElfRelocationEntry* entry) const
750 {
751     QString s;
752     if (!entry)
753         return s;
754 
755     s += QLatin1String("<b>Relocation</b><br/>");
756     s += "Offset: 0x" + QString::number(entry->offset(), 16);
757     const auto sym = entry->relocationTable()->file()->symbolTable()->entryContainingValue(entry->offset());
758     if (sym) {
759         s += QLatin1String(" (") + printSymbolName(sym) + " + 0x" + QString::number(entry->offset() - sym->value(), 16) + ')';
760     } else {
761         foreach (const auto shdr, entry->relocationTable()->file()->sectionHeaders()) {
762             if (shdr->virtualAddress() <= entry->offset() && entry->offset() < shdr->virtualAddress() + shdr->size()) {
763                 s += QLatin1String(" (") + shdr->name() + " + 0x" + QString::number(entry->offset() - shdr->virtualAddress(), 16) + ')';
764                 break;
765             }
766         }
767     }
768     s += QLatin1String("<br/>");
769     s += "Type: " + RelocationPrinter::description(entry) + " (" + RelocationPrinter::label(entry) + ")<br/>";
770     const auto sourceSym = entry->symbol();
771     if (sourceSym) {
772         s += QLatin1String("Symbol: ") + printSymbolName(sourceSym) + "<br/>";
773         s += QLatin1String("Demangled symbol: ") + QString(Demangler::demangleFull(sourceSym->name())).toHtmlEscaped() + "<br/>";
774     } else {
775         s += QStringLiteral("Symbol: &lt;none&gt;<br/>");
776     }
777     s += "Addend: 0x" + QString::number(entry->addend(), 16);
778     return s;
779 }
780 
printDwarfDie(DwarfDie * die) const781 QString DataVisitor::printDwarfDie(DwarfDie* die) const
782 {
783     assert(die);
784     QString s;
785     s += "TAG: " + QLatin1String(die->tagName()) + "<br/>";
786     s += "Name: " + QString::fromUtf8(die->name()).toHtmlEscaped() + "<br/>";
787     s += "Offset: " + QString::number(die->offset()) + "<br/>";
788     foreach (const auto attrType, die->attributes()) {
789         const QVariant attrValue = die->attribute(attrType);
790         QString attrValueStr;
791         if (DwarfDie *die = attrValue.value<DwarfDie*>())
792             attrValueStr = printDwarfDieName(die);
793         else
794             attrValueStr = attrValue.toString().toHtmlEscaped();
795         s += QLatin1String(die->attributeName(attrType)) + ": " + attrValueStr + "<br/>";
796     }
797     return s;
798 }
799 
printDwarfDieName(DwarfDie * die) const800 QString DataVisitor::printDwarfDieName(DwarfDie* die) const
801 {
802     const auto idx = m_model->indexForNode(die);
803     const auto url = idx.data(ElfModel::NodeUrl).toUrl();
804 
805     QString s(QStringLiteral("<a href=\""));
806     s += url.toEncoded();
807     s += QLatin1String("\">");
808     s += die->displayName().toHtmlEscaped();
809     s += QLatin1String("</a>");
810 
811     return s;
812 }
813