forked from qt-creator/qt-creator
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:
@@ -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;
|
||||||
|
@@ -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}
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
|
|
||||||
|
@@ -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
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user