Trk: Memory error handling, endianness.

Pass a memory read error from trkserver to gdb via adapter. Make it
possible to swap register endianness.
This commit is contained in:
Friedemann Kleint
2009-07-29 16:40:25 +02:00
parent 3b9dc0e128
commit 5d2a5521e9
5 changed files with 91 additions and 45 deletions

View File

@@ -105,9 +105,10 @@ static inline void dumpRegister(int n, uint value, QByteArray &a)
} }
struct AdapterOptions { struct AdapterOptions {
AdapterOptions() : verbose(1) {} AdapterOptions() : verbose(1),registerEndianness(BigEndian) {}
int verbose; int verbose;
Endianness registerEndianness;
QString gdbServer; QString gdbServer;
QString trkServer; QString trkServer;
}; };
@@ -124,6 +125,7 @@ public:
void setGdbServerName(const QString &name); void setGdbServerName(const QString &name);
void setTrkServerName(const QString &name) { m_trkServerName = name; } void setTrkServerName(const QString &name) { m_trkServerName = name; }
void setVerbose(int verbose) { m_verbose = verbose; } void setVerbose(int verbose) { m_verbose = verbose; }
void setRegisterEndianness(Endianness r) { m_registerEndianness = r; }
bool startServer(); bool startServer();
private: private:
@@ -136,19 +138,21 @@ private:
struct TrkMessage struct TrkMessage
{ {
TrkMessage() { code = token = 0; callBack = 0; } TrkMessage() : code(0), token(0), callBack(0), invokeOnFailure(0) {}
byte code; byte code;
byte token; byte token;
QByteArray data; QByteArray data;
QVariant cookie; QVariant cookie;
TrkCallBack callBack; TrkCallBack callBack;
bool invokeOnFailure;
}; };
bool openTrkPort(const QString &port); // or server name for local server bool openTrkPort(const QString &port); // or server name for local server
void sendTrkMessage(byte code, void sendTrkMessage(byte code,
TrkCallBack callBack = 0, TrkCallBack calBack = 0,
const QByteArray &data = QByteArray(), const QByteArray &data = QByteArray(),
const QVariant &cookie = QVariant()); const QVariant &cookie = QVariant(),
bool invokeOnFailure = false);
// adds message to 'send' queue // adds message to 'send' queue
void queueTrkMessage(const TrkMessage &msg); void queueTrkMessage(const TrkMessage &msg);
void tryTrkWrite(); void tryTrkWrite();
@@ -229,9 +233,11 @@ private:
Session m_session; // global-ish data (process id, target information) Session m_session; // global-ish data (process id, target information)
Snapshot m_snapshot; // local-ish data (memory and registers) Snapshot m_snapshot; // local-ish data (memory and registers)
int m_verbose; int m_verbose;
Endianness m_registerEndianness;
}; };
Adapter::Adapter() Adapter::Adapter() :
m_registerEndianness(BigEndian)
{ {
// Trk // Trk
#if USE_NATIVE #if USE_NATIVE
@@ -305,8 +311,8 @@ bool Adapter::startServer()
return false; return false;
} }
logMessage(QString("Gdb server running on %1:%2. Run arm-gdb now.") logMessage(QString("Gdb server running on %1:%2.\nRegister endianness: %3\nRun arm-gdb now.")
.arg(m_gdbServerName).arg(m_gdbServer.serverPort()), true); .arg(m_gdbServerName).arg(m_gdbServer.serverPort()).arg(m_registerEndianness), true);
connect(&m_gdbServer, SIGNAL(newConnection()), connect(&m_gdbServer, SIGNAL(newConnection()),
this, SLOT(handleGdbConnection())); this, SLOT(handleGdbConnection()));
@@ -608,12 +614,12 @@ void Adapter::handleGdbResponse(const QByteArray &response)
QByteArray logMsg = "read register"; QByteArray logMsg = "read register";
if (registerNumber == RegisterPSGdb) { if (registerNumber == RegisterPSGdb) {
QByteArray ba; QByteArray ba;
appendInt(&ba, m_snapshot.registers[RegisterPSTrk]); appendInt(&ba, m_snapshot.registers[RegisterPSTrk], m_registerEndianness);
dumpRegister(registerNumber, m_snapshot.registers[RegisterPSTrk], logMsg); dumpRegister(registerNumber, m_snapshot.registers[RegisterPSTrk], logMsg);
sendGdbMessage(ba.toHex(), logMsg); sendGdbMessage(ba.toHex(), logMsg);
} else if (registerNumber < RegisterCount) { } else if (registerNumber < RegisterCount) {
QByteArray ba; QByteArray ba;
appendInt(&ba, m_snapshot.registers[registerNumber]); appendInt(&ba, m_snapshot.registers[registerNumber], m_registerEndianness);
dumpRegister(registerNumber, m_snapshot.registers[registerNumber], logMsg); dumpRegister(registerNumber, m_snapshot.registers[registerNumber], logMsg);
sendGdbMessage(ba.toHex(), logMsg); sendGdbMessage(ba.toHex(), logMsg);
} else { } else {
@@ -793,7 +799,7 @@ byte Adapter::nextTrkWriteToken()
} }
void Adapter::sendTrkMessage(byte code, TrkCallBack callBack, void Adapter::sendTrkMessage(byte code, TrkCallBack callBack,
const QByteArray &data, const QVariant &cookie) const QByteArray &data, const QVariant &cookie, bool invokeOnFailure)
{ {
TrkMessage msg; TrkMessage msg;
msg.code = code; msg.code = code;
@@ -801,6 +807,7 @@ void Adapter::sendTrkMessage(byte code, TrkCallBack callBack,
msg.callBack = callBack; msg.callBack = callBack;
msg.data = data; msg.data = data;
msg.cookie = cookie; msg.cookie = cookie;
msg.invokeOnFailure = invokeOnFailure;
queueTrkMessage(msg); queueTrkMessage(msg);
} }
@@ -945,7 +952,6 @@ void Adapter::handleResult(const TrkResult &result)
result1.cookie = msg.cookie; result1.cookie = msg.cookie;
TrkCallBack cb = msg.callBack; TrkCallBack cb = msg.callBack;
if (cb) { if (cb) {
//logMessage("HANDLE: " << stringFromArray(result.data));
(this->*cb)(result1); (this->*cb)(result1);
} else { } else {
QString msg = result.cookie.toString(); QString msg = result.cookie.toString();
@@ -956,8 +962,14 @@ void Adapter::handleResult(const TrkResult &result)
} }
case 0xff: { // NAK case 0xff: { // NAK
logMessage(prefix + "NAK: " + str); logMessage(prefix + "NAK: " + str);
//logMessage(prefix << "TOKEN: " << result.token);
logMessage(prefix + "ERROR: " + errorMessage(result.data.at(0))); logMessage(prefix + "ERROR: " + errorMessage(result.data.at(0)));
TrkMessage msg = m_writtenTrkMessages.take(result.token);
// Invoke failure if desired
if (msg.callBack && msg.invokeOnFailure) {
TrkResult result1 = result;
result1.cookie = msg.cookie;
(this->*msg.callBack)(result1);
}
break; break;
} }
case 0x90: { // Notified Stopped case 0x90: { // Notified Stopped
@@ -1153,9 +1165,11 @@ void Adapter::handleAndReportReadRegisters(const TrkResult &result)
} }
//QByteArray ba = result.data.toHex(); //QByteArray ba = result.data.toHex();
QByteArray ba; QByteArray ba;
for (int i = 0; i < 16; ++i) for (int i = 0; i < 16; ++i) {
ba += hexNumber(m_snapshot.registers[i], 8); const uint reg = m_registerEndianness == LittleEndian ? swapEndian(m_snapshot.registers[i]) : m_snapshot.registers[i];
QByteArray logMsg = "contents"; ba += hexNumber(reg, 8);
}
QByteArray logMsg = "register contents";
if (m_verbose > 1) { if (m_verbose > 1) {
for (int i = 0; i < RegisterCount; ++i) for (int i = 0; i < RegisterCount; ++i)
dumpRegister(i, m_snapshot.registers[i], logMsg); dumpRegister(i, m_snapshot.registers[i], logMsg);
@@ -1163,16 +1177,20 @@ void Adapter::handleAndReportReadRegisters(const TrkResult &result)
sendGdbMessage(ba, logMsg); sendGdbMessage(ba, logMsg);
} }
static inline QString msgMemoryReadError(uint addr)
{
return QString::fromLatin1("Memory read error at: 0x%1").arg(addr, 0 ,16);
}
void Adapter::handleReadMemory(const TrkResult &result) void Adapter::handleReadMemory(const TrkResult &result)
{ {
//logMessage(" RESULT READ MEMORY: " + result.data.toHex()); const uint blockaddr = result.cookie.toInt();
QByteArray ba = result.data.mid(1); if (result.code == 0xff) {
uint blockaddr = result.cookie.toInt(); logMessage(msgMemoryReadError(blockaddr));
//qDebug() << "READING " << ba.size() << " BYTES: " } else {
// << quoteUnprintableLatin1(ba) const QByteArray ba = result.data.mid(1);
// << "ADDR: " << hexNumber(blockaddr) m_snapshot.memory.insert(blockaddr , ba);
// << "COOKIE: " << result.cookie; }
m_snapshot.memory[blockaddr] = ba;
} }
// Format log message for memory access with some smartness about registers // Format log message for memory access with some smartness about registers
@@ -1208,20 +1226,31 @@ QByteArray Adapter::memoryReadLogMessage(uint addr, uint len, const QByteArray &
void Adapter::reportReadMemory(const TrkResult &result) void Adapter::reportReadMemory(const TrkResult &result)
{ {
qulonglong cookie = result.cookie.toLongLong(); const qulonglong cookie = result.cookie.toLongLong();
uint addr = cookie >> 32; const uint addr = cookie >> 32;
uint len = uint(cookie); const uint len = uint(cookie);
// Gdb accepts less memory according to documentation.
// Send E on complete failure.
QByteArray ba; QByteArray ba;
uint blockaddr = (addr / MemoryChunkSize) * MemoryChunkSize; uint blockaddr = (addr / MemoryChunkSize) * MemoryChunkSize;
for (; blockaddr < addr + len; blockaddr += MemoryChunkSize) { for (; blockaddr < addr + len; blockaddr += MemoryChunkSize) {
QByteArray blockdata = m_snapshot.memory[blockaddr]; const Snapshot::Memory::const_iterator it = m_snapshot.memory.constFind(blockaddr);
Q_ASSERT(!blockdata.isEmpty()); if (it == m_snapshot.memory.constEnd())
ba.append(blockdata); break;
ba.append(it.value());
}
const int previousChunkOverlap = addr % MemoryChunkSize;
if (previousChunkOverlap != 0 && ba.size() > previousChunkOverlap)
ba.remove(0, previousChunkOverlap);
if (ba.size() > int(len))
ba.truncate(len);
if (ba.isEmpty()) {
ba = "E20";
sendGdbMessage(ba, msgMemoryReadError(addr).toLatin1());
} else {
sendGdbMessage(ba.toHex(), memoryReadLogMessage(addr, len, ba));
} }
ba = ba.mid(addr % MemoryChunkSize, len);
sendGdbMessage(ba.toHex(), memoryReadLogMessage(addr, len, ba));
} }
void Adapter::setTrkBreakpoint(const Breakpoint &bp) void Adapter::setTrkBreakpoint(const Breakpoint &bp)
@@ -1393,7 +1422,7 @@ void Adapter::readMemory(uint addr, uint len)
appendInt(&ba, m_session.pid); appendInt(&ba, m_session.pid);
appendInt(&ba, m_session.tid); appendInt(&ba, m_session.tid);
// Read Memory // Read Memory
sendTrkMessage(0x10, CB(handleReadMemory), ba, QVariant(blockaddr)); sendTrkMessage(0x10, CB(handleReadMemory), ba, QVariant(blockaddr), true);
} }
} }
qulonglong cookie = (qulonglong(addr) << 32) + len; qulonglong cookie = (qulonglong(addr) << 32) + len;
@@ -1440,6 +1469,8 @@ static bool readAdapterArgs(const QStringList &args, AdapterOptions *o)
o->verbose++; o->verbose++;
} else if (*it == QLatin1String("-q")) { } else if (*it == QLatin1String("-q")) {
o->verbose = 0; o->verbose = 0;
} else if (*it == QLatin1String("-l")) {
o->registerEndianness = LittleEndian;
} }
} else { } else {
switch (argNumber++) { switch (argNumber++) {
@@ -1465,9 +1496,10 @@ int main(int argc, char *argv[])
AdapterOptions options; AdapterOptions options;
if (!readAdapterArgs(app.arguments(), &options)) { if (!readAdapterArgs(app.arguments(), &options)) {
qDebug("Usage: %s [-v|-q] <trkservername> <gdbserverport>\n" qDebug("Usage: %s [-v|-q] [-l] <trkservername> <gdbserverport>\n"
"Options: -v verbose\n" "Options: -v verbose\n"
" -q quiet\n", argv[0]); " -q quiet\n"
" -l Set register endianness to little\n", argv[0]);
return 1; return 1;
} }
@@ -1475,6 +1507,7 @@ int main(int argc, char *argv[])
adapter.setTrkServerName(options.trkServer); adapter.setTrkServerName(options.trkServer);
adapter.setGdbServerName(options.gdbServer); adapter.setGdbServerName(options.gdbServer);
adapter.setVerbose(options.verbose); adapter.setVerbose(options.verbose);
adapter.setRegisterEndianness(options.registerEndianness);
if (adapter.startServer()) if (adapter.startServer())
return app.exec(); return app.exec();
return 4; return 4;

View File

@@ -2,6 +2,8 @@
ADAPTER_OPTIONS="" ADAPTER_OPTIONS=""
TRKSERVEROPTIONS="" TRKSERVEROPTIONS=""
DUMP_POSTFIX='-BigEndian.bin'
ENDIANESS='big'
while expr " $1" : " -.*" >/dev/null while expr " $1" : " -.*" >/dev/null
do do
@@ -17,6 +19,11 @@ do
elif [ " $1" = " -tq" ] elif [ " $1" = " -tq" ]
then then
TRKSERVEROPTIONS="$TRKSERVEROPTIONS -q" TRKSERVEROPTIONS="$TRKSERVEROPTIONS -q"
elif [ " $1" = " -l" ]
then
DUMP_POSTFIX='.bin'
ENDIANESS='little'
ADAPTER_OPTIONS="$ADAPTER_OPTIONS -l"
fi fi
shift 1 shift 1
done done
@@ -30,24 +37,23 @@ userid=`id -u`
trkservername="TRKSERVER-${userid}"; trkservername="TRKSERVER-${userid}";
gdbserverip=127.0.0.1 gdbserverip=127.0.0.1
gdbserverport=$[2222 + ${userid}] gdbserverport=$[2222 + ${userid}]
memorydump=TrkDump-78-6a-40-00.bin
memorydump=TrkDump-78-6a-40-00-BigEndian.bin
fuser -n tcp -k ${gdbserverport} fuser -n tcp -k ${gdbserverport}
rm /tmp/${trkservername} rm /tmp/${trkservername}
./trkserver $TRKSERVEROPTIONS ${trkservername} ${memorydump} & MEMORYDUMP="TrkDump-78-6a-40-00$DUMP_POSTFIX"
ADDITIONAL_DUMPS="0x00402000$DUMP_POSTFIX 0x786a4000$DUMP_POSTFIX 0x00600000$DUMP_POSTFIX"
./trkserver $TRKSERVEROPTIONS ${trkservername} ${MEMORYDUMP} ${ADDITIONAL_DUMPS}&
trkserverpid=$! trkserverpid=$!
sleep 1 sleep 1
./adapter $ADAPTER_OPTIONS ${trkservername} ${gdbserverip}:${gdbserverport} & ./adapter $ADAPTER_OPTIONS ${trkservername} ${gdbserverip}:${gdbserverport} &
adapterpid=$! adapterpid=$!
echo "# This is generated. Changes will be lost. echo "# This is generated. Changes will be lost.
#set remote noack-packet on #set remote noack-packet on
set confirm off set confirm off
set endian big set endian $ENDIANESS
#set debug remote 1 #set debug remote 1
#target remote ${gdbserverip}:${gdbserverport} #target remote ${gdbserverip}:${gdbserverport}
target extended-remote ${gdbserverip}:${gdbserverport} target extended-remote ${gdbserverip}:${gdbserverport}

View File

@@ -314,8 +314,6 @@ bool TrkServer::handleMemoryRequest(uint addr, ushort len, byte option, QByteArr
return true; return true;
} }
} }
for (int i = 0; i != len / 4; ++i)
appendInt(ba, 0xDEADBEEF);
logMessage(QString::fromLatin1("ADDRESS OUTSIDE ANY SEGMENTS: 0X%1").arg(addr, 0, 16), true); logMessage(QString::fromLatin1("ADDRESS OUTSIDE ANY SEGMENTS: 0X%1").arg(addr, 0, 16), true);
return false; return false;
} }
@@ -340,8 +338,12 @@ void TrkServer::handleAdapterMessage(const TrkResult &result)
Q_UNUSED(option); Q_UNUSED(option);
const ushort len = extractShort(p + 1); const ushort len = extractShort(p + 1);
const uint addr = extractInt(p + 3);; const uint addr = extractInt(p + 3);;
handleMemoryRequest(addr, len, option, &data); if (handleMemoryRequest(addr, len, option, &data)) {
writeToAdapter(0x80, result.token, data); writeToAdapter(0x80, result.token, data);
} else {
data[0] =32; // NAK, bad hair day
writeToAdapter(0xff, result.token, data);
}
break; break;
} }
case 0x12: { // Read Registers case 0x12: { // Read Registers

View File

@@ -298,6 +298,9 @@ QByteArray errorMessage(byte code)
return "Unknown error"; return "Unknown error";
} }
uint swapEndian(uint in)
{
return (in>>24) | ((in<<8) & 0x00FF0000) | ((in>>8) & 0x0000FF00) | (in<<24);
}
} // namespace trk } // namespace trk

View File

@@ -177,6 +177,8 @@ ushort isValidTrkResult(const QByteArray &buffer);
TrkResult extractResult(QByteArray *buffer); TrkResult extractResult(QByteArray *buffer);
QByteArray errorMessage(byte code); QByteArray errorMessage(byte code);
QByteArray hexNumber(uint n, int digits = 0); QByteArray hexNumber(uint n, int digits = 0);
uint swapEndian(uint in);
} // namespace trk } // namespace trk