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("<local>");
271 break;
272 case VER_NDX_GLOBAL:
273 s += QLatin1String("<global>");
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 += " " + 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: <none><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