diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index c6c59fccfce5d61be6484c0044aec5a44556c5a5..6753c47ba47bd0d7767e00d88bc50b5c7a313b7e 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -3852,7 +3852,8 @@ void GdbEngine::handleFetchMemory(const GdbResponse &response) GdbMi data = memory0.findChild("data"); foreach (const GdbMi &child, data.children()) { bool ok = true; - unsigned char c = child.data().toUInt(&ok, 0); + unsigned char c = '?'; + c = child.data().toUInt(&ok, 0); QTC_ASSERT(ok, return); ba.append(c); } diff --git a/src/plugins/debugger/gdb/trkgdbadapter.cpp b/src/plugins/debugger/gdb/trkgdbadapter.cpp index a51d6a864fc4a0159abcc8c29cf7b656b4db07cf..85c6419c762bcc14058c8ec4e668cace33952eab 100644 --- a/src/plugins/debugger/gdb/trkgdbadapter.cpp +++ b/src/plugins/debugger/gdb/trkgdbadapter.cpp @@ -53,9 +53,19 @@ #define TrkCB(s) TrkCallback(this, &TrkGdbAdapter::s) +//#define DEBUG_MEMORY 1 +#if DEBUG_MEMORY +# define MEMORY_DEBUG(s) qDebug() << s +#else +# define MEMORY_DEBUG(s) +#endif +#define MEMORY_DEBUGX(s) qDebug() << s using namespace trk; +namespace Debugger { +namespace Internal { + enum { KnownRegisters = RegisterPSGdb + 1}; static const char *registerNames[KnownRegisters] = @@ -83,8 +93,99 @@ static QByteArray dumpRegister(int n, uint value) return ba; } -namespace Debugger { -namespace Internal { +QDebug operator<<(QDebug d, MemoryRange range) +{ + return d << QString("[%1,%2] (size %3) ") + .arg(range.from, 0, 16).arg(range.to, 0, 16).arg(range.size()); +} + +/////////////////////////////////////////////////////////////////////////// +// +// MemoryRange +// +/////////////////////////////////////////////////////////////////////////// + +bool MemoryRange::intersects(const MemoryRange &other) const +{ + Q_UNUSED(other); + return false; // FIXME +} + +void MemoryRange::operator-=(const MemoryRange &other) +{ + if (from == 0 && to == 0) + return; + MEMORY_DEBUG(" SUB: " << *this << " - " << other); + if (other.from <= from && to <= other.to) { + from = to = 0; + return; + } + if (other.from <= from && other.to <= to) { + from = qMax(from, other.to); + return; + } + if (from <= other.from && to <= other.to) { + to = qMin(other.from, to); + return; + } + // This would split the range. + QTC_ASSERT(false, qDebug() << "Memory::operator-() not handled for: " + << *this << " - " << other); +} + +/////////////////////////////////////////////////////////////////////////// +// +// Snapshot +// +/////////////////////////////////////////////////////////////////////////// + +void Snapshot::reset() +{ + memory.clear(); + for (int i = 0; i < RegisterCount; ++i) + registers[i] = 0; + wantedMemory = MemoryRange(); +} + +void Snapshot::insertMemory(const MemoryRange &range, const QByteArray &ba) +{ + QTC_ASSERT(range.size() == ba.size(), + qDebug() << "RANGE: " << range << " BA SIZE: " << ba.size(); return); + + MEMORY_DEBUG("INSERT: " << range); + // Try to combine with existing chunk. + Snapshot::Memory::iterator it = memory.begin(); + Snapshot::Memory::iterator et = memory.end(); + for ( ; it != et; ++it) { + if (range.from == it.key().to) { + MEMORY_DEBUG("COMBINING " << it.key() << " AND " << range); + QByteArray data = *it; + data.append(ba); + memory.remove(it.key()); + memory.insert(MemoryRange(it.key().from, range.to), data); + MEMORY_DEBUG(" TO " << MemoryRange(it.key().from, range.to)); + return; + } + if (it.key().from == range.to) { + MEMORY_DEBUG("COMBINING " << range << " AND " << it.key()); + QByteArray data = ba; + data.append(*it); + memory.remove(it.key()); + memory.insert(MemoryRange(range.from, it.key().to), data); + MEMORY_DEBUG(" TO " << MemoryRange(range.from, it.key().to)); + return; + } + } + + // Not combinable, add chunk. + memory.insert(range, ba); +} + +/////////////////////////////////////////////////////////////////////////// +// +// TrkGdbAdapter +// +/////////////////////////////////////////////////////////////////////////// TrkGdbAdapter::TrkGdbAdapter(GdbEngine *engine, const TrkOptionsPtr &options) : AbstractGdbAdapter(engine), @@ -92,7 +193,7 @@ TrkGdbAdapter::TrkGdbAdapter(GdbEngine *engine, const TrkOptionsPtr &options) : m_running(false), m_gdbAckMode(true), m_verbose(2), - m_bufferedMemoryRead(false), + m_bufferedMemoryRead(true), m_waitCount(0) { m_gdbServer = 0; @@ -223,18 +324,23 @@ QByteArray TrkGdbAdapter::trkWriteRegisterMessage(byte reg, uint value) return ba; } -QByteArray TrkGdbAdapter::trkReadMemoryMessage(uint addr, uint len) +QByteArray TrkGdbAdapter::trkReadMemoryMessage(uint from, uint len) { QByteArray ba; ba.reserve(11); appendByte(&ba, 0x08); // Options, FIXME: why? appendShort(&ba, len); - appendInt(&ba, addr); + appendInt(&ba, from); appendInt(&ba, m_session.pid); appendInt(&ba, m_session.tid); return ba; } +QByteArray TrkGdbAdapter::trkReadMemoryMessage(const MemoryRange &range) +{ + return trkReadMemoryMessage(range.from, range.size()); +} + QByteArray TrkGdbAdapter::trkWriteMemoryMessage(uint addr, const QByteArray &data) { QByteArray ba; @@ -305,7 +411,7 @@ void TrkGdbAdapter::startInferiorEarly() static int direction = 0; direction = (direction + 1) % 4; showStatusMessage(_("Please start TRK on your device! %1") - .arg(QChar("/|\\-"[direction]))); + .arg(QChar("/-\\|"[direction]))); } // Do not loop forever if (m_waitCount++ < (m_options->mode == TrkOptions::BlueTooth ? 60 : 5)) { @@ -633,7 +739,7 @@ void TrkGdbAdapter::handleGdbServerCommand(const QByteArray &cmd) break; } while (false); if (len) { - readMemory(addr, len); + readMemory(addr, len, m_bufferedMemoryRead); } else { sendGdbServerMessage("E20", "Error " + cmd); } @@ -1184,27 +1290,14 @@ static QString msgMemoryReadError(int code, uint addr, uint len = 0) .arg(code).arg(addr, 0 ,16).arg(lenS); } -void TrkGdbAdapter::handleReadMemoryBuffered(const TrkResult &result) -{ - if (extractShort(result.data.data() + 1) + 3 != result.data.size()) - logMessage("\n BAD MEMORY RESULT: " + result.data.toHex() + "\n"); - const uint blockaddr = result.cookie.toUInt(); - if (const int errorCode = result.errorCode()) { - logMessage(msgMemoryReadError(errorCode, blockaddr)); - return; - } - const QByteArray ba = result.data.mid(3); - m_snapshot.memory.insert(blockaddr, ba); -} - // Format log message for memory access with some smartness about registers -QByteArray TrkGdbAdapter::memoryReadLogMessage(uint addr, uint len, const QByteArray &ba) const +QByteArray TrkGdbAdapter::memoryReadLogMessage(uint addr, const QByteArray &ba) const { QByteArray logMsg = "memory contents"; if (m_verbose > 1) { logMsg += " addr: " + hexxNumber(addr); // indicate dereferencing of registers - if (len == 4) { + if (ba.size() == 4) { if (addr == m_snapshot.registers[RegisterPC]) { logMsg += "[PC]"; } else if (addr == m_snapshot.registers[RegisterPSTrk]) { @@ -1221,27 +1314,112 @@ QByteArray TrkGdbAdapter::memoryReadLogMessage(uint addr, uint len, const QByteA } } logMsg += " length "; - logMsg += QByteArray::number(len); + logMsg += QByteArray::number(ba.size()); logMsg += " :"; logMsg += stringFromArray(ba, 16).toAscii(); } return logMsg; } -void TrkGdbAdapter::reportReadMemoryBuffered(const TrkResult &result) +void TrkGdbAdapter::handleReadMemoryBuffered(const TrkResult &result) { - const qulonglong cookie = result.cookie.toULongLong(); - const uint addr = cookie >> 32; - const uint len = uint(cookie); - reportReadMemoryBuffered(addr, len); + if (extractShort(result.data.data() + 1) + 3 != result.data.size()) + logMessage("\n BAD MEMORY RESULT: " + result.data.toHex() + "\n"); + const MemoryRange range = result.cookie.value<MemoryRange>(); + if (const int errorCode = result.errorCode()) { + logMessage(_("TEMPORARY: ") + msgMemoryReadError(errorCode, range.from)); + logMessage(_("RETRYING UNBUFFERED")); + // FIXME: This does not handle large requests properly. + sendTrkMessage(0x10, TrkCB(handleReadMemoryUnbuffered), + trkReadMemoryMessage(range), QVariant::fromValue(range)); + return; + } + const QByteArray ba = result.data.mid(3); + m_snapshot.insertMemory(range, ba); + tryAnswerGdbMemoryRequest(true); } -void TrkGdbAdapter::reportReadMemoryBuffered(uint addr, uint len) +void TrkGdbAdapter::handleReadMemoryUnbuffered(const TrkResult &result) { + if (extractShort(result.data.data() + 1) + 3 != result.data.size()) + logMessage("\n BAD MEMORY RESULT: " + result.data.toHex() + "\n"); + const MemoryRange range = result.cookie.value<MemoryRange>(); + if (const int errorCode = result.errorCode()) { + logMessage(_("TEMPORARY: ") + msgMemoryReadError(errorCode, range.from)); + logMessage(_("RETRYING UNBUFFERED")); + const QByteArray ba = "E20"; + sendGdbServerMessage(ba, msgMemoryReadError(32, range.from).toLatin1()); + return; + } + const QByteArray ba = result.data.mid(3); + m_snapshot.insertMemory(range, ba); + tryAnswerGdbMemoryRequest(false); +} + +void TrkGdbAdapter::tryAnswerGdbMemoryRequest(bool buffered) +{ + //logMessage("UNBUFFERED MEMORY READ: " + stringFromArray(result.data)); + + MemoryRange wanted = m_snapshot.wantedMemory; + MemoryRange needed = m_snapshot.wantedMemory; + MEMORY_DEBUG("WANTED: " << wanted); + Snapshot::Memory::const_iterator it = m_snapshot.memory.begin(); + Snapshot::Memory::const_iterator et = m_snapshot.memory.end(); + for ( ; it != et; ++it) { + MEMORY_DEBUG(" NEEDED: " << needed); + needed -= it.key(); + } + MEMORY_DEBUG("NEEDED: " << needed); + + if (needed.to == 0) { + // FIXME: need to combine chunks first. + + // All fine. Send package to gdb. + it = m_snapshot.memory.begin(); + et = m_snapshot.memory.end(); + for ( ; it != et; ++it) { + if (it.key().from <= wanted.from && wanted.to <= it.key().to) { + int offset = wanted.from - it.key().from; + int len = wanted.to - wanted.from; + QByteArray ba = it.value().mid(offset, len); + sendGdbServerMessage(ba.toHex(), memoryReadLogMessage(wanted.from, ba)); + return; + } + } + // Happens when chunks are not comnbined + QTC_ASSERT(false, /**/); + return; + } + + MEMORY_DEBUG("NEEDED AND UNSATISFIED: " << needed); + if (buffered) { + uint blockaddr = (needed.from / MemoryChunkSize) * MemoryChunkSize; + logMessage(_("Requesting buffered memory %1 bytes from 0x%2") + .arg(MemoryChunkSize).arg(blockaddr, 0, 16)); + MemoryRange range(blockaddr, blockaddr + MemoryChunkSize); + MEMORY_DEBUGX(" FETCH MEMORY : " << range); + sendTrkMessage(0x10, TrkCB(handleReadMemoryBuffered), + trkReadMemoryMessage(range), + QVariant::fromValue(range)); + } else { // Unbuffered, direct requests + int len = needed.to - needed.from; + logMessage(_("Requesting unbuffered memory %1 bytes from 0x%2") + .arg(len).arg(needed.from, 0, 16)); + sendTrkMessage(0x10, TrkCB(handleReadMemoryUnbuffered), + trkReadMemoryMessage(needed), + QVariant::fromValue(needed)); + MEMORY_DEBUGX(" FETCH MEMORY : " << needed); + } +} + +/* +void TrkGdbAdapter::reportReadMemoryBuffered(const TrkResult &result) +{ + const MemoryRange range = result.cookie.value<MemoryRange>(); // Gdb accepts less memory according to documentation. // Send E on complete failure. QByteArray ba; - uint blockaddr = (addr / MemoryChunkSize) * MemoryChunkSize; + uint blockaddr = (range.from / MemoryChunkSize) * MemoryChunkSize; for (; blockaddr < addr + len; blockaddr += MemoryChunkSize) { const Snapshot::Memory::const_iterator it = m_snapshot.memory.constFind(blockaddr); if (it == m_snapshot.memory.constEnd()) @@ -1261,21 +1439,7 @@ void TrkGdbAdapter::reportReadMemoryBuffered(uint addr, uint len) sendGdbServerMessage(ba.toHex(), memoryReadLogMessage(addr, len, ba)); } } - -void TrkGdbAdapter::handleReadMemoryUnbuffered(const TrkResult &result) -{ - //logMessage("UNBUFFERED MEMORY READ: " + stringFromArray(result.data)); - const uint blockaddr = result.cookie.toUInt(); - if (extractShort(result.data.data() + 1) + 3 != result.data.size()) - logMessage("\n BAD MEMORY RESULT: " + result.data.toHex() + "\n"); - if (const int errorCode = result.errorCode()) { - const QByteArray ba = "E20"; - sendGdbServerMessage(ba, msgMemoryReadError(32, blockaddr).toLatin1()); - } else { - const QByteArray ba = result.data.mid(3); - sendGdbServerMessage(ba.toHex(), memoryReadLogMessage(blockaddr, ba.size(), ba)); - } -} +*/ void TrkGdbAdapter::handleStepInto(const TrkResult &result) { @@ -1398,7 +1562,7 @@ void TrkGdbAdapter::handleDisconnect(const TrkResult & /*result*/) logMessage(QLatin1String("Trk disconnected")); } -void TrkGdbAdapter::readMemory(uint addr, uint len) +void TrkGdbAdapter::readMemory(uint addr, uint len, bool buffered) { Q_ASSERT(len < (2 << 16)); @@ -1407,43 +1571,15 @@ void TrkGdbAdapter::readMemory(uint addr, uint len) logMessage(_("readMemory %1 bytes from 0x%2 blocksize=%3") .arg(len).arg(addr, 0, 16).arg(MemoryChunkSize)); - if (m_bufferedMemoryRead) { - uint requests = 0; - uint blockaddr = (addr / MemoryChunkSize) * MemoryChunkSize; - for (; blockaddr < addr + len; blockaddr += MemoryChunkSize) { - if (!m_snapshot.memory.contains(blockaddr)) { - if (m_verbose) - logMessage(_("Requesting buffered " - "memory %1 bytes from 0x%2") - .arg(MemoryChunkSize).arg(blockaddr, 0, 16)); - sendTrkMessage(0x10, TrkCB(handleReadMemoryBuffered), - trkReadMemoryMessage(blockaddr, MemoryChunkSize), - QVariant(blockaddr)); - requests++; - } - } - // If requests have been sent: Sync - if (requests) { - const qulonglong cookie = (qulonglong(addr) << 32) + len; - sendTrkMessage(TRK_WRITE_QUEUE_NOOP_CODE, TrkCB(reportReadMemoryBuffered), - QByteArray(), cookie); - } else { - // Everything is already buffered: invoke callback directly - reportReadMemoryBuffered(addr, len); - } - } else { // Unbuffered, direct requests - if (m_verbose) - logMessage(_("Requesting unbuffered memory %1 " - "bytes from 0x%2").arg(len).arg(addr, 0, 16)); - sendTrkMessage(0x10, TrkCB(handleReadMemoryUnbuffered), - trkReadMemoryMessage(addr, len), QVariant(addr)); - } + m_snapshot.wantedMemory = MemoryRange(addr, addr + len); + tryAnswerGdbMemoryRequest(buffered); + } void TrkGdbAdapter::interruptInferior() { QTC_ASSERT(state() == AdapterStarted, qDebug() << state()); - qDebug() << "TRYING TO INTERRUPT INFERIOR"; + logMessage("TRYING TO INTERRUPT INFERIOR"); sendTrkMessage(0x1a, TrkCallback(), trkInterruptMessage(), "Interrupting..."); } diff --git a/src/plugins/debugger/gdb/trkgdbadapter.h b/src/plugins/debugger/gdb/trkgdbadapter.h index 018f52b51f81164e4731fcd70d088c5faa2dacef..b2fe1aee0ca615ff8c3236dfd8ac1441671a4f6c 100644 --- a/src/plugins/debugger/gdb/trkgdbadapter.h +++ b/src/plugins/debugger/gdb/trkgdbadapter.h @@ -49,6 +49,67 @@ namespace Debugger { namespace Internal { +enum CodeMode +{ + ArmMode = 0, + ThumbMode, +}; + +enum TargetConstants +{ + + RegisterCount = 17, + RegisterSP = 13, // Stack Pointer + RegisterLR = 14, // Return address + RegisterPC = 15, // Program counter + RegisterPSGdb = 25, // gdb's view of the world + RegisterPSTrk = 16, // TRK's view of the world + + MemoryChunkSize = 256 +}; + +struct MemoryRange +{ + MemoryRange() : from(0), to(0) {} + MemoryRange(uint f, uint t) : from(f), to(t) {} + void operator-=(const MemoryRange &other); + bool intersects(const MemoryRange &other) const; + quint64 hash() const { return (quint64(from) << 32) + to; } + bool operator==(const MemoryRange &other) const { return hash() == other.hash(); } + bool operator<(const MemoryRange &other) const { return hash() < other.hash(); } + int size() const { return to - from; } + + uint from; // Inclusive. + uint to; // Exclusive. +}; + +struct Snapshot +{ + void reset(); + void insertMemory(const MemoryRange &range, const QByteArray &ba); + + uint registers[RegisterCount]; + typedef QMap<MemoryRange, QByteArray> Memory; + Memory memory; + + // Current state. + MemoryRange wantedMemory; +}; + + +struct Breakpoint +{ + Breakpoint(uint offset_ = 0) + { + number = 0; + offset = offset_; + mode = ArmMode; + } + uint offset; + ushort number; + CodeMode mode; +}; + struct GdbResult { QByteArray data; @@ -155,7 +216,7 @@ private: void handleAndReportCreateProcess(const TrkResult &result); void handleAndReportReadRegistersAfterStop(const TrkResult &result); void reportRegisters(); - QByteArray memoryReadLogMessage(uint addr, uint len, const QByteArray &ba) const; + QByteArray memoryReadLogMessage(uint addr, const QByteArray &ba) const; void handleAndReportSetBreakpoint(const TrkResult &result); void handleReadMemoryBuffered(const TrkResult &result); void handleReadMemoryUnbuffered(const TrkResult &result); @@ -164,12 +225,12 @@ private: void handleStepOver(const TrkResult &result); void handleStepOver2(const TrkResult &result); void handleReadRegisters(const TrkResult &result); - void reportReadMemoryBuffered(const TrkResult &result); - void reportReadMemoryBuffered(uint addr, uint len); void handleWriteRegister(const TrkResult &result); void reportToGdb(const TrkResult &result); + //void reportReadMemoryBuffered(const TrkResult &result); + //void reportReadMemoryUnbuffered(const TrkResult &result); - void readMemory(uint addr, uint len); + void readMemory(uint addr, uint len, bool buffered); void handleDirectTrk(const TrkResult &response); void directStep(uint addr); @@ -190,8 +251,9 @@ private: QByteArray trkContinueMessage(); QByteArray trkReadRegistersMessage(); QByteArray trkWriteRegisterMessage(byte reg, uint value); + QByteArray trkReadMemoryMessage(const MemoryRange &range); QByteArray trkReadMemoryMessage(uint addr, uint len); - QByteArray trkWriteMemoryMessage(uint add, const QByteArray &date); + QByteArray trkWriteMemoryMessage(uint addr, const QByteArray &date); QByteArray trkBreakpointMessage(uint addr, uint len, bool armMode = true); QByteArray trkStepRangeMessage(byte option); QByteArray trkDeleteProcessMessage(); @@ -228,6 +290,7 @@ private: const QByteArray &logNote = QByteArray()); void sendGdbServerAck(); bool sendGdbServerPacket(const QByteArray &packet, bool doFlush); + void tryAnswerGdbMemoryRequest(bool buffered); Q_SLOT void handleGdbError(QProcess::ProcessError error); Q_SLOT void handleGdbFinished(int exitCode, QProcess::ExitStatus exitStatus); @@ -259,7 +322,7 @@ private: // Debuggee state Q_SLOT void executeCommand(const QString &msg); trk::Session m_session; // global-ish data (process id, target information) - trk::Snapshot m_snapshot; // local-ish data (memory and registers) + Snapshot m_snapshot; // local-ish data (memory and registers) QString m_remoteExecutable; QString m_symbolFile; int m_verbose; @@ -270,4 +333,6 @@ private: } // namespace Internal } // namespace Debugger +Q_DECLARE_METATYPE(Debugger::Internal::MemoryRange); + #endif // DEBUGGER_TRKGDBADAPTER_H diff --git a/src/plugins/debugger/gdb/trkoptions.h b/src/plugins/debugger/gdb/trkoptions.h index cacf1a93cbea8d051d9b4966d8eda102450bbece..9e50796ea7cf941c17730da0dc4a5831b86a7fe2 100644 --- a/src/plugins/debugger/gdb/trkoptions.h +++ b/src/plugins/debugger/gdb/trkoptions.h @@ -65,8 +65,15 @@ struct TrkOptions QString cygwin; // ignored on Linux }; -inline bool operator==(const TrkOptions &o1, const TrkOptions &o2) { return o1.equals(o2); } -inline bool operator!=(const TrkOptions &o1, const TrkOptions &o2) { return !o1.equals(o2); } +inline bool operator==(const TrkOptions &o1, const TrkOptions &o2) +{ + return o1.equals(o2); +} + +inline bool operator!=(const TrkOptions &o1, const TrkOptions &o2) +{ + return !o1.equals(o2); +} } // namespace Internal } // namespace Debugger diff --git a/src/shared/trk/trkutils.cpp b/src/shared/trk/trkutils.cpp index e40944a66cff3f7c23647ad8816b33d1513bd7e1..a45084bb8cddd881ff8133cbe83595f8551d7046 100644 --- a/src/shared/trk/trkutils.cpp +++ b/src/shared/trk/trkutils.cpp @@ -362,12 +362,5 @@ QString TrkResult::errorString() const return errorMessage(data.at(0)); } -void Snapshot::reset() -{ - memory.clear(); - for (int i = 0; i < RegisterCount; ++i) - registers[i] = 0; -} - } // namespace trk diff --git a/src/shared/trk/trkutils.h b/src/shared/trk/trkutils.h index 36bff80c4db3f0324b92eed8ab5321f2fb2fcf3f..a57ec750f6d207791ada26adac7dd48b8ad1f573 100644 --- a/src/shared/trk/trkutils.h +++ b/src/shared/trk/trkutils.h @@ -95,25 +95,6 @@ void appendShort(QByteArray *ba, ushort s, Endianness = TargetByteOrder); void appendInt(QByteArray *ba, uint i, Endianness = TargetByteOrder); void appendString(QByteArray *ba, const QByteArray &str, Endianness = TargetByteOrder, bool appendNullTerminator = true); -enum CodeMode -{ - ArmMode = 0, - ThumbMode, -}; - -enum TargetConstants -{ - - RegisterCount = 17, - RegisterSP = 13, // Stack Pointer - RegisterLR = 14, // Return address - RegisterPC = 15, // Program counter - RegisterPSGdb = 25, // gdb's view of the world - RegisterPSTrk = 16, // TRK's view of the world - - MemoryChunkSize = 256 -}; - struct Library { Library() {} @@ -166,29 +147,6 @@ struct Session QStringList modules; }; -struct Snapshot -{ - void reset(); - - uint registers[RegisterCount]; - typedef QHash<uint, QByteArray> Memory; - Memory memory; -}; - - -struct Breakpoint -{ - Breakpoint(uint offset_ = 0) - { - number = 0; - offset = offset_; - mode = ArmMode; - } - uint offset; - ushort number; - CodeMode mode; -}; - struct TrkResult { TrkResult();