Commit 5e7a26d8 authored by hjk's avatar hjk
Browse files

debugger: rework fetching of memory from device

still a few cases for chunked fetching missing
parent 05805ce0
......@@ -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);
}
......
......@@ -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...");
}
......
......@@ -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
......@@ -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
......
......@@ -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
......@@ -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
{