mirror of
https://github.com/markdavidlong/AppleSAWS.git
synced 2024-12-27 00:29:17 +00:00
Added viewer to show jumps in disassembly viewer
This commit is contained in:
parent
93f1b143d3
commit
e85b95b66b
@ -66,7 +66,9 @@ SOURCES += \
|
|||||||
src/binaryfile/AssemblerSymbolModel.cpp \
|
src/binaryfile/AssemblerSymbolModel.cpp \
|
||||||
src/ui/diskexplorer/DiskExplorer.cpp \
|
src/ui/diskexplorer/DiskExplorer.cpp \
|
||||||
src/ui/diskexplorer/DiskExplorerMapWidget.cpp \
|
src/ui/diskexplorer/DiskExplorerMapWidget.cpp \
|
||||||
src/applesoftfile/ApplesoftRetokenizer.cpp
|
src/applesoftfile/ApplesoftRetokenizer.cpp \
|
||||||
|
src/internals/JumpLineManager.cpp \
|
||||||
|
src/ui/widgets/FlowLineTextBrowser.cpp
|
||||||
|
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
@ -116,7 +118,9 @@ HEADERS += \
|
|||||||
src/ui/diskexplorer/DiskExplorer.h \
|
src/ui/diskexplorer/DiskExplorer.h \
|
||||||
src/ui/diskexplorer/DiskExplorerMapWidget.h \
|
src/ui/diskexplorer/DiskExplorerMapWidget.h \
|
||||||
src/applesoftfile/ApplesoftRetokenizer.h \
|
src/applesoftfile/ApplesoftRetokenizer.h \
|
||||||
src/util/AppleColors.h
|
src/util/AppleColors.h \
|
||||||
|
src/internals/JumpLineManager.h \
|
||||||
|
src/ui/widgets/FlowLineTextBrowser.h
|
||||||
|
|
||||||
FORMS += \
|
FORMS += \
|
||||||
src/ui/catalogwidget.ui \
|
src/ui/catalogwidget.ui \
|
||||||
|
@ -15,6 +15,8 @@ Disassembler::Disassembler(QByteArray memimage)
|
|||||||
QList<DisassembledItem> Disassembler::disassemble(quint16 from, quint16 to,
|
QList<DisassembledItem> Disassembler::disassemble(quint16 from, quint16 to,
|
||||||
QList<quint16> entryPoints,
|
QList<quint16> entryPoints,
|
||||||
bool processRecursively) {
|
bool processRecursively) {
|
||||||
|
m_from = from;
|
||||||
|
m_to = to;
|
||||||
QList<DisassembledItem> retval;
|
QList<DisassembledItem> retval;
|
||||||
qDebug() << "\n\n*****************\n\nDisassemble: From"<<uint16ToHex(from)<<"to"<<uint16ToHex(to);
|
qDebug() << "\n\n*****************\n\nDisassemble: From"<<uint16ToHex(from)<<"to"<<uint16ToHex(to);
|
||||||
//#define OLDDISSEM
|
//#define OLDDISSEM
|
||||||
@ -148,6 +150,12 @@ QList<DisassembledItem> Disassembler::disassemble(quint16 from, quint16 to,
|
|||||||
// }
|
// }
|
||||||
// qDebug() << "Operations Args:" << hexdump;
|
// qDebug() << "Operations Args:" << hexdump;
|
||||||
|
|
||||||
|
if (processRecursively)
|
||||||
|
{
|
||||||
|
// m_jlm.dumpJumps();
|
||||||
|
m_jumplines = m_jlm.buildJumpLines();
|
||||||
|
qDebug() << "Num Channels: " << m_jlm.getNumJumpLineChannels();
|
||||||
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
@ -165,7 +173,10 @@ bool Disassembler::disassembleOp(quint16 address, DisassembledItem &retval, Memo
|
|||||||
retval.setInstruction(op);
|
retval.setInstruction(op);
|
||||||
|
|
||||||
if (opcode == 0x6C || opcode == 0x7c) // Indirect jumps
|
if (opcode == 0x6C || opcode == 0x7c) // Indirect jumps
|
||||||
|
{
|
||||||
|
m_jlm.addJump(address,address,IsUnknownJump,m_from,m_to);
|
||||||
retval.setCanNotFollow(true);
|
retval.setCanNotFollow(true);
|
||||||
|
}
|
||||||
|
|
||||||
QString disassemblyLine;
|
QString disassemblyLine;
|
||||||
QString hexValueString;
|
QString hexValueString;
|
||||||
@ -254,6 +265,10 @@ bool Disassembler::disassembleOp(quint16 address, DisassembledItem &retval, Memo
|
|||||||
quint16 offsetAddress = address+2+offset;
|
quint16 offsetAddress = address+2+offset;
|
||||||
|
|
||||||
retval.setTargetAddress(offsetAddress);
|
retval.setTargetAddress(offsetAddress);
|
||||||
|
if (opcode == 0x80) // BRA
|
||||||
|
m_jlm.addJump(address,offsetAddress,IsBRA,m_from,m_to);
|
||||||
|
else
|
||||||
|
m_jlm.addJump(address,offsetAddress,IsBranch,m_from,m_to);
|
||||||
|
|
||||||
disassemblyLine = QString("%1 _ARG16_ {%2%3}").arg(op.mnemonic())
|
disassemblyLine = QString("%1 _ARG16_ {%2%3}").arg(op.mnemonic())
|
||||||
.arg((offset<0)?"-":"+")
|
.arg((offset<0)?"-":"+")
|
||||||
@ -301,16 +316,19 @@ bool Disassembler::disassembleOp(quint16 address, DisassembledItem &retval, Memo
|
|||||||
|
|
||||||
if (opcode == 0x20 || opcode == 0x4c) {
|
if (opcode == 0x20 || opcode == 0x4c) {
|
||||||
retval.setTargetAddress(makeWord(hexValues[1],hexValues[2]));
|
retval.setTargetAddress(makeWord(hexValues[1],hexValues[2]));
|
||||||
}
|
|
||||||
|
|
||||||
if (opcode == 0x4c)
|
if (opcode == 0x4c) // JMP
|
||||||
{
|
{
|
||||||
qDebug() << "JMP: Adding flow address "
|
qDebug() << "JMP: Adding flow address "
|
||||||
<< uint16ToHex(makeWord(hexValues[1],hexValues[2])) << "to jump table";
|
<< uint16ToHex(makeWord(hexValues[1],hexValues[2])) << "to jump table";
|
||||||
|
m_jlm.addJump(address,argval,IsJMP,m_from,m_to);
|
||||||
m_stack.push(argval);
|
m_stack.push(argval);
|
||||||
retval.setCanNotFollow(true);
|
retval.setCanNotFollow(true);
|
||||||
|
}
|
||||||
|
else // JSR
|
||||||
|
{
|
||||||
|
m_jlm.addJump(address,argval,IsJSR,m_from,m_to);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
retval.setAddress(address);
|
retval.setAddress(address);
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "MemoryUsageMap.h"
|
#include "MemoryUsageMap.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "JumpLineManager.h"
|
||||||
|
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
@ -10,6 +11,7 @@
|
|||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QStack>
|
#include <QStack>
|
||||||
|
|
||||||
|
|
||||||
enum AddressMode {
|
enum AddressMode {
|
||||||
AM_InvalidOp,
|
AM_InvalidOp,
|
||||||
AM_Absolute, // a
|
AM_Absolute, // a
|
||||||
@ -163,6 +165,9 @@ private:
|
|||||||
class Disassembler
|
class Disassembler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Disassembler(QByteArray memimage);
|
Disassembler(QByteArray memimage);
|
||||||
|
|
||||||
enum ProcessorType {
|
enum ProcessorType {
|
||||||
@ -184,12 +189,16 @@ public:
|
|||||||
return m_opcodeinfo[opcode].mnemonic();
|
return m_opcodeinfo[opcode].mnemonic();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
JumpLines getJumpLines() const { return m_jumplines; }
|
||||||
|
|
||||||
|
private:
|
||||||
bool disassembleOp(quint16 address, DisassembledItem &retval, MemoryUsageMap *memuse = Q_NULLPTR);
|
bool disassembleOp(quint16 address, DisassembledItem &retval, MemoryUsageMap *memuse = Q_NULLPTR);
|
||||||
void makeOpcodeTable();
|
void makeOpcodeTable();
|
||||||
|
|
||||||
|
|
||||||
|
quint16 m_from;
|
||||||
|
quint16 m_to;
|
||||||
|
|
||||||
QHash<quint8,AssyInstruction> m_opcodeinfo;
|
QHash<quint8,AssyInstruction> m_opcodeinfo;
|
||||||
QByteArray m_memimage;
|
QByteArray m_memimage;
|
||||||
|
|
||||||
@ -197,6 +206,10 @@ private:
|
|||||||
|
|
||||||
MemoryUsageMap m_memusagemap;
|
MemoryUsageMap m_memusagemap;
|
||||||
|
|
||||||
|
JumpLineManager m_jlm;
|
||||||
|
|
||||||
|
JumpLines m_jumplines;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DISASSEMBLER_H
|
#endif // DISASSEMBLER_H
|
||||||
|
173
src/internals/JumpLineManager.cpp
Normal file
173
src/internals/JumpLineManager.cpp
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
#include "JumpLineManager.h"
|
||||||
|
|
||||||
|
JumpLineManager::JumpLineManager(quint16 from, quint16 to)
|
||||||
|
: m_start(from),
|
||||||
|
m_end(to)
|
||||||
|
{
|
||||||
|
qDebug() << "JumpLineManager(from:"<<uint16ToHex(m_start)<<", to:"<<uint16ToHex(m_end) << ")";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void JumpLineManager::addJump(quint16 src, quint16 dest, JumpType type, quint16 from, quint16 to)
|
||||||
|
{
|
||||||
|
TJump jump(src,dest);
|
||||||
|
if (src >= from && src <= to && dest >= from && dest <= to)
|
||||||
|
{
|
||||||
|
if (!m_jumpmap.contains(jump))
|
||||||
|
{
|
||||||
|
// qDebug() << "JumpLineManager::addJump: Added Jump from" << uint16ToHex(src) << "to" << uint16ToHex(dest) << ", Type:" << type;
|
||||||
|
m_jumpmap.insert(jump,type);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qDebug() << "JumpLineManager::addJump: Not adding duplicate jump:" << uint16ToHex(src) << "," << uint16ToHex(dest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qDebug() << "JumpLineManager::addJump: Address range is out of bounds";
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JumpLineManager::dumpJumps() const {
|
||||||
|
dumpJumps(m_jumpmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JumpLineManager::dumpJumps(JumpMap map) const
|
||||||
|
{
|
||||||
|
qDebug() << "JumpLineManager::dumpJumps()\n JumpTable:";
|
||||||
|
QMapIterator<TJump,JumpType> it(map);
|
||||||
|
while (it.hasNext())
|
||||||
|
{
|
||||||
|
it.next();
|
||||||
|
QString jumptypelabel;
|
||||||
|
if (it.value() == IsUnknownJump) { jumptypelabel = "Unknown Jump"; }
|
||||||
|
if (it.value() == IsJMP) { jumptypelabel = "JMP"; }
|
||||||
|
if (it.value() == IsBranch) { jumptypelabel = "Branch"; }
|
||||||
|
if (it.value() == IsJSR) { jumptypelabel = "JSR"; }
|
||||||
|
if (it.value() == IsBRA) { jumptypelabel = "BRA"; }
|
||||||
|
qDebug() << " Jump from" << uint16ToHex(it.key().first) << "to"
|
||||||
|
<< uint16ToHex(it.key().second) << jumptypelabel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JumpLines JumpLineManager::buildJumpLines()
|
||||||
|
{
|
||||||
|
qDebug() << "A";
|
||||||
|
|
||||||
|
m_channelsAtAddress.clear();
|
||||||
|
m_jumplines.m_maxChannel = 0;
|
||||||
|
QMapIterator<TJump, JumpType> it(m_jumpmap);
|
||||||
|
while (it.hasNext())
|
||||||
|
{
|
||||||
|
it.next();
|
||||||
|
TJump range = it.key();
|
||||||
|
|
||||||
|
JumpLine jl;
|
||||||
|
jl.type = it.value();
|
||||||
|
jl.from = range.first;
|
||||||
|
jl.to = range.second;
|
||||||
|
int channel = findBestChannel(jl);
|
||||||
|
setChannelForJumpLine(channel,jl);
|
||||||
|
|
||||||
|
m_jumplines.jumpLines.append(jl);
|
||||||
|
m_jumplines.m_maxChannel = qMax(m_jumplines.m_maxChannel, channel);
|
||||||
|
}
|
||||||
|
qDebug() << "A";
|
||||||
|
|
||||||
|
|
||||||
|
return m_jumplines;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int JumpLineManager::findBestChannel(JumpLine &jl)
|
||||||
|
{
|
||||||
|
qDebug() << "findBestChannel()";
|
||||||
|
if (m_jumplines.jumpLines.count() == 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int potentialChannel = 0;
|
||||||
|
bool foundChannel = false;
|
||||||
|
while (!foundChannel)
|
||||||
|
{
|
||||||
|
qDebug() << "Tryning potential channel" << potentialChannel;
|
||||||
|
bool matched = false;
|
||||||
|
for (quint16 addr = jl.min(); addr <= jl.max(); addr++)
|
||||||
|
{
|
||||||
|
// If any of these addresses contain the potential channel, move on
|
||||||
|
if (m_channelsAtAddress[addr].contains(potentialChannel))
|
||||||
|
{
|
||||||
|
matched = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (matched)
|
||||||
|
{
|
||||||
|
potentialChannel++;
|
||||||
|
matched = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foundChannel = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return potentialChannel;
|
||||||
|
}
|
||||||
|
|
||||||
|
void JumpLineManager::setChannelForJumpLine(int channel, JumpLine &jl)
|
||||||
|
{
|
||||||
|
jl.channel = channel;
|
||||||
|
for (quint16 addr = jl.min(); addr <= jl.max(); addr++)
|
||||||
|
{
|
||||||
|
m_channelsAtAddress[addr].append(channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JumpLineManager::dumpJumpLines() const
|
||||||
|
{
|
||||||
|
foreach (JumpLine jl, m_jumplines.jumpLines)
|
||||||
|
{
|
||||||
|
qDebug() << " JumpLine from:" << uint16ToHex(jl.from)
|
||||||
|
<< " to:" << uint16ToHex(jl.to)
|
||||||
|
<< "channel: " << jl.channel << " type:" << jl.type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JumpLineManager::doJumpsIntersect(TJump &A, TJump &B) const
|
||||||
|
{
|
||||||
|
|
||||||
|
if (A == B) return false;
|
||||||
|
if (isLineWithinRange(A.first,B) || isLineWithinRange(A.second,B))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (isLineWithinRange(B.first,A) || isLineWithinRange(B.second,A))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JumpLineManager::isLineWithinRange(quint16 line, TJump &jm) const
|
||||||
|
{
|
||||||
|
quint16 min = qMin(jm.first,jm.second);
|
||||||
|
quint16 max = qMax(jm.first,jm.second);
|
||||||
|
|
||||||
|
return (line > min && line < max);
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<JumpLine> JumpLines::jumpLinesAtAddress(quint16 addrs)
|
||||||
|
{
|
||||||
|
QList<JumpLine> list;
|
||||||
|
foreach (JumpLine jl, jumpLines)
|
||||||
|
{
|
||||||
|
if (addrs >= jl.min() && addrs <= jl.max())
|
||||||
|
{
|
||||||
|
list.append(jl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
102
src/internals/JumpLineManager.h
Normal file
102
src/internals/JumpLineManager.h
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
#ifndef JUMPLINEMANAGER_H
|
||||||
|
#define JUMPLINEMANAGER_H
|
||||||
|
|
||||||
|
#include <QPair>
|
||||||
|
#include <QMap>
|
||||||
|
#include <QMapIterator>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
typedef QPair<quint16,quint16> TJump;
|
||||||
|
typedef enum {
|
||||||
|
IsUnknownJump,
|
||||||
|
IsJMP,
|
||||||
|
IsBranch,
|
||||||
|
IsJSR,
|
||||||
|
IsBRA
|
||||||
|
} JumpType;
|
||||||
|
typedef QMap<TJump,JumpType> JumpMap;
|
||||||
|
|
||||||
|
class JumpLine {
|
||||||
|
public:
|
||||||
|
JumpLine() : from(0), to(0), channel(-1), type(IsUnknownJump) { }
|
||||||
|
quint16 from;
|
||||||
|
quint16 to;
|
||||||
|
int channel;
|
||||||
|
JumpType type;
|
||||||
|
|
||||||
|
inline quint16 min() const { return qMin(from,to); }
|
||||||
|
inline quint16 max() const { return qMax(from,to); }
|
||||||
|
inline bool isUp() const { return (from > to); }
|
||||||
|
inline bool isDown() const { return !isUp(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
//////////////////
|
||||||
|
|
||||||
|
class JumpLines
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
JumpLines() : m_maxChannel(0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<int> channelsAtAddress(quint16 address)
|
||||||
|
{
|
||||||
|
return m_channelsAtAddress[address];
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<JumpLine> jumpLinesAtAddress(quint16 addrs);
|
||||||
|
|
||||||
|
QList<JumpLine> jumpLines;
|
||||||
|
|
||||||
|
int m_maxChannel;
|
||||||
|
|
||||||
|
QMap<quint16, QList<int> > m_channelsAtAddress;
|
||||||
|
};
|
||||||
|
|
||||||
|
//////////////////
|
||||||
|
|
||||||
|
class JumpLineManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
JumpLineManager(quint16 from = 0x0000, quint16 to = 0xffff);
|
||||||
|
|
||||||
|
void addJump(quint16 src, quint16 dest, JumpType type,quint16 from = 0, quint16 to = 0xffff);
|
||||||
|
void dumpJumps() const;
|
||||||
|
|
||||||
|
JumpLines buildJumpLines();
|
||||||
|
JumpLines getJumpLines() const { return m_jumplines; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void clear() { m_jumpmap.clear(); }
|
||||||
|
void dumpJumpLines() const;
|
||||||
|
|
||||||
|
int getNumJumpLineChannels() const { return m_jumplines.m_maxChannel; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int findBestChannel(JumpLine &jl);
|
||||||
|
|
||||||
|
void setChannelForJumpLine(int channel, JumpLine &jl);
|
||||||
|
|
||||||
|
private:
|
||||||
|
quint16 m_start;
|
||||||
|
quint16 m_end;
|
||||||
|
|
||||||
|
JumpMap m_jumpmap;
|
||||||
|
|
||||||
|
JumpLines m_jumplines;
|
||||||
|
|
||||||
|
QMap<quint16, QList<int>> m_channelsAtAddress;
|
||||||
|
|
||||||
|
|
||||||
|
bool doJumpsIntersect(TJump &A, TJump &B) const;
|
||||||
|
bool isLineWithinRange(quint16 line, TJump &jm) const;
|
||||||
|
|
||||||
|
void dumpJumps(JumpMap map) const;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // JUMPLINEMANAGER_H
|
@ -104,8 +104,8 @@ void DisassemblerViewer::handleDisassembleRequest(QList<quint16> addresses)
|
|||||||
{
|
{
|
||||||
QStringList strings;
|
QStringList strings;
|
||||||
|
|
||||||
strings += getDisassemblyStrings(addresses);
|
disassemble(addresses);
|
||||||
|
strings += getDisassemblyStrings();
|
||||||
qSort(strings);
|
qSort(strings);
|
||||||
strings.removeDuplicates();
|
strings.removeDuplicates();
|
||||||
|
|
||||||
@ -126,7 +126,11 @@ void DisassemblerViewer::handleDisassembleRequest(QList<quint16> addresses)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QStringList DisassemblerViewer::getDisassemblyStrings(QList<quint16> entryPoints) {
|
QStringList DisassemblerViewer::getDisassemblyStrings() {
|
||||||
|
return m_disassemblyStrings;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DisassemblerViewer::disassemble(QList<quint16> entryPoints) {
|
||||||
|
|
||||||
Disassembler dis(m_mem.values());
|
Disassembler dis(m_mem.values());
|
||||||
|
|
||||||
@ -136,6 +140,7 @@ QStringList DisassemblerViewer::getDisassemblyStrings(QList<quint16> entryPoints
|
|||||||
m_file->address()+length,
|
m_file->address()+length,
|
||||||
entryPoints);
|
entryPoints);
|
||||||
dis.setUnknownToData(m_file->address(),m_file->address()+length);
|
dis.setUnknownToData(m_file->address(),m_file->address()+length);
|
||||||
|
m_jumpLines = dis.getJumpLines();
|
||||||
|
|
||||||
QStringList formattedLines;
|
QStringList formattedLines;
|
||||||
|
|
||||||
@ -176,7 +181,7 @@ QStringList DisassemblerViewer::getDisassemblyStrings(QList<quint16> entryPoints
|
|||||||
}
|
}
|
||||||
qSort(formattedLines);
|
qSort(formattedLines);
|
||||||
|
|
||||||
return formattedLines;
|
m_disassemblyStrings = formattedLines;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1500,12 +1505,9 @@ void DisassemblerViewer::showMetadataDialog()
|
|||||||
void DisassemblerViewer::setData(QByteArray data)
|
void DisassemblerViewer::setData(QByteArray data)
|
||||||
{
|
{
|
||||||
ui->textArea->setText(data);
|
ui->textArea->setText(data);
|
||||||
|
ui->textArea->setJumpLines(&m_jumpLines);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisassemblerViewer::setText(QString text)
|
|
||||||
{
|
|
||||||
ui->textArea->setHtml(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DisassemblerViewer::canPrint() const { return true; }
|
bool DisassemblerViewer::canPrint() const { return true; }
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "relocatablefile.h"
|
#include "relocatablefile.h"
|
||||||
#include "fileviewerinterface.h"
|
#include "fileviewerinterface.h"
|
||||||
#include "DisassemblerMetadataDialog.h"
|
#include "DisassemblerMetadataDialog.h"
|
||||||
|
#include "JumpLineManager.h"
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class DisassemblerViewer;
|
class DisassemblerViewer;
|
||||||
@ -25,7 +26,6 @@ public:
|
|||||||
void setFile(BinaryFile *file);
|
void setFile(BinaryFile *file);
|
||||||
void setFile(RelocatableFile *file);
|
void setFile(RelocatableFile *file);
|
||||||
void setData(QByteArray data);
|
void setData(QByteArray data);
|
||||||
void setText(QString text);
|
|
||||||
|
|
||||||
QString getPotentialLabel(quint16 address);
|
QString getPotentialLabel(quint16 address);
|
||||||
virtual bool optionsMenuItems(QMenu *);
|
virtual bool optionsMenuItems(QMenu *);
|
||||||
@ -35,7 +35,8 @@ public:
|
|||||||
|
|
||||||
QString makeDescriptorStringForVal(quint8 val);
|
QString makeDescriptorStringForVal(quint8 val);
|
||||||
|
|
||||||
QStringList getDisassemblyStrings(QList<quint16> entryPoints);
|
void disassemble(QList<quint16> entryPoints);
|
||||||
|
QStringList getDisassemblyStrings();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setFile(GenericFile *file);
|
void setFile(GenericFile *file);
|
||||||
@ -60,6 +61,9 @@ private:
|
|||||||
Memory m_mem;
|
Memory m_mem;
|
||||||
|
|
||||||
bool m_isRelo;
|
bool m_isRelo;
|
||||||
|
|
||||||
|
QStringList m_disassemblyStrings;
|
||||||
|
JumpLines m_jumpLines;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DISASSEMBLERVIEWER_H
|
#endif // DISASSEMBLERVIEWER_H
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QTextBrowser" name="textArea">
|
<widget class="FlowLineTextBrowser" name="textArea">
|
||||||
<property name="font">
|
<property name="font">
|
||||||
<font>
|
<font>
|
||||||
<family>Courier</family>
|
<family>Courier</family>
|
||||||
@ -36,6 +36,11 @@
|
|||||||
<header>viewerbase.h</header>
|
<header>viewerbase.h</header>
|
||||||
<container>1</container>
|
<container>1</container>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>FlowLineTextBrowser</class>
|
||||||
|
<extends>QTextBrowser</extends>
|
||||||
|
<header>FlowLineTextBrowser.h</header>
|
||||||
|
</customwidget>
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections/>
|
<connections/>
|
||||||
|
299
src/ui/widgets/FlowLineTextBrowser.cpp
Normal file
299
src/ui/widgets/FlowLineTextBrowser.cpp
Normal file
@ -0,0 +1,299 @@
|
|||||||
|
#include "FlowLineTextBrowser.h"
|
||||||
|
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QTextBlock>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
#include <QTextDocument>
|
||||||
|
#include <QTextCursor>
|
||||||
|
#include <QAbstractTextDocumentLayout>
|
||||||
|
#include <QScrollBar>
|
||||||
|
|
||||||
|
FlowLineTextBrowser::FlowLineTextBrowser(QWidget *parent) : QTextBrowser(parent)
|
||||||
|
{
|
||||||
|
m_lineArea = new LineArea(this);
|
||||||
|
m_jl = Q_NULLPTR;
|
||||||
|
|
||||||
|
//this->verticalScrollBar()->setSliderPosition(this->verticalScrollBar()->sliderPosition());
|
||||||
|
|
||||||
|
// connect(this->document(), SIGNAL(blockCountChanged(int)), SLOT(updateLineAreaWidth(int)));
|
||||||
|
connect(this, SIGNAL(updateRequest(QRect,int)), SLOT(updateLineArea(QRect,int)));
|
||||||
|
updateLineAreaWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
int FlowLineTextBrowser::getFirstVisibleBlock(QTextBlock *firstBlock) const
|
||||||
|
{
|
||||||
|
|
||||||
|
QTextCursor curs = QTextCursor(this->document());
|
||||||
|
curs.movePosition(QTextCursor::Start);
|
||||||
|
for(int i=0; i < this->document()->blockCount(); ++i)
|
||||||
|
{
|
||||||
|
QTextBlock block = curs.block();
|
||||||
|
|
||||||
|
QRect r1 = this->viewport()->geometry();
|
||||||
|
QRect r2 = this->document()->documentLayout()->blockBoundingRect(block).translated(
|
||||||
|
this->viewport()->geometry().x(), this->viewport()->geometry().y() - (
|
||||||
|
this->verticalScrollBar()->sliderPosition()
|
||||||
|
) ).toRect();
|
||||||
|
|
||||||
|
if (r1.contains(r2, true) || r1.intersects(r2))
|
||||||
|
{
|
||||||
|
qDebug() << r2;
|
||||||
|
if (firstBlock)
|
||||||
|
*firstBlock = block;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
curs.movePosition(QTextCursor::NextBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstBlock)
|
||||||
|
*firstBlock = QTextBlock();
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlowLineTextBrowser::showEvent(QShowEvent *)
|
||||||
|
{
|
||||||
|
this->verticalScrollBar()->setSliderPosition(this->verticalScrollBar()->sliderPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlowLineTextBrowser::lineAreaPaintEvent(QPaintEvent *event)
|
||||||
|
{
|
||||||
|
|
||||||
|
QPainter painter(m_lineArea);
|
||||||
|
painter.fillRect(event->rect(), Qt::lightGray);
|
||||||
|
|
||||||
|
painter.setPen(Qt::red);
|
||||||
|
painter.setBrush(Qt::red);
|
||||||
|
|
||||||
|
QTextBlock block;
|
||||||
|
getFirstVisibleBlock(&block);
|
||||||
|
|
||||||
|
qDebug() << block.text();
|
||||||
|
bool foundFirst = false;
|
||||||
|
quint16 linenum;
|
||||||
|
|
||||||
|
QTextCursor curs = QTextCursor(this->document());
|
||||||
|
curs.movePosition(QTextCursor::Start);
|
||||||
|
bool inBlankLine = false;
|
||||||
|
// for each visible block
|
||||||
|
while (isBlockVisible(block) && block.next().isValid())
|
||||||
|
{
|
||||||
|
QString text = block.text();
|
||||||
|
if (text.contains(QRegularExpression("[0-9A-Fa-f]{4}:")))
|
||||||
|
{
|
||||||
|
bool ok = true;
|
||||||
|
quint16 addr = (quint16) text.left(4).toInt(&ok,16);
|
||||||
|
if (ok)
|
||||||
|
{
|
||||||
|
// qDebug() << "Addr:" << uint16ToHex(addr);
|
||||||
|
linenum = addr;
|
||||||
|
foundFirst = true;
|
||||||
|
inBlankLine = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// qDebug() << "No address!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
inBlankLine = true;
|
||||||
|
}
|
||||||
|
// qDebug() << "Channels:" << m_jl->channelsAtAddress(linenum);
|
||||||
|
|
||||||
|
if (foundFirst)
|
||||||
|
{
|
||||||
|
QRect blockRect = getBlockGeometry(block);
|
||||||
|
float topInY = blockRect.top() + ((1./6.) * blockRect.height());
|
||||||
|
float topOutY = blockRect.top() + ((2./6.) * blockRect.height());
|
||||||
|
float botOutY = blockRect.top() + ((3./6.) * blockRect.height());
|
||||||
|
float botInY = blockRect.top() + ((4./6.) * blockRect.height());
|
||||||
|
|
||||||
|
// painter.drawLine(0,blockRect.top(),m_lineArea->width(),blockRect.bottom());
|
||||||
|
|
||||||
|
QList<JumpLine> jllist = m_jl->jumpLinesAtAddress(linenum);
|
||||||
|
|
||||||
|
foreach (JumpLine jl, jllist)
|
||||||
|
{
|
||||||
|
int offset = getChannelOffset(jl.channel);
|
||||||
|
if (!inBlankLine)
|
||||||
|
{
|
||||||
|
if (jl.from == linenum)
|
||||||
|
{
|
||||||
|
if (jl.from == jl.to)
|
||||||
|
{
|
||||||
|
painter.drawLine(offset, botInY,
|
||||||
|
m_lineArea->width(), botInY);
|
||||||
|
painter.drawLine(offset, botInY, offset, topOutY);
|
||||||
|
painter.drawLine(offset, topOutY,
|
||||||
|
m_lineArea->width(), topOutY);
|
||||||
|
// painter.drawEllipse(QPointF(m_lineArea->width(),topOutY),2,2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (jl.isUp())
|
||||||
|
{
|
||||||
|
painter.drawLine(offset, topOutY,
|
||||||
|
offset, blockRect.top());
|
||||||
|
painter.drawLine(offset, topOutY,
|
||||||
|
m_lineArea->width(), topOutY);
|
||||||
|
painter.drawEllipse(QPointF(m_lineArea->width(),topOutY),2,2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
painter.drawLine(offset, botOutY,
|
||||||
|
offset, blockRect.bottom());
|
||||||
|
painter.drawLine(offset, botOutY,
|
||||||
|
m_lineArea->width(), botOutY);
|
||||||
|
// painter.drawEllipse(QPointF(m_lineArea->width(),botOutY),2,2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (jl.to == linenum)
|
||||||
|
{
|
||||||
|
if (jl.isUp())
|
||||||
|
{
|
||||||
|
painter.drawLine(offset, botInY,
|
||||||
|
offset, blockRect.bottom());
|
||||||
|
painter.drawLine(offset, botInY,
|
||||||
|
m_lineArea->width(), botInY);
|
||||||
|
|
||||||
|
QPolygonF varrow;
|
||||||
|
varrow.append(QPointF(offset, botInY));
|
||||||
|
varrow.append(QPointF(offset-3, botInY+5));
|
||||||
|
varrow.append(QPointF(offset+3, botInY+5));
|
||||||
|
painter.drawConvexPolygon(varrow);
|
||||||
|
|
||||||
|
|
||||||
|
QPolygonF harrow;
|
||||||
|
harrow.append(QPointF(m_lineArea->width(),botInY));
|
||||||
|
harrow.append(QPointF(m_lineArea->width()-4,botInY-3));
|
||||||
|
harrow.append(QPointF(m_lineArea->width()-4,botInY+3));
|
||||||
|
painter.drawConvexPolygon(harrow);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
painter.drawLine(offset, topInY,
|
||||||
|
offset, blockRect.top());
|
||||||
|
painter.drawLine(offset, topInY,
|
||||||
|
m_lineArea->width(), topInY);
|
||||||
|
QPolygonF varrow;
|
||||||
|
varrow.append(QPointF(offset, topInY));
|
||||||
|
varrow.append(QPointF(offset-3, topInY-5));
|
||||||
|
varrow.append(QPointF(offset+3, topInY-5));
|
||||||
|
painter.drawConvexPolygon(varrow);
|
||||||
|
|
||||||
|
QPolygonF harrow;
|
||||||
|
harrow.append(QPointF(m_lineArea->width(),topInY));
|
||||||
|
harrow.append(QPointF(m_lineArea->width()-4,topInY-3));
|
||||||
|
harrow.append(QPointF(m_lineArea->width()-4,topInY+3));
|
||||||
|
painter.drawConvexPolygon(harrow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (linenum > jl.min() && linenum < jl.max())
|
||||||
|
{
|
||||||
|
painter.drawLine(offset, blockRect.top(),offset, blockRect.bottom());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // inBlankLine
|
||||||
|
{
|
||||||
|
if (jl.from == linenum)
|
||||||
|
{
|
||||||
|
if (jl.from != jl.to)
|
||||||
|
{
|
||||||
|
if (jl.isDown())
|
||||||
|
{
|
||||||
|
painter.drawLine(offset, blockRect.top(),offset, blockRect.bottom());
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (jl.to == linenum)
|
||||||
|
{
|
||||||
|
if (jl.isUp())
|
||||||
|
{
|
||||||
|
painter.drawLine(offset, blockRect.top(),offset, blockRect.bottom());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (linenum > jl.min() && linenum < jl.max())
|
||||||
|
{
|
||||||
|
painter.drawLine(offset, blockRect.top(),offset, blockRect.bottom());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
block = block.next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QRect FlowLineTextBrowser::getBlockGeometry(QTextBlock block) const
|
||||||
|
{
|
||||||
|
QRect rect = this->document()->documentLayout()->blockBoundingRect(block).translated(
|
||||||
|
this->viewport()->geometry().x(), this->viewport()->geometry().y() - (
|
||||||
|
this->verticalScrollBar()->sliderPosition()
|
||||||
|
) ).toRect();
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FlowLineTextBrowser::isBlockVisible(QTextBlock block) const
|
||||||
|
{
|
||||||
|
QRect r1 = this->viewport()->geometry();
|
||||||
|
QRect r2 = this->document()->documentLayout()->blockBoundingRect(block).translated(
|
||||||
|
this->viewport()->geometry().x(), this->viewport()->geometry().y() - (
|
||||||
|
this->verticalScrollBar()->sliderPosition()
|
||||||
|
) ).toRect();
|
||||||
|
|
||||||
|
return (r1.contains(r2, true) || r1.intersects(r2));
|
||||||
|
}
|
||||||
|
|
||||||
|
int FlowLineTextBrowser::getChannelOffset(int channel)
|
||||||
|
{
|
||||||
|
int width = lineAreaWidth();
|
||||||
|
return width - (channel * 9)- 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FlowLineTextBrowser::lineAreaWidth()
|
||||||
|
{
|
||||||
|
if (!m_jl) return 10;
|
||||||
|
return m_jl->m_maxChannel* 9 + 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlowLineTextBrowser::setJumpLines(JumpLines *jl)
|
||||||
|
{
|
||||||
|
m_jl = jl;
|
||||||
|
m_lineArea->setJumpLines(jl);
|
||||||
|
updateLineAreaWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlowLineTextBrowser::paintEvent(QPaintEvent *event)
|
||||||
|
{
|
||||||
|
m_lineArea->update();
|
||||||
|
QTextBrowser::paintEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlowLineTextBrowser::resizeEvent(QResizeEvent *event)
|
||||||
|
{
|
||||||
|
QTextBrowser::resizeEvent(event);
|
||||||
|
|
||||||
|
QRect cr = contentsRect();
|
||||||
|
m_lineArea->setGeometry(QRect(cr.left(), cr.top(), lineAreaWidth(), cr.height()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlowLineTextBrowser::updateLineAreaWidth()
|
||||||
|
{
|
||||||
|
setViewportMargins(lineAreaWidth(),0,0,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlowLineTextBrowser::updateLineArea(const QRect &rect, int dy)
|
||||||
|
{
|
||||||
|
if (dy)
|
||||||
|
m_lineArea->scroll(0, dy);
|
||||||
|
else
|
||||||
|
m_lineArea->update(0, rect.y(), m_lineArea->width(), rect.height());
|
||||||
|
|
||||||
|
if (rect.contains(viewport()->rect()))
|
||||||
|
updateLineAreaWidth();
|
||||||
|
}
|
74
src/ui/widgets/FlowLineTextBrowser.h
Normal file
74
src/ui/widgets/FlowLineTextBrowser.h
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#ifndef FLOWLINETEXTBROWSER_H
|
||||||
|
#define FLOWLINETEXTBROWSER_H
|
||||||
|
|
||||||
|
#include "JumpLineManager.h"
|
||||||
|
|
||||||
|
#include <QTextBrowser>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QResizeEvent>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QPaintEvent>
|
||||||
|
#include <QResizeEvent>
|
||||||
|
#include <QSize>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QScrollEvent>
|
||||||
|
|
||||||
|
class LineArea;
|
||||||
|
|
||||||
|
class FlowLineTextBrowser : public QTextBrowser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FlowLineTextBrowser(QWidget *parent = Q_NULLPTR);
|
||||||
|
|
||||||
|
void lineAreaPaintEvent(QPaintEvent *event);
|
||||||
|
int lineAreaWidth();
|
||||||
|
|
||||||
|
void setJumpLines(JumpLines *jl);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;
|
||||||
|
void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
int getFirstVisibleBlock(QTextBlock *firstBlock) const;
|
||||||
|
|
||||||
|
int getChannelOffset(int channel);
|
||||||
|
QRect getBlockGeometry(QTextBlock block) const;
|
||||||
|
bool isBlockVisible(QTextBlock block) const;
|
||||||
|
void showEvent(QShowEvent *) Q_DECL_OVERRIDE;
|
||||||
|
private slots:
|
||||||
|
void updateLineAreaWidth();
|
||||||
|
void updateLineArea(const QRect &, int);
|
||||||
|
|
||||||
|
private:
|
||||||
|
LineArea *m_lineArea;
|
||||||
|
|
||||||
|
JumpLines *m_jl;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LineArea : public QWidget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LineArea(FlowLineTextBrowser *browser) : QWidget(browser)
|
||||||
|
{
|
||||||
|
m_browser = browser;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setJumpLines(JumpLines *jl) { m_jl = jl; }
|
||||||
|
|
||||||
|
QSize sizeHint() const Q_DECL_OVERRIDE
|
||||||
|
{
|
||||||
|
return QSize(m_browser->lineAreaWidth(),0);
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE
|
||||||
|
{
|
||||||
|
m_browser->lineAreaPaintEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
FlowLineTextBrowser *m_browser;
|
||||||
|
JumpLines *m_jl;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // FLOWLINETEXTBROWSER_H
|
Loading…
Reference in New Issue
Block a user