Major fixes to disassembler

This commit is contained in:
Mark Long 2016-10-30 22:45:45 -05:00
parent 570b87dfd5
commit e75ed40ce0
5 changed files with 191 additions and 136 deletions

View File

@ -8,14 +8,17 @@ Disassembler::Disassembler(QByteArray memimage)
{ {
m_memimage = memimage, makeOpcodeTable(); m_memimage = memimage, makeOpcodeTable();
m_memusagemap.clearData(); m_memusagemap.clearData();
} }
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) {
QList<DisassembledItem> retval; QList<DisassembledItem> retval;
qDebug() << "Disassemble: From"<<uint16ToHex(from)<<"to"<<uint16ToHex(to); qDebug() << "\n\n*****************\n\nDisassemble: From"<<uint16ToHex(from)<<"to"<<uint16ToHex(to);
//#define OLDDISSEM //#define OLDDISSEM
#ifdef OLDDISSEM #ifdef OLDDISSEM
for (int idx = from; idx <= to; ) for (int idx = from; idx <= to; )
{ {
@ -34,10 +37,11 @@ QList<DisassembledItem> Disassembler::disassemble(quint16 from, quint16 to,
bool stopping = false; bool stopping = false;
quint16 next = from; quint16 next = from;
if (entryPoints.count()) while (entryPoints.count())
{ {
next = entryPoints.takeFirst(); next = entryPoints.takeFirst();
m_jumps.append(entryPoints); //m_jumps.append(entryPoints);
m_stack.push(next);
} }
while (!stopping) while (!stopping)
@ -59,19 +63,31 @@ QList<DisassembledItem> Disassembler::disassemble(quint16 from, quint16 to,
if (item.isBranch()) if (item.isBranch())
{ {
qDebug() << "Is Branch"; qDebug() << "Is Branch";
if (!m_jumps.contains(item.targetAddress())) m_stack.push(item.targetAddress());
{ // if (!m_jumps.contains(item.targetAddress()))
m_jumps.append(item.targetAddress()); // {
} // m_jumps.append(item.targetAddress());
// qDebug() << "Appending branch" << uint16ToHex(item.targetAddress()) << "to jump table";
// }
} }
if (item.isJsr() && !item.canNotFollow()) if (item.isJsr() && !item.canNotFollow())
{ {
if (item.targetAddress() <= to) //TODO: Remove this to not limit disassembly to program range if (item.targetAddress() <= to) //TODO: Remove this to not limit disassembly to program range
if (!m_jumps.contains(item.targetAddress())) {
if (m_stack.push(item.targetAddress()))
//if (!m_jumps.contains(item.targetAddress()))
{ {
m_jumps.append(item.targetAddress()); qDebug() << "Appending" << uint16ToHex(item.targetAddress()) << "to jump table";
//m_jumps.append(item.targetAddress());
} }
else
{
qDebug() << "Not adding" << uint16ToHex(item.targetAddress()) << "to jump table";
}
}
} }
if (next <= to) //TODO: Remove this to not limit disassembly to program range if (next <= to) //TODO: Remove this to not limit disassembly to program range
@ -99,19 +115,21 @@ QList<DisassembledItem> Disassembler::disassemble(quint16 from, quint16 to,
m_memusagemap.merge(memuse); m_memusagemap.merge(memuse);
if (processRecursively) if (processRecursively)
while (m_jumps.size()) //while (m_jumps.size())
{ while (!m_stack.isEmpty())
quint16 num = m_jumps.takeFirst();
if (!m_memusagemap[num].testFlag(Operation))
{ {
if (num >= from && num <= to) // TODO: remove this to not limit disassembly to program range // quint16 num = m_jumps.takeFirst();
quint16 num = m_stack.pop();
if (!m_memusagemap[num].testFlag(Operation))
{ {
qDebug() << "Calling recursively to"<<uint16ToHex(num); if (num >= from && num <= to) // TODO: remove this to not limit disassembly to program range
retval.append(disassemble(from,to,QList<quint16>() << num,false)); {
qDebug() << "Return from recursive call."; qDebug() << "Calling recursively to"<<uint16ToHex(num);
retval.append(disassemble(from,to,QList<quint16>() << num,false));
qDebug() << "Return from recursive call.";
}
} }
} }
}
#endif #endif
qSort(retval); qSort(retval);
@ -173,7 +191,11 @@ bool Disassembler::disassembleOp(quint16 address, DisassembledItem &retval, Memo
if (op.numArgs() == 1) if (op.numArgs() == 1)
argval = (quint8) hexValues[1]; argval = (quint8) hexValues[1];
else if (op.numArgs() == 2) else if (op.numArgs() == 2)
argval = (quint8) hexValues[1] + ((quint8) hexValues[2] * 256); {
argval = makeWord(hexValues[1],hexValues[2]);
}
for (int idx = 0; idx < hexValues.length(); idx++) { for (int idx = 0; idx < hexValues.length(); idx++) {
hexValueString.append(QString("%1 ").arg((quint8) hexValues[idx],2,16,QChar('0'))); hexValueString.append(QString("%1 ").arg((quint8) hexValues[idx],2,16,QChar('0')));
@ -184,109 +206,112 @@ bool Disassembler::disassembleOp(quint16 address, DisassembledItem &retval, Memo
// Disassemble instruction // Disassemble instruction
switch (op.addressMode()) { switch (op.addressMode()) {
case AM_InvalidOp: { case AM_InvalidOp: {
disassemblyLine = op.mnemonic(); disassemblyLine = op.mnemonic();
retval.setIsInvalidOp(true); retval.setIsInvalidOp(true);
break; break;
} }
case AM_Absolute:{ case AM_Absolute:{
disassemblyLine = QString("%1 _ARG16_").arg(op.mnemonic()); disassemblyLine = QString("%1 _ARG16_").arg(op.mnemonic());
retval.setRawArgument(argval); retval.setRawArgument(argval);
break; break;
} }
case AM_AbsoluteIndexedIndirect:{ case AM_AbsoluteIndexedIndirect:{
disassemblyLine = QString("%1 (_ARG16_,x)").arg(op.mnemonic()); disassemblyLine = QString("%1 (_ARG16_,x)").arg(op.mnemonic());
retval.setRawArgument(argval); retval.setRawArgument(argval);
break; break;
} }
case AM_AbsoluteIndexedWithX:{ case AM_AbsoluteIndexedWithX:{
disassemblyLine = QString("%1 _ARG16_,x").arg(op.mnemonic()); disassemblyLine = QString("%1 _ARG16_,x").arg(op.mnemonic());
retval.setRawArgument(argval); retval.setRawArgument(argval);
break; break;
} }
case AM_AbsoluteIndexedWithY:{ case AM_AbsoluteIndexedWithY:{
disassemblyLine = QString("%1 _ARG16_,y").arg(op.mnemonic()); disassemblyLine = QString("%1 _ARG16_,y").arg(op.mnemonic());
retval.setRawArgument(argval); retval.setRawArgument(argval);
break; break;
} }
case AM_AbsoluteIndirect:{ case AM_AbsoluteIndirect:{
disassemblyLine = QString("%1 (_ARG16_)").arg(op.mnemonic()); disassemblyLine = QString("%1 (_ARG16_)").arg(op.mnemonic());
retval.setRawArgument(argval); retval.setRawArgument(argval);
break; break;
} }
case AM_Immediate:{ case AM_Immediate:{
disassemblyLine = QString("%1 #%2").arg(op.mnemonic()).arg((quint8) hexValues[1],2,16,QChar('0')).toUpper(); disassemblyLine = QString("%1 #%2").arg(op.mnemonic()).arg((quint8) hexValues[1],2,16,QChar('0')).toUpper();
retval.setRawArgument(argval); retval.setRawArgument(argval);
break; break;
} }
case AM_Implied:{ case AM_Implied:{
disassemblyLine = op.mnemonic(); disassemblyLine = op.mnemonic();
break; break;
} }
case AM_Accumulator:{ case AM_Accumulator:{
disassemblyLine = op.mnemonic(); disassemblyLine = op.mnemonic();
break; break;
} }
case AM_ProgramCounterRelative:{ case AM_ProgramCounterRelative:{
qint8 offset = (qint8) hexValues[1]; qint8 offset = (qint8) hexValues[1];
quint16 offsetAddress = address+2+offset; quint16 offsetAddress = address+2+offset;
retval.setTargetAddress(offsetAddress); retval.setTargetAddress(offsetAddress);
disassemblyLine = QString("%1 _ARG16_ {%2%3}").arg(op.mnemonic()) disassemblyLine = QString("%1 _ARG16_ {%2%3}").arg(op.mnemonic())
.arg((offset<0)?"-":"+") .arg((offset<0)?"-":"+")
.arg(abs(offset)); .arg(abs(offset));
retval.setRawArgument(offsetAddress); retval.setRawArgument(offsetAddress);
break; break;
} }
case AM_ZeroPage:{ case AM_ZeroPage:{
disassemblyLine = QString("%1 _ARG8_").arg(op.mnemonic()); disassemblyLine = QString("%1 _ARG8_").arg(op.mnemonic());
retval.setRawArgument(argval); retval.setRawArgument(argval);
break; break;
} }
case AM_ZeroPageIndirectIndexedWithY:{ case AM_ZeroPageIndirectIndexedWithY:{
disassemblyLine = QString("%1 (_ARG8_),Y").arg(op.mnemonic()); disassemblyLine = QString("%1 (_ARG8_),Y").arg(op.mnemonic());
retval.setRawArgument(argval); retval.setRawArgument(argval);
break; break;
} }
case AM_ZeroPageIndexedIndirect:{ case AM_ZeroPageIndexedIndirect:{
disassemblyLine = QString("%1 (_ARG8_,x)").arg(op.mnemonic()); disassemblyLine = QString("%1 (_ARG8_,x)").arg(op.mnemonic());
retval.setRawArgument(argval); retval.setRawArgument(argval);
break; break;
} }
case AM_ZeroPageIndexedWithX:{ case AM_ZeroPageIndexedWithX:{
disassemblyLine = QString("%1 _ARG8_,x").arg(op.mnemonic()); disassemblyLine = QString("%1 _ARG8_,x").arg(op.mnemonic());
retval.setRawArgument(argval); retval.setRawArgument(argval);
break; break;
} }
case AM_ZeroPageIndexedWithY:{ case AM_ZeroPageIndexedWithY:{
disassemblyLine = QString("%1 _ARG8_,y").arg(op.mnemonic()); disassemblyLine = QString("%1 _ARG8_,y").arg(op.mnemonic());
retval.setRawArgument(argval); retval.setRawArgument(argval);
break; break;
} }
case AM_ZeroPageIndirect:{ case AM_ZeroPageIndirect:{
disassemblyLine = QString("%1 (_ARG8_)").arg(op.mnemonic()); disassemblyLine = QString("%1 (_ARG8_)").arg(op.mnemonic());
retval.setRawArgument(argval); retval.setRawArgument(argval);
break; break;
} }
default:{ default:{
disassemblyLine = op.mnemonic(); disassemblyLine = op.mnemonic();
retval.setIsInvalidOp(true); retval.setIsInvalidOp(true);
qDebug() << "Unhandled Address Mode: " << op.addressMode(); qDebug() << "Unhandled Address Mode: " << op.addressMode();
break; break;
} }
} }
if (opcode == 0x20 || opcode == 0x4c) { if (opcode == 0x20 || opcode == 0x4c) {
retval.setTargetAddress(hexValues[2]*256 + hexValues[1]); retval.setTargetAddress(makeWord(hexValues[1],hexValues[2]));
} }
if (opcode == 0x4c) if (opcode == 0x4c)
{ {
qDebug() << "JMP: Setting next flow address to"<<uint16ToHex(hexValues[2]*256 + hexValues[1]); qDebug() << "JMP: Adding flow address "
retval.setNextFlowAddress(hexValues[2]*256 + hexValues[1]); << uint16ToHex(makeWord(hexValues[1],hexValues[2])) << "to jump table";
}
m_stack.push(argval);
retval.setCanNotFollow(true);
}
retval.setAddress(address); retval.setAddress(address);
retval.setDisassembledString(disassemblyLine.toUpper()); retval.setDisassembledString(disassemblyLine.toUpper());
@ -865,30 +890,31 @@ AssyInstruction::AssyInstruction(quint8 opcode, QString mnemonic, AddressMode am
quint8 AssyInstruction::numArgs() { quint8 AssyInstruction::numArgs() {
switch (m_addressMode) { switch (m_addressMode) {
case AM_Absolute: case AM_Absolute:
case AM_AbsoluteIndexedIndirect: case AM_AbsoluteIndexedIndirect:
case AM_AbsoluteIndexedWithX: case AM_AbsoluteIndexedWithX:
case AM_AbsoluteIndexedWithY: case AM_AbsoluteIndexedWithY:
case AM_AbsoluteIndirect: case AM_AbsoluteIndirect:
return 2; return 2;
case AM_ProgramCounterRelative: case AM_ProgramCounterRelative:
case AM_ZeroPage: case AM_ZeroPage:
case AM_ZeroPageIndirectIndexedWithY: case AM_ZeroPageIndirectIndexedWithY:
case AM_ZeroPageIndexedIndirect: case AM_ZeroPageIndexedIndirect:
case AM_ZeroPageIndexedWithX: case AM_ZeroPageIndexedWithX:
case AM_ZeroPageIndexedWithY: case AM_ZeroPageIndexedWithY:
case AM_ZeroPageIndirect: case AM_ZeroPageIndirect:
case AM_Immediate: case AM_Immediate:
return 1; return 1;
case AM_InvalidOp: case AM_InvalidOp:
case AM_Implied: case AM_Implied:
case AM_Accumulator: case AM_Accumulator:
default: default:
return 0; return 0;
} }
} }
DisassembledItem::DisassembledItem(AssyInstruction instr) { DisassembledItem::DisassembledItem(AssyInstruction instr) {
m_canNotFollow = false;
setInstruction(instr); setInstruction(instr);
} }

View File

@ -8,6 +8,7 @@
#include <QStringList> #include <QStringList>
#include <QHash> #include <QHash>
#include <QDebug> #include <QDebug>
#include <QStack>
enum AddressMode { enum AddressMode {
AM_InvalidOp, AM_InvalidOp,
@ -29,6 +30,30 @@ enum AddressMode {
}; };
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
class AddressStack
{
public:
AddressStack() { }
bool push(quint16 address, bool force = false) {
if (force || (!m_stack.contains(address)))
{
qDebug() << " PUSH: " << uint16ToHex(address);
m_stack.push(address);
return true;
}
return false;
}
bool isEmpty() { return m_stack.isEmpty(); }
quint16 pop() { return m_stack.pop(); }
private:
QStack<quint16> m_stack;
};
//////////////////////////////////////////////////////////////////////////////
struct AssyInstruction { struct AssyInstruction {
public: public:
@ -93,7 +118,7 @@ public:
bool stopsProcessing() { bool stopsProcessing() {
if (isReturn()) qDebug() << "Is Return"; if (isReturn()) qDebug() << "Is Return";
if (isInvalidOp()) qDebug() << "Is Invalid Op" << uint8ToHex(m_instruction.opcode()); if (isInvalidOp()) qDebug() << "Is Invalid Op" << uint8ToHex(m_instruction.opcode());
if (canNotFollow()) qDebug() << "Can not follow indirect jump"; if (canNotFollow()) qDebug() << "Not following jump";
if (isBreak()) qDebug() << "Is Break"; if (isBreak()) qDebug() << "Is Break";
return isBreak() || isInvalidOp() || isReturn() || canNotFollow(); } return isBreak() || isInvalidOp() || isReturn() || canNotFollow(); }
@ -168,7 +193,7 @@ private:
QHash<quint8,AssyInstruction> m_opcodeinfo; QHash<quint8,AssyInstruction> m_opcodeinfo;
QByteArray m_memimage; QByteArray m_memimage;
QList<quint16> m_jumps; AddressStack m_stack;
MemoryUsageMap m_memusagemap; MemoryUsageMap m_memusagemap;

View File

@ -39,6 +39,7 @@ public slots:
protected: protected:
QString makeTextStr(QByteArray data); QString makeTextStr(QByteArray data);
QString makeHexStr(QByteArray data); QString makeHexStr(QByteArray data);
private: private:
Ui::TextHexDumpViewer *ui; Ui::TextHexDumpViewer *ui;

View File

@ -111,7 +111,7 @@ void ViewerBase::setFile(GenericFile *file)
} }
else if (dynamic_cast<TextFile*>(file)) else if (dynamic_cast<TextFile*>(file))
{ {
BinaryFile *bf = dynamic_cast<BinaryFile*>(file); TextFile *bf = dynamic_cast<TextFile*>(file);
TextHexDumpViewer *thdv = new TextHexDumpViewer(); TextHexDumpViewer *thdv = new TextHexDumpViewer();
thdv->setFile(bf); thdv->setFile(bf);

View File

@ -69,7 +69,10 @@ inline QString uint32ToHex(quint32 val) {
return retval; return retval;
} }
inline quint16 makeWord(quint8 lo, quint8 hi)
{
return hi*256 + lo;
}