157d156
< #ifndef NDEBUG
160,161c159
< void
< debugger()
---
> class HardBreakpoint : public PCEvent
163,169c161,172
< static int current_debugger = -1;
< if (current_debugger >= 0 && current_debugger < (int)debuggers.size()) {
< BaseRemoteGDB *gdb = debuggers[current_debugger];
< if (!gdb->isattached())
< gdb->listener->accept();
< if (gdb->isattached())
< gdb->trap(SIGILL);
---
> private:
> BaseRemoteGDB *gdb;
>
> public:
> int refcount;
>
> public:
> HardBreakpoint(BaseRemoteGDB *_gdb, PCEventQueue *q, Addr pc)
> : PCEvent(q, "HardBreakpoint Event", pc),
> gdb(_gdb), refcount(0)
> {
> DPRINTF(GDBMisc, "creating hardware breakpoint at %#x\n", evpc);
171,172d173
< }
< #endif
174,177c175
< ///////////////////////////////////////////////////////////
< //
< //
< //
---
> const std::string name() const { return gdb->name() + ".hwbkpt"; }
179,181c177,180
< GDBListener::InputEvent::InputEvent(GDBListener *l, int fd, int e)
< : PollEvent(fd, e), listener(l)
< {}
---
> void
> process(ThreadContext *tc) override
> {
> DPRINTF(GDBMisc, "handling hardware breakpoint at %#x\n", pc());
183,184c182,190
< void
< GDBListener::InputEvent::process(int revent)
---
> if (tc == gdb->tc)
> gdb->trap(SIGTRAP);
> }
> };
>
> namespace {
>
> // Exception to throw when the connection to the client is broken.
> struct BadClient
186,187c192,195
< listener->accept();
< }
---
> const char *warning;
> BadClient(const char *_warning=NULL) : warning(_warning)
> {}
> };
189,190c197,198
< GDBListener::GDBListener(BaseRemoteGDB *g, int p)
< : inputEvent(NULL), gdb(g), port(p)
---
> // Exception to throw when an error needs to be reported to the client.
> struct CmdError
192,194c200,203
< assert(!gdb->listener);
< gdb->listener = this;
< }
---
> string error;
> CmdError(std::string _error) : error(_error)
> {}
> };
196c205,211
< GDBListener::~GDBListener()
---
> // Exception to throw when something isn't supported.
> class Unsupported {};
>
> // Convert a hex digit into an integer.
> // This returns -1 if the argument passed is no valid hex digit.
> int
> digit2i(char c)
198c213,220
< delete inputEvent;
---
> if (c >= '0' && c <= '9')
> return (c - '0');
> else if (c >= 'a' && c <= 'f')
> return (c - 'a' + 10);
> else if (c >= 'A' && c <= 'F')
> return (c - 'A' + 10);
> else
> return (-1);
201,202c223,225
< string
< GDBListener::name()
---
> // Convert the low 4 bits of an integer into an hex digit.
> char
> i2digit(int n)
204c227
< return gdb->name() + ".listener";
---
> return ("0123456789abcdef"[n & 0x0f]);
206a230
> // Convert a byte array into an hex string.
208c232
< GDBListener::listen()
---
> mem2hex(char *vdst, const char *vsrc, int len)
210,213c234,235
< if (ListenSocket::allDisabled()) {
< warn_once("Sockets disabled, not accepting gdb connections");
< return;
< }
---
> char *dst = vdst;
> const char *src = vsrc;
215,217c237,239
< while (!listener.listen(port, true)) {
< DPRINTF(GDBMisc, "Can't bind port %d\n", port);
< port++;
---
> while (len--) {
> *dst++ = i2digit(*src >> 4);
> *dst++ = i2digit(*src++);
219,234c241
<
< inputEvent = new InputEvent(this, listener.getfd(), POLLIN);
< pollQueue.schedule(inputEvent);
<
< #ifndef NDEBUG
< gdb->number = debuggers.size();
< debuggers.push_back(gdb);
< #endif
<
< #ifndef NDEBUG
< ccprintf(cerr, "%d: %s: listening for remote gdb #%d on port %d\n",
< curTick(), name(), gdb->number, port);
< #else
< ccprintf(cerr, "%d: %s: listening for remote gdb on port %d\n",
< curTick(), name(), port);
< #endif
---
> *dst = '\0';
237,238c244,249
< void
< GDBListener::accept()
---
> // Convert an hex string into a byte array.
> // This returns a pointer to the character following the last valid
> // hex digit. If the string ends in the middle of a byte, NULL is
> // returned.
> const char *
> hex2mem(char *vdst, const char *src, int maxlen)
240,241c251,252
< if (!listener.islistening())
< panic("GDBListener::accept(): cannot accept if we're not listening!");
---
> char *dst = vdst;
> int msb, lsb;
243,249c254,261
< int sfd = listener.accept(true);
<
< if (sfd != -1) {
< if (gdb->isattached())
< close(sfd);
< else
< gdb->attach(sfd);
---
> while (*src && maxlen--) {
> msb = digit2i(*src++);
> if (msb < 0)
> return (src - 1);
> lsb = digit2i(*src++);
> if (lsb < 0)
> return (NULL);
> *dst++ = (msb << 4) | lsb;
250a263
> return src;
253,254c266,270
< int
< GDBListener::getPort() const
---
> // Convert an hex string into an integer.
> // This returns a pointer to the character following the last valid
> // hex digit.
> Addr
> hex2i(const char **srcp)
256,258c272,274
< panic_if(!listener.islistening(),
< "Remote GDB port is unknown until GDBListener::listen() has "
< "been called.\n");
---
> const char *src = *srcp;
> Addr r = 0;
> int nibble;
260c276,282
< return port;
---
> while ((nibble = digit2i(*src)) >= 0) {
> r *= 16;
> r += nibble;
> src++;
> }
> *srcp = src;
> return r;
263,265c285,291
< BaseRemoteGDB::InputEvent::InputEvent(BaseRemoteGDB *g, int fd, int e)
< : PollEvent(fd, e), gdb(g)
< {}
---
> enum GdbBreakpointType {
> GdbSoftBp = '0',
> GdbHardBp = '1',
> GdbWriteWp = '2',
> GdbReadWp = '3',
> GdbAccWp = '4',
> };
267,268c293,294
< void
< BaseRemoteGDB::InputEvent::process(int revent)
---
> const char *
> break_type(char c)
270,273c296,302
< if (gdb->trapEvent.scheduled()) {
< warn("GDB trap event has already been scheduled! "
< "Ignoring this input event.");
< return;
---
> switch(c) {
> case GdbSoftBp: return "software breakpoint";
> case GdbHardBp: return "hardware breakpoint";
> case GdbWriteWp: return "write watchpoint";
> case GdbReadWp: return "read watchpoint";
> case GdbAccWp: return "access watchpoint";
> default: return "unknown breakpoint/watchpoint";
275,282d303
<
< if (revent & POLLIN) {
< gdb->trapEvent.type(SIGILL);
< gdb->scheduleInstCommitEvent(&gdb->trapEvent, 0);
< } else if (revent & POLLNVAL) {
< gdb->descheduleInstCommitEvent(&gdb->trapEvent);
< gdb->detach();
< }
285,286c306,309
< void
< BaseRemoteGDB::TrapEvent::process()
---
> std::map<Addr, HardBreakpoint *> hardBreakMap;
>
> EventQueue *
> getComInstEventQueue(ThreadContext *tc)
288c311
< gdb->trap(_type);
---
> return tc->getCpuPtr()->comInstEventQueue[tc->threadId()];
291,296d313
< void
< BaseRemoteGDB::processSingleStepEvent()
< {
< if (!singleStepEvent.scheduled())
< scheduleInstCommitEvent(&singleStepEvent, 1);
< trap(SIGTRAP);
299,303c316,319
< BaseRemoteGDB::BaseRemoteGDB(System *_system, ThreadContext *c) :
< inputEvent(NULL), trapEvent(this), listener(NULL), number(-1),
< fd(-1), active(false), attached(false), system(_system),
< context(c),
< singleStepEvent([this]{ processSingleStepEvent(); }, name())
---
> BaseRemoteGDB::BaseRemoteGDB(System *_system, ThreadContext *c, int _port) :
> connectEvent(nullptr), dataEvent(nullptr), _port(_port), fd(-1),
> active(false), attached(false), sys(_system), tc(c),
> trapEvent(this), singleStepEvent(*this)
304a321
> debuggers.push_back(this);
309,310c326,327
< if (inputEvent)
< delete inputEvent;
---
> delete connectEvent;
> delete dataEvent;
316c333
< return system->name() + ".remote_gdb";
---
> return sys->name() + ".remote_gdb";
319,321c336,342
< bool
< BaseRemoteGDB::isattached()
< { return attached; }
---
> void
> BaseRemoteGDB::listen()
> {
> if (ListenSocket::allDisabled()) {
> warn_once("Sockets disabled, not accepting gdb connections");
> return;
> }
322a344,355
> while (!listener.listen(_port, true)) {
> DPRINTF(GDBMisc, "Can't bind port %d\n", _port);
> _port++;
> }
>
> connectEvent = new ConnectEvent(this, listener.getfd(), POLLIN);
> pollQueue.schedule(connectEvent);
>
> ccprintf(cerr, "%d: %s: listening for remote gdb on port %d\n",
> curTick(), name(), _port);
> }
>
323a357,380
> BaseRemoteGDB::connect()
> {
> panic_if(!listener.islistening(),
> "Cannot accept GDB connections if we're not listening!");
>
> int sfd = listener.accept(true);
>
> if (sfd != -1) {
> if (isAttached())
> close(sfd);
> else
> attach(sfd);
> }
> }
>
> int
> BaseRemoteGDB::port() const
> {
> panic_if(!listener.islistening(),
> "Remote GDB port is unknown until listen() has been called.\n");
> return _port;
> }
>
> void
328,329c385,386
< inputEvent = new InputEvent(this, fd, POLLIN);
< pollQueue.schedule(inputEvent);
---
> dataEvent = new DataEvent(this, fd, POLLIN);
> pollQueue.schedule(dataEvent);
344c401
< pollQueue.remove(inputEvent);
---
> pollQueue.remove(dataEvent);
348,350c405,412
< /////////////////////////
< //
< //
---
> // This function does all command processing for interfacing to a
> // remote gdb. Note that the error codes are ignored by gdb at
> // present, but might eventually become meaningful. (XXX) It might
> // makes sense to use POSIX errno values, because that is what the
> // gdb/remote.c functions want to return.
> bool
> BaseRemoteGDB::trap(int type)
> {
351a414,501
> if (!attached)
> return false;
>
> DPRINTF(GDBMisc, "trap: PC=%s\n", tc->pcState());
>
> clearSingleStep();
>
> /*
> * The first entry to this function is normally through
> * a breakpoint trap in kgdb_connect(), in which case we
> * must advance past the breakpoint because gdb will not.
> *
> * On the first entry here, we expect that gdb is not yet
> * listening to us, so just enter the interaction loop.
> * After the debugger is "active" (connected) it will be
> * waiting for a "signaled" message from us.
> */
> if (!active) {
> active = true;
> } else {
> // Tell remote host that an exception has occurred.
> send(csprintf("S%02x", type).c_str());
> }
>
> // Stick frame regs into our reg cache.
> regCachePtr = gdbRegs();
> regCachePtr->getRegs(tc);
>
> char data[GDBPacketBufLen + 1];
> GdbCommand::Context cmdCtx;
> cmdCtx.type = type;
> cmdCtx.data = &data[1];
>
> for (;;) {
> try {
> size_t datalen = recv(data, sizeof(data));
> if (datalen < 1)
> throw BadClient();
>
> data[datalen] = 0; // Sentinel
> cmdCtx.cmd_byte = data[0];
> cmdCtx.len = datalen - 1;
>
> auto cmdIt = command_map.find(cmdCtx.cmd_byte);
> if (cmdIt == command_map.end()) {
> DPRINTF(GDBMisc, "Unknown command: %c(%#x)\n",
> cmdCtx.cmd_byte, cmdCtx.cmd_byte);
> throw Unsupported();
> }
> cmdCtx.cmd = &(cmdIt->second);
>
> if (!(this->*(cmdCtx.cmd->func))(cmdCtx))
> break;
>
> } catch (BadClient &e) {
> if (e.warning)
> warn(e.warning);
> detach();
> break;
> } catch (Unsupported &e) {
> send("");
> } catch (CmdError &e) {
> send(e.error.c_str());
> } catch (...) {
> panic("Unrecognzied GDB exception.");
> }
> }
>
> return true;
> }
>
> void
> BaseRemoteGDB::incomingData(int revent)
> {
> if (trapEvent.scheduled()) {
> warn("GDB trap event has already been scheduled!");
> return;
> }
>
> if (revent & POLLIN) {
> trapEvent.type(SIGILL);
> scheduleInstCommitEvent(&trapEvent, 0);
> } else if (revent & POLLNVAL) {
> descheduleInstCommitEvent(&trapEvent);
> detach();
> }
> }
>
371,399d520
< // Send a packet to gdb
< void
< BaseRemoteGDB::send(const char *bp)
< {
< const char *p;
< uint8_t csum, c;
<
< DPRINTF(GDBSend, "send: %s\n", bp);
<
< do {
< p = bp;
< // Start sending a packet
< putbyte(GDBStart);
< // Send the contents, and also keep a check sum.
< for (csum = 0; (c = *p); p++) {
< putbyte(c);
< csum += c;
< }
< // Send the ending character.
< putbyte(GDBEnd);
< // Send the checksum.
< putbyte(i2digit(csum >> 4));
< putbyte(i2digit(csum));
< // Try transmitting over and over again until the other end doesn't
< // send an error back.
< c = getbyte();
< } while ((c & 0x7f) == GDBBadP);
< }
<
462a584,612
> // Send a packet to gdb
> void
> BaseRemoteGDB::send(const char *bp)
> {
> const char *p;
> uint8_t csum, c;
>
> DPRINTF(GDBSend, "send: %s\n", bp);
>
> do {
> p = bp;
> // Start sending a packet
> putbyte(GDBStart);
> // Send the contents, and also keep a check sum.
> for (csum = 0; (c = *p); p++) {
> putbyte(c);
> csum += c;
> }
> // Send the ending character.
> putbyte(GDBEnd);
> // Send the checksum.
> putbyte(i2digit(csum >> 4));
> putbyte(i2digit(csum));
> // Try transmitting over and over again until the other end doesn't
> // send an error back.
> c = getbyte();
> } while ((c & 0x7f) == GDBBadP);
> }
>
478c628
< FSTranslatingPortProxy &proxy = context->getVirtProxy();
---
> FSTranslatingPortProxy &proxy = tc->getVirtProxy();
481c631
< SETranslatingPortProxy &proxy = context->getMemProxy();
---
> SETranslatingPortProxy &proxy = tc->getMemProxy();
521c671
< FSTranslatingPortProxy &proxy = context->getVirtProxy();
---
> FSTranslatingPortProxy &proxy = tc->getVirtProxy();
524c674
< SETranslatingPortProxy &proxy = context->getMemProxy();
---
> SETranslatingPortProxy &proxy = tc->getMemProxy();
532c682
< BaseRemoteGDB::clearSingleStep()
---
> BaseRemoteGDB::singleStep()
534,539d683
< descheduleInstCommitEvent(&singleStepEvent);
< }
<
< void
< BaseRemoteGDB::setSingleStep()
< {
541a686
> trap(SIGTRAP);
544,555d688
< PCEventQueue *BaseRemoteGDB::getPcEventQueue()
< {
< return &system->pcEventQueue;
< }
<
< EventQueue *
< BaseRemoteGDB::getComInstEventQueue()
< {
< BaseCPU *cpu = context->getCpuPtr();
< return cpu->comInstEventQueue[context->threadId()];
< }
<
557c690
< BaseRemoteGDB::scheduleInstCommitEvent(Event *ev, int delta)
---
> BaseRemoteGDB::clearSingleStep()
559,562c692
< EventQueue *eq = getComInstEventQueue();
< // Here "ticks" aren't simulator ticks which measure time, they're
< // instructions committed by the CPU.
< eq->schedule(ev, eq->getCurTick() + delta);
---
> descheduleInstCommitEvent(&singleStepEvent);
566c696
< BaseRemoteGDB::descheduleInstCommitEvent(Event *ev)
---
> BaseRemoteGDB::setSingleStep()
568,569c698,699
< if (ev->scheduled())
< getComInstEventQueue()->deschedule(ev);
---
> if (!singleStepEvent.scheduled())
> scheduleInstCommitEvent(&singleStepEvent, 1);
572,584d701
< bool
< BaseRemoteGDB::checkBpLen(size_t len)
< {
< return len == sizeof(MachInst);
< }
<
< BaseRemoteGDB::HardBreakpoint::HardBreakpoint(BaseRemoteGDB *_gdb, Addr pc)
< : PCEvent(_gdb->getPcEventQueue(), "HardBreakpoint Event", pc),
< gdb(_gdb), refcount(0)
< {
< DPRINTF(GDBMisc, "creating hardware breakpoint at %#x\n", evpc);
< }
<
586,594d702
< BaseRemoteGDB::HardBreakpoint::process(ThreadContext *tc)
< {
< DPRINTF(GDBMisc, "handling hardware breakpoint at %#x\n", pc());
<
< if (tc == gdb->context)
< gdb->trap(SIGTRAP);
< }
<
< void
622c730
< bkpt = new HardBreakpoint(this, addr);
---
> bkpt = new HardBreakpoint(this, &sys->pcEventQueue, addr);
635c743
< break_iter_t i = hardBreakMap.find(addr);
---
> auto i = hardBreakMap.find(addr);
646a755,762
> BaseRemoteGDB::clearTempBreakpoint(Addr &bkpt)
> {
> DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n", bkpt);
> removeHardBreak(bkpt, sizeof(TheISA::MachInst));
> bkpt = 0;
> }
>
> void
654c770
< BaseRemoteGDB::clearTempBreakpoint(Addr &bkpt)
---
> BaseRemoteGDB::scheduleInstCommitEvent(Event *ev, int delta)
656,658c772,775
< DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n", bkpt);
< removeHardBreak(bkpt, sizeof(TheISA::MachInst));
< bkpt = 0;
---
> EventQueue *eq = getComInstEventQueue(tc);
> // Here "ticks" aren't simulator ticks which measure time, they're
> // instructions committed by the CPU.
> eq->schedule(ev, eq->getCurTick() + delta);
661,670c778,779
< enum GdbBreakpointType {
< GdbSoftBp = '0',
< GdbHardBp = '1',
< GdbWriteWp = '2',
< GdbReadWp = '3',
< GdbAccWp = '4',
< };
<
< const char *
< BaseRemoteGDB::break_type(char c)
---
> void
> BaseRemoteGDB::descheduleInstCommitEvent(Event *ev)
672,679c781,782
< switch(c) {
< case GdbSoftBp: return "software breakpoint";
< case GdbHardBp: return "hardware breakpoint";
< case GdbWriteWp: return "write watchpoint";
< case GdbReadWp: return "read watchpoint";
< case GdbAccWp: return "access watchpoint";
< default: return "unknown breakpoint/watchpoint";
< }
---
> if (ev->scheduled())
> getComInstEventQueue(tc)->deschedule(ev);
682c785
< std::map<char, GdbCommand> BaseRemoteGDB::command_map = {
---
> std::map<char, BaseRemoteGDB::GdbCommand> BaseRemoteGDB::command_map = {
738a842,846
> bool
> BaseRemoteGDB::checkBpLen(size_t len)
> {
> return len == sizeof(MachInst);
> }
762c870
< context->pcState(newPc);
---
> tc->pcState(newPc);
775c883
< context->pcState(newPc);
---
> tc->pcState(newPc);
806c914
< regCachePtr->setRegs(context);
---
> regCachePtr->setRegs(tc);
886c994
< context->pcState(newPc);
---
> tc->pcState(newPc);
898c1006
< context->pcState(newPc);
---
> tc->pcState(newPc);
969,1126d1076
<
<
< // This function does all command processing for interfacing to a
< // remote gdb. Note that the error codes are ignored by gdb at
< // present, but might eventually become meaningful. (XXX) It might
< // makes sense to use POSIX errno values, because that is what the
< // gdb/remote.c functions want to return.
< bool
< BaseRemoteGDB::trap(int type)
< {
<
< if (!attached)
< return false;
<
< DPRINTF(GDBMisc, "trap: PC=%s\n", context->pcState());
<
< clearSingleStep();
<
< /*
< * The first entry to this function is normally through
< * a breakpoint trap in kgdb_connect(), in which case we
< * must advance past the breakpoint because gdb will not.
< *
< * On the first entry here, we expect that gdb is not yet
< * listening to us, so just enter the interaction loop.
< * After the debugger is "active" (connected) it will be
< * waiting for a "signaled" message from us.
< */
< if (!active) {
< active = true;
< } else {
< // Tell remote host that an exception has occurred.
< send(csprintf("S%02x", type).c_str());
< }
<
< // Stick frame regs into our reg cache.
< regCachePtr = gdbRegs();
< regCachePtr->getRegs(context);
<
< char data[GDBPacketBufLen + 1];
< GdbCommand::Context cmdCtx;
< cmdCtx.type = type;
< cmdCtx.data = &data[1];
<
< for (;;) {
< try {
< size_t datalen = recv(data, sizeof(data));
< if (datalen < 1)
< throw BadClient();
<
< data[datalen] = 0; // Sentinel
< cmdCtx.cmd_byte = data[0];
< cmdCtx.len = datalen - 1;
<
< auto cmdIt = command_map.find(cmdCtx.cmd_byte);
< if (cmdIt == command_map.end()) {
< DPRINTF(GDBMisc, "Unknown command: %c(%#x)\n",
< cmdCtx.cmd_byte, cmdCtx.cmd_byte);
< throw Unsupported();
< }
< cmdCtx.cmd = &(cmdIt->second);
<
< if (!(this->*(cmdCtx.cmd->func))(cmdCtx))
< break;
<
< } catch (BadClient &e) {
< if (e.warning)
< warn(e.warning);
< detach();
< break;
< } catch (Unsupported &e) {
< send("");
< } catch (CmdError &e) {
< send(e.error.c_str());
< } catch (...) {
< panic("Unrecognzied GDB exception.");
< }
< }
<
< return true;
< }
<
< // Convert a hex digit into an integer.
< // This returns -1 if the argument passed is no valid hex digit.
< int
< BaseRemoteGDB::digit2i(char c)
< {
< if (c >= '0' && c <= '9')
< return (c - '0');
< else if (c >= 'a' && c <= 'f')
< return (c - 'a' + 10);
< else if (c >= 'A' && c <= 'F')
< return (c - 'A' + 10);
< else
< return (-1);
< }
<
< // Convert the low 4 bits of an integer into an hex digit.
< char
< BaseRemoteGDB::i2digit(int n)
< {
< return ("0123456789abcdef"[n & 0x0f]);
< }
<
< // Convert a byte array into an hex string.
< void
< BaseRemoteGDB::mem2hex(char *vdst, const char *vsrc, int len)
< {
< char *dst = vdst;
< const char *src = vsrc;
<
< while (len--) {
< *dst++ = i2digit(*src >> 4);
< *dst++ = i2digit(*src++);
< }
< *dst = '\0';
< }
<
< // Convert an hex string into a byte array.
< // This returns a pointer to the character following the last valid
< // hex digit. If the string ends in the middle of a byte, NULL is
< // returned.
< const char *
< BaseRemoteGDB::hex2mem(char *vdst, const char *src, int maxlen)
< {
< char *dst = vdst;
< int msb, lsb;
<
< while (*src && maxlen--) {
< msb = digit2i(*src++);
< if (msb < 0)
< return (src - 1);
< lsb = digit2i(*src++);
< if (lsb < 0)
< return (NULL);
< *dst++ = (msb << 4) | lsb;
< }
< return src;
< }
<
< // Convert an hex string into an integer.
< // This returns a pointer to the character following the last valid
< // hex digit.
< Addr
< BaseRemoteGDB::hex2i(const char **srcp)
< {
< const char *src = *srcp;
< Addr r = 0;
< int nibble;
<
< while ((nibble = digit2i(*src)) >= 0) {
< r *= 16;
< r += nibble;
< src++;
< }
< *srcp = src;
< return r;
< }