debugger: rework fetching of memory from device

still a few cases for chunked fetching missing
This commit is contained in:
hjk
2009-10-05 17:37:15 +02:00
parent 05805ce0aa
commit 5e7a26d863
6 changed files with 296 additions and 136 deletions

View File

@@ -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...");
}