Make ProgramViewer output similar to a binutil objdump
MODIFY
src/codeeditor.cpp
src/codeeditor.cpp
@@ -30,6 +30,7 @@ CodeEditor::CodeEditor(QWidget* parent) : QPlainTextEdit(parent) {
m_font = QFont("Inconsolata", 11);
setFont(m_font);
m_fontTimer.setSingleShot(true);
+ setTabStopDistance(QFontMetricsF(m_font).horizontalAdvance(' ') * 4);
// set event filter for catching scroll events
installEventFilter(this);

MODIFY
src/edittab.cpp
src/edittab.cpp
@@ -78,7 +78,7 @@ void EditTab::clearAssemblyEditor() {
}
void EditTab::emitProgramChanged() {
- setDisassemblerText();
+ updateProgramViewer();
emit programChanged(&m_activeProgram);
}
@@ -119,14 +119,8 @@ void EditTab::enableAssemblyInput() {
emit editorStateChanged(m_editorEnabled);
}
-void EditTab::setDisassemblerText() {
- const auto* textSection = m_activeProgram.getSection(TEXT_SECTION_NAME);
- if (!textSection)
- return;
-
- auto text = m_ui->disassembledViewButton->isChecked() ? Parser::getParser()->disassemble(textSection->data)
- : Parser::getParser()->binarize(textSection->data);
- m_ui->programViewer->setPlainText(text);
+void EditTab::updateProgramViewer() {
+ m_ui->programViewer->updateProgram(m_activeProgram, !m_ui->disassembledViewButton->isChecked());
}
void EditTab::enableEditor() {
@@ -144,7 +138,7 @@ void EditTab::disableEditor() {
}
void EditTab::on_disassembledViewButton_toggled() {
- setDisassemblerText();
+ updateProgramViewer();
}
bool EditTab::loadFlatBinaryFile(Program& program, QFile& file, unsigned long entryPoint, unsigned long loadAt) {

MODIFY
src/edittab.h
src/edittab.h
@@ -27,7 +27,7 @@ public:
~EditTab() override;
void setAssemblyText(const QString& text);
- void setDisassemblerText();
+ void updateProgramViewer();
QString getAssemblyText();
void newProgram();
void clearAssemblyEditor();

MODIFY
src/edittab.ui
src/edittab.ui
<item>
<widget class="QLabel" name="label_2">
<property name="text">
- <string>Assembled code</string>
+ <string>Executable code</string>
</property>
</widget>
</item>

MODIFY
src/loaddialog.cpp
src/loaddialog.cpp
@@ -53,8 +53,8 @@ LoadDialog::LoadDialog(QWidget* parent) : QDialog(parent), m_ui(new Ui::LoadDial
m_ui->currentISA->setText(ProcessorHandler::get()->currentISA()->name());
// default selection
- m_ui->filePath->setText(s_filePath);
m_fileTypeButtons->button(s_typeIndex)->toggle();
+ m_ui->filePath->setText(s_filePath);
}
void LoadDialog::inputTypeChanged() {

MODIFY
src/loaddialog.h
src/loaddialog.h
@@ -56,7 +56,7 @@ private:
void paletteValidate(QWidget* w, bool valid);
- FileType m_fileType;
+ FileType m_fileType = FileType::Assembly;
LoadFileParams m_params;
Ui::LoadDialog* m_ui = nullptr;

MODIFY
src/parser.cpp
src/parser.cpp
@@ -24,8 +24,8 @@ Parser::Parser() {
Parser::~Parser() {}
-QString Parser::disassemble(const QByteArray& text) const {
- return stringifyByteArray(text, 4, [this](const std::vector<char>& buffer, uint32_t index) {
+QString Parser::disassemble(const Program& program) const {
+ return stringifyProgram(program, 4, [this](const std::vector<char>& buffer, uint32_t index) {
// Hardcoded for RV32 for now
uint32_t instr = 0;
for (int i = 0; i < 4; i++) {
@@ -35,8 +35,8 @@ QString Parser::disassemble(const QByteArray& text) const {
});
}
-QString Parser::binarize(const QByteArray& text) const {
- return stringifyByteArray(text, 4, [](const std::vector<char>& buffer, uint32_t) {
+QString Parser::binarize(const Program& program) const {
+ return stringifyProgram(program, 4, [](const std::vector<char>& buffer, uint32_t) {
QString binaryString;
for (auto byte : buffer) {
binaryString.prepend(QString().setNum(static_cast<uint8_t>(byte), 2).rightJustified(8, '0'));
@@ -45,18 +45,39 @@ QString Parser::binarize(const QByteArray& text) const {
});
}
-QString Parser::stringifyByteArray(const QByteArray& data, unsigned stride,
+QString Parser::stringifyProgram(const Program& program, unsigned stride,
std::function<QString(const std::vector<char>&, uint32_t index)> stringifier) const {
+ const auto* textSection = program.getSection(TEXT_SECTION_NAME);
+ if (!textSection)
+ return QString();
+
QString out;
- auto dataStream = QDataStream(data);
+ auto dataStream = QDataStream(textSection->data);
std::vector<char> buffer;
buffer.resize(stride);
uint32_t byteIndex = 0;
- for (int i = 0; i < data.length(); i += stride) {
+ for (unsigned long addr = textSection->address; addr < textSection->address + textSection->data.length();
+ addr += stride) {
dataStream.readRawData(buffer.data(), stride);
- out += stringifier(buffer, byteIndex);
- out += "\n";
+
+ // Function label
+ if (program.symbols.count(addr)) {
+ out += "\n" + QString::number(addr, 16).rightJustified(8, '0') + " <" + program.symbols.at(addr) + ">:\n";
+ }
+
+ // Instruction address
+ out += "\t" + QString::number(addr, 16) + ":\t\t";
+
+ // Instruction word
+ QString wordString;
+ for (auto byte : buffer) {
+ wordString.prepend(QString().setNum(static_cast<uint8_t>(byte), 16).rightJustified(2, '0'));
+ }
+ out += wordString + "\t\t";
+
+ // Stringified instruction
+ out += stringifier(buffer, byteIndex) + "\n";
byteIndex += stride;
}
return out;

MODIFY
src/parser.h
src/parser.h
#include <functional>
#include <unordered_map>
#include <vector>
+
#include "defines.h"
+#include "program.h"
namespace Ripes {
@@ -34,12 +36,11 @@ public:
std::vector<uint32_t> decodeRInstr(uint32_t instr) const { return m_decodeRInstr(instr); }
std::vector<uint32_t> decodeBInstr(uint32_t instr) const { return m_decodeBInstr(instr); }
- QString disassemble(const QByteArray& text) const;
- QString binarize(const QByteArray& text) const;
+ QString disassemble(const Program& program) const;
+ QString binarize(const Program& program) const;
private:
- QString
- stringifyByteArray(const QByteArray& data, unsigned stride,
+ QString stringifyProgram(const Program& program, unsigned stride,
std::function<QString(const std::vector<char>& buffer, uint32_t index)> stringifier) const;
Parser();

MODIFY
src/programviewer.cpp
src/programviewer.cpp
#include "programviewer.h"
#include "defines.h"
+#include "parser.h"
#include "processorhandler.h"
-#include <QMenu>
#include <QAction>
-#include <QTextBlock>
-#include <QEvent>
#include <QApplication>
+#include <QEvent>
+#include <QFontMetricsF>
+#include <QMenu>
+#include <QTextBlock>
namespace Ripes {
-ProgramViewer::ProgramViewer(QWidget* parent) : QPlainTextEdit(parent)
-{
+ProgramViewer::ProgramViewer(QWidget* parent) : QPlainTextEdit(parent) {
m_breakpointArea = new BreakpointArea(this);
connect(this, &QPlainTextEdit::blockCountChanged, this, &ProgramViewer::updateSidebarWidth);
connect(this, &QPlainTextEdit::updateRequest, this, &ProgramViewer::updateSidebar);
updateSidebarWidth(0);
-
// Set font for the entire widget. calls to fontMetrics() will get the
// dimensions of the currently set font
m_font = QFont("Inconsolata", 11);
setFont(m_font);
m_fontTimer.setSingleShot(true);
+
+ setTabStopDistance(QFontMetricsF(m_font).horizontalAdvance(' ') * 4);
}
bool ProgramViewer::eventFilter(QObject*, QEvent* event) {
@@ -63,11 +65,14 @@ void ProgramViewer::resizeEvent(QResizeEvent* e) {
m_breakpointArea->setGeometry(cr.left(), cr.top(), m_breakpointArea->width(), cr.height());
}
-void ProgramViewer::updateSidebar(const QRect& rect, int dy) {
+void ProgramViewer::updateProgram(const Program& program, bool binary) {
+ const auto text = binary ? Parser::getParser()->binarize(program) : Parser::getParser()->disassemble(program);
+ setPlainText(text);
+}
+void ProgramViewer::updateSidebar(const QRect& rect, int dy) {
m_breakpointArea->update(0, rect.y(), m_breakpointArea->width(), rect.height());
-
if (rect.contains(viewport()->rect()))
updateSidebarWidth(0);
}
@@ -92,8 +97,8 @@ void ProgramViewer::breakpointAreaPaintEvent(QPaintEvent* event) {
painter.fillRect(area, gradient);
QTextBlock block = firstVisibleBlock();
- uint32_t address = ProcessorHandler::get()->getTextStart() +
- block.blockNumber() * ProcessorHandler::get()->currentISA()->bytes();
+ uint32_t address =
+ ProcessorHandler::get()->getTextStart() + block.blockNumber() * ProcessorHandler::get()->currentISA()->bytes();
int top = static_cast<int>(blockBoundingGeometry(block).translated(contentOffset()).top());
int bottom = top + static_cast<int>(blockBoundingRect(block).height());
@@ -110,10 +115,8 @@ void ProgramViewer::breakpointAreaPaintEvent(QPaintEvent* event) {
bottom = top + static_cast<int>(blockBoundingRect(block).height());
address += ProcessorHandler::get()->currentISA()->bytes();
}
-
}
-
long ProgramViewer::addressForPos(const QPoint& pos) const {
// Get line height
QTextBlock block = firstVisibleBlock();
@@ -176,4 +179,4 @@ void BreakpointArea::contextMenuEvent(QContextMenuEvent* event) {
contextMenu.exec(event->globalPos());
}
-}
+} // namespace Ripes

MODIFY
src/programviewer.h
src/programviewer.h
#include <QScrollBar>
#include <QTimer>
+#include "program.h"
+
namespace Ripes {
class BreakpointArea;
@@ -21,6 +23,13 @@ public:
long addressForPos(const QPoint& pos) const;
void clearBreakpoints();
+ ///
+ /// \brief updateProgram
+ /// Refreshes the programViewer view with @p program, using the parser to either disassemble or (if @p binary is
+ /// true) show the raw binary version of the loaded program.
+ ///
+ void updateProgram(const Program& program, bool binary = false);
+
protected:
void resizeEvent(QResizeEvent* event) override;

Make ProgramViewer output similar to a binutil objdump