Handle non-instruction lines in ProgramViewer wrt. setting breakpoints
The parser will now record all non-instruction lines with their index as well
as sum of non-instruction lines up to the given point.
Using this, we are able to determine whether it is valid for a line to be
a breakpoint.
MODIFY
src/parser.cpp
src/parser.cpp
@@ -24,29 +24,41 @@ Parser::Parser() {
Parser::~Parser() {}
-QString Parser::disassemble(const Program& program) const {
- return stringifyProgram(program, 4, [this](const std::vector<char>& buffer, uint32_t index) {
+QString Parser::disassemble(const Program& program, AddrOffsetMap& addrOffsetMap) 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++) {
instr |= (buffer[i] & 0xFF) << (CHAR_BIT * i);
}
return disassemble(instr, index);
- });
+ },
+ addrOffsetMap);
}
-QString Parser::binarize(const Program& program) const {
- return stringifyProgram(program, 4, [](const std::vector<char>& buffer, uint32_t) {
+QString Parser::binarize(const Program& program, AddrOffsetMap& addrOffsetMap) 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'));
}
return binaryString;
- });
+ },
+ addrOffsetMap);
}
+namespace {
+void incrementAddressOffsetMap(const QString& text, AddrOffsetMap& map, int& offsets) {
+ map[text.count('\n')] = offsets++;
+}
+} // namespace
+
QString Parser::stringifyProgram(const Program& program, unsigned stride,
- std::function<QString(const std::vector<char>&, uint32_t index)> stringifier) const {
+ std::function<QString(const std::vector<char>&, uint32_t index)> stringifier,
+ AddrOffsetMap& addrOffsetMap) const {
const auto* textSection = program.getSection(TEXT_SECTION_NAME);
if (!textSection)
return QString();
@@ -57,13 +69,20 @@ QString Parser::stringifyProgram(const Program& program, unsigned stride,
buffer.resize(stride);
uint32_t byteIndex = 0;
+ int infoOffsets = 0;
+
for (unsigned long addr = textSection->address; addr < textSection->address + textSection->data.length();
addr += stride) {
dataStream.readRawData(buffer.data(), stride);
// Function label
if (program.symbols.count(addr)) {
- out += "\n" + QString::number(addr, 16).rightJustified(8, '0') + " <" + program.symbols.at(addr) + ">:\n";
+ // 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') + " <" + program.symbols.at(addr) + ">:\n";
}
// Instruction address

MODIFY
src/parser.h
src/parser.h
@@ -19,6 +19,8 @@ namespace Ripes {
using namespace std;
typedef std::function<std::vector<uint32_t>(uint32_t)> decode_functor;
+using AddrOffsetMap = std::map<unsigned long, int>;
+
class Parser {
public:
static Parser* getParser() {
@@ -36,12 +38,13 @@ 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 Program& program) const;
- QString binarize(const Program& program) const;
+ QString disassemble(const Program& program, AddrOffsetMap& addrOffsetMap) const;
+ QString binarize(const Program& program, AddrOffsetMap& addrOffsetMap) const;
private:
QString stringifyProgram(const Program& program, unsigned stride,
- std::function<QString(const std::vector<char>& buffer, uint32_t index)> stringifier) const;
+ std::function<QString(const std::vector<char>& buffer, uint32_t index)> stringifier,
+ AddrOffsetMap& addrOffsetMap) const;
Parser();
~Parser();

MODIFY
src/programviewer.cpp
src/programviewer.cpp
#include "programviewer.h"
#include "defines.h"
-#include "parser.h"
#include "processorhandler.h"
#include <QAction>
@@ -66,7 +65,9 @@ void ProgramViewer::resizeEvent(QResizeEvent* e) {
}
void ProgramViewer::updateProgram(const Program& program, bool binary) {
- const auto text = binary ? Parser::getParser()->binarize(program) : Parser::getParser()->disassemble(program);
+ m_labelAddrOffsetMap.clear();
+ const auto text = binary ? Parser::getParser()->binarize(program, m_labelAddrOffsetMap)
+ : Parser::getParser()->disassemble(program, m_labelAddrOffsetMap);
setPlainText(text);
}
@@ -97,13 +98,20 @@ void ProgramViewer::breakpointAreaPaintEvent(QPaintEvent* event) {
painter.fillRect(area, gradient);
QTextBlock block = firstVisibleBlock();
- 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());
while (block.isValid() && top <= event->rect().bottom()) {
- if (block.isVisible() && bottom >= event->rect().top()) {
+ volatile int line = block.blockNumber();
+ const bool invalidLine = m_labelAddrOffsetMap.count(block.blockNumber());
+ if (block.isVisible() && bottom >= event->rect().top() && !invalidLine) {
+ int adjustedLineNumber = block.blockNumber();
+ auto offsetsToLine = m_labelAddrOffsetMap.lower_bound(adjustedLineNumber);
+ if (offsetsToLine != m_labelAddrOffsetMap.end()) {
+ adjustedLineNumber -= offsetsToLine->second;
+ }
+ const unsigned long address = ProcessorHandler::get()->getTextStart() +
+ adjustedLineNumber * ProcessorHandler::get()->currentISA()->bytes();
if (ProcessorHandler::get()->hasBreakpoint(address)) {
painter.drawPixmap(m_breakpointArea->padding, top, m_breakpointArea->imageWidth,
m_breakpointArea->imageHeight, m_breakpointArea->m_breakpoint);
@@ -113,7 +121,6 @@ void ProgramViewer::breakpointAreaPaintEvent(QPaintEvent* event) {
block = block.next();
top = bottom;
bottom = top + static_cast<int>(blockBoundingRect(block).height());
- address += ProcessorHandler::get()->currentISA()->bytes();
}
}
@@ -138,8 +145,23 @@ long ProgramViewer::addressForPos(const QPoint& pos) const {
if (!block.isValid())
return -1;
+ const int lineNumber = block.blockNumber();
+
+ // Clicking an invalid line? (non-instruction line)
+ if (m_labelAddrOffsetMap.count(lineNumber)) {
+ return -1;
+ }
+
+ // To identify the program address corresponding to the selected line, we find the lower bound of the selected block
+ // in the m_labelAddrOffsetMap and subtract the invalid line count up to the given point.
+ int adjustedLineNumber = lineNumber;
+ auto offsetsToLine = m_labelAddrOffsetMap.lower_bound(lineNumber);
+ if (offsetsToLine != m_labelAddrOffsetMap.end()) {
+ adjustedLineNumber -= offsetsToLine->second;
+ }
+
// Toggle breakpoint
- return block.blockNumber() * ProcessorHandler::get()->currentISA()->bytes() +
+ return adjustedLineNumber * ProcessorHandler::get()->currentISA()->bytes() +
ProcessorHandler::get()->getTextStart();
}

MODIFY
src/programviewer.h
src/programviewer.h
#include <QScrollBar>
#include <QTimer>
+#include "parser.h"
#include "program.h"
namespace Ripes {
@@ -48,6 +49,15 @@ private:
BreakpointArea* m_breakpointArea;
+ /**
+ * @brief m_labelAddrOffsetMap
+ * To correctly correlate a line index with program address location whilst accounting for additional output in the
+ * disassembled view of a program, we provide the AddrOffsetMap. Key in this map indicate line numbers (starting
+ * from 0) which does >not< correspond with an address. The value of the key corresponds to the total sum of
+ * non-address lines encountered up to and including the given label.
+ */
+ AddrOffsetMap m_labelAddrOffsetMap;
+
bool eventFilter(QObject* observed, QEvent* event) override;
};

Handle non-instruction lines in ProgramViewer wrt. setting breakpoints

The parser will now record all non-instruction lines with their index as well
as sum of non-instruction lines up to the given point.
Using this, we are able to determine whether it is valid for a line to be
a breakpoint.