/************************************************************************** ** ** This file is part of Qt Creator ** ** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). ** ** Contact: http://www.qt-project.org/ ** ** ** GNU Lesser General Public License Usage ** ** This file may be used under the terms of the GNU Lesser General Public ** License version 2.1 as published by the Free Software Foundation and ** appearing in the file LICENSE.LGPL included in the packaging of this file. ** Please review the following information to ensure the GNU Lesser General ** Public License version 2.1 requirements will be met: ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** Other Usage ** ** Alternatively, this file may be used in accordance with the terms and ** conditions contained in a signed written agreement between you and Nokia. ** ** **************************************************************************/ #include "moduleshandler.h" #include <utils/elfreader.h> #include <utils/qtcassert.h> #include <QDebug> #include <QSortFilterProxyModel> using namespace Utils; ////////////////////////////////////////////////////////////////// // // ModulesModel // ////////////////////////////////////////////////////////////////// namespace Debugger { namespace Internal { class ModulesModel : public QAbstractItemModel { public: explicit ModulesModel(QObject *parent) : QAbstractItemModel(parent) {} int columnCount(const QModelIndex &parent) const { return parent.isValid() ? 0 : 5; } int rowCount(const QModelIndex &parent) const { return parent.isValid() ? 0 : m_modules.size(); } QModelIndex parent(const QModelIndex &) const { return QModelIndex(); } QModelIndex index(int row, int column, const QModelIndex &) const { return createIndex(row, column); } QVariant headerData(int section, Qt::Orientation orientation, int role) const; QVariant data(const QModelIndex &index, int role) const; void clearModel(); void removeModule(const QString &modulePath); void setModules(const Modules &modules); void updateModule(const Module &module); int indexOfModule(const QString &modulePath) const; Modules m_modules; }; QVariant ModulesModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { static QString headers[] = { ModulesHandler::tr("Module name") + QLatin1String(" "), ModulesHandler::tr("Module path") + QLatin1String(" "), ModulesHandler::tr("Symbols read") + QLatin1String(" "), ModulesHandler::tr("Symbols type") + QLatin1String(" "), ModulesHandler::tr("Start address") + QLatin1String(" "), ModulesHandler::tr("End address") + QLatin1String(" ") }; return headers[section]; } return QVariant(); } QVariant ModulesModel::data(const QModelIndex &index, int role) const { int row = index.row(); if (row < 0 || row >= m_modules.size()) return QVariant(); const Module &module = m_modules.at(row); switch (index.column()) { case 0: if (role == Qt::DisplayRole) return module.moduleName; // FIXME: add icons //if (role == Qt::DecorationRole) // return module.symbolsRead ? icon2 : icon; break; case 1: if (role == Qt::DisplayRole) return module.modulePath; if (role == Qt::ToolTipRole) { QString msg; if (!module.elfData.buildId.isEmpty()) msg += QString::fromLatin1("Build Id: " + module.elfData.buildId); if (!module.elfData.debugLink.isEmpty()) msg += QString::fromLatin1("Debug Link: " + module.elfData.debugLink); return msg; } break; case 2: if (role == Qt::DisplayRole) switch (module.symbolsRead) { case Module::UnknownReadState: return ModulesHandler::tr("unknown"); case Module::ReadFailed: return ModulesHandler::tr("no"); case Module::ReadOk: return ModulesHandler::tr("yes"); } break; case 3: if (role == Qt::DisplayRole) switch (module.elfData.symbolsType) { case UnknownSymbols: return ModulesHandler::tr("unknown"); case NoSymbols: return ModulesHandler::tr("none"); case PlainSymbols: return ModulesHandler::tr("plain"); case FastSymbols: return ModulesHandler::tr("fast"); case LinkedSymbols: return ModulesHandler::tr("debuglnk"); case BuildIdSymbols: return ModulesHandler::tr("buildid"); } else if (role == Qt::ToolTipRole) switch (module.elfData.symbolsType) { case UnknownSymbols: return ModulesHandler::tr( "It is unknown whether this module contains debug " "information.\nUse \"Examine Symbols\" from the " "context menu to initiate a check."); case NoSymbols: return ModulesHandler::tr( "This module neither contains nor references debug " "information.\nStepping into the module or setting " "breakpoints by file and line will not work."); case PlainSymbols: return ModulesHandler::tr( "This module contains debug information.\nStepping " "into the module or setting breakpoints by file and " "is expected to work."); case FastSymbols: return ModulesHandler::tr( "This module contains debug information.\nStepping " "into the module or setting breakpoints by file and " "is expected to work."); case LinkedSymbols: case BuildIdSymbols: return ModulesHandler::tr( "This module does not contain debug information " "itself, but contains a reference to external " "debug information."); } break; case 4: if (role == Qt::DisplayRole) if (module.startAddress) return QString(QLatin1String("0x") + QString::number(module.startAddress, 16)); break; case 5: if (role == Qt::DisplayRole) { if (module.endAddress) return QString(QLatin1String("0x") + QString::number(module.endAddress, 16)); //: End address of loaded module return ModulesHandler::tr("<unknown>", "address"); } break; } return QVariant(); } void ModulesModel::setModules(const Modules &m) { m_modules = m; reset(); } void ModulesModel::clearModel() { if (!m_modules.isEmpty()) { m_modules.clear(); reset(); } } int ModulesModel::indexOfModule(const QString &modulePath) const { // Recent modules are more likely to be unloaded first. for (int i = m_modules.size() - 1; i >= 0; i--) if (m_modules.at(i).modulePath == modulePath) return i; return -1; } void ModulesModel::removeModule(const QString &modulePath) { const int row = indexOfModule(modulePath); QTC_ASSERT(row != -1, return); beginRemoveRows(QModelIndex(), row, row); m_modules.remove(row); endRemoveRows(); } void ModulesModel::updateModule(const Module &module) { const int row = indexOfModule(module.modulePath); ElfReader reader(module.modulePath); ElfData elfData = reader.readHeaders(); if (row == -1) { const int n = m_modules.size(); beginInsertRows(QModelIndex(), n, n); m_modules.push_back(module); m_modules.back().elfData = elfData; endInsertRows(); } else { m_modules[row] = module; m_modules[row].elfData = elfData; dataChanged(index(row, 0, QModelIndex()), index(row, 4, QModelIndex())); } } ////////////////////////////////////////////////////////////////// // // ModulesHandler // ////////////////////////////////////////////////////////////////// ModulesHandler::ModulesHandler() { m_model = new ModulesModel(this); m_proxyModel = new QSortFilterProxyModel(this); m_proxyModel->setSourceModel(m_model); } QAbstractItemModel *ModulesHandler::model() const { return m_proxyModel; } void ModulesHandler::removeAll() { m_model->clearModel(); } void ModulesHandler::removeModule(const QString &modulePath) { m_model->removeModule(modulePath); } void ModulesHandler::updateModule(const Module &module) { m_model->updateModule(module); } void ModulesHandler::setModules(const Modules &modules) { m_model->setModules(modules); } Modules ModulesHandler::modules() const { return m_model->m_modules; } } // namespace Internal } // namespace Debugger