Add symbol navigator dialog
ADD
resources/icons/compass.svg
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
+<circle style="fill:#ECF0F9;" cx="256" cy="256" r="209.455"/>
+<polygon style="fill:#D5E3EF;" points="232.727,232.727 128,407.273 302.545,302.545 407.273,128 "/>
+<path style="fill:#595A66;" d="M256,0C114.036,0,0,114.036,0,256s114.036,256,256,256s256-114.036,256-256S397.964,0,256,0z
+ M256,465.455C140.8,465.455,46.545,371.2,46.545,256S140.8,46.545,256,46.545S465.455,140.8,465.455,256S371.2,465.455,256,465.455
+ z"/>
+<path style="fill:#D5E3EF;" d="M64,273.455C64,158.255,158.255,64,273.455,64c53.527,0,102.4,19.782,138.473,53.527
+ C373.527,73.309,318.836,46.545,256,46.545C140.8,46.545,46.545,140.8,46.545,256c0,62.836,26.764,117.527,70.982,155.927
+ C83.782,375.855,64,326.982,64,273.455z"/>
+<path style="fill:#595A66;" d="M58.182,267.636H11.636C4.655,267.636,0,262.982,0,256l0,0c0-6.982,4.655-11.636,11.636-11.636
+ h46.545c6.982,0,11.636,4.655,11.636,11.636l0,0C69.818,262.982,65.164,267.636,58.182,267.636z"/>
+<path style="fill:#494A52;" d="M47.709,244.364c-1.164,3.491-1.164,8.145-1.164,11.636c0,3.491,0,8.145,1.164,11.636h10.473
+ c2.327,0,4.655-1.164,5.818-2.327c0-5.818,1.164-12.8,1.164-18.618c-1.164-1.164-3.491-2.327-6.982-2.327H47.709z"/>
+<g>
+ <path style="fill:#595A66;" d="M500.364,267.636h-46.545c-6.982,0-11.636-4.655-11.636-11.636l0,0
+ c0-6.982,4.655-11.636,11.636-11.636h46.545c6.982,0,11.636,4.655,11.636,11.636l0,0C512,262.982,507.345,267.636,500.364,267.636z
+ "/>
+ <path style="fill:#595A66;" d="M244.364,58.182V11.636C244.364,4.655,249.018,0,256,0l0,0c6.982,0,11.636,4.655,11.636,11.636
+ v46.545c0,6.982-4.655,11.636-11.636,11.636l0,0C249.018,69.818,244.364,65.164,244.364,58.182z"/>
+</g>
+<path style="fill:#494A52;" d="M256,46.545c-3.491,0-8.145,0-11.636,1.164v10.473c0,3.491,1.164,5.818,3.491,8.145
+ c5.818-1.164,11.636-1.164,18.618-1.164c0-2.327,1.164-4.655,1.164-6.982V47.709C264.145,46.545,259.491,46.545,256,46.545z"/>
+<path style="fill:#595A66;" d="M244.364,500.364v-46.545c0-6.982,4.655-11.636,11.636-11.636l0,0
+ c6.982,0,11.636,4.655,11.636,11.636v46.545c0,6.982-4.655,11.636-11.636,11.636l0,0C249.018,512,244.364,507.345,244.364,500.364z"
+ />
+<path style="fill:#B0C4D9;" d="M256,384c-6.982,0-11.636-4.655-11.636-11.636V139.636c0-6.982,4.655-11.636,11.636-11.636
+ c6.982,0,11.636,4.655,11.636,11.636v232.727C267.636,379.345,262.982,384,256,384z"/>
+<polygon style="fill:#89ABC6;" points="244.364,336.291 267.636,322.327 267.636,212.945 244.364,225.745 "/>
+<path style="fill:#B0C4D9;" d="M313.018,313.018c-4.655,4.655-11.636,4.655-16.291,0l-98.909-98.909
+ c-4.655-4.655-4.655-11.636,0-16.291s11.636-4.655,16.291,0l98.909,98.909C317.673,301.382,317.673,309.527,313.018,313.018z"/>
+<polygon style="fill:#89ABC6;" points="292.073,308.364 302.545,302.545 308.364,292.073 243.2,226.909 232.727,232.727
+ 226.909,243.2 "/>
+<path style="fill:#B0C4D9;" d="M128,256c0-6.982,4.655-11.636,11.636-11.636h232.727c6.982,0,11.636,4.655,11.636,11.636
+ c0,6.982-4.655,11.636-11.636,11.636H139.636C132.655,267.636,128,262.982,128,256z"/>
+<polygon style="fill:#89ABC6;" points="212.945,267.636 322.327,267.636 336.291,244.364 225.745,244.364 "/>
+<polygon style="fill:#F04B4D;" points="290.909,290.909 221.091,221.091 395.636,116.364 "/>
+<polygon style="fill:#4C9CD6;" points="221.091,221.091 290.909,290.909 116.364,395.636 "/>
+<polygon style="fill:#70B7E5;" points="221.091,221.091 116.364,395.636 256,256 "/>
+<polygon style="fill:#F26A56;" points="256,256 395.636,116.364 221.091,221.091 "/>
+<circle style="fill:#595A66;" cx="256" cy="256" r="23.273"/>
+<path style="fill:#494A52;" d="M265.309,235.055c1.164,3.491,2.327,5.818,2.327,9.309c0,12.8-10.473,23.273-23.273,23.273
+ c-3.491,0-6.982-1.164-9.309-2.327c3.491,8.145,11.636,13.964,20.945,13.964c12.8,0,23.273-10.473,23.273-23.273
+ C279.273,246.691,273.455,238.545,265.309,235.055z"/>
+<path style="fill:#6F707E;" d="M256,0L256,0C114.036,0,0,114.036,0,256l0,0c12.8,0,23.273-9.309,24.436-22.109
+ C30.255,178.036,54.691,126.836,93.091,89.6c37.236-36.073,86.109-60.509,140.8-65.164C246.691,23.273,256,12.8,256,0z"/>
+<path style="fill:#494A52;" d="M256,512L256,512c141.964,0,256-114.036,256-256l0,0c-12.8,0-23.273,9.309-24.436,22.109
+ c-4.655,54.691-29.091,103.564-65.164,140.8c-37.236,38.4-87.273,62.836-144.291,68.655C265.309,488.727,256,499.2,256,512z"/>
+<circle style="fill:#6F707E;" cx="250.182" cy="250.182" r="5.818"/>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>

MODIFY
resources/icons/icons.qrc
resources/icons/icons.qrc
<file>crosshair.svg</file>
<file>build.svg</file>
<file>trace.svg</file>
+ <file>compass.svg</file>
</qresource>
</RCC>

MODIFY
src/edittab.cpp
src/edittab.cpp
#include "parser.h"
#include "processorhandler.h"
#include "program.h"
+#include "symbolnavigator.h"
namespace Ripes {
EditTab::EditTab(QToolBar* toolbar, QWidget* parent) : RipesTab(toolbar, parent), m_ui(new Ui::EditTab) {
m_ui->setupUi(this);
+ m_symbolNavigatorAction = new QAction(this);
+ m_symbolNavigatorAction->setIcon(QIcon(":/icons/compass.svg"));
+ m_symbolNavigatorAction->setText("Navigate symbols");
+ connect(m_symbolNavigatorAction, &QAction::triggered, this, &EditTab::showSymbolNavigator);
+ m_toolbar->addAction(m_symbolNavigatorAction);
+
m_followAction = new QAction(this);
m_followAction->setIcon(QIcon(":/icons/trace.svg"));
m_followAction->setCheckable(true);
@@ -66,6 +73,13 @@ EditTab::EditTab(QToolBar* toolbar, QWidget* parent) : RipesTab(toolbar, parent)
sourceTypeChanged();
}
+void EditTab::showSymbolNavigator() {
+ SymbolNavigator nav(m_ui->programViewer->addressOffsetMap(), this);
+ if (nav.exec()) {
+ m_ui->programViewer->setCenterAddress(nav.getSelectedSymbolAddress());
+ }
+}
+
void EditTab::loadExternalFile(const LoadFileParams& params) {
if (params.type == SourceType::C) {
// Try to enable C input and verify that source type was changed successfully. This allows us to trigger the

MODIFY
src/edittab.h
src/edittab.h
@@ -64,6 +64,7 @@ public slots:
void enableAssemblyInput();
private slots:
+ void showSymbolNavigator();
void sourceCodeChanged();
void on_disassembledViewButton_toggled();
@@ -82,6 +83,7 @@ private:
QAction* m_buildAction = nullptr;
QAction* m_followAction = nullptr;
+ QAction* m_symbolNavigatorAction = nullptr;
Ui::EditTab* m_ui = nullptr;
std::unique_ptr<Assembler> m_assembler;

MODIFY
src/parser.cpp
src/parser.cpp
@@ -51,8 +51,9 @@ QString Parser::binarize(std::weak_ptr<const Program> program, AddrOffsetMap& ad
}
namespace {
-void incrementAddressOffsetMap(const QString& text, AddrOffsetMap& map, int& offsets) {
- map[text.count('\n')] = offsets++;
+void incrementAddressOffsetMap(const QString& text, AddrOffsetMap& map, int& offsets,
+ const QString& symbol = QString()) {
+ map[text.count('\n')] = {offsets++, symbol};
}
} // namespace
@@ -75,14 +76,15 @@ QString Parser::stringifyProgram(std::weak_ptr<const Program> program, unsigned
addr += stride) {
dataStream.readRawData(buffer.data(), stride);
- // Function label
+ // symbol label
if (sp->symbols.count(addr)) {
+ const auto& symbol = sp->symbols.at(addr);
// We are adding non-instruction lines to the output string. Record the line number as well as the sum
// of invalid lines up to the given point.
incrementAddressOffsetMap(out, addrOffsetMap, infoOffsets);
out += "\n";
- incrementAddressOffsetMap(out, addrOffsetMap, infoOffsets);
- out += QString::number(addr, 16).rightJustified(8, '0') + " <" + sp->symbols.at(addr) + ">:\n";
+ incrementAddressOffsetMap(out, addrOffsetMap, infoOffsets, symbol);
+ out += QString::number(addr, 16).rightJustified(8, '0') + " <" + symbol + ">:\n";
}
// Instruction address

MODIFY
src/parser.h
src/parser.h
@@ -20,7 +20,17 @@ namespace Ripes {
using namespace std;
typedef std::function<std::vector<uint32_t>(uint32_t)> decode_functor;
-using AddrOffsetMap = std::map<unsigned long, int>;
+/**
+ * AddrOffsetMap
+ * To preserve accurate mappings between the program viewers disassembled view - which contains additional lines for
+ * marking symbols, and the addresses of the current program, we provide the AddrOffsetMap.
+ * Keys represent the editor line number of which an additional line was inserted, in addition to lines corresponding to
+ * the disassembled program.
+ * The value is a pair containing:
+ * first: # of offset lines up to (not including) the given offset
+ * second: An optional QString() referencing the symbol displayed at the offset.
+ */
+using AddrOffsetMap = std::map<unsigned long, std::pair<int, QString>>;
class Parser {
public:

MODIFY
src/programviewer.cpp
src/programviewer.cpp
@@ -72,18 +72,22 @@ void ProgramViewer::updateSidebarWidth(int /* newBlockCount */) {
setViewportMargins(m_sidebarWidth, 0, 0, 0);
}
-void ProgramViewer::updateCenterAddress() {
- const auto stageInfo = ProcessorHandler::get()->getProcessor()->stageInfo(0);
- auto block = blockForAddress(stageInfo.pc);
+void ProgramViewer::setCenterAddress(const long address) {
+ auto block = blockForAddress(address);
setTextCursor(QTextCursor(block));
ensureCursorVisible();
}
+void ProgramViewer::updateCenterAddressFromProcessor() {
+ const auto stageInfo = ProcessorHandler::get()->getProcessor()->stageInfo(0);
+ setCenterAddress(stageInfo.pc);
+}
+
void ProgramViewer::setFollowEnabled(bool enabled) {
m_following = enabled;
if (enabled) {
- updateCenterAddress();
+ updateCenterAddressFromProcessor();
}
}
@@ -129,7 +133,7 @@ void ProgramViewer::updateHighlightedAddresses() {
setExtraSelections(highlights);
if (m_following) {
- updateCenterAddress();
+ updateCenterAddressFromProcessor();
}
}
@@ -213,9 +217,9 @@ QTextBlock ProgramViewer::blockForAddress(unsigned long addr) const {
return false;
bool valid = true;
- valid &= (low->first - low->second) <= adjustedLineNumber;
+ valid &= (low->first - low->second.first) <= adjustedLineNumber;
if (high != m_labelAddrOffsetMap.end()) {
- valid &= adjustedLineNumber < (high->first - high->second);
+ valid &= adjustedLineNumber < (high->first - high->second.first);
}
return valid;
};
@@ -227,7 +231,7 @@ QTextBlock ProgramViewer::blockForAddress(unsigned long addr) const {
lineNumber = low->first + 1;
}
- const int offsetSum = high == m_labelAddrOffsetMap.end() ? low->second + 1 : high->second;
+ const int offsetSum = high == m_labelAddrOffsetMap.end() ? low->second.first + 1 : high->second.first;
lineNumber = offsetSum + adjustedLineNumber;
return document()->findBlockByNumber(lineNumber);
@@ -264,7 +268,7 @@ long ProgramViewer::addressForBlock(QTextBlock block) const {
low = std::prev(m_labelAddrOffsetMap.lower_bound(lineNumber));
}
- adjustedLineNumber -= (low->second + 1);
+ adjustedLineNumber -= (low->second.first + 1);
return calcAddressFunc(adjustedLineNumber);
}

MODIFY
src/programviewer.h
src/programviewer.h
@@ -29,6 +29,9 @@ public:
long addressForPos(const QPoint& pos) const;
long addressForBlock(QTextBlock block) const;
QTextBlock blockForAddress(unsigned long) const;
+ void setCenterAddress(const long address);
+
+ const AddrOffsetMap& addressOffsetMap() const { return m_labelAddrOffsetMap; }
///
/// \brief updateProgram
@@ -53,7 +56,7 @@ private:
* If program following is enabled, this function will ensure that the current instruction in the first stage of the
* processor is always visible within the program viewer.
*/
- void updateCenterAddress();
+ void updateCenterAddressFromProcessor();
// A timer is needed for only catching one of the multiple wheel events that
// occur on a regular mouse scroll

ADD
src/symbolnavigator.cpp
+#include "symbolnavigator.h"
+#include "ui_symbolnavigator.h"
+
+#include "processorhandler.h"
+#include "radix.h"
+
+#include <QPushButton>
+
+namespace Ripes {
+
+SymbolNavigator::SymbolNavigator(const AddrOffsetMap& symbolmap, QWidget* parent)
+ : QDialog(parent), m_ui(new Ui::SymbolNavigator) {
+ m_ui->setupUi(this);
+
+ setWindowTitle("Symbol navigator");
+
+ m_ui->symbolTable->setColumnCount(2);
+ m_ui->symbolTable->setSelectionBehavior(QAbstractItemView::SelectRows);
+ m_ui->symbolTable->setSelectionMode(QAbstractItemView::SingleSelection);
+ m_ui->symbolTable->verticalHeader()->hide();
+ m_ui->symbolTable->setHorizontalHeaderLabels({"Address", "Label"});
+ m_ui->symbolTable->horizontalHeader()->setStretchLastSection(true);
+ m_ui->buttonBox->button(QDialogButtonBox::Ok)->setText("Go to symbol");
+
+ for (const auto& iter : symbolmap) {
+ if (!iter.second.second.isEmpty()) {
+ const long address = (iter.first - iter.second.first) * ProcessorHandler::get()->currentISA()->bytes() +
+ ProcessorHandler::get()->getTextStart();
+ addSymbol(address, iter.second.second);
+ }
+ }
+ m_ui->symbolTable->selectRow(0);
+}
+
+long SymbolNavigator::getSelectedSymbolAddress() const {
+ const auto selected = m_ui->symbolTable->selectedItems();
+ if (selected.size() > 0) {
+ return selected[0]->data(Qt::UserRole).toUInt();
+ }
+ return 0;
+}
+
+void SymbolNavigator::addSymbol(const long address, const QString& label) {
+ m_ui->symbolTable->setRowCount(m_ui->symbolTable->rowCount() + 1);
+ QTableWidgetItem* addrItem = new QTableWidgetItem();
+ QTableWidgetItem* labelItem = new QTableWidgetItem();
+
+ addrItem->setData(Qt::DisplayRole, encodeRadixValue(address, Radix::Hex));
+ labelItem->setData(Qt::DisplayRole, label);
+
+ addrItem->setFlags(addrItem->flags() ^ Qt::ItemIsEditable);
+ labelItem->setFlags(labelItem->flags() ^ Qt::ItemIsEditable);
+
+ addrItem->setData(Qt::UserRole, QVariant::fromValue(address));
+ labelItem->setData(Qt::UserRole, QVariant::fromValue(address));
+
+ const int row = m_ui->symbolTable->rowCount() - 1;
+ m_ui->symbolTable->setItem(row, 0, addrItem);
+ m_ui->symbolTable->setItem(row, 1, labelItem);
+}
+
+SymbolNavigator::~SymbolNavigator() {
+ delete m_ui;
+}
+} // namespace Ripes

ADD
src/symbolnavigator.h
+#pragma once
+
+#include <QDialog>
+
+#include "parser.h"
+
+namespace Ripes {
+
+namespace Ui {
+class SymbolNavigator;
+}
+
+class SymbolNavigator : public QDialog {
+ Q_OBJECT
+
+public:
+ SymbolNavigator(const AddrOffsetMap& symbolmap, QWidget* parent = nullptr);
+ ~SymbolNavigator();
+
+ long getSelectedSymbolAddress() const;
+
+private:
+ void addSymbol(const long address, const QString& label);
+
+ Ui::SymbolNavigator* m_ui;
+};
+} // namespace Ripes

ADD
src/symbolnavigator.ui
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Ripes::SymbolNavigator</class>
+ <widget class="QDialog" name="Ripes::SymbolNavigator">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>398</width>
+ <height>344</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QTableWidget" name="symbolTable"/>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0">
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>Ripes::SymbolNavigator</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>Ripes::SymbolNavigator</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>

Add symbol navigator dialog