diff --git a/AppleSAWS.pro b/AppleSAWS.pro index 6e2cdd8..e074f75 100644 --- a/AppleSAWS.pro +++ b/AppleSAWS.pro @@ -109,7 +109,8 @@ HEADERS += \ src/ui/widgets/LocationInfoDialog.h \ src/binaryfile/EntryPoints.h \ src/binaryfile/AssemblerSymbols.h \ - src/binaryfile/AssemblerSymbolModel.h + src/binaryfile/AssemblerSymbolModel.h \ + src/binaryfile/MemoryUsageMap.h FORMS += \ src/ui/catalogwidget.ui \ diff --git a/src/binaryfile/MemoryUsageMap.h b/src/binaryfile/MemoryUsageMap.h new file mode 100644 index 0000000..27c49b1 --- /dev/null +++ b/src/binaryfile/MemoryUsageMap.h @@ -0,0 +1,107 @@ +#ifndef MEMORYUSAGEMAP_H +#define MEMORYUSAGEMAP_H + +#include +#include +#include + +enum MemoryUsage { + Unknown = 0x00000000, + Data = 0x00000001, + Operation = 0x00000002, + // OperationArgHi = 0x00000004, + // OperationArgLo = 0x00000008, + OperationArg = 0x00000010, + + RefAddressHi = 0x00000100, + RefAddressLo = 0x00000200, + RefAddress = RefAddressLo | RefAddressHi, + ZeroPageRefAddress = 0x00000400, + + InvalidOperation = 0x00001000, + Break = 0x00002000, + UndeterminedJump = 0x00004000, + StopsExecution = InvalidOperation | Break | UndeterminedJump, + + EntryPointAddr = 0x00010000, + BranchOffsetAddr = 0x00020000, + Jump = 0x00040000, + Return = 0x00080000, +}; +Q_DECLARE_FLAGS(MemoryUsages,MemoryUsage) + + +class MemoryUsageMap : public QVector +{ + +public: + MemoryUsageMap() + { + fill(MemoryUsage::Unknown,65536); + } + + void clearData() + { + for (int idx = 0; idx < size(); idx++) + { + (*this)[idx] = MemoryUsage::Unknown; + } + } + + void merge(const MemoryUsageMap &other) + { + if (other.size() != size()) + { + qWarning("Mismatched size of MemoryMaps!"); + return; + } + for (int idx = 0; idx < size(); idx++) + { + (*this)[idx] |= other[idx]; + } + } + + QList addressesWhichContain(MemoryUsage usage) + { + QList retval; + for (int idx = 0; idx < size(); idx++) + { + if (value(idx).testFlag(usage)) + { + retval.append((quint16) idx); + } + } + return retval; + } + +private: + void clear(); + void append(const MemoryUsages &); + void append(MemoryUsages &&); + void append(const QVector); + void insert(int,const MemoryUsages &); + void insert(int,int,const MemoryUsages &); + void move(int,int); + void prepend(const MemoryUsages&); + void push_back(const MemoryUsages&); + void push_back(MemoryUsages&&); + void push_front(const MemoryUsages&); + void remove(int); + void remove(int,int); + void removeAll(const MemoryUsages&); + void removeAt(int); + void removeFirst(); + void removeLast(); + bool removeOne(const MemoryUsages&); + void reserve(int); + void resize(int); + void swap(QVector&); + MemoryUsages &takeAt(int); + MemoryUsages &takeFirst(); + MemoryUsages &takeLast(); + +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(MemoryUsages) + +#endif // MEMORYUSAGEMAP_H diff --git a/src/binaryfile/disassembler.cxx b/src/binaryfile/disassembler.cxx index ee16d25..81eddac 100644 --- a/src/binaryfile/disassembler.cxx +++ b/src/binaryfile/disassembler.cxx @@ -4,58 +4,182 @@ #include -QList Disassembler::disassemble(quint16 from, quint16 to) { - QList retval; +Disassembler::Disassembler(QByteArray memimage) +{ + m_memimage = memimage, makeOpcodeTable(); + m_memusagemap.clearData(); +} - quint16 next = 0; +QList Disassembler::disassemble(quint16 from, quint16 to,bool processRecursively) { + QList retval; + qDebug() << "Disassemble: From"< 0xffff || (next < from)) { + idx = item.nextContiguousAddress(); + if (idx > 0xffff || (idx < from)) { qDebug() << "Breaking."; break; } } +#else + MemoryUsageMap memuse; + + bool stopping = false; + quint16 next = from; + + while (!stopping) + { + // quint8 opcode = m_memimage[next]; + // qDebug() << "Opcode: " << uint8ToHex(opcode); + DisassembledItem item; + bool ok = false; + + if (next >= from && next <= to) //TODO: Remove this to not limit disassembly to program range + ok = disassembleOp(next,item,&memuse); + + if (ok) + { + retval.append(item); + + quint16 flow = item.nextFlowAddress(); + qDebug() << uint16ToHex(next) << uint16ToHex(flow); + if (item.isBranch()) + { + qDebug() << "Is Branch"; + if (!m_jumps.contains(item.targetAddress())) + { + m_jumps.append(item.targetAddress()); + } + } + + if (item.isJsr() && !item.canNotFollow()) + { + if (item.targetAddress() <= to) //TODO: Remove this to not limit disassembly to program range + if (!m_jumps.contains(item.targetAddress())) + { + m_jumps.append(item.targetAddress()); + } + } + + if (next <= to) //TODO: Remove this to not limit disassembly to program range + { + next = flow; + stopping = item.stopsProcessing(); + } + else stopping = true; + } + else + { + stopping = true; // already processed this address + } + + // if (found.contains(next)) stopping = true; + if (next >= to) stopping = true; + // if (stopping) { + // qDebug() << "Stopping. Stops processing: " + // << item.stopsProcessing() + // << ", next>=to: " << (next >= to) + // << ", alreadyFound: " << ((!ok)?"true":"false"); + // } + } + + m_memusagemap.merge(memuse); + + if (processRecursively) + while (m_jumps.size()) + { + 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 + { + qDebug() << "Calling recursively to"< #include #include +#include enum AddressMode { AM_InvalidOp, @@ -39,6 +43,8 @@ public: quint8 numArgs(); + QString debugStr() { return QString("%1 %2 %3").arg(uint8ToHex(m_opcode)).arg(m_mnemonic).arg(m_addressMode); } + private: QString m_mnemonic; quint8 m_opcode; @@ -52,6 +58,7 @@ public: DisassembledItem(AssyInstruction instr); + bool operator<(const DisassembledItem &other) const { return (address() < other.address()); } void setInstruction(AssyInstruction instr); @@ -64,6 +71,8 @@ public: void setJsr(bool jsr) { m_is_jsr = jsr; } void setTargetAddress(quint16 ta) { m_unknown_ta = false; m_target_address = ta; } void setRawArgument(quint16 arg) { m_has_arg = true; m_raw_arg = arg; } + void setCanNotFollow(bool canNotFollow) { m_canNotFollow = canNotFollow; } + void setIsInvalidOp(bool isInvalid) { m_isInvalidOp = isInvalid; } AssyInstruction assyInstruction() const { return m_instruction; } QString rawDisassembledString() const { return m_disassembly_text; } @@ -75,8 +84,24 @@ public: bool isBranch() const { return m_is_branch; } bool isJump() const { return m_is_jump; } bool isJsr() const { return m_is_jsr; } - bool isReturn() { return (m_instruction.opcode() == 0x60); } + bool isReturn() { return (m_instruction.opcode() == 0x60) || m_instruction.opcode() == 0x40; } bool isBreak() { return (m_instruction.opcode() == 0x00); } + bool isInvalidOp() { return m_isInvalidOp; } + + bool canNotFollow() { return m_canNotFollow; } + + bool stopsProcessing() { + if (isReturn()) qDebug() << "Is Return"; + if (isInvalidOp()) qDebug() << "Is Invalid Op" << uint8ToHex(m_instruction.opcode()); + if (canNotFollow()) qDebug() << "Can not follow indirect jump"; + if (isBreak()) qDebug() << "Is Break"; + return isBreak() || isInvalidOp() || isReturn() || canNotFollow(); } + + quint16 nextContiguousAddress() { return m_nextContiguousAddress; } + quint16 nextFlowAddress() { return m_nextFlowAddress; } + + void setNextContiguousAddress(quint16 addr) { m_nextContiguousAddress = addr; } + void setNextFlowAddress(quint16 addr) { m_nextFlowAddress = addr; } quint16 targetAddress() const { return m_target_address; } bool hasArg() const { return m_has_arg; } @@ -89,17 +114,22 @@ private: void init(); quint16 m_address; + quint16 m_nextContiguousAddress; + quint16 m_nextFlowAddress; + quint16 m_target_address; + QByteArray m_hexvalues; QString m_disassembly_text; QString m_hexstring; bool m_is_branch; bool m_is_jump; bool m_is_jsr; - quint16 m_target_address; AssyInstruction m_instruction; bool m_unknown_ta; quint16 m_raw_arg; bool m_has_arg; + bool m_isInvalidOp; + bool m_canNotFollow; }; @@ -108,23 +138,30 @@ private: class Disassembler { public: - Disassembler(QByteArray memimage) { m_memimage = memimage, makeOpcodeTable(); } + Disassembler(QByteArray memimage); enum ProcessorType { P6502, P65C02 }; - QList disassemble(quint16 from, quint16 to); + QList disassemble(quint16 from, quint16 to,bool processRecursively = true); + + MemoryUsageMap *memoryUsageMap() { return &m_memusagemap; } private: - DisassembledItem disassembleOp(quint16 address, quint16 *nextAddress = 0); + bool disassembleOp(quint16 address, DisassembledItem &retval, MemoryUsageMap *memuse = Q_NULLPTR); void makeOpcodeTable(); QHash m_opcodeinfo; QByteArray m_memimage; + QList m_jumps; + // QList found; + + MemoryUsageMap m_memusagemap; + }; #endif // DISASSEMBLER_H diff --git a/src/ui/widgets/DisassemblerMetadataDialog.cpp b/src/ui/widgets/DisassemblerMetadataDialog.cpp index 95eec83..3d8fb05 100644 --- a/src/ui/widgets/DisassemblerMetadataDialog.cpp +++ b/src/ui/widgets/DisassemblerMetadataDialog.cpp @@ -112,7 +112,6 @@ void DisassemblerMetadataDialog::handleRemoveSymbolButton() } - void DisassemblerMetadataDialog::processSymbols() { m_as->doTestData();