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 "elfmodel.h" 0019 0020 #include <elf/elffile.h> 0021 #include <elf/elfheader.h> 0022 #include <elf/elfgotentry.h> 0023 0024 #include "rowcountvisitor.h" 0025 #include "indexvisitor.h" 0026 #include "parentvisitor.h" 0027 #include "datavisitor.h" 0028 0029 #include <QUrl> 0030 0031 ElfModel::ElfModel(QObject* parent) : QAbstractItemModel(parent) 0032 { 0033 } 0034 0035 ElfModel::~ElfModel() 0036 { 0037 clearInternalPointerMap(); 0038 } 0039 0040 ElfFileSet* ElfModel::fileSet() const 0041 { 0042 return m_fileSet; 0043 } 0044 0045 void ElfModel::setFileSet(ElfFileSet *fileSet) 0046 { 0047 beginResetModel(); 0048 clearInternalPointerMap(); 0049 m_fileSet = fileSet; 0050 0051 auto v = new ElfNodeVariant; 0052 v->payload = m_fileSet; 0053 v->type = ElfNodeVariant::FileSet; 0054 m_internalPointerMap.insert(m_fileSet, v); 0055 0056 endResetModel(); 0057 } 0058 0059 void ElfModel::clearInternalPointerMap() 0060 { 0061 for (auto it = m_internalPointerMap.cbegin(); it != m_internalPointerMap.cend(); ++it) 0062 delete it.value(); 0063 m_internalPointerMap.clear(); 0064 } 0065 0066 QVariant ElfModel::data(const QModelIndex& index, int role) const 0067 { 0068 if (!index.isValid() || !m_fileSet) 0069 return QVariant(); 0070 0071 if (role == NodeUrl) 0072 return urlForIndex(index); 0073 0074 ElfNodeVariant var = contentForIndex(index); 0075 0076 DataVisitor v(this, index.column()); 0077 switch (index.column()) { 0078 case 0: 0079 return v.visit(&var, role); 0080 case 1: 0081 return v.visit(&var, role == Qt::DisplayRole ? SizeRole : role); // TODO proper formatting 0082 } 0083 0084 return QVariant(); 0085 } 0086 0087 int ElfModel::columnCount(const QModelIndex& parent) const 0088 { 0089 Q_UNUSED(parent); 0090 return 2; 0091 } 0092 0093 int ElfModel::rowCount(const QModelIndex& parent) const 0094 { 0095 if (!m_fileSet || (parent.isValid() && parent.column() != 0)) 0096 return 0; 0097 0098 RowCountVisitor v; 0099 ElfNodeVariant var = contentForIndex(parent); 0100 return v.visit(&var); 0101 } 0102 0103 QModelIndex ElfModel::parent(const QModelIndex& child) const 0104 { 0105 if (!m_fileSet || !child.isValid()) 0106 return QModelIndex(); 0107 0108 ParentVisitor v(this); 0109 auto parentData = v.visit(variantForIndex(child)); 0110 if (!parentData.first) 0111 return QModelIndex(); 0112 Q_ASSERT(m_internalPointerMap.contains(parentData.first->payload)); 0113 return createIndex(parentData.second, 0, parentData.first); 0114 } 0115 0116 QModelIndex ElfModel::index(int row, int column, const QModelIndex& parent) const 0117 { 0118 if (!m_fileSet || !hasIndex(row, column, parent)) 0119 return QModelIndex(); 0120 0121 if (!parent.isValid()) 0122 return createIndex(row, column, m_internalPointerMap.value(m_fileSet)); 0123 0124 IndexVisitor v; 0125 auto childValue = v.visit(variantForIndex(parent), parent.row()); 0126 ElfNodeVariant *var = makeVariant(childValue.first, childValue.second); 0127 return createIndex(row, column, var); 0128 } 0129 0130 QVariant ElfModel::headerData(int section, Qt::Orientation orientation, int role) const 0131 { 0132 if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { 0133 switch (section) { 0134 case 0: return tr("Entry"); 0135 case 1: return tr("Size"); 0136 } 0137 } 0138 return QAbstractItemModel::headerData(section, orientation, role); 0139 } 0140 0141 QModelIndex ElfModel::indexForNode(ElfSection* section) const 0142 { 0143 return indexForNode(section, ElfNodeVariant::Section); 0144 } 0145 0146 QModelIndex ElfModel::indexForNode(ElfSymbolTableEntry* symbol) const 0147 { 0148 return indexForNode(symbol, ElfNodeVariant::SymbolTableEntry); 0149 } 0150 0151 QModelIndex ElfModel::indexForNode(ElfGotEntry* entry) const 0152 { 0153 return indexForNode(entry, ElfNodeVariant::GotEntry); 0154 } 0155 0156 QModelIndex ElfModel::indexForNode(ElfPltEntry* entry) const 0157 { 0158 return indexForNode(entry, ElfNodeVariant::PltEntry); 0159 } 0160 0161 QModelIndex ElfModel::indexForNode(DwarfDie* die) const 0162 { 0163 return indexForNode(die, ElfNodeVariant::DwarfDie); 0164 } 0165 0166 QModelIndex ElfModel::indexForNode(void* payload, ElfNodeVariant::Type type) const 0167 { 0168 if (!m_fileSet || !payload) 0169 return {}; 0170 0171 ElfNodeVariant var; 0172 var.payload = payload; 0173 var.type = type; 0174 ParentVisitor parentV(this); 0175 const auto parentData = parentV.visit(&var); 0176 Q_ASSERT(m_internalPointerMap.contains(parentData.first->payload)); 0177 return createIndex(parentData.second, 0, parentData.first); 0178 } 0179 0180 ElfNodeVariant* ElfModel::variantForIndex(const QModelIndex& index) const 0181 { 0182 return static_cast<ElfNodeVariant*>(index.internalPointer()); 0183 } 0184 0185 ElfNodeVariant ElfModel::contentForIndex(const QModelIndex& index) const 0186 { 0187 if (!index.isValid()) 0188 return *m_internalPointerMap.value(m_fileSet); 0189 0190 ElfNodeVariant *parentVar = variantForIndex(index); 0191 0192 IndexVisitor v; 0193 auto childData = v.visit(parentVar, index.row()); 0194 ElfNodeVariant var; 0195 var.payload = childData.first; 0196 var.type = childData.second; 0197 return var; 0198 } 0199 0200 ElfNodeVariant* ElfModel::makeVariant(void* payload, ElfNodeVariant::Type type) const 0201 { 0202 auto it = m_internalPointerMap.constFind(payload); 0203 if (it != m_internalPointerMap.cend()) 0204 return it.value(); 0205 auto var = new ElfNodeVariant; 0206 var->payload = payload; 0207 var->type = type; 0208 m_internalPointerMap.insert(payload, var); 0209 return var; 0210 } 0211 0212 QUrl ElfModel::urlForIndex(const QModelIndex& index) const 0213 { 0214 QUrl url; 0215 if (!index.isValid()) 0216 return url; 0217 0218 const auto parentIdx = parent(index); 0219 if (!parentIdx.isValid()) { 0220 url.setScheme(QStringLiteral("elfmodel")); 0221 url.setPath(QString::number(index.row())); 0222 return url; 0223 } 0224 0225 url = parentIdx.data(NodeUrl).toUrl(); 0226 url.setPath(url.path() + "/" + QString::number(index.row())); 0227 0228 return url; 0229 } 0230 0231 QModelIndex ElfModel::indexForUrl(const QUrl& url) const 0232 { 0233 Q_ASSERT(url.scheme() == QLatin1String("elfmodel")); 0234 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) 0235 const auto rows = url.path().split(QLatin1Char('/'), QString::SkipEmptyParts); 0236 #else 0237 const auto rows = url.path().split(QLatin1Char('/'), Qt::SkipEmptyParts); 0238 #endif 0239 0240 QModelIndex idx; 0241 for (const auto &r : rows) { 0242 idx = index(r.toInt(), 0, idx); 0243 } 0244 return idx; 0245 }