| 1 |
63 |
julius |
// ----------------------------------------------------------------------------
|
| 2 |
|
|
|
| 3 |
|
|
// SystemC GDB RSP server: implementation
|
| 4 |
|
|
|
| 5 |
|
|
// Copyright (C) 2008 Embecosm Limited <info@embecosm.com>
|
| 6 |
|
|
|
| 7 |
|
|
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
|
| 8 |
|
|
// Contributor Julius Baxter <julius@orsoc.se>
|
| 9 |
|
|
|
| 10 |
|
|
// This file is part of the GDB interface to the cycle accurate model of the
|
| 11 |
|
|
// OpenRISC 1000 based system-on-chip, ORPSoC, built using Verilator.
|
| 12 |
|
|
|
| 13 |
|
|
// This program is free software: you can redistribute it and/or modify it
|
| 14 |
|
|
// under the terms of the GNU Lesser General Public License as published by
|
| 15 |
|
|
// the Free Software Foundation, either version 3 of the License, or (at your
|
| 16 |
|
|
// option) any later version.
|
| 17 |
|
|
|
| 18 |
|
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
| 19 |
|
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
| 20 |
|
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
| 21 |
|
|
// License for more details.
|
| 22 |
|
|
|
| 23 |
|
|
// You should have received a copy of the GNU Lesser General Public License
|
| 24 |
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 25 |
|
|
|
| 26 |
|
|
// ----------------------------------------------------------------------------
|
| 27 |
|
|
|
| 28 |
|
|
// $Id$
|
| 29 |
|
|
|
| 30 |
|
|
#include <iostream>
|
| 31 |
|
|
#include <iomanip>
|
| 32 |
|
|
|
| 33 |
|
|
#include "GdbServerSC.h"
|
| 34 |
|
|
#include "Utils.h"
|
| 35 |
|
|
|
| 36 |
|
|
#include <errno.h>
|
| 37 |
|
|
#include <fcntl.h>
|
| 38 |
462 |
julius |
extern int monitor_to_gdb_pipe[2][2]; // [0][] - monitor to gdb, [1][] - gdb to monitor, [][0] - read, [][1] - write
|
| 39 |
63 |
julius |
|
| 40 |
|
|
using std::cerr;
|
| 41 |
|
|
using std::dec;
|
| 42 |
|
|
using std::endl;
|
| 43 |
|
|
using std::hex;
|
| 44 |
|
|
|
| 45 |
|
|
using sc_core::sc_fifo;
|
| 46 |
|
|
using sc_core::sc_module_name;
|
| 47 |
|
|
using sc_core::sc_stop;
|
| 48 |
|
|
using sc_core::sc_time;
|
| 49 |
|
|
|
| 50 |
462 |
julius |
SC_HAS_PROCESS(GdbServerSC);
|
| 51 |
63 |
julius |
|
| 52 |
|
|
//-----------------------------------------------------------------------------
|
| 53 |
|
|
//! Constructor for the GDB RSP server.
|
| 54 |
|
|
|
| 55 |
|
|
//! We create a SC_THREAD which will act as the listener. Must be a
|
| 56 |
|
|
//! thread, since we need to wait for the actions to complete.
|
| 57 |
|
|
|
| 58 |
|
|
//! The current scan chain is marked as undefined.
|
| 59 |
|
|
|
| 60 |
|
|
//! This makes use of the Embecosm cycle accurate SystemC JTAG interface.
|
| 61 |
|
|
|
| 62 |
|
|
//! @see Embecosm Application Note 5 "Using JTAG with SystemC: Implementation
|
| 63 |
|
|
//! of a Cycle Accurate Interface"
|
| 64 |
|
|
//! (http://www.embecosm.com/download/ean5.html)
|
| 65 |
|
|
|
| 66 |
|
|
//! @todo We do not handle a user coded l.trap properly (i.e. one that is not
|
| 67 |
|
|
//! a breakpoint). Effectively it is ignored, whereas we ought to set up
|
| 68 |
|
|
//! the exception registers and redirect through the trap vector.
|
| 69 |
|
|
|
| 70 |
|
|
//! @param[in] name Name of this module, passed to the parent
|
| 71 |
|
|
//! constructor.
|
| 72 |
|
|
//! @param[in] _tapActionQueue Pointer to fifo of actions to be performed by
|
| 73 |
|
|
//! the JTAG interface
|
| 74 |
|
|
//-----------------------------------------------------------------------------
|
| 75 |
462 |
julius |
GdbServerSC::GdbServerSC(sc_module_name name,
|
| 76 |
|
|
uint32_t _flashStart,
|
| 77 |
|
|
uint32_t _flashEnd,
|
| 78 |
|
|
int rspPort,
|
| 79 |
|
|
sc_fifo <
|
| 80 |
|
|
TapAction * >*tapActionQueue):sc_module(name),
|
| 81 |
|
|
flashStart(_flashStart), flashEnd(_flashEnd)
|
| 82 |
63 |
julius |
{
|
| 83 |
462 |
julius |
pkt = new RspPacket(RSP_PKT_MAX);
|
| 84 |
|
|
rsp = new RspConnection(rspPort);
|
| 85 |
|
|
debugUnit = new DebugUnitSC("debug-unit", tapActionQueue);
|
| 86 |
|
|
mpHash = new MpHash();
|
| 87 |
63 |
julius |
|
| 88 |
462 |
julius |
/* Setup the pipes between or1200 monitor module and GDB stub */
|
| 89 |
|
|
pipe(monitor_to_gdb_pipe[0]);
|
| 90 |
|
|
pipe(monitor_to_gdb_pipe[1]);
|
| 91 |
|
|
|
| 92 |
|
|
// Set non-blocking reads
|
| 93 |
|
|
#ifdef O_NONBLOCK /* The POSIX way */
|
| 94 |
|
|
fcntl(monitor_to_gdb_pipe[0][0], F_SETFL, O_NONBLOCK);
|
| 95 |
|
|
fcntl(monitor_to_gdb_pipe[1][0], F_SETFL, O_NONBLOCK);
|
| 96 |
63 |
julius |
#elif defined (O_NDELAY)
|
| 97 |
462 |
julius |
fcntl(monitor_to_gdb_pipe[0][0], F_SETFL, O_NDELAY);
|
| 98 |
|
|
fcntl(monitor_to_gdb_pipe[1][0], F_SETFL, O_NDELAY);
|
| 99 |
63 |
julius |
#endif /* O_NONBLOCK */
|
| 100 |
|
|
|
| 101 |
462 |
julius |
SC_THREAD(rspServer);
|
| 102 |
63 |
julius |
|
| 103 |
462 |
julius |
} // GdbServerSC ()
|
| 104 |
63 |
julius |
|
| 105 |
|
|
//-----------------------------------------------------------------------------
|
| 106 |
|
|
//! Destructor
|
| 107 |
|
|
|
| 108 |
|
|
//! Free up data structures
|
| 109 |
|
|
//-----------------------------------------------------------------------------
|
| 110 |
462 |
julius |
GdbServerSC::~GdbServerSC()
|
| 111 |
63 |
julius |
{
|
| 112 |
462 |
julius |
delete mpHash;
|
| 113 |
|
|
delete debugUnit;
|
| 114 |
|
|
delete rsp;
|
| 115 |
|
|
delete pkt;
|
| 116 |
63 |
julius |
|
| 117 |
462 |
julius |
} // ~GdbServerSC
|
| 118 |
63 |
julius |
|
| 119 |
|
|
//-----------------------------------------------------------------------------
|
| 120 |
|
|
//! SystemC thread to listen for RSP requests
|
| 121 |
|
|
|
| 122 |
|
|
//! JTAG actions will be queued as appropriate. Runs forever
|
| 123 |
|
|
|
| 124 |
|
|
//! We don't allow any actions until the target is out of its startup mode
|
| 125 |
|
|
//! (where the ROM is mapped into RAM space). This is determined by seeing if
|
| 126 |
|
|
//! the PPC is still in flash memory.
|
| 127 |
|
|
|
| 128 |
|
|
//! Have to use a thread, since we will end up waiting for actions to
|
| 129 |
|
|
//! complete.
|
| 130 |
|
|
//-----------------------------------------------------------------------------
|
| 131 |
|
|
void
|
| 132 |
462 |
julius |
GdbServerSC::rspServer()
|
| 133 |
63 |
julius |
{
|
| 134 |
462 |
julius |
// Reset the debug unit, and wait for ORPSoC to be ready, by noting when it
|
| 135 |
|
|
// accesses an address outside of flash. Note that we use NPC, not PPC since
|
| 136 |
|
|
// at reset PPC is zero, and would trigger a false positive.
|
| 137 |
63 |
julius |
|
| 138 |
462 |
julius |
debugUnit->resetDebugUnit();
|
| 139 |
|
|
rsp_sigval = TARGET_SIGNAL_NONE;
|
| 140 |
|
|
/*
|
| 141 |
|
|
uint32_t npc;
|
| 142 |
|
|
do
|
| 143 |
|
|
{
|
| 144 |
|
|
npc = debugUnit->readSpr (SPR_NPC);
|
| 145 |
|
|
}
|
| 146 |
|
|
while ((flashStart <= npc) && (npc <= flashEnd));
|
| 147 |
|
|
*/
|
| 148 |
|
|
debugUnit->stall();
|
| 149 |
|
|
targetStopped = true;
|
| 150 |
|
|
|
| 151 |
|
|
// Make sure we are connected.
|
| 152 |
|
|
while (!rsp->isConnected()) {
|
| 153 |
|
|
// Reconnect and stall the processor on a new connection
|
| 154 |
|
|
if (!rsp->rspConnect()) {
|
| 155 |
|
|
// Serious failure. Must abort execution.
|
| 156 |
|
|
cerr << "*** Unable to continue: ABORTING" << endl;
|
| 157 |
|
|
sc_stop();
|
| 158 |
|
|
}
|
| 159 |
|
|
// Stall the processor until we get a command to handle.
|
| 160 |
|
|
if (!debugUnit->isStalled()) {
|
| 161 |
|
|
debugUnit->stall();
|
| 162 |
|
|
}
|
| 163 |
|
|
|
| 164 |
|
|
targetStopped = true; // Processor now not running
|
| 165 |
63 |
julius |
}
|
| 166 |
|
|
|
| 167 |
462 |
julius |
// Loop processing commands forever
|
| 168 |
|
|
while (true) {
|
| 169 |
|
|
if (!rsp->isConnected()) {
|
| 170 |
|
|
sc_stop();
|
| 171 |
|
|
return;
|
| 172 |
|
|
}
|
| 173 |
|
|
// Wait until the target has stopped. In this simplified implementation,
|
| 174 |
|
|
// the only reasons for stopping are hitting a breakpoint (l.trap),
|
| 175 |
|
|
// hardware single stepping or hitting a non-breakpoint l.trap. This
|
| 176 |
|
|
// last is not cleanly handled at the moment (we ought to redirect the
|
| 177 |
|
|
// restart through the trap exception vector).
|
| 178 |
|
|
while (!targetStopped) {
|
| 179 |
63 |
julius |
|
| 180 |
462 |
julius |
/* First check to see if the or1200 monitor module wants us to stall */
|
| 181 |
|
|
if (checkMonitorPipe())
|
| 182 |
|
|
break;
|
| 183 |
63 |
julius |
|
| 184 |
462 |
julius |
rspCheckForException();
|
| 185 |
63 |
julius |
|
| 186 |
462 |
julius |
if (debugUnit->isStalled()) {
|
| 187 |
|
|
targetStopped = true;
|
| 188 |
|
|
|
| 189 |
|
|
// If it's a breakpoint, then we need to back up one
|
| 190 |
|
|
// instruction, so on restart we execute the actual
|
| 191 |
|
|
// instruction.
|
| 192 |
|
|
uint32_t ppc = debugUnit->readSpr(SPR_PPC);
|
| 193 |
|
|
|
| 194 |
|
|
if (NULL != mpHash->lookup(BP_MEMORY, ppc)
|
| 195 |
|
|
&& rsp_sigval == TARGET_SIGNAL_TRAP) {
|
| 196 |
|
|
writeNpc(ppc);
|
| 197 |
|
|
}
|
| 198 |
|
|
// Tell the client we've stopped.
|
| 199 |
|
|
rspReportException();
|
| 200 |
|
|
} else if (rsp->rspSocketPeek() > 0) {
|
| 201 |
|
|
if (rsp->rspSocketPeek() == 0x03) // ETX, end of text control char
|
| 202 |
|
|
{
|
| 203 |
|
|
// Got an interrupt command from GDB, this function should
|
| 204 |
|
|
// pull the packet off the socket and stall the processor.
|
| 205 |
|
|
// and then send a stop reply packet with signal
|
| 206 |
|
|
// TARGET_SIGNAL_NONE.
|
| 207 |
|
|
rspInterrupt();
|
| 208 |
|
|
targetStopped = true; // Processor now not running
|
| 209 |
|
|
}
|
| 210 |
|
|
}
|
| 211 |
63 |
julius |
}
|
| 212 |
462 |
julius |
|
| 213 |
|
|
// Get a RSP client request
|
| 214 |
|
|
rspClientRequest();
|
| 215 |
63 |
julius |
}
|
| 216 |
462 |
julius |
} // rspServer ()
|
| 217 |
63 |
julius |
|
| 218 |
|
|
//-----------------------------------------------------------------------------
|
| 219 |
|
|
//! Deal with a request from the GDB client session
|
| 220 |
|
|
|
| 221 |
|
|
//! In general, apart from the simplest requests, this function replies on
|
| 222 |
|
|
//! other functions to implement the functionality.
|
| 223 |
|
|
|
| 224 |
|
|
//! @note It is the responsibility of the recipient to delete the packet when
|
| 225 |
|
|
//! it is finished with. It is permissible to reuse the packet for a
|
| 226 |
|
|
//! reply.
|
| 227 |
|
|
|
| 228 |
|
|
//! @todo Is this the implementation of the 'D' packet really the intended
|
| 229 |
|
|
//! meaning? Or does it just mean that only vAttach will be recognized
|
| 230 |
|
|
//! after this?
|
| 231 |
|
|
|
| 232 |
|
|
//! @param[in] pkt The received RSP packet
|
| 233 |
|
|
//-----------------------------------------------------------------------------
|
| 234 |
462 |
julius |
void GdbServerSC::rspClientRequest()
|
| 235 |
63 |
julius |
{
|
| 236 |
462 |
julius |
if (!rsp->getPkt(pkt)) {
|
| 237 |
|
|
rsp->rspClose(); // Comms failure
|
| 238 |
|
|
return;
|
| 239 |
|
|
}
|
| 240 |
|
|
//Uncomment the next line for the RSP client to print out every packet it gets from GDB
|
| 241 |
|
|
//cerr << "rspClientRequest: " << pkt->data/*[0]*/ << endl;
|
| 242 |
|
|
switch (pkt->data[0]) {
|
| 243 |
|
|
case '!':
|
| 244 |
|
|
// Request for extended remote mode
|
| 245 |
|
|
pkt->packStr("OK");
|
| 246 |
|
|
rsp->putPkt(pkt);
|
| 247 |
|
|
return;
|
| 248 |
63 |
julius |
|
| 249 |
462 |
julius |
case '?':
|
| 250 |
|
|
// Return last signal ID
|
| 251 |
|
|
rspReportException();
|
| 252 |
|
|
return;
|
| 253 |
63 |
julius |
|
| 254 |
462 |
julius |
case 'A':
|
| 255 |
|
|
// Initialization of argv not supported
|
| 256 |
|
|
cerr << "Warning: RSP 'A' packet not supported: ignored" <<
|
| 257 |
|
|
endl;
|
| 258 |
|
|
pkt->packStr("E01");
|
| 259 |
|
|
rsp->putPkt(pkt);
|
| 260 |
|
|
return;
|
| 261 |
63 |
julius |
|
| 262 |
462 |
julius |
case 'b':
|
| 263 |
|
|
// Setting baud rate is deprecated
|
| 264 |
|
|
cerr << "Warning: RSP 'b' packet is deprecated and not "
|
| 265 |
|
|
<< "supported: ignored" << endl;
|
| 266 |
|
|
return;
|
| 267 |
63 |
julius |
|
| 268 |
462 |
julius |
case 'B':
|
| 269 |
|
|
// Breakpoints should be set using Z packets
|
| 270 |
|
|
cerr << "Warning: RSP 'B' packet is deprecated (use 'Z'/'z' "
|
| 271 |
|
|
<< "packets instead): ignored" << endl;
|
| 272 |
|
|
return;
|
| 273 |
63 |
julius |
|
| 274 |
462 |
julius |
case 'c':
|
| 275 |
|
|
// Continue
|
| 276 |
|
|
rspContinue(EXCEPT_NONE);
|
| 277 |
|
|
return;
|
| 278 |
63 |
julius |
|
| 279 |
462 |
julius |
case 'C':
|
| 280 |
|
|
// Continue with signal (in the packet)
|
| 281 |
|
|
rspContinue();
|
| 282 |
|
|
return;
|
| 283 |
63 |
julius |
|
| 284 |
462 |
julius |
case 'd':
|
| 285 |
|
|
// Disable debug using a general query
|
| 286 |
|
|
cerr << "Warning: RSP 'd' packet is deprecated (define a 'Q' "
|
| 287 |
|
|
<< "packet instead: ignored" << endl;
|
| 288 |
|
|
return;
|
| 289 |
63 |
julius |
|
| 290 |
462 |
julius |
case 'D':
|
| 291 |
|
|
// Detach GDB. Do this by closing the client. The rules say that
|
| 292 |
|
|
// execution should continue, so unstall the processor.
|
| 293 |
|
|
pkt->packStr("OK");
|
| 294 |
|
|
rsp->putPkt(pkt);
|
| 295 |
|
|
rsp->rspClose();
|
| 296 |
|
|
//debugUnit->unstall ();
|
| 297 |
|
|
return;
|
| 298 |
63 |
julius |
|
| 299 |
462 |
julius |
case 'F':
|
| 300 |
|
|
// File I/O is not currently supported
|
| 301 |
|
|
cerr << "Warning: RSP file I/O not currently supported: 'F' "
|
| 302 |
|
|
<< "packet ignored" << endl;
|
| 303 |
|
|
return;
|
| 304 |
63 |
julius |
|
| 305 |
462 |
julius |
case 'g':
|
| 306 |
|
|
rspReadAllRegs();
|
| 307 |
|
|
return;
|
| 308 |
63 |
julius |
|
| 309 |
462 |
julius |
case 'G':
|
| 310 |
|
|
rspWriteAllRegs();
|
| 311 |
|
|
return;
|
| 312 |
63 |
julius |
|
| 313 |
462 |
julius |
case 'H':
|
| 314 |
|
|
// Set the thread number of subsequent operations. For now ignore
|
| 315 |
|
|
// silently and just reply "OK"
|
| 316 |
|
|
pkt->packStr("OK");
|
| 317 |
|
|
rsp->putPkt(pkt);
|
| 318 |
|
|
return;
|
| 319 |
63 |
julius |
|
| 320 |
462 |
julius |
case 'i':
|
| 321 |
|
|
case 'I':
|
| 322 |
|
|
// Single cycle step not currently supported. Mark the target as
|
| 323 |
|
|
// running, so that next time it will be detected as stopped (it is
|
| 324 |
|
|
// still stalled in reality) and an ack sent back to the client.
|
| 325 |
|
|
cerr << "Warning: RSP cycle stepping not supported: target "
|
| 326 |
|
|
<< "stopped immediately" << endl;
|
| 327 |
|
|
targetStopped = false;
|
| 328 |
|
|
return;
|
| 329 |
63 |
julius |
|
| 330 |
462 |
julius |
case 'k':
|
| 331 |
|
|
// Kill request. Do nothing for now.
|
| 332 |
|
|
return;
|
| 333 |
63 |
julius |
|
| 334 |
462 |
julius |
case 'm':
|
| 335 |
|
|
// Read memory (symbolic)
|
| 336 |
|
|
rspReadMem();
|
| 337 |
|
|
return;
|
| 338 |
63 |
julius |
|
| 339 |
462 |
julius |
case 'M':
|
| 340 |
|
|
// Write memory (symbolic)
|
| 341 |
|
|
rspWriteMem();
|
| 342 |
|
|
return;
|
| 343 |
63 |
julius |
|
| 344 |
462 |
julius |
case 'p':
|
| 345 |
|
|
// Read a register
|
| 346 |
|
|
rspReadReg();
|
| 347 |
|
|
return;
|
| 348 |
63 |
julius |
|
| 349 |
462 |
julius |
case 'P':
|
| 350 |
|
|
// Write a register
|
| 351 |
|
|
rspWriteReg();
|
| 352 |
|
|
return;
|
| 353 |
63 |
julius |
|
| 354 |
462 |
julius |
case 'q':
|
| 355 |
|
|
// Any one of a number of query packets
|
| 356 |
|
|
rspQuery();
|
| 357 |
|
|
return;
|
| 358 |
63 |
julius |
|
| 359 |
462 |
julius |
case 'Q':
|
| 360 |
|
|
// Any one of a number of set packets
|
| 361 |
|
|
rspSet();
|
| 362 |
|
|
return;
|
| 363 |
63 |
julius |
|
| 364 |
462 |
julius |
case 'r':
|
| 365 |
|
|
// Reset the system. Deprecated (use 'R' instead)
|
| 366 |
|
|
cerr << "Warning: RSP 'r' packet is deprecated (use 'R' "
|
| 367 |
|
|
<< "packet instead): ignored" << endl;
|
| 368 |
|
|
return;
|
| 369 |
63 |
julius |
|
| 370 |
462 |
julius |
case 'R':
|
| 371 |
|
|
// Restart the program being debugged.
|
| 372 |
|
|
rspRestart();
|
| 373 |
|
|
return;
|
| 374 |
63 |
julius |
|
| 375 |
462 |
julius |
case 's':
|
| 376 |
|
|
// Single step one machine instruction.
|
| 377 |
|
|
rspStep(EXCEPT_NONE);
|
| 378 |
|
|
return;
|
| 379 |
63 |
julius |
|
| 380 |
462 |
julius |
case 'S':
|
| 381 |
|
|
// Single step one machine instruction.
|
| 382 |
|
|
rspStep();
|
| 383 |
|
|
return;
|
| 384 |
63 |
julius |
|
| 385 |
462 |
julius |
case 't':
|
| 386 |
|
|
// Search. This is not well defined in the manual and for now we don't
|
| 387 |
|
|
// support it. No response is defined.
|
| 388 |
|
|
cerr << "Warning: RSP 't' packet not supported: ignored"
|
| 389 |
|
|
<< endl;
|
| 390 |
|
|
return;
|
| 391 |
63 |
julius |
|
| 392 |
462 |
julius |
case 'T':
|
| 393 |
|
|
// Is the thread alive. We are bare metal, so don't have a thread
|
| 394 |
|
|
// context. The answer is always "OK".
|
| 395 |
|
|
pkt->packStr("OK");
|
| 396 |
|
|
rsp->putPkt(pkt);
|
| 397 |
|
|
return;
|
| 398 |
63 |
julius |
|
| 399 |
462 |
julius |
case 'v':
|
| 400 |
|
|
// Any one of a number of packets to control execution
|
| 401 |
|
|
rspVpkt();
|
| 402 |
|
|
return;
|
| 403 |
63 |
julius |
|
| 404 |
462 |
julius |
case 'X':
|
| 405 |
|
|
// Write memory (binary)
|
| 406 |
|
|
rspWriteMemBin();
|
| 407 |
|
|
return;
|
| 408 |
63 |
julius |
|
| 409 |
462 |
julius |
case 'z':
|
| 410 |
|
|
// Remove a breakpoint/watchpoint.
|
| 411 |
|
|
rspRemoveMatchpoint();
|
| 412 |
|
|
return;
|
| 413 |
63 |
julius |
|
| 414 |
462 |
julius |
case 'Z':
|
| 415 |
|
|
// Insert a breakpoint/watchpoint.
|
| 416 |
|
|
rspInsertMatchpoint();
|
| 417 |
|
|
return;
|
| 418 |
63 |
julius |
|
| 419 |
462 |
julius |
default:
|
| 420 |
|
|
// Unknown commands are ignored
|
| 421 |
|
|
cerr << "Warning: Unknown RSP request" << pkt->data << endl;
|
| 422 |
|
|
return;
|
| 423 |
|
|
}
|
| 424 |
|
|
} // rspClientRequest ()
|
| 425 |
63 |
julius |
|
| 426 |
|
|
//-----------------------------------------------------------------------------
|
| 427 |
|
|
//! Check if processor is stalled. If it is, read the DRR and return the
|
| 428 |
|
|
//! target signal code.
|
| 429 |
|
|
//-----------------------------------------------------------------------------
|
| 430 |
462 |
julius |
void GdbServerSC::rspCheckForException()
|
| 431 |
63 |
julius |
{
|
| 432 |
|
|
|
| 433 |
462 |
julius |
uint32_t drr;
|
| 434 |
63 |
julius |
|
| 435 |
462 |
julius |
if (!debugUnit->isStalled()) {
|
| 436 |
|
|
// Processor not stalled. Just return;
|
| 437 |
|
|
return;
|
| 438 |
|
|
}
|
| 439 |
|
|
|
| 440 |
|
|
switch ((debugUnit->readSpr(SPR_DRR) & 0xffffffff)) {
|
| 441 |
|
|
case SPR_DRR_RSTE:
|
| 442 |
|
|
rsp_sigval = TARGET_SIGNAL_PWR;
|
| 443 |
|
|
break;
|
| 444 |
|
|
case SPR_DRR_BUSEE:
|
| 445 |
|
|
rsp_sigval = TARGET_SIGNAL_BUS;
|
| 446 |
|
|
break;
|
| 447 |
|
|
case SPR_DRR_DPFE:
|
| 448 |
|
|
rsp_sigval = TARGET_SIGNAL_SEGV;
|
| 449 |
|
|
break;
|
| 450 |
|
|
case SPR_DRR_IPFE:
|
| 451 |
|
|
rsp_sigval = TARGET_SIGNAL_SEGV;
|
| 452 |
|
|
break;
|
| 453 |
|
|
case SPR_DRR_TTE:
|
| 454 |
|
|
rsp_sigval = TARGET_SIGNAL_ALRM;
|
| 455 |
|
|
break;
|
| 456 |
|
|
case SPR_DRR_AE:
|
| 457 |
|
|
rsp_sigval = TARGET_SIGNAL_BUS;
|
| 458 |
|
|
break;
|
| 459 |
|
|
case SPR_DRR_IIE:
|
| 460 |
|
|
rsp_sigval = TARGET_SIGNAL_ILL;
|
| 461 |
|
|
break;
|
| 462 |
|
|
case SPR_DRR_IE:
|
| 463 |
|
|
rsp_sigval = TARGET_SIGNAL_INT;
|
| 464 |
|
|
break;
|
| 465 |
|
|
case SPR_DRR_DME:
|
| 466 |
|
|
rsp_sigval = TARGET_SIGNAL_SEGV;
|
| 467 |
|
|
break;
|
| 468 |
|
|
case SPR_DRR_IME:
|
| 469 |
|
|
rsp_sigval = TARGET_SIGNAL_SEGV;
|
| 470 |
|
|
break;
|
| 471 |
|
|
case SPR_DRR_RE:
|
| 472 |
|
|
rsp_sigval = TARGET_SIGNAL_FPE;
|
| 473 |
|
|
break;
|
| 474 |
|
|
case SPR_DRR_SCE:
|
| 475 |
|
|
rsp_sigval = TARGET_SIGNAL_USR2;
|
| 476 |
|
|
break;
|
| 477 |
|
|
case SPR_DRR_FPE:
|
| 478 |
|
|
rsp_sigval = TARGET_SIGNAL_FPE;
|
| 479 |
|
|
break;
|
| 480 |
|
|
case SPR_DRR_TE:
|
| 481 |
|
|
rsp_sigval = TARGET_SIGNAL_TRAP;
|
| 482 |
|
|
break;
|
| 483 |
|
|
|
| 484 |
|
|
default:
|
| 485 |
|
|
// This must be the case of single step (which does not set DRR)
|
| 486 |
|
|
rsp_sigval = TARGET_SIGNAL_TRAP;
|
| 487 |
|
|
break;
|
| 488 |
|
|
}
|
| 489 |
|
|
|
| 490 |
|
|
return;
|
| 491 |
63 |
julius |
}
|
| 492 |
|
|
|
| 493 |
|
|
//-----------------------------------------------------------------------------
|
| 494 |
|
|
//! Send a packet acknowledging an exception has occurred
|
| 495 |
|
|
|
| 496 |
|
|
//! The only signal we ever see in this implementation is TRAP.
|
| 497 |
|
|
//-----------------------------------------------------------------------------
|
| 498 |
462 |
julius |
void GdbServerSC::rspReportException()
|
| 499 |
63 |
julius |
{
|
| 500 |
462 |
julius |
// Construct a signal received packet
|
| 501 |
|
|
pkt->data[0] = 'S';
|
| 502 |
|
|
pkt->data[1] = Utils::hex2Char(rsp_sigval >> 4);
|
| 503 |
|
|
pkt->data[2] = Utils::hex2Char(rsp_sigval % 16);
|
| 504 |
|
|
pkt->data[3] = '\0';
|
| 505 |
|
|
pkt->setLen(strlen(pkt->data));
|
| 506 |
63 |
julius |
|
| 507 |
462 |
julius |
rsp->putPkt(pkt);
|
| 508 |
63 |
julius |
|
| 509 |
462 |
julius |
} // rspReportException ()
|
| 510 |
63 |
julius |
|
| 511 |
|
|
//-----------------------------------------------------------------------------
|
| 512 |
|
|
//! Handle a RSP continue request
|
| 513 |
|
|
|
| 514 |
|
|
//! This version is typically used for the 'c' packet, to continue without
|
| 515 |
|
|
//! signal, in which case EXCEPT_NONE is passed in as the exception to use.
|
| 516 |
|
|
|
| 517 |
|
|
//! At present other exceptions are not supported
|
| 518 |
|
|
|
| 519 |
|
|
//! @param[in] except The OpenRISC 1000 exception to use
|
| 520 |
|
|
//-----------------------------------------------------------------------------
|
| 521 |
462 |
julius |
void GdbServerSC::rspContinue(uint32_t except)
|
| 522 |
63 |
julius |
{
|
| 523 |
462 |
julius |
uint32_t addr; // Address to continue from, if any
|
| 524 |
63 |
julius |
|
| 525 |
462 |
julius |
// Reject all except 'c' packets
|
| 526 |
|
|
if ('c' != pkt->data[0]) {
|
| 527 |
|
|
cerr <<
|
| 528 |
|
|
"Warning: Continue with signal not currently supported: " <<
|
| 529 |
|
|
"ignored" << endl;
|
| 530 |
|
|
return;
|
| 531 |
|
|
}
|
| 532 |
|
|
// Get an address if we have one
|
| 533 |
|
|
if (0 == strcmp("c", pkt->data)) {
|
| 534 |
|
|
addr = readNpc(); // Default uses current NPC
|
| 535 |
|
|
} else if (1 != sscanf(pkt->data, "c%lx", &addr)) {
|
| 536 |
|
|
cerr << "Warning: RSP continue address " << pkt->data
|
| 537 |
|
|
<< " not recognized: ignored" << endl;
|
| 538 |
|
|
addr = readNpc(); // Default uses current NPC
|
| 539 |
|
|
}
|
| 540 |
63 |
julius |
|
| 541 |
462 |
julius |
rspContinue(addr, EXCEPT_NONE);
|
| 542 |
63 |
julius |
|
| 543 |
462 |
julius |
} // rspContinue ()
|
| 544 |
63 |
julius |
|
| 545 |
|
|
//-----------------------------------------------------------------------------
|
| 546 |
|
|
//! Handle a RSP continue with signal request
|
| 547 |
|
|
|
| 548 |
|
|
//! @todo Currently does nothing. Will use the underlying generic continue
|
| 549 |
|
|
//! function.
|
| 550 |
|
|
//-----------------------------------------------------------------------------
|
| 551 |
462 |
julius |
void GdbServerSC::rspContinue()
|
| 552 |
63 |
julius |
{
|
| 553 |
462 |
julius |
cerr << "RSP continue with signal '" << pkt->data
|
| 554 |
|
|
<< "' received" << endl;
|
| 555 |
63 |
julius |
|
| 556 |
462 |
julius |
} // rspContinue ()
|
| 557 |
63 |
julius |
|
| 558 |
|
|
//-----------------------------------------------------------------------------
|
| 559 |
|
|
//! Generic processing of a continue request
|
| 560 |
|
|
|
| 561 |
|
|
//! The signal may be EXCEPT_NONE if there is no exception to be
|
| 562 |
|
|
//! handled. Currently the exception is ignored.
|
| 563 |
|
|
|
| 564 |
|
|
//! The single step flag is cleared in the debug registers and then the
|
| 565 |
|
|
//! processor is unstalled.
|
| 566 |
|
|
|
| 567 |
|
|
//! @param[in] addr Address from which to step
|
| 568 |
|
|
//! @param[in] except The exception to use (if any)
|
| 569 |
|
|
//-----------------------------------------------------------------------------
|
| 570 |
462 |
julius |
void GdbServerSC::rspContinue(uint32_t addr, uint32_t except)
|
| 571 |
63 |
julius |
{
|
| 572 |
462 |
julius |
// Set the address as the value of the next program counter
|
| 573 |
|
|
writeNpc(addr);
|
| 574 |
63 |
julius |
|
| 575 |
462 |
julius |
/*
|
| 576 |
|
|
// If we're continuing from a breakpoint, replace that instruction in the memory
|
| 577 |
|
|
// ... actually no, I was wrong about this.
|
| 578 |
|
|
if (NULL != mpHash->lookup (BP_MEMORY, addr) && rsp_sigval == TARGET_SIGNAL_TRAP)
|
| 579 |
|
|
{
|
| 580 |
|
|
MpEntry *entry = mpHash->lookup (BP_MEMORY, addr);
|
| 581 |
|
|
debugUnit->writeMem32(entry->addr, entry->instr);
|
| 582 |
|
|
}
|
| 583 |
|
|
*/
|
| 584 |
63 |
julius |
|
| 585 |
462 |
julius |
// Clear Debug Reason Register and watchpoint break generation in Debug Mode
|
| 586 |
|
|
// Register 2 for watchpoints that we triggered to stop this time.
|
| 587 |
|
|
debugUnit->writeSpr(SPR_DRR, 0);
|
| 588 |
|
|
if (rsp_sigval == TARGET_SIGNAL_TRAP) {
|
| 589 |
|
|
/*
|
| 590 |
|
|
Disable last trap generation on watchpoint if this is why we stopped
|
| 591 |
|
|
last time.
|
| 592 |
|
|
*/
|
| 593 |
|
|
uint32_t temp_dmr2 = debugUnit->readSpr(SPR_DMR2);
|
| 594 |
|
|
if (temp_dmr2 & SPR_DMR2_WBS) {
|
| 595 |
|
|
/*
|
| 596 |
|
|
One of these breakpoints is responsible for our stopping, so
|
| 597 |
|
|
disable it this time we start. GDB will send a packet re-enabling
|
| 598 |
|
|
it next time we continue.
|
| 599 |
|
|
*/
|
| 600 |
|
|
debugUnit->writeSpr(SPR_DMR2,
|
| 601 |
|
|
temp_dmr2 &
|
| 602 |
|
|
~((temp_dmr2 & SPR_DMR2_WBS) >>
|
| 603 |
|
|
10));
|
| 604 |
|
|
}
|
| 605 |
|
|
}
|
| 606 |
|
|
// Clear the single step trigger in Debug Mode Register 1 and set traps to
|
| 607 |
|
|
// be handled by the debug unit in the Debug Stop Register
|
| 608 |
|
|
debugUnit->andSpr(SPR_DMR1, ~SPR_DMR1_ST);
|
| 609 |
|
|
debugUnit->orSpr(SPR_DSR, SPR_DSR_TE);
|
| 610 |
63 |
julius |
|
| 611 |
462 |
julius |
// Unstall the processor. Note the GDB client is now waiting for a reply,
|
| 612 |
|
|
// which it will get as soon as the processor stalls again.
|
| 613 |
|
|
debugUnit->unstall();
|
| 614 |
|
|
targetStopped = false;
|
| 615 |
63 |
julius |
|
| 616 |
462 |
julius |
} // rspContinue ()
|
| 617 |
63 |
julius |
|
| 618 |
|
|
//------------------------------------------------------------------------------
|
| 619 |
|
|
//!Handle an interrupt from GDB
|
| 620 |
|
|
|
| 621 |
|
|
//! Detect an interrupt from GDB and stall the processor
|
| 622 |
|
|
//------------------------------------------------------------------------------
|
| 623 |
462 |
julius |
void GdbServerSC::rspInterrupt()
|
| 624 |
63 |
julius |
{
|
| 625 |
462 |
julius |
unsigned char c;
|
| 626 |
63 |
julius |
|
| 627 |
462 |
julius |
c = rsp->getRspChar();
|
| 628 |
|
|
if (c < 0) {
|
| 629 |
|
|
// Had issues, just return
|
| 630 |
|
|
return;
|
| 631 |
|
|
}
|
| 632 |
|
|
// Ensure this is a ETX control char (0x3), currently, we only call this
|
| 633 |
|
|
// function when we've peeked and seen it, otherwise, ignore, return and pray
|
| 634 |
|
|
// things go back to normal...
|
| 635 |
|
|
if (c != 0x03) {
|
| 636 |
|
|
cerr <<
|
| 637 |
|
|
"* Warning: Interrupt character expected but not found on socket"
|
| 638 |
|
|
<< endl;
|
| 639 |
|
|
return;
|
| 640 |
|
|
}
|
| 641 |
|
|
// Otherwise, it's an interrupt packet, stall the processor, and upon return
|
| 642 |
|
|
// to the main handle_rsp() loop, it will inform GDB.
|
| 643 |
63 |
julius |
|
| 644 |
462 |
julius |
debugUnit->stall();
|
| 645 |
63 |
julius |
|
| 646 |
462 |
julius |
// Send a stop reply response, manually set rsp.sigval to TARGET_SIGNAL_NONE
|
| 647 |
|
|
rsp_sigval = TARGET_SIGNAL_NONE;
|
| 648 |
|
|
rspReportException();
|
| 649 |
63 |
julius |
|
| 650 |
462 |
julius |
return;
|
| 651 |
|
|
|
| 652 |
63 |
julius |
}
|
| 653 |
|
|
|
| 654 |
|
|
//-----------------------------------------------------------------------------
|
| 655 |
|
|
//! Handle a RSP read all registers request
|
| 656 |
|
|
|
| 657 |
|
|
//! The registers follow the GDB sequence for OR1K: GPR0 through GPR31, PPC
|
| 658 |
|
|
//! (i.e. SPR PPC), NPC (i.e. SPR NPC) and SR (i.e. SPR SR). Each register is
|
| 659 |
|
|
//! returned as a sequence of bytes in target endian order.
|
| 660 |
|
|
|
| 661 |
|
|
//! Each byte is packed as a pair of hex digits.
|
| 662 |
|
|
//-----------------------------------------------------------------------------
|
| 663 |
462 |
julius |
void GdbServerSC::rspReadAllRegs()
|
| 664 |
63 |
julius |
{
|
| 665 |
462 |
julius |
// The GPRs
|
| 666 |
|
|
for (int r = 0; r < max_gprs; r++) {
|
| 667 |
|
|
Utils::reg2Hex(readGpr(r), &(pkt->data[r * 8]));
|
| 668 |
|
|
}
|
| 669 |
63 |
julius |
|
| 670 |
462 |
julius |
// PPC, NPC and SR
|
| 671 |
|
|
Utils::reg2Hex(debugUnit->readSpr(SPR_PPC),
|
| 672 |
|
|
&(pkt->data[PPC_REGNUM * 8]));
|
| 673 |
|
|
Utils::reg2Hex(readNpc(), &(pkt->data[NPC_REGNUM * 8]));
|
| 674 |
|
|
Utils::reg2Hex(debugUnit->readSpr(SPR_SR), &(pkt->data[SR_REGNUM * 8]));
|
| 675 |
63 |
julius |
|
| 676 |
462 |
julius |
// Finalize the packet and send it
|
| 677 |
|
|
pkt->data[NUM_REGS * 8] = 0;
|
| 678 |
|
|
pkt->setLen(NUM_REGS * 8);
|
| 679 |
|
|
rsp->putPkt(pkt);
|
| 680 |
63 |
julius |
|
| 681 |
462 |
julius |
} // rspReadAllRegs ()
|
| 682 |
63 |
julius |
|
| 683 |
|
|
//-----------------------------------------------------------------------------
|
| 684 |
|
|
//! Handle a RSP write all registers request
|
| 685 |
|
|
|
| 686 |
|
|
//! The registers follow the GDB sequence for OR1K: GPR0 through GPR31, PPC
|
| 687 |
|
|
//! (i.e. SPR PPC), NPC (i.e. SPR NPC) and SR (i.e. SPR SR). Each register is
|
| 688 |
|
|
//! supplied as a sequence of bytes in target endian order.
|
| 689 |
|
|
|
| 690 |
|
|
//! Each byte is packed as a pair of hex digits.
|
| 691 |
|
|
|
| 692 |
|
|
//! @todo There is no error checking at present. Non-hex chars will generate a
|
| 693 |
|
|
//! warning message, but there is no other check that the right amount
|
| 694 |
|
|
//! of data is present. The result is always "OK".
|
| 695 |
|
|
//-----------------------------------------------------------------------------
|
| 696 |
462 |
julius |
void GdbServerSC::rspWriteAllRegs()
|
| 697 |
63 |
julius |
{
|
| 698 |
462 |
julius |
// The GPRs
|
| 699 |
|
|
for (int r = 0; r < max_gprs; r++) {
|
| 700 |
|
|
writeGpr(r, Utils::hex2Reg(&(pkt->data[r * 8])));
|
| 701 |
|
|
}
|
| 702 |
63 |
julius |
|
| 703 |
462 |
julius |
// PPC, NPC and SR
|
| 704 |
|
|
debugUnit->writeSpr(SPR_PPC,
|
| 705 |
|
|
Utils::hex2Reg(&(pkt->data[PPC_REGNUM * 8])));
|
| 706 |
|
|
debugUnit->writeSpr(SPR_SR,
|
| 707 |
|
|
Utils::hex2Reg(&(pkt->data[SR_REGNUM * 8])));
|
| 708 |
|
|
writeNpc(Utils::hex2Reg(&(pkt->data[NPC_REGNUM * 8])));
|
| 709 |
63 |
julius |
|
| 710 |
462 |
julius |
// Acknowledge (always OK for now).
|
| 711 |
|
|
pkt->packStr("OK");
|
| 712 |
|
|
rsp->putPkt(pkt);
|
| 713 |
63 |
julius |
|
| 714 |
462 |
julius |
} // rspWriteAllRegs ()
|
| 715 |
63 |
julius |
|
| 716 |
|
|
//-----------------------------------------------------------------------------
|
| 717 |
|
|
//! Handle a RSP read memory (symbolic) request
|
| 718 |
|
|
|
| 719 |
|
|
//! Syntax is:
|
| 720 |
|
|
|
| 721 |
|
|
//! m<addr>,<length>:
|
| 722 |
|
|
|
| 723 |
|
|
//! The response is the bytes, lowest address first, encoded as pairs of hex
|
| 724 |
|
|
//! digits.
|
| 725 |
|
|
|
| 726 |
|
|
//! The length given is the number of bytes to be read.
|
| 727 |
|
|
//-----------------------------------------------------------------------------
|
| 728 |
462 |
julius |
void GdbServerSC::rspReadMem()
|
| 729 |
63 |
julius |
{
|
| 730 |
462 |
julius |
unsigned int addr; // Where to read the memory
|
| 731 |
|
|
int len; // Number of bytes to read
|
| 732 |
|
|
int off; // Offset into the memory
|
| 733 |
63 |
julius |
|
| 734 |
462 |
julius |
if (2 != sscanf(pkt->data, "m%x,%x:", &addr, &len)) {
|
| 735 |
|
|
cerr << "Warning: Failed to recognize RSP read memory command: "
|
| 736 |
|
|
<< pkt->data << endl;
|
| 737 |
|
|
pkt->packStr("E01");
|
| 738 |
|
|
rsp->putPkt(pkt);
|
| 739 |
|
|
return;
|
| 740 |
|
|
}
|
| 741 |
|
|
// Make sure we won't overflow the buffer (2 chars per byte)
|
| 742 |
|
|
if ((len * 2) >= pkt->getBufSize()) {
|
| 743 |
|
|
cerr << "Warning: Memory read " << pkt->data
|
| 744 |
|
|
<< " too large for RSP packet: truncated" << endl;
|
| 745 |
|
|
len = (pkt->getBufSize() - 1) / 2;
|
| 746 |
|
|
}
|
| 747 |
|
|
//cerr << "rspReadMem: " << len << " bytes@0x"<< hex << addr << endl;
|
| 748 |
|
|
// Refill the buffer with the reply
|
| 749 |
|
|
for (off = 0; off < len; off++) {
|
| 750 |
|
|
unsigned char ch = debugUnit->readMem8(addr + off);
|
| 751 |
63 |
julius |
|
| 752 |
462 |
julius |
pkt->data[off * 2] = Utils::hex2Char(ch >> 4);
|
| 753 |
|
|
pkt->data[off * 2 + 1] = Utils::hex2Char(ch & 0xf);
|
| 754 |
|
|
}
|
| 755 |
63 |
julius |
|
| 756 |
462 |
julius |
pkt->data[off * 2] = '\0'; // End of string
|
| 757 |
|
|
pkt->setLen(strlen(pkt->data));
|
| 758 |
|
|
rsp->putPkt(pkt);
|
| 759 |
63 |
julius |
|
| 760 |
462 |
julius |
} // rsp_read_mem ()
|
| 761 |
63 |
julius |
|
| 762 |
|
|
//-----------------------------------------------------------------------------
|
| 763 |
|
|
//! Handle a RSP write memory (symbolic) request
|
| 764 |
|
|
|
| 765 |
|
|
//! Syntax is:
|
| 766 |
|
|
|
| 767 |
|
|
//! m<addr>,<length>:<data>
|
| 768 |
|
|
|
| 769 |
|
|
//! The data is the bytes, lowest address first, encoded as pairs of hex
|
| 770 |
|
|
//! digits.
|
| 771 |
|
|
|
| 772 |
|
|
//! The length given is the number of bytes to be written.
|
| 773 |
|
|
//-----------------------------------------------------------------------------
|
| 774 |
462 |
julius |
void GdbServerSC::rspWriteMem()
|
| 775 |
63 |
julius |
{
|
| 776 |
462 |
julius |
uint32_t addr; // Where to write the memory
|
| 777 |
|
|
int len; // Number of bytes to write
|
| 778 |
63 |
julius |
|
| 779 |
462 |
julius |
if (2 != sscanf(pkt->data, "M%x,%x:", &addr, &len)) {
|
| 780 |
|
|
cerr << "Warning: Failed to recognize RSP write memory "
|
| 781 |
|
|
<< pkt->data << endl;
|
| 782 |
|
|
pkt->packStr("E01");
|
| 783 |
|
|
rsp->putPkt(pkt);
|
| 784 |
|
|
return;
|
| 785 |
|
|
}
|
| 786 |
|
|
// Find the start of the data and check there is the amount we expect.
|
| 787 |
|
|
char *symDat = (char *)(memchr(pkt->data, ':', pkt->getBufSize())) + 1;
|
| 788 |
|
|
int datLen = pkt->getLen() - (symDat - pkt->data);
|
| 789 |
63 |
julius |
|
| 790 |
462 |
julius |
// Sanity check
|
| 791 |
|
|
if (len * 2 != datLen) {
|
| 792 |
|
|
cerr << "Warning: Write of " << len *
|
| 793 |
|
|
2 << "digits requested, but " << datLen <<
|
| 794 |
|
|
" digits supplied: packet ignored" << endl;
|
| 795 |
|
|
pkt->packStr("E01");
|
| 796 |
|
|
rsp->putPkt(pkt);
|
| 797 |
|
|
return;
|
| 798 |
|
|
}
|
| 799 |
|
|
// Write the bytes to memory (no check the address is OK here)
|
| 800 |
|
|
for (int off = 0; off < len; off++) {
|
| 801 |
|
|
uint8_t nyb1 = Utils::char2Hex(symDat[off * 2]);
|
| 802 |
|
|
uint8_t nyb2 = Utils::char2Hex(symDat[off * 2 + 1]);
|
| 803 |
63 |
julius |
|
| 804 |
462 |
julius |
if (!debugUnit->writeMem8(addr + off, (nyb1 << 4) | nyb2)) {
|
| 805 |
|
|
pkt->packStr("E01");
|
| 806 |
|
|
rsp->putPkt(pkt);
|
| 807 |
|
|
return;
|
| 808 |
|
|
}
|
| 809 |
63 |
julius |
}
|
| 810 |
|
|
|
| 811 |
462 |
julius |
pkt->packStr("OK");
|
| 812 |
|
|
rsp->putPkt(pkt);
|
| 813 |
63 |
julius |
|
| 814 |
462 |
julius |
} // rspWriteMem ()
|
| 815 |
63 |
julius |
|
| 816 |
|
|
//-----------------------------------------------------------------------------
|
| 817 |
|
|
//! Read a single register
|
| 818 |
|
|
|
| 819 |
|
|
//! The registers follow the GDB sequence for OR1K: GPR0 through GPR31, PC
|
| 820 |
|
|
//! (i.e. SPR NPC) and SR (i.e. SPR SR). The register is returned as a
|
| 821 |
|
|
//! sequence of bytes in target endian order.
|
| 822 |
|
|
|
| 823 |
|
|
//! Each byte is packed as a pair of hex digits.
|
| 824 |
|
|
//-----------------------------------------------------------------------------
|
| 825 |
462 |
julius |
void GdbServerSC::rspReadReg()
|
| 826 |
63 |
julius |
{
|
| 827 |
462 |
julius |
unsigned int regNum;
|
| 828 |
63 |
julius |
|
| 829 |
462 |
julius |
// Break out the fields from the data
|
| 830 |
|
|
if (1 != sscanf(pkt->data, "p%x", ®Num)) {
|
| 831 |
|
|
cerr <<
|
| 832 |
|
|
"Warning: Failed to recognize RSP read register command: "
|
| 833 |
|
|
<< pkt->data << endl;
|
| 834 |
|
|
pkt->packStr("E01");
|
| 835 |
|
|
rsp->putPkt(pkt);
|
| 836 |
|
|
return;
|
| 837 |
|
|
}
|
| 838 |
|
|
// Get the relevant register
|
| 839 |
|
|
if (regNum < max_gprs) {
|
| 840 |
|
|
Utils::Utils::reg2Hex(readGpr(regNum), pkt->data);
|
| 841 |
|
|
} else if (PPC_REGNUM == regNum) {
|
| 842 |
|
|
Utils::Utils::reg2Hex(debugUnit->readSpr(SPR_PPC), pkt->data);
|
| 843 |
|
|
} else if (NPC_REGNUM == regNum) {
|
| 844 |
|
|
Utils::Utils::reg2Hex(readNpc(), pkt->data);
|
| 845 |
|
|
} else if (SR_REGNUM == regNum) {
|
| 846 |
|
|
Utils::Utils::reg2Hex(debugUnit->readSpr(SPR_SR), pkt->data);
|
| 847 |
|
|
} else {
|
| 848 |
|
|
// Error response if we don't know the register
|
| 849 |
|
|
cerr << "Warning: Attempt to read unknown register" << regNum
|
| 850 |
|
|
<< ": ignored" << endl;
|
| 851 |
|
|
pkt->packStr("E01");
|
| 852 |
|
|
rsp->putPkt(pkt);
|
| 853 |
|
|
return;
|
| 854 |
|
|
}
|
| 855 |
63 |
julius |
|
| 856 |
462 |
julius |
pkt->setLen(strlen(pkt->data));
|
| 857 |
|
|
rsp->putPkt(pkt);
|
| 858 |
63 |
julius |
|
| 859 |
462 |
julius |
} // rspWriteReg ()
|
| 860 |
63 |
julius |
|
| 861 |
|
|
//-----------------------------------------------------------------------------
|
| 862 |
|
|
//! Write a single register
|
| 863 |
|
|
|
| 864 |
|
|
//! The registers follow the GDB sequence for OR1K: GPR0 through GPR31, PC
|
| 865 |
|
|
//! (i.e. SPR NPC) and SR (i.e. SPR SR). The register is specified as a
|
| 866 |
|
|
//! sequence of bytes in target endian order.
|
| 867 |
|
|
|
| 868 |
|
|
//! Each byte is packed as a pair of hex digits.
|
| 869 |
|
|
//-----------------------------------------------------------------------------
|
| 870 |
462 |
julius |
void GdbServerSC::rspWriteReg()
|
| 871 |
63 |
julius |
{
|
| 872 |
462 |
julius |
unsigned int regNum;
|
| 873 |
|
|
char valstr[9]; // Allow for EOS on the string
|
| 874 |
63 |
julius |
|
| 875 |
462 |
julius |
// Break out the fields from the data
|
| 876 |
|
|
if (2 != sscanf(pkt->data, "P%x=%8s", ®Num, valstr)) {
|
| 877 |
|
|
cerr <<
|
| 878 |
|
|
"Warning: Failed to recognize RSP write register command "
|
| 879 |
|
|
<< pkt->data << endl;
|
| 880 |
|
|
pkt->packStr("E01");
|
| 881 |
|
|
rsp->putPkt(pkt);
|
| 882 |
|
|
return;
|
| 883 |
|
|
}
|
| 884 |
|
|
// Set the relevant register
|
| 885 |
|
|
if (regNum < max_gprs) {
|
| 886 |
|
|
writeGpr(regNum, Utils::hex2Reg(valstr));
|
| 887 |
|
|
} else if (PPC_REGNUM == regNum) {
|
| 888 |
|
|
debugUnit->writeSpr(SPR_PPC, Utils::hex2Reg(valstr));
|
| 889 |
|
|
} else if (NPC_REGNUM == regNum) {
|
| 890 |
|
|
writeNpc(Utils::hex2Reg(valstr));
|
| 891 |
|
|
} else if (SR_REGNUM == regNum) {
|
| 892 |
|
|
debugUnit->writeSpr(SPR_SR, Utils::hex2Reg(valstr));
|
| 893 |
|
|
} else {
|
| 894 |
|
|
// Error response if we don't know the register
|
| 895 |
|
|
cerr << "Warning: Attempt to write unknown register " << regNum
|
| 896 |
|
|
<< ": ignored" << endl;
|
| 897 |
|
|
pkt->packStr("E01");
|
| 898 |
|
|
rsp->putPkt(pkt);
|
| 899 |
|
|
return;
|
| 900 |
|
|
}
|
| 901 |
63 |
julius |
|
| 902 |
462 |
julius |
pkt->packStr("OK");
|
| 903 |
|
|
rsp->putPkt(pkt);
|
| 904 |
63 |
julius |
|
| 905 |
462 |
julius |
} // rspWriteReg ()
|
| 906 |
63 |
julius |
|
| 907 |
|
|
//-----------------------------------------------------------------------------
|
| 908 |
|
|
//! Handle a RSP query request
|
| 909 |
|
|
//-----------------------------------------------------------------------------
|
| 910 |
462 |
julius |
void GdbServerSC::rspQuery()
|
| 911 |
63 |
julius |
{
|
| 912 |
462 |
julius |
if (0 == strcmp("qAttached", pkt->data)) {
|
| 913 |
|
|
// We are always attaching to an existing process with the bare metal
|
| 914 |
|
|
// embedded system.
|
| 915 |
|
|
pkt->packStr("1");
|
| 916 |
|
|
rsp->putPkt(pkt);
|
| 917 |
|
|
} else if (0 == strcmp("qC", pkt->data)) {
|
| 918 |
|
|
// Return the current thread ID (unsigned hex). A null response
|
| 919 |
|
|
// indicates to use the previously selected thread. We use the constant
|
| 920 |
|
|
// OR1KSIM_TID to represent our single thread of control.
|
| 921 |
|
|
sprintf(pkt->data, "QC%x", OR1KSIM_TID);
|
| 922 |
|
|
pkt->setLen(strlen(pkt->data));
|
| 923 |
|
|
rsp->putPkt(pkt);
|
| 924 |
|
|
} else if (0 == strncmp("qCRC", pkt->data, strlen("qCRC"))) {
|
| 925 |
|
|
// Return CRC of memory area
|
| 926 |
|
|
cerr << "Warning: RSP CRC query not supported" << endl;
|
| 927 |
|
|
pkt->packStr("E01");
|
| 928 |
|
|
rsp->putPkt(pkt);
|
| 929 |
|
|
} else if (0 == strcmp("qfThreadInfo", pkt->data)) {
|
| 930 |
|
|
// Return info about active threads. We return just the constant
|
| 931 |
|
|
// OR1KSIM_TID to represent our single thread of control.
|
| 932 |
|
|
sprintf(pkt->data, "m%x", OR1KSIM_TID);
|
| 933 |
|
|
pkt->setLen(strlen(pkt->data));
|
| 934 |
|
|
rsp->putPkt(pkt);
|
| 935 |
|
|
} else if (0 == strcmp("qsThreadInfo", pkt->data)) {
|
| 936 |
|
|
// Return info about more active threads. We have no more, so return the
|
| 937 |
|
|
// end of list marker, 'l'
|
| 938 |
|
|
pkt->packStr("l");
|
| 939 |
|
|
rsp->putPkt(pkt);
|
| 940 |
|
|
} else if (0 ==
|
| 941 |
|
|
strncmp("qGetTLSAddr:", pkt->data, strlen("qGetTLSAddr:"))) {
|
| 942 |
|
|
// We don't support this feature
|
| 943 |
|
|
pkt->packStr("");
|
| 944 |
|
|
rsp->putPkt(pkt);
|
| 945 |
|
|
} else if (0 == strncmp("qL", pkt->data, strlen("qL"))) {
|
| 946 |
|
|
// Deprecated and replaced by 'qfThreadInfo'
|
| 947 |
|
|
cerr << "Warning: RSP qL deprecated: no info returned" << endl;
|
| 948 |
|
|
pkt->packStr("qM001");
|
| 949 |
|
|
rsp->putPkt(pkt);
|
| 950 |
|
|
} else if (0 == strcmp("qOffsets", pkt->data)) {
|
| 951 |
|
|
// Report any relocation
|
| 952 |
|
|
pkt->packStr("Text=0;Data=0;Bss=0");
|
| 953 |
|
|
rsp->putPkt(pkt);
|
| 954 |
|
|
} else if (0 == strncmp("qP", pkt->data, strlen("qP"))) {
|
| 955 |
|
|
// Deprecated and replaced by 'qThreadExtraInfo'
|
| 956 |
|
|
cerr << "Warning: RSP qP deprecated: no info returned" << endl;
|
| 957 |
|
|
pkt->packStr("");
|
| 958 |
|
|
rsp->putPkt(pkt);
|
| 959 |
|
|
} else if (0 == strncmp("qRcmd,", pkt->data, strlen("qRcmd,"))) {
|
| 960 |
|
|
// This is used to interface to commands to do "stuff"
|
| 961 |
|
|
rspCommand();
|
| 962 |
|
|
} else if (0 == strncmp("qSupported", pkt->data, strlen("qSupported"))) {
|
| 963 |
|
|
// Report a list of the features we support. For now we just ignore any
|
| 964 |
|
|
// supplied specific feature queries, but in the future these may be
|
| 965 |
|
|
// supported as well. Note that the packet size allows for 'G' + all the
|
| 966 |
|
|
// registers sent to us, or a reply to 'g' with all the registers and an
|
| 967 |
|
|
// EOS so the buffer is a well formed string.
|
| 968 |
|
|
sprintf(pkt->data, "PacketSize=%x", pkt->getBufSize());
|
| 969 |
|
|
pkt->setLen(strlen(pkt->data));
|
| 970 |
|
|
rsp->putPkt(pkt);
|
| 971 |
|
|
} else if (0 == strncmp("qSymbol:", pkt->data, strlen("qSymbol:"))) {
|
| 972 |
|
|
// Offer to look up symbols. Nothing we want (for now). TODO. This just
|
| 973 |
|
|
// ignores any replies to symbols we looked up, but we didn't want to
|
| 974 |
|
|
// do that anyway!
|
| 975 |
|
|
pkt->packStr("OK");
|
| 976 |
|
|
rsp->putPkt(pkt);
|
| 977 |
|
|
} else if (0 == strncmp("qThreadExtraInfo,", pkt->data,
|
| 978 |
|
|
strlen("qThreadExtraInfo,"))) {
|
| 979 |
|
|
// Report that we are runnable, but the text must be hex ASCI
|
| 980 |
|
|
// digits. For now do this by steam, reusing the original packet
|
| 981 |
|
|
sprintf(pkt->data, "%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
| 982 |
|
|
'R', 'u', 'n', 'n', 'a', 'b', 'l', 'e', 0);
|
| 983 |
|
|
pkt->setLen(strlen(pkt->data));
|
| 984 |
|
|
rsp->putPkt(pkt);
|
| 985 |
|
|
} else if (0 == strncmp("qTStatus", pkt->data, strlen("qTstatus"))) {
|
| 986 |
|
|
// We don't support tracing, return empty packet
|
| 987 |
|
|
pkt->packStr("");
|
| 988 |
|
|
rsp->putPkt(pkt);
|
| 989 |
|
|
} else if (0 == strncmp("qXfer:", pkt->data, strlen("qXfer:"))) {
|
| 990 |
|
|
// For now we support no 'qXfer' requests, but these should not be
|
| 991 |
|
|
// expected, since they were not reported by 'qSupported'
|
| 992 |
|
|
cerr << "Warning: RSP 'qXfer' not supported: ignored" << endl;
|
| 993 |
|
|
pkt->packStr("");
|
| 994 |
|
|
rsp->putPkt(pkt);
|
| 995 |
|
|
} else {
|
| 996 |
|
|
cerr << "Unrecognized RSP query: ignored" << endl;
|
| 997 |
|
|
}
|
| 998 |
|
|
} // rspQuery ()
|
| 999 |
63 |
julius |
|
| 1000 |
|
|
//-----------------------------------------------------------------------------
|
| 1001 |
|
|
//! Handle a RSP qRcmd request
|
| 1002 |
|
|
|
| 1003 |
|
|
//! The actual command follows the "qRcmd," in ASCII encoded to hex
|
| 1004 |
|
|
//-----------------------------------------------------------------------------
|
| 1005 |
462 |
julius |
void GdbServerSC::rspCommand()
|
| 1006 |
63 |
julius |
{
|
| 1007 |
462 |
julius |
char cmd[RSP_PKT_MAX];
|
| 1008 |
63 |
julius |
|
| 1009 |
462 |
julius |
Utils::hex2Ascii(cmd, &(pkt->data[strlen("qRcmd,")]));
|
| 1010 |
63 |
julius |
|
| 1011 |
462 |
julius |
// Work out which command it is
|
| 1012 |
|
|
if (0 == strncmp("readspr ", cmd, strlen("readspr"))) {
|
| 1013 |
|
|
unsigned int sprNum;
|
| 1014 |
63 |
julius |
|
| 1015 |
462 |
julius |
// Parse and return error if we fail
|
| 1016 |
|
|
if (1 != sscanf(cmd, "readspr %4x", &sprNum)) {
|
| 1017 |
|
|
cerr << "Warning: qRcmd " << cmd
|
| 1018 |
|
|
<< "not recognized: ignored" << endl;
|
| 1019 |
|
|
pkt->packStr("E01");
|
| 1020 |
|
|
rsp->putPkt(pkt);
|
| 1021 |
|
|
return;
|
| 1022 |
|
|
}
|
| 1023 |
|
|
// SPR out of range
|
| 1024 |
|
|
if (sprNum > MAX_SPRS) {
|
| 1025 |
|
|
cerr << "Warning: qRcmd readspr " << hex << sprNum
|
| 1026 |
|
|
<< dec << " too large: ignored" << endl;
|
| 1027 |
|
|
pkt->packStr("E01");
|
| 1028 |
|
|
rsp->putPkt(pkt);
|
| 1029 |
|
|
return;
|
| 1030 |
|
|
}
|
| 1031 |
|
|
// Construct the reply
|
| 1032 |
|
|
sprintf(cmd, "%8lx", debugUnit->readSpr(sprNum));
|
| 1033 |
|
|
Utils::ascii2Hex(pkt->data, cmd);
|
| 1034 |
|
|
pkt->setLen(strlen(pkt->data));
|
| 1035 |
|
|
rsp->putPkt(pkt);
|
| 1036 |
|
|
} else if (0 == strncmp("writespr ", cmd, strlen("writespr"))) {
|
| 1037 |
|
|
unsigned int sprNum;
|
| 1038 |
|
|
uint32_t val;
|
| 1039 |
63 |
julius |
|
| 1040 |
462 |
julius |
// Parse and return error if we fail
|
| 1041 |
|
|
if (2 != sscanf(cmd, "writespr %4x %8lx", &sprNum, &val)) {
|
| 1042 |
|
|
cerr << "Warning: qRcmd " << cmd <<
|
| 1043 |
|
|
" not recognized: ignored" << endl;
|
| 1044 |
|
|
pkt->packStr("E01");
|
| 1045 |
|
|
rsp->putPkt(pkt);
|
| 1046 |
|
|
return;
|
| 1047 |
|
|
}
|
| 1048 |
|
|
// SPR out of range
|
| 1049 |
|
|
if (sprNum > MAX_SPRS) {
|
| 1050 |
|
|
cerr << "Warning: qRcmd writespr " << hex << sprNum
|
| 1051 |
|
|
<< dec << " too large: ignored" << endl;
|
| 1052 |
|
|
pkt->packStr("E01");
|
| 1053 |
|
|
rsp->putPkt(pkt);
|
| 1054 |
|
|
return;
|
| 1055 |
|
|
}
|
| 1056 |
|
|
// Update the SPR and reply "OK"
|
| 1057 |
|
|
debugUnit->writeSpr(sprNum, val);
|
| 1058 |
|
|
pkt->packStr("OK");
|
| 1059 |
|
|
rsp->putPkt(pkt);
|
| 1060 |
63 |
julius |
}
|
| 1061 |
|
|
|
| 1062 |
462 |
julius |
} // rspCommand ()
|
| 1063 |
63 |
julius |
|
| 1064 |
|
|
//-----------------------------------------------------------------------------
|
| 1065 |
|
|
//! Handle a RSP set request
|
| 1066 |
|
|
//-----------------------------------------------------------------------------
|
| 1067 |
462 |
julius |
void GdbServerSC::rspSet()
|
| 1068 |
63 |
julius |
{
|
| 1069 |
462 |
julius |
if (0 == strncmp("QPassSignals:", pkt->data, strlen("QPassSignals:"))) {
|
| 1070 |
|
|
// Passing signals not supported
|
| 1071 |
|
|
pkt->packStr("");
|
| 1072 |
|
|
rsp->putPkt(pkt);
|
| 1073 |
|
|
} else if ((0 == strncmp("QTDP", pkt->data, strlen("QTDP"))) ||
|
| 1074 |
|
|
(0 == strncmp("QFrame", pkt->data, strlen("QFrame"))) ||
|
| 1075 |
|
|
(0 == strcmp("QTStart", pkt->data)) ||
|
| 1076 |
|
|
(0 == strcmp("QTStop", pkt->data)) ||
|
| 1077 |
|
|
(0 == strcmp("QTinit", pkt->data)) ||
|
| 1078 |
|
|
(0 == strncmp("QTro", pkt->data, strlen("QTro")))) {
|
| 1079 |
|
|
// All tracepoint features are not supported. This reply is really only
|
| 1080 |
|
|
// needed to 'QTDP', since with that the others should not be
|
| 1081 |
|
|
// generated.
|
| 1082 |
|
|
pkt->packStr("");
|
| 1083 |
|
|
rsp->putPkt(pkt);
|
| 1084 |
|
|
} else {
|
| 1085 |
|
|
cerr << "Unrecognized RSP set request: ignored" << endl;
|
| 1086 |
|
|
delete pkt;
|
| 1087 |
|
|
}
|
| 1088 |
|
|
} // rspSet ()
|
| 1089 |
63 |
julius |
|
| 1090 |
|
|
//-----------------------------------------------------------------------------
|
| 1091 |
|
|
//! Handle a RSP restart request
|
| 1092 |
|
|
|
| 1093 |
|
|
//! For now we just put the program counter back to the reset vector. If we
|
| 1094 |
|
|
//! supported the vRun request, we should use the address specified
|
| 1095 |
|
|
//! there. There is no point in unstalling the processor, since we'll never
|
| 1096 |
|
|
//! get control back.
|
| 1097 |
|
|
//-----------------------------------------------------------------------------
|
| 1098 |
462 |
julius |
void GdbServerSC::rspRestart()
|
| 1099 |
63 |
julius |
{
|
| 1100 |
462 |
julius |
writeNpc(EXCEPT_RESET);
|
| 1101 |
63 |
julius |
|
| 1102 |
462 |
julius |
} // rspRestart ()
|
| 1103 |
63 |
julius |
|
| 1104 |
|
|
//-----------------------------------------------------------------------------
|
| 1105 |
|
|
//! Handle a RSP step request
|
| 1106 |
|
|
|
| 1107 |
|
|
//! This version is typically used for the 's' packet, to continue without
|
| 1108 |
|
|
//! signal, in which case EXCEPT_NONE is passed in as the exception to use.
|
| 1109 |
|
|
|
| 1110 |
|
|
//! @param[in] except The exception to use. Only EXCEPT_NONE should be set
|
| 1111 |
|
|
//! this way.
|
| 1112 |
|
|
//-----------------------------------------------------------------------------
|
| 1113 |
462 |
julius |
void GdbServerSC::rspStep(uint32_t except)
|
| 1114 |
63 |
julius |
{
|
| 1115 |
462 |
julius |
uint32_t addr; // The address to step from, if any
|
| 1116 |
63 |
julius |
|
| 1117 |
462 |
julius |
// Reject all except 's' packets
|
| 1118 |
|
|
if ('s' != pkt->data[0]) {
|
| 1119 |
|
|
cerr << "Warning: Step with signal not currently supported: "
|
| 1120 |
|
|
<< "ignored" << endl;
|
| 1121 |
|
|
return;
|
| 1122 |
|
|
}
|
| 1123 |
63 |
julius |
|
| 1124 |
462 |
julius |
if (0 == strcmp("s", pkt->data)) {
|
| 1125 |
|
|
addr = readNpc(); // Default uses current NPC
|
| 1126 |
|
|
} else if (1 != sscanf(pkt->data, "s%lx", &addr)) {
|
| 1127 |
|
|
cerr << "Warning: RSP step address " << pkt->data
|
| 1128 |
|
|
<< " not recognized: ignored" << endl;
|
| 1129 |
|
|
addr = readNpc(); // Default uses current NPC
|
| 1130 |
|
|
}
|
| 1131 |
63 |
julius |
|
| 1132 |
462 |
julius |
rspStep(addr, EXCEPT_NONE);
|
| 1133 |
63 |
julius |
|
| 1134 |
462 |
julius |
} // rspStep ()
|
| 1135 |
63 |
julius |
|
| 1136 |
|
|
//-----------------------------------------------------------------------------
|
| 1137 |
|
|
//! Handle a RSP step with signal request
|
| 1138 |
|
|
|
| 1139 |
|
|
//! @todo Currently null. Will use the underlying generic step function.
|
| 1140 |
|
|
//-----------------------------------------------------------------------------
|
| 1141 |
462 |
julius |
void GdbServerSC::rspStep()
|
| 1142 |
63 |
julius |
{
|
| 1143 |
462 |
julius |
cerr << "RSP step with signal '" << pkt->data << "' received" << endl;
|
| 1144 |
63 |
julius |
|
| 1145 |
462 |
julius |
} // rspStep ()
|
| 1146 |
63 |
julius |
|
| 1147 |
|
|
//-----------------------------------------------------------------------------
|
| 1148 |
|
|
//! Generic processing of a step request
|
| 1149 |
|
|
|
| 1150 |
|
|
//! The signal may be EXCEPT_NONE if there is no exception to be
|
| 1151 |
|
|
//! handled. Currently the exception is ignored.
|
| 1152 |
|
|
|
| 1153 |
|
|
//! The single step flag is set in the debug registers and then the processor
|
| 1154 |
|
|
//! is unstalled.
|
| 1155 |
|
|
|
| 1156 |
|
|
//! @todo There appears to be a bug in the ORPSoC debug unit, whereby multiple
|
| 1157 |
|
|
//! single steps make a mess of the pipeline, leading to multiple
|
| 1158 |
|
|
//! executions of the same instruction. A fix would be to use l.trap (as
|
| 1159 |
|
|
//! for continue) for any consecutive calls to step.
|
| 1160 |
|
|
|
| 1161 |
|
|
//! @param[in] addr Address from which to step
|
| 1162 |
|
|
//! @param[in] except The exception to use (if any)
|
| 1163 |
|
|
//-----------------------------------------------------------------------------
|
| 1164 |
462 |
julius |
void GdbServerSC::rspStep(uint32_t addr, uint32_t except)
|
| 1165 |
63 |
julius |
{
|
| 1166 |
462 |
julius |
// Set the address as the value of the next program counter
|
| 1167 |
|
|
writeNpc(addr);
|
| 1168 |
63 |
julius |
|
| 1169 |
462 |
julius |
/*
|
| 1170 |
|
|
// If we're continuing from a breakpoint, replace that instruction in the memory
|
| 1171 |
|
|
// ... actually no, I was wrong about this.
|
| 1172 |
|
|
if (NULL != mpHash->lookup (BP_MEMORY, addr) && rsp_sigval == TARGET_SIGNAL_TRAP)
|
| 1173 |
|
|
{
|
| 1174 |
|
|
MpEntry *entry = mpHash->lookup (BP_MEMORY, addr);
|
| 1175 |
|
|
debugUnit->writeMem32(entry->addr, entry->instr);
|
| 1176 |
|
|
}
|
| 1177 |
|
|
*/
|
| 1178 |
63 |
julius |
|
| 1179 |
462 |
julius |
// Clear Debug Reason Register and watchpoint break generation in Debug Mode
|
| 1180 |
|
|
// Register 2 for watchpoints that we triggered to stop this time.
|
| 1181 |
|
|
debugUnit->writeSpr(SPR_DRR, 0);
|
| 1182 |
|
|
if (rsp_sigval == TARGET_SIGNAL_TRAP) {
|
| 1183 |
|
|
/*
|
| 1184 |
|
|
Disable last trap generation on watchpoint if this is why we stopped
|
| 1185 |
|
|
last time.
|
| 1186 |
|
|
*/
|
| 1187 |
|
|
uint32_t temp_dmr2 = debugUnit->readSpr(SPR_DMR2);
|
| 1188 |
|
|
if (temp_dmr2 & SPR_DMR2_WBS) {
|
| 1189 |
|
|
/*
|
| 1190 |
|
|
One of these breakpoints is responsible for our stopping, so
|
| 1191 |
|
|
disable it this time we start. GDB will send a packet re-enabling
|
| 1192 |
|
|
it next time we continue.
|
| 1193 |
|
|
*/
|
| 1194 |
|
|
debugUnit->writeSpr(SPR_DMR2,
|
| 1195 |
|
|
temp_dmr2 &
|
| 1196 |
|
|
~((temp_dmr2 & SPR_DMR2_WBS) >>
|
| 1197 |
|
|
10));
|
| 1198 |
|
|
}
|
| 1199 |
|
|
}
|
| 1200 |
|
|
// Set the single step trigger in Debug Mode Register 1 and set traps to be
|
| 1201 |
|
|
// handled by the debug unit in the Debug Stop Register
|
| 1202 |
|
|
debugUnit->orSpr(SPR_DMR1, SPR_DMR1_ST);
|
| 1203 |
|
|
debugUnit->orSpr(SPR_DSR, SPR_DSR_TE);
|
| 1204 |
63 |
julius |
|
| 1205 |
462 |
julius |
// Unstall the processor. Note the GDB client is now waiting for a reply,
|
| 1206 |
|
|
// which it will get as soon as the processor stalls again.
|
| 1207 |
|
|
debugUnit->unstall();
|
| 1208 |
|
|
targetStopped = false;
|
| 1209 |
63 |
julius |
|
| 1210 |
462 |
julius |
} // rspStep ()
|
| 1211 |
63 |
julius |
|
| 1212 |
|
|
//-----------------------------------------------------------------------------
|
| 1213 |
|
|
//! Handle a RSP 'v' packet
|
| 1214 |
|
|
|
| 1215 |
|
|
//! These are commands associated with executing the code on the target
|
| 1216 |
|
|
//-----------------------------------------------------------------------------
|
| 1217 |
462 |
julius |
void GdbServerSC::rspVpkt()
|
| 1218 |
63 |
julius |
{
|
| 1219 |
462 |
julius |
if (0 == strncmp("vAttach;", pkt->data, strlen("vAttach;"))) {
|
| 1220 |
|
|
// Attaching is a null action, since we have no other process. We just
|
| 1221 |
|
|
// return a stop packet (using TRAP) to indicate we are stopped.
|
| 1222 |
|
|
pkt->packStr("S05");
|
| 1223 |
|
|
rsp->putPkt(pkt);
|
| 1224 |
|
|
return;
|
| 1225 |
|
|
} else if (0 == strcmp("vCont?", pkt->data)) {
|
| 1226 |
|
|
// For now we don't support this.
|
| 1227 |
|
|
pkt->packStr("");
|
| 1228 |
|
|
rsp->putPkt(pkt);
|
| 1229 |
|
|
return;
|
| 1230 |
|
|
} else if (0 == strncmp("vCont", pkt->data, strlen("vCont"))) {
|
| 1231 |
|
|
// This shouldn't happen, because we've reported non-support via vCont?
|
| 1232 |
|
|
// above
|
| 1233 |
|
|
cerr << "Warning: RSP vCont not supported: ignored" << endl;
|
| 1234 |
|
|
return;
|
| 1235 |
|
|
} else if (0 == strncmp("vFile:", pkt->data, strlen("vFile:"))) {
|
| 1236 |
|
|
// For now we don't support this.
|
| 1237 |
|
|
cerr << "Warning: RSP vFile not supported: ignored" << endl;
|
| 1238 |
|
|
pkt->packStr("");
|
| 1239 |
|
|
rsp->putPkt(pkt);
|
| 1240 |
|
|
return;
|
| 1241 |
|
|
} else if (0 ==
|
| 1242 |
|
|
strncmp("vFlashErase:", pkt->data, strlen("vFlashErase:"))) {
|
| 1243 |
|
|
// For now we don't support this.
|
| 1244 |
|
|
cerr << "Warning: RSP vFlashErase not supported: ignored" <<
|
| 1245 |
|
|
endl;
|
| 1246 |
|
|
pkt->packStr("E01");
|
| 1247 |
|
|
rsp->putPkt(pkt);
|
| 1248 |
|
|
return;
|
| 1249 |
|
|
} else if (0 ==
|
| 1250 |
|
|
strncmp("vFlashWrite:", pkt->data, strlen("vFlashWrite:"))) {
|
| 1251 |
|
|
// For now we don't support this.
|
| 1252 |
|
|
cerr << "Warning: RSP vFlashWrite not supported: ignored" <<
|
| 1253 |
|
|
endl;
|
| 1254 |
|
|
pkt->packStr("E01");
|
| 1255 |
|
|
rsp->putPkt(pkt);
|
| 1256 |
|
|
return;
|
| 1257 |
|
|
} else if (0 == strcmp("vFlashDone", pkt->data)) {
|
| 1258 |
|
|
// For now we don't support this.
|
| 1259 |
|
|
cerr << "Warning: RSP vFlashDone not supported: ignored" <<
|
| 1260 |
|
|
endl;;
|
| 1261 |
|
|
pkt->packStr("E01");
|
| 1262 |
|
|
rsp->putPkt(pkt);
|
| 1263 |
|
|
return;
|
| 1264 |
|
|
} else if (0 == strncmp("vRun;", pkt->data, strlen("vRun;"))) {
|
| 1265 |
|
|
// We shouldn't be given any args, but check for this
|
| 1266 |
|
|
if (pkt->getLen() > strlen("vRun;")) {
|
| 1267 |
|
|
cerr << "Warning: Unexpected arguments to RSP vRun "
|
| 1268 |
|
|
"command: ignored" << endl;
|
| 1269 |
|
|
}
|
| 1270 |
|
|
// Restart the current program. However unlike a "R" packet, "vRun"
|
| 1271 |
|
|
// should behave as though it has just stopped. We use signal 5 (TRAP).
|
| 1272 |
|
|
rspRestart();
|
| 1273 |
|
|
pkt->packStr("S05");
|
| 1274 |
|
|
rsp->putPkt(pkt);
|
| 1275 |
|
|
} else {
|
| 1276 |
|
|
cerr << "Warning: Unknown RSP 'v' packet type " << pkt->data
|
| 1277 |
|
|
<< ": ignored" << endl;
|
| 1278 |
|
|
pkt->packStr("E01");
|
| 1279 |
|
|
rsp->putPkt(pkt);
|
| 1280 |
|
|
return;
|
| 1281 |
63 |
julius |
}
|
| 1282 |
462 |
julius |
} // rspVpkt ()
|
| 1283 |
63 |
julius |
|
| 1284 |
|
|
//-----------------------------------------------------------------------------
|
| 1285 |
|
|
//! Handle a RSP write memory (binary) request
|
| 1286 |
|
|
|
| 1287 |
|
|
//! Syntax is:
|
| 1288 |
|
|
|
| 1289 |
|
|
//! X<addr>,<length>:
|
| 1290 |
|
|
|
| 1291 |
|
|
//! Followed by the specified number of bytes as raw binary. Response should be
|
| 1292 |
|
|
//! "OK" if all copied OK, E<nn> if error <nn> has occurred.
|
| 1293 |
|
|
|
| 1294 |
|
|
//! The length given is the number of bytes to be written. The data buffer has
|
| 1295 |
|
|
//! already been unescaped, so will hold this number of bytes.
|
| 1296 |
|
|
|
| 1297 |
|
|
//! The data is in model-endian format, so no transformation is needed.
|
| 1298 |
|
|
//-----------------------------------------------------------------------------
|
| 1299 |
462 |
julius |
void GdbServerSC::rspWriteMemBin()
|
| 1300 |
63 |
julius |
{
|
| 1301 |
462 |
julius |
uint32_t addr; // Where to write the memory
|
| 1302 |
|
|
int len; // Number of bytes to write
|
| 1303 |
63 |
julius |
|
| 1304 |
462 |
julius |
if (2 != sscanf(pkt->data, "X%x,%x:", &addr, &len)) {
|
| 1305 |
|
|
cerr <<
|
| 1306 |
|
|
"Warning: Failed to recognize RSP write memory command: %s"
|
| 1307 |
|
|
<< pkt->data << endl;
|
| 1308 |
|
|
pkt->packStr("E01");
|
| 1309 |
|
|
rsp->putPkt(pkt);
|
| 1310 |
|
|
return;
|
| 1311 |
|
|
}
|
| 1312 |
|
|
// Find the start of the data and "unescape" it. Bindat must be unsigned, or
|
| 1313 |
|
|
// all sorts of horrible sign extensions will happen when val is computed
|
| 1314 |
|
|
// below!
|
| 1315 |
|
|
uint8_t *bindat = (uint8_t *) (memchr(pkt->data, ':',
|
| 1316 |
|
|
pkt->getBufSize())) + 1;
|
| 1317 |
|
|
int off = (char *)bindat - pkt->data;
|
| 1318 |
|
|
int newLen = Utils::rspUnescape((char *)bindat, pkt->getLen() - off);
|
| 1319 |
63 |
julius |
|
| 1320 |
462 |
julius |
// Sanity check
|
| 1321 |
|
|
if (newLen != len) {
|
| 1322 |
|
|
int minLen = len < newLen ? len : newLen;
|
| 1323 |
63 |
julius |
|
| 1324 |
462 |
julius |
cerr << "Warning: Write of " << len << " bytes requested, but "
|
| 1325 |
|
|
<< newLen << " bytes supplied. " << minLen <<
|
| 1326 |
|
|
" will be written" << endl;
|
| 1327 |
|
|
len = minLen;
|
| 1328 |
|
|
}
|
| 1329 |
|
|
// Write the bytes to memory. More efficent to do this in 32-bit chunks
|
| 1330 |
|
|
int startBytes = addr & 0x3;
|
| 1331 |
|
|
int endBytes = (addr + len) & 0x3;
|
| 1332 |
63 |
julius |
|
| 1333 |
462 |
julius |
// First partial word. Access bindat in an endian independent fashion.
|
| 1334 |
|
|
for (off = 0; off < startBytes; off++) {
|
| 1335 |
|
|
if (!debugUnit->writeMem8(addr + off, bindat[off])) {
|
| 1336 |
|
|
pkt->packStr("E01");
|
| 1337 |
|
|
rsp->putPkt(pkt);
|
| 1338 |
|
|
return;
|
| 1339 |
|
|
}
|
| 1340 |
63 |
julius |
}
|
| 1341 |
|
|
|
| 1342 |
462 |
julius |
// The bulk as words. Convert to model endian before writing.
|
| 1343 |
|
|
for (off = startBytes; off < len; off += 4) {
|
| 1344 |
|
|
uint32_t val = *((uint32_t *) (&(bindat[off])));
|
| 1345 |
63 |
julius |
|
| 1346 |
462 |
julius |
if (!debugUnit->writeMem32(addr + off, Utils::htotl(val))) {
|
| 1347 |
|
|
pkt->packStr("E01");
|
| 1348 |
|
|
rsp->putPkt(pkt);
|
| 1349 |
|
|
return;
|
| 1350 |
|
|
}
|
| 1351 |
63 |
julius |
}
|
| 1352 |
|
|
|
| 1353 |
462 |
julius |
// Last partial word. Access bindat in an endian independent fashion.
|
| 1354 |
|
|
for (off = len - endBytes; off < len; off++) {
|
| 1355 |
|
|
uint32_t base = (addr + len) & 0xfffffffc;
|
| 1356 |
63 |
julius |
|
| 1357 |
462 |
julius |
if (!debugUnit->writeMem8(base + off, bindat[off])) {
|
| 1358 |
|
|
pkt->packStr("E01");
|
| 1359 |
|
|
rsp->putPkt(pkt);
|
| 1360 |
|
|
return;
|
| 1361 |
|
|
}
|
| 1362 |
63 |
julius |
}
|
| 1363 |
|
|
|
| 1364 |
462 |
julius |
pkt->packStr("OK");
|
| 1365 |
|
|
rsp->putPkt(pkt);
|
| 1366 |
63 |
julius |
|
| 1367 |
462 |
julius |
} // rspWriteMemBin ()
|
| 1368 |
63 |
julius |
|
| 1369 |
|
|
//-----------------------------------------------------------------------------
|
| 1370 |
|
|
//! Handle a RSP remove breakpoint or matchpoint request
|
| 1371 |
|
|
|
| 1372 |
|
|
//! For now only memory breakpoints are implemented, which are implemented by
|
| 1373 |
|
|
//! substituting a breakpoint at the specified address. The implementation must
|
| 1374 |
|
|
//! cope with the possibility of duplicate packets.
|
| 1375 |
|
|
|
| 1376 |
|
|
//! @todo This doesn't work with icache/immu yet
|
| 1377 |
|
|
//-----------------------------------------------------------------------------
|
| 1378 |
462 |
julius |
void GdbServerSC::rspRemoveMatchpoint()
|
| 1379 |
63 |
julius |
{
|
| 1380 |
462 |
julius |
MpType type; // What sort of matchpoint
|
| 1381 |
|
|
uint32_t addr; // Address specified
|
| 1382 |
|
|
uint32_t instr; // Instruction value found
|
| 1383 |
|
|
int len; // Matchpoint length (not used)
|
| 1384 |
63 |
julius |
|
| 1385 |
462 |
julius |
// Break out the instruction
|
| 1386 |
|
|
if (3 != sscanf(pkt->data, "z%1d,%lx,%1d", (int *)&type, &addr, &len)) {
|
| 1387 |
|
|
cerr << "Warning: RSP matchpoint deletion request not "
|
| 1388 |
|
|
<< "recognized: ignored" << endl;
|
| 1389 |
|
|
pkt->packStr("E01");
|
| 1390 |
|
|
rsp->putPkt(pkt);
|
| 1391 |
|
|
return;
|
| 1392 |
63 |
julius |
}
|
| 1393 |
462 |
julius |
// Sanity check that the length is 4
|
| 1394 |
|
|
if (4 != len) {
|
| 1395 |
|
|
cerr << "Warning: RSP matchpoint deletion length " << len
|
| 1396 |
|
|
<< "not valid: 4 assumed" << endl;
|
| 1397 |
|
|
len = 4;
|
| 1398 |
63 |
julius |
}
|
| 1399 |
462 |
julius |
// Sort out the type of matchpoint
|
| 1400 |
|
|
switch (type) {
|
| 1401 |
|
|
case BP_MEMORY:
|
| 1402 |
|
|
// Memory breakpoint - replace the original instruction.
|
| 1403 |
|
|
if (mpHash->remove(type, addr, &instr)) {
|
| 1404 |
|
|
//cerr << "rspRemoveMatchpoint at 0x" << hex << addr << " restoring instruction: 0x" << hex << instr <<endl;
|
| 1405 |
|
|
debugUnit->writeMem32(addr, instr);
|
| 1406 |
|
|
}
|
| 1407 |
63 |
julius |
|
| 1408 |
462 |
julius |
pkt->packStr("OK");
|
| 1409 |
|
|
rsp->putPkt(pkt);
|
| 1410 |
|
|
return;
|
| 1411 |
63 |
julius |
|
| 1412 |
462 |
julius |
case BP_HARDWARE:
|
| 1413 |
|
|
int off;
|
| 1414 |
|
|
for (off = 0; off < 8; off++)
|
| 1415 |
|
|
if ((debugUnit->readSpr(SPR_DCR0 + off) == (0x23)) &&
|
| 1416 |
|
|
(debugUnit->readSpr(SPR_DVR0 + off) == addr))
|
| 1417 |
|
|
break;
|
| 1418 |
|
|
if (off > 7) {
|
| 1419 |
|
|
pkt->packStr("E02"); // Failed ot find breakpoint
|
| 1420 |
|
|
rsp->putPkt(pkt);
|
| 1421 |
|
|
return;
|
| 1422 |
|
|
}
|
| 1423 |
|
|
// Clear DCR's CT and DVR, WGB bit
|
| 1424 |
|
|
debugUnit->writeSpr(SPR_DCR0 + off, 0);
|
| 1425 |
|
|
debugUnit->writeSpr(SPR_DVR0 + off, 0);
|
| 1426 |
|
|
debugUnit->writeSpr(SPR_DMR2,
|
| 1427 |
|
|
debugUnit->readSpr(SPR_DMR2) & ~((1 << off)
|
| 1428 |
|
|
<<
|
| 1429 |
|
|
SPR_DMR2_WGB_SHIFT));
|
| 1430 |
|
|
pkt->packStr("OK");
|
| 1431 |
|
|
rsp->putPkt(pkt);
|
| 1432 |
|
|
return;
|
| 1433 |
63 |
julius |
|
| 1434 |
462 |
julius |
case WP_WRITE:
|
| 1435 |
|
|
{
|
| 1436 |
|
|
int off;
|
| 1437 |
|
|
for (off = 0; off < 8; off++) {
|
| 1438 |
|
|
if ((debugUnit->readSpr(SPR_DCR0 + off) ==
|
| 1439 |
|
|
(0x63))
|
| 1440 |
|
|
&& (debugUnit->readSpr(SPR_DVR0 + off) ==
|
| 1441 |
|
|
addr))
|
| 1442 |
|
|
break;
|
| 1443 |
|
|
}
|
| 1444 |
|
|
if (off > 7) {
|
| 1445 |
|
|
pkt->packStr("E02"); // Failed ot find breakpoint
|
| 1446 |
|
|
rsp->putPkt(pkt);
|
| 1447 |
|
|
return;
|
| 1448 |
|
|
}
|
| 1449 |
|
|
// Clear DCR's CT and DVR, WGB bit
|
| 1450 |
|
|
debugUnit->writeSpr(SPR_DCR0 + off, 0);
|
| 1451 |
|
|
debugUnit->writeSpr(SPR_DVR0 + off, 0);
|
| 1452 |
|
|
debugUnit->writeSpr(SPR_DMR2,
|
| 1453 |
|
|
debugUnit->readSpr(SPR_DMR2) &
|
| 1454 |
|
|
~((1 << off) <<
|
| 1455 |
|
|
SPR_DMR2_WGB_SHIFT));
|
| 1456 |
|
|
pkt->packStr("OK");
|
| 1457 |
|
|
rsp->putPkt(pkt);
|
| 1458 |
|
|
return;
|
| 1459 |
|
|
}
|
| 1460 |
63 |
julius |
|
| 1461 |
462 |
julius |
case WP_READ:
|
| 1462 |
|
|
{
|
| 1463 |
|
|
int off;
|
| 1464 |
|
|
for (off = 0; off < 8; off++) {
|
| 1465 |
|
|
if ((debugUnit->readSpr(SPR_DCR0 + off) ==
|
| 1466 |
|
|
(0x43))
|
| 1467 |
|
|
&& (debugUnit->readSpr(SPR_DVR0 + off) ==
|
| 1468 |
|
|
addr))
|
| 1469 |
|
|
break;
|
| 1470 |
|
|
}
|
| 1471 |
|
|
if (off > 7) {
|
| 1472 |
|
|
pkt->packStr("E02"); // Failed ot find breakpoint
|
| 1473 |
|
|
rsp->putPkt(pkt);
|
| 1474 |
|
|
return;
|
| 1475 |
|
|
}
|
| 1476 |
|
|
// Clear DCR's CT and DVR, WGB bit
|
| 1477 |
|
|
debugUnit->writeSpr(SPR_DCR0 + off, 0);
|
| 1478 |
|
|
debugUnit->writeSpr(SPR_DVR0 + off, 0);
|
| 1479 |
|
|
debugUnit->writeSpr(SPR_DMR2,
|
| 1480 |
|
|
debugUnit->readSpr(SPR_DMR2) &
|
| 1481 |
|
|
~((1 << off) <<
|
| 1482 |
|
|
SPR_DMR2_WGB_SHIFT));
|
| 1483 |
|
|
pkt->packStr("OK");
|
| 1484 |
|
|
rsp->putPkt(pkt);
|
| 1485 |
|
|
return;
|
| 1486 |
|
|
}
|
| 1487 |
63 |
julius |
|
| 1488 |
462 |
julius |
case WP_ACCESS:
|
| 1489 |
|
|
{
|
| 1490 |
|
|
int off;
|
| 1491 |
|
|
for (off = 0; off < 8; off++) {
|
| 1492 |
|
|
//printf("WP_ACCESS remove check off=%d DCR=0x%.8x DVR=0x%.8x\n",
|
| 1493 |
|
|
//off,debugUnit->readSpr (SPR_DCR0+off),debugUnit->readSpr (SPR_DVR0+off));
|
| 1494 |
|
|
if ((debugUnit->readSpr(SPR_DCR0 + off) ==
|
| 1495 |
|
|
(0xc3))
|
| 1496 |
|
|
&& (debugUnit->readSpr(SPR_DVR0 + off) ==
|
| 1497 |
|
|
addr))
|
| 1498 |
|
|
break;
|
| 1499 |
|
|
}
|
| 1500 |
|
|
if (off > 7) {
|
| 1501 |
|
|
//printf("rspRemoveWatchpoint: WP_ACCESS remove ERROR, regpair %d for 0x%.8x\n",off, addr);
|
| 1502 |
|
|
pkt->packStr("E02"); // Failed ot find breakpoint
|
| 1503 |
|
|
rsp->putPkt(pkt);
|
| 1504 |
|
|
return;
|
| 1505 |
|
|
}
|
| 1506 |
|
|
//printf("rspRemoveWatchpoint: WP_ACCESS remove, regpair %d for 0x%.8x\n",off, addr);
|
| 1507 |
|
|
|
| 1508 |
|
|
// Clear DCR's CT and DVR, WGB bit
|
| 1509 |
|
|
debugUnit->writeSpr(SPR_DCR0 + off, 0);
|
| 1510 |
|
|
debugUnit->writeSpr(SPR_DVR0 + off, 0);
|
| 1511 |
|
|
debugUnit->writeSpr(SPR_DMR2,
|
| 1512 |
|
|
debugUnit->readSpr(SPR_DMR2) &
|
| 1513 |
|
|
~((1 << off) <<
|
| 1514 |
|
|
SPR_DMR2_WGB_SHIFT));
|
| 1515 |
|
|
pkt->packStr("OK");
|
| 1516 |
|
|
rsp->putPkt(pkt);
|
| 1517 |
|
|
return;
|
| 1518 |
|
|
}
|
| 1519 |
|
|
default:
|
| 1520 |
|
|
cerr << "Warning: RSP matchpoint type " << type
|
| 1521 |
|
|
<< " not recognized: ignored" << endl;
|
| 1522 |
|
|
pkt->packStr("E01");
|
| 1523 |
|
|
rsp->putPkt(pkt);
|
| 1524 |
|
|
return;
|
| 1525 |
|
|
}
|
| 1526 |
|
|
} // rspRemoveMatchpoint ()
|
| 1527 |
|
|
|
| 1528 |
63 |
julius |
//---------------------------------------------------------------------------*/
|
| 1529 |
|
|
//! Handle a RSP insert breakpoint or matchpoint request
|
| 1530 |
|
|
|
| 1531 |
|
|
//! For now only memory breakpoints are implemented, which are implemented by
|
| 1532 |
|
|
//! substituting a breakpoint at the specified address. The implementation must
|
| 1533 |
|
|
//! cope with the possibility of duplicate packets.
|
| 1534 |
|
|
|
| 1535 |
|
|
//! @todo This doesn't work with icache/immu yet
|
| 1536 |
|
|
//---------------------------------------------------------------------------*/
|
| 1537 |
462 |
julius |
void GdbServerSC::rspInsertMatchpoint()
|
| 1538 |
63 |
julius |
{
|
| 1539 |
462 |
julius |
MpType type; // What sort of matchpoint
|
| 1540 |
|
|
uint32_t addr; // Address specified
|
| 1541 |
|
|
int len; // Matchpoint length (not used)
|
| 1542 |
63 |
julius |
|
| 1543 |
462 |
julius |
// Break out the instruction
|
| 1544 |
|
|
if (3 != sscanf(pkt->data, "Z%1d,%lx,%1d", (int *)&type, &addr, &len)) {
|
| 1545 |
|
|
cerr << "Warning: RSP matchpoint insertion request not "
|
| 1546 |
|
|
<< "recognized: ignored" << endl;
|
| 1547 |
|
|
pkt->packStr("E01");
|
| 1548 |
|
|
rsp->putPkt(pkt);
|
| 1549 |
|
|
return;
|
| 1550 |
|
|
}
|
| 1551 |
|
|
// Sanity check that the length is 4
|
| 1552 |
|
|
if (4 != len) {
|
| 1553 |
|
|
cerr << "Warning: RSP matchpoint insertion length " << len
|
| 1554 |
|
|
<< "not valid: 4 assumed" << endl;
|
| 1555 |
|
|
len = 4;
|
| 1556 |
|
|
}
|
| 1557 |
|
|
// Sort out the type of matchpoint
|
| 1558 |
|
|
switch (type) {
|
| 1559 |
|
|
case BP_MEMORY:
|
| 1560 |
|
|
// Memory breakpoint - substitute a TRAP instruction
|
| 1561 |
|
|
mpHash->add(type, addr, debugUnit->readMem32(addr));
|
| 1562 |
|
|
debugUnit->writeMem32(addr, OR1K_TRAP_INSTR);
|
| 1563 |
|
|
pkt->packStr("OK");
|
| 1564 |
|
|
rsp->putPkt(pkt);
|
| 1565 |
|
|
return;
|
| 1566 |
63 |
julius |
|
| 1567 |
462 |
julius |
case BP_HARDWARE:
|
| 1568 |
|
|
{
|
| 1569 |
|
|
int off;
|
| 1570 |
|
|
for (off = 0; off < 8; off++)
|
| 1571 |
|
|
if (!
|
| 1572 |
|
|
(debugUnit->readSpr(SPR_DCR0 + off) &
|
| 1573 |
|
|
SPR_DCR_CT_MASK))
|
| 1574 |
|
|
break;
|
| 1575 |
|
|
if (off > 7) {
|
| 1576 |
|
|
pkt->packStr(""); // No room
|
| 1577 |
|
|
rsp->putPkt(pkt);
|
| 1578 |
|
|
return;
|
| 1579 |
|
|
}
|
| 1580 |
|
|
// CC = equal, CT = Instruction fetch EA, set WGB bit
|
| 1581 |
|
|
debugUnit->writeSpr(SPR_DCR0 + off, 0x22);
|
| 1582 |
|
|
debugUnit->writeSpr(SPR_DVR0 + off, addr);
|
| 1583 |
|
|
debugUnit->writeSpr(SPR_DMR2,
|
| 1584 |
|
|
debugUnit->readSpr(SPR_DMR2) |
|
| 1585 |
|
|
((1 << off) << SPR_DMR2_WGB_SHIFT));
|
| 1586 |
|
|
pkt->packStr("OK");
|
| 1587 |
|
|
rsp->putPkt(pkt);
|
| 1588 |
|
|
return;
|
| 1589 |
|
|
}
|
| 1590 |
63 |
julius |
|
| 1591 |
462 |
julius |
case WP_WRITE:
|
| 1592 |
|
|
{
|
| 1593 |
|
|
int off;
|
| 1594 |
|
|
for (off = 0; off < 8; off++)
|
| 1595 |
|
|
if (!
|
| 1596 |
|
|
(debugUnit->readSpr(SPR_DCR0 + off) &
|
| 1597 |
|
|
SPR_DCR_CT_MASK))
|
| 1598 |
|
|
break;
|
| 1599 |
|
|
//printf("rspInsertWatchpoint: WP_WRITE, regpair %d for 0x%.8x\n",off, addr);
|
| 1600 |
|
|
if (off > 7) {
|
| 1601 |
|
|
pkt->packStr(""); // No room
|
| 1602 |
|
|
rsp->putPkt(pkt);
|
| 1603 |
|
|
return;
|
| 1604 |
|
|
}
|
| 1605 |
|
|
// CC = equal, CT = Store EA, set WGB bit
|
| 1606 |
|
|
debugUnit->writeSpr(SPR_DCR0 + off, 0x62);
|
| 1607 |
|
|
debugUnit->writeSpr(SPR_DVR0 + off, addr);
|
| 1608 |
|
|
debugUnit->writeSpr(SPR_DMR2,
|
| 1609 |
|
|
debugUnit->readSpr(SPR_DMR2) |
|
| 1610 |
|
|
((1 << off) << SPR_DMR2_WGB_SHIFT));
|
| 1611 |
|
|
pkt->packStr("OK");
|
| 1612 |
|
|
rsp->putPkt(pkt);
|
| 1613 |
|
|
return;
|
| 1614 |
|
|
}
|
| 1615 |
63 |
julius |
|
| 1616 |
462 |
julius |
case WP_READ:
|
| 1617 |
|
|
{
|
| 1618 |
|
|
int off;
|
| 1619 |
|
|
for (off = 0; off < 8; off++)
|
| 1620 |
|
|
if (!
|
| 1621 |
|
|
(debugUnit->readSpr(SPR_DCR0 + off) &
|
| 1622 |
|
|
SPR_DCR_CT_MASK))
|
| 1623 |
|
|
break;
|
| 1624 |
|
|
//printf("rspInsertWatchpoint: WP_WRITE, regpair %d for 0x%.8x\n",off, addr);
|
| 1625 |
|
|
if (off > 7) {
|
| 1626 |
|
|
pkt->packStr(""); // No room
|
| 1627 |
|
|
rsp->putPkt(pkt);
|
| 1628 |
|
|
return;
|
| 1629 |
|
|
}
|
| 1630 |
|
|
// CC = equal, CT = Load EA, set WGB bit
|
| 1631 |
|
|
debugUnit->writeSpr(SPR_DCR0 + off, 0x42);
|
| 1632 |
|
|
debugUnit->writeSpr(SPR_DVR0 + off, addr);
|
| 1633 |
|
|
debugUnit->writeSpr(SPR_DMR2,
|
| 1634 |
|
|
debugUnit->readSpr(SPR_DMR2) |
|
| 1635 |
|
|
((1 << off) << SPR_DMR2_WGB_SHIFT));
|
| 1636 |
|
|
pkt->packStr("OK");
|
| 1637 |
|
|
rsp->putPkt(pkt);
|
| 1638 |
|
|
return;
|
| 1639 |
|
|
}
|
| 1640 |
63 |
julius |
|
| 1641 |
462 |
julius |
pkt->packStr(""); // Not supported
|
| 1642 |
|
|
rsp->putPkt(pkt);
|
| 1643 |
|
|
return;
|
| 1644 |
63 |
julius |
|
| 1645 |
462 |
julius |
case WP_ACCESS:
|
| 1646 |
|
|
{
|
| 1647 |
|
|
int off;
|
| 1648 |
|
|
for (off = 0; off < 8; off++)
|
| 1649 |
|
|
if (!
|
| 1650 |
|
|
(debugUnit->readSpr(SPR_DCR0 + off) &
|
| 1651 |
|
|
SPR_DCR_CT_MASK))
|
| 1652 |
|
|
break;
|
| 1653 |
|
|
//printf("rspInsertWatchpoint: WP_ACCESS, regpair %d for 0x%.8x\n",off, addr);
|
| 1654 |
|
|
if (off > 7) {
|
| 1655 |
|
|
pkt->packStr(""); // No room
|
| 1656 |
|
|
rsp->putPkt(pkt);
|
| 1657 |
|
|
return;
|
| 1658 |
|
|
}
|
| 1659 |
|
|
// CC = equal, CT = Load/Store EA, set WGB bit
|
| 1660 |
|
|
debugUnit->writeSpr(SPR_DCR0 + off, 0xc2);
|
| 1661 |
|
|
debugUnit->writeSpr(SPR_DVR0 + off, addr);
|
| 1662 |
|
|
debugUnit->writeSpr(SPR_DMR2,
|
| 1663 |
|
|
debugUnit->readSpr(SPR_DMR2) |
|
| 1664 |
|
|
((1 << off) << SPR_DMR2_WGB_SHIFT));
|
| 1665 |
|
|
pkt->packStr("OK");
|
| 1666 |
|
|
rsp->putPkt(pkt);
|
| 1667 |
|
|
return;
|
| 1668 |
|
|
}
|
| 1669 |
63 |
julius |
|
| 1670 |
462 |
julius |
default:
|
| 1671 |
|
|
cerr << "Warning: RSP matchpoint type " << type
|
| 1672 |
|
|
<< "not recognized: ignored" << endl;
|
| 1673 |
|
|
pkt->packStr("E01");
|
| 1674 |
|
|
rsp->putPkt(pkt);
|
| 1675 |
|
|
return;
|
| 1676 |
|
|
}
|
| 1677 |
|
|
} // rspInsertMatchpoint ()
|
| 1678 |
63 |
julius |
|
| 1679 |
|
|
//-----------------------------------------------------------------------------
|
| 1680 |
|
|
//! Read the value of the Next Program Counter (a SPR)
|
| 1681 |
|
|
|
| 1682 |
|
|
//! A convenience routine.
|
| 1683 |
|
|
|
| 1684 |
|
|
//! Setting the NPC flushes the pipeline, so subsequent reads will return
|
| 1685 |
|
|
//! zero until the processor has refilled the pipeline. This will not be
|
| 1686 |
|
|
//! happening if the processor is stalled (as it is when GDB had control).
|
| 1687 |
|
|
|
| 1688 |
|
|
//! However for debugging we always want to know what the effective value of
|
| 1689 |
|
|
//! the NPC will be (i.e. the value that will be used once the pipeline has
|
| 1690 |
|
|
//! refilled). Fortunately SPR cacheing in the debug unit silently solves this
|
| 1691 |
|
|
//! for us.
|
| 1692 |
|
|
|
| 1693 |
|
|
//! @return The value of the NPC
|
| 1694 |
|
|
//-----------------------------------------------------------------------------
|
| 1695 |
462 |
julius |
uint32_t GdbServerSC::readNpc()
|
| 1696 |
63 |
julius |
{
|
| 1697 |
462 |
julius |
return debugUnit->readSpr(SPR_NPC);
|
| 1698 |
63 |
julius |
|
| 1699 |
462 |
julius |
} // readNpc ()
|
| 1700 |
63 |
julius |
|
| 1701 |
|
|
//-----------------------------------------------------------------------------
|
| 1702 |
|
|
//! Write the value of the Next Program Counter (a SPR)
|
| 1703 |
|
|
|
| 1704 |
|
|
//! A convenience function.
|
| 1705 |
|
|
|
| 1706 |
|
|
//! Setting the NPC flushes the pipeline, so subsequent reads will return
|
| 1707 |
|
|
//! zero until the processor has refilled the pipeline. This will not be
|
| 1708 |
|
|
//! happening if the processor is stalled (as it is when GDB had control).
|
| 1709 |
|
|
|
| 1710 |
|
|
//! However for debugging we always want to know what the effective value of
|
| 1711 |
|
|
//! the NPC will be (i.e. the value that will be used once the pipeline has
|
| 1712 |
|
|
//! refilled). Fortunately SPR cacheing in the debug unit silently solves this
|
| 1713 |
|
|
//! for us.
|
| 1714 |
|
|
|
| 1715 |
|
|
//! There is one other caveat for the NPC. We do not wish to write it (whether
|
| 1716 |
|
|
//! or not it is cached) if it has not changed. So unlike all other SPRs we
|
| 1717 |
|
|
//! always read it first before writing.
|
| 1718 |
|
|
|
| 1719 |
|
|
//! @param[in] The address to write into the NPC
|
| 1720 |
|
|
//-----------------------------------------------------------------------------
|
| 1721 |
462 |
julius |
void GdbServerSC::writeNpc(uint32_t addr)
|
| 1722 |
63 |
julius |
{
|
| 1723 |
462 |
julius |
if (addr != readNpc()) {
|
| 1724 |
|
|
debugUnit->writeSpr(SPR_NPC, addr);
|
| 1725 |
|
|
}
|
| 1726 |
|
|
} // writeNpc ()
|
| 1727 |
63 |
julius |
|
| 1728 |
|
|
//-----------------------------------------------------------------------------
|
| 1729 |
|
|
//! Read the value of an OpenRISC 1000 General Purpose Register
|
| 1730 |
|
|
|
| 1731 |
|
|
//! A convenience function. This is just a wrapper for reading a SPR, since
|
| 1732 |
|
|
//! the GPR's are mapped into SPR space
|
| 1733 |
|
|
|
| 1734 |
|
|
//! @param[in] regNum The GPR to read
|
| 1735 |
|
|
|
| 1736 |
|
|
//! @return The value of the GPR
|
| 1737 |
|
|
//-----------------------------------------------------------------------------
|
| 1738 |
462 |
julius |
uint32_t GdbServerSC::readGpr(int regNum)
|
| 1739 |
63 |
julius |
{
|
| 1740 |
462 |
julius |
return debugUnit->readSpr(SPR_GPR0 + regNum);
|
| 1741 |
63 |
julius |
|
| 1742 |
462 |
julius |
} // readGpr ()
|
| 1743 |
63 |
julius |
|
| 1744 |
|
|
//-----------------------------------------------------------------------------
|
| 1745 |
|
|
//! Write the value of an OpenRISC 1000 General Purpose Register
|
| 1746 |
|
|
|
| 1747 |
|
|
//! A convenience function. This is just a wrapper for writing a SPR, since
|
| 1748 |
|
|
//! the GPR's are mapped into SPR space
|
| 1749 |
|
|
|
| 1750 |
|
|
//! @param[in] regNum The GPR to read
|
| 1751 |
|
|
|
| 1752 |
|
|
//! @return The value of the GPR
|
| 1753 |
|
|
//-----------------------------------------------------------------------------
|
| 1754 |
462 |
julius |
void GdbServerSC::writeGpr(int regNum, uint32_t value)
|
| 1755 |
63 |
julius |
{
|
| 1756 |
462 |
julius |
debugUnit->writeSpr(SPR_GPR0 + regNum, value);
|
| 1757 |
63 |
julius |
|
| 1758 |
462 |
julius |
} // writeGpr ()
|
| 1759 |
63 |
julius |
|
| 1760 |
|
|
//-----------------------------------------------------------------------------
|
| 1761 |
|
|
//! Check if we received anything via the pipe from the or1200 monitor
|
| 1762 |
|
|
|
| 1763 |
|
|
//! We stall the processor, and behave in a manner similar to if an interrupt
|
| 1764 |
|
|
//! had been received. Perhaps the sigval should be set differently/more
|
| 1765 |
|
|
//! more appropriately.
|
| 1766 |
|
|
//! Read from the pipe should be NON-blocking.
|
| 1767 |
|
|
|
| 1768 |
|
|
//! @return false if nothing received, else true
|
| 1769 |
|
|
//-----------------------------------------------------------------------------
|
| 1770 |
462 |
julius |
bool GdbServerSC::checkMonitorPipe()
|
| 1771 |
63 |
julius |
{
|
| 1772 |
462 |
julius |
char readChar;
|
| 1773 |
|
|
int n = read(monitor_to_gdb_pipe[0][0], &readChar, sizeof(char));
|
| 1774 |
|
|
if (!(((n < 0) && (errno == EAGAIN)) || (n == 0)) && !targetStopped) {
|
| 1775 |
|
|
debugUnit->stall();
|
| 1776 |
|
|
// Send a stop reply response, manually set rsp.sigval to TARGET_SIGNAL_NONE
|
| 1777 |
|
|
rsp_sigval = TARGET_SIGNAL_NONE;
|
| 1778 |
|
|
rspReportException();
|
| 1779 |
|
|
targetStopped = true; // Processor now not running
|
| 1780 |
|
|
write(monitor_to_gdb_pipe[1][1], &readChar, sizeof(char));
|
| 1781 |
|
|
return true;
|
| 1782 |
|
|
}
|
| 1783 |
|
|
|
| 1784 |
|
|
return false;
|
| 1785 |
|
|
|
| 1786 |
|
|
} // checkMonitorPipe ()
|