132 #include <sys/select.h>
133 #include <sys/signal.h>
134 #include <sys/time.h>
154 #include "debug/GDBAll.hh"
184 DPRINTF(GDBMisc,
"creating hardware breakpoint at %#x\n",
evpc);
187 const std::string
name()
const override {
return gdb->
name() +
".hwbkpt"; }
192 DPRINTF(GDBMisc,
"handling hardware breakpoint at %#x\n",
pc());
205 BadClient(
const char *_warning=NULL) :
warning(_warning)
213 CmdError(std::string _error) :
error(_error)
218 class Unsupported {};
225 if (
c >=
'0' &&
c <=
'9')
227 else if (
c >=
'a' &&
c <=
'f')
228 return (
c -
'a' + 10);
229 else if (
c >=
'A' &&
c <=
'F')
230 return (
c -
'A' + 10);
237 hex2c(
char c0,
char c1)
239 char temp[3] = {c0,c1,
'\0'};
240 return std::stoi(temp,0,16);
245 [[maybe_unused]] std::string
246 hexS2string(std::string hex_in)
249 for (
unsigned int i = 0;
i + 1 < hex_in.length();
i += 2){
250 out.push_back(hex2c(hex_in[
i],hex_in[
i+1]));
257 string2hexS(std::string in)
259 std::string out =
"";
262 std::snprintf(temp,3,
"%02hhx",ch);
272 return "0123456789abcdef"[
n & 0x0f];
277 mem2hex(
char *vdst,
const char *vsrc,
int len)
280 const char *src = vsrc;
283 *dst++ = i2digit(*src >> 4);
284 *dst++ = i2digit(*src++);
294 hex2mem(
char *vdst,
const char *src,
int max_len)
299 while (*src && max_len--) {
300 msb = digit2i(*src++);
303 lsb = digit2i(*src++);
306 *dst++ = (msb << 4) | lsb;
315 hex2i(
const char **srcp)
317 const char *src = *srcp;
321 while ((nibble = digit2i(*src)) >= 0) {
331 parseThreadId(
const char **srcp,
bool &all,
bool &any,
ContextID &tid)
335 const char *src = *srcp;
367 enum GdbBreakpointType
380 case GdbSoftBp:
return "software breakpoint";
381 case GdbHardBp:
return "hardware breakpoint";
382 case GdbWriteWp:
return "write watchpoint";
383 case GdbReadWp:
return "read watchpoint";
384 case GdbAccWp:
return "access watchpoint";
385 default:
return "unknown breakpoint/watchpoint";
389 std::map<Addr, HardBreakpoint *> hardBreakMap;
394 incomingConnectionEvent(nullptr), incomingDataEvent(nullptr),
395 _port(_port),
fd(-1), sys(_system),
396 connectEvent(this), disconnectEvent(this), trapEvent(this),
397 singleStepEvent(*this)
409 return sys->
name() +
".remote_gdb";
416 warn_once(
"Sockets disabled, not accepting gdb connections");
429 ccprintf(std::cerr,
"%d: %s: listening for remote gdb on port %d\n",
437 "Can't accept GDB connections without any threads!");
455 "Remote GDB port is unknown until listen() has been called.\n");
513 assert(it_success.second);
563 DPRINTF(GDBMisc,
"Finishing thread switch");
589 DPRINTF(GDBMisc,
"passing message %s\n", message);
598 warn(
"GDB connect event has already been scheduled!");
602 if (revent & POLLIN) {
611 warn(
"GDB trap event has already been scheduled!");
615 if (revent & POLLIN) {
617 }
else if (revent & POLLNVAL) {
635 panic(
"try_getbyte called with a null pointer as c");
645 struct timeval tv;
struct timeval* tv_ptr;
646 if (timeout_ms >= 0){
647 tv.tv_sec = timeout_ms/1000;
648 tv.tv_usec = timeout_ms%1000;
657 retval = ::select(
fd + 1, &rfds, NULL, NULL, tv_ptr);
658 if (retval < 0 && errno != EINTR){
659 DPRINTF(GDBMisc,
"getbyte failed errno=%i retval=%i\n",
661 throw BadClient(
"Couldn't read data from debugger.");
665 }
while (errno == EINTR);
670 if (res ==
sizeof(*
c))
681 throw BadClient(
"Couldn't write data to the debugger.");
712 csum -= digit2i(
getbyte()) * 16;
720 if (bp.size() > 2 && bp[2] ==
':') {
723 auto begin = std::begin(bp);
724 bp.erase(begin, std::next(begin, 3));
733 DPRINTF(GDBRecv,
"recv: %s\n", bp.data());
743 DPRINTF(GDBSend,
"send: %s\n", bp);
751 for (csum = 0; (
c = *
p);
p++) {
764 DPRINTF(GDBSend,
"PacketError\n");
776 cmd_ctx.
type = signum;
782 if (
data.size() == 1)
791 DPRINTF(GDBMisc,
"Unknown command: %c(%#x)\n",
795 cmd_ctx.
cmd = &(cmd_it->second);
797 if (!(this->*(cmd_ctx.
cmd->
func))(cmd_ctx))
800 }
catch (BadClient &
e) {
805 }
catch (Unsupported &
e) {
807 }
catch (CmdError &
e) {
809 }
catch (std::exception &
e) {
810 panic(
"Unrecognized GDB exception: %s",
e.what());
812 panic(
"Unrecognized GDB exception.");
843 DPRINTF(GDBRead,
"read: addr=%#x, size=%d",
vaddr, size);
851 if (debug::GDBRead) {
852 if (debug::GDBExtra) {
854 mem2hex(buf,
data, size);
868 if (debug::GDBWrite) {
870 if (debug::GDBExtra) {
872 mem2hex(buf,
data, size);
905 throw BadClient(
"Invalid breakpoint kind.\n");
914 throw BadClient(
"Invalid breakpoint kind.\n");
923 throw BadClient(
"Invalid breakpoint kind.\n");
925 DPRINTF(GDBMisc,
"Inserting hardware breakpoint at %#x\n",
addr);
938 throw BadClient(
"Invalid breakpoint kind.\n");
940 DPRINTF(GDBMisc,
"Removing hardware breakpoint at %#x\n",
addr);
942 auto i = hardBreakMap.find(
addr);
943 if (
i == hardBreakMap.end())
944 throw CmdError(
"E0C");
949 hardBreakMap.erase(
i);
955 const std::string& stopReason)
957 if (!stopReason.empty()){
958 send(
"T%02xcore:%x;thread:%x;%s;",errnum,
id + 1,
id + 1,stopReason);
960 send(
"T%02xcore:%x;thread:%x;",errnum,
id + 1,
id + 1);
965 send(
"S%02x",errnum);
969 send(
"O" + string2hexS(message));
974 std::string stopReason){
976 panic_if(_tc ==
nullptr,
"Unknown context id :%i",
id);
1078 throw Unsupported();
1092 const char *
p = ctx.
data;
1094 Addr new_pc = hex2i(&
p);
1104 const char *
p = ctx.
data;
1107 Addr new_pc = hex2i(&
p);
1134 const char *
p = ctx.
data;
1136 if (
p == NULL || *
p !=
'\0')
1137 throw CmdError(
"E01");
1148 const char *
p = ctx.
data;
1149 char subcommand = *
p++;
1152 if (!parseThreadId(&
p, all, any, tid))
1153 throw CmdError(
"E01");
1155 if (subcommand ==
'c') {
1159 throw CmdError(
"E02");
1160 }
else if (subcommand ==
'g') {
1165 throw CmdError(
"E03");
1171 throw CmdError(
"E04");
1178 throw CmdError(
"E05");
1188 const char *
p = ctx.
data;
1191 if (!parseThreadId(&
p, all, any, tid))
1192 throw CmdError(
"E01");
1194 throw CmdError(
"E03");
1196 throw CmdError(
"E04");
1204 const char *
p = ctx.
data;
1207 throw CmdError(
"E02");
1208 size_t len = hex2i(&
p);
1210 throw CmdError(
"E03");
1212 throw CmdError(
"E05");
1216 throw CmdError(
"E05");
1218 char temp[2 *
len + 1];
1219 temp[2 *
len] =
'\0';
1220 mem2hex(temp, buf,
len);
1228 const char *
p = ctx.
data;
1231 throw CmdError(
"E06");
1232 size_t len = hex2i(&
p);
1234 throw CmdError(
"E07");
1236 throw CmdError(
"E08");
1238 p = (
char *)hex2mem(buf,
p,
len);
1240 throw CmdError(
"E09");
1242 throw CmdError(
"E0A");
1244 throw CmdError(
"E0B");
1254 strtok(ctx.
data,
";?");
1255 char* sep = strtok(NULL,
";:?");
1257 int txt_len = (sep != NULL) ? (sep - ctx.
data) : strlen(ctx.
data);
1258 DPRINTF(GDBMisc,
"Multi-letter: %s , len=%i\n", ctx.
data,txt_len);
1259 new_ctx.
cmdTxt = std::string(ctx.
data,txt_len);
1261 new_ctx.
len = ctx.
len - txt_len;
1266 throw Unsupported();
1268 new_ctx.
cmd = &(cmd_it->second);
1270 return (this->*(new_ctx.
cmd->
func))(new_ctx);
1273 }
catch (CmdError &
e) {
1279 std::map<std::string, BaseRemoteGDB::GdbMultiLetterCommand>
1296 warn(
"GDB command for kill received detaching instead");
1304 DPRINTF(GDBMisc,
"Unsupported Multi name command : %s\n",
1307 throw Unsupported();
1313 splitAt(std::string str,
const char *
const delim)
1315 size_t pos = str.find_first_of(delim);
1316 if (pos == std::string::npos)
1320 str.substr(0, pos), str.substr(pos + 1));
1325 std::map<std::string, BaseRemoteGDB::QuerySetCommand>
1345 std::ostringstream oss;
1349 oss <<
"PacketSize=1024";
1351 oss <<
';' << feature;
1358 auto split = splitAt(ctx.
args.at(0),
":");
1359 auto object = split.first;
1361 split = splitAt(split.second,
":");
1362 auto operation = split.first;
1365 if (
object !=
"features" || operation !=
"read")
1366 throw Unsupported();
1369 split = splitAt(split.second,
":");
1370 auto annex = split.first;
1373 std::string content;
1375 throw CmdError(
"E00");
1378 split = splitAt(split.second,
",");
1379 auto offset_str = split.first;
1380 auto length_str = split.second;
1382 const char *offset_ptr = offset_str.c_str();
1383 const char *length_ptr = length_str.c_str();
1384 auto offset = hex2i(&offset_ptr);
1385 auto length = hex2i(&length_ptr);
1386 if (offset_ptr != offset_str.c_str() + offset_str.length() ||
1387 length_ptr != length_str.c_str() + length_str.length()) {
1388 throw CmdError(
"E00");
1391 std::string encoded;
1406 if (!ctx.
args.empty() && !ctx.
args[0].empty()){
1409 DPRINTF(GDBMisc,
"QAttached : pid=%s\n",pid);
1431 send(
"m%x", encodeThreadId(it->second->contextId()));
1440 auto query_split = splitAt({ ctx.
data, (size_t)ctx.
len },
":");
1441 const auto &query_str = query_split.first;
1444 auto query_it =
queryMap.find(query_str);
1446 DPRINTF(GDBMisc,
"Unknown query %s\n",
s);
1447 throw Unsupported();
1453 const auto &query = query_it->second;
1454 auto remaining = std::move(query_split.second);
1455 if (!query.argSep) {
1456 qctx.
args.emplace_back(std::move(remaining));
1458 while (remaining !=
"") {
1459 auto arg_split = splitAt(remaining, query.argSep);
1460 qctx.
args.emplace_back(std::move(arg_split.first));
1461 remaining = std::move(arg_split.second);
1465 (this->*(query.func))(qctx);
1478 const std::string &annex, std::string &
output)
1485 const std::string &unencoded, std::string &encoded)
const
1487 for (
const char&
c : unencoded) {
1488 if (
c ==
'$' ||
c ==
'#' ||
c ==
'}' ||
c ==
'*') {
1490 encoded +=
c ^ 0x20;
1499 std::string &encoded,
size_t offset,
size_t unencoded_length)
const
1501 if (
offset + unencoded_length < unencoded.length())
1518 const char *
p = ctx.
data;
1521 Addr new_pc = hex2i(&
p);
1532 const char *
p = ctx.
data;
1533 Addr new_pc = hex2i(&
p);
1543 const char *
p = ctx.
data;
1544 char sub_cmd = *
p++;
1546 throw CmdError(
"E0D");
1549 throw CmdError(
"E0D");
1550 size_t kind = hex2i(&
p);
1552 DPRINTF(GDBMisc,
"clear %s, addr=%#x, kind=%d\n",
1553 breakType(sub_cmd),
addr, kind);
1566 throw Unsupported();
1576 const char *
p = ctx.
data;
1577 char sub_cmd = *
p++;
1579 throw CmdError(
"E0D");
1582 throw CmdError(
"E0D");
1583 size_t kind = hex2i(&
p);
1585 DPRINTF(GDBMisc,
"set %s, addr=%#x, kind=%d\n",
1586 breakType(sub_cmd),
addr, kind);
1599 throw Unsupported();
#define DDUMP(x, data, count)
DPRINTF is a debugging trace facility that allows one to selectively enable tracing statements.
void stopReason(std::string s)
void removeHardBreak(Addr addr, size_t kind)
std::map< ContextID, ThreadContext * > threads
void querySymbol(QuerySetCommand::Context &ctx)
bool cmdQueryVar(GdbCommand::Context &ctx)
bool cmdCont(GdbCommand::Context &ctx)
virtual bool checkBpKind(size_t kind)
EventWrapper< BaseRemoteGDB, &BaseRemoteGDB::connect > connectEvent
bool cmdDetach(GdbCommand::Context &ctx)
EventWrapper< BaseRemoteGDB, &BaseRemoteGDB::detach > disconnectEvent
bool cmdReplyEmpty(GdbMultiLetterCommand::Context &ctx)
EventWrapper< BaseRemoteGDB, &BaseRemoteGDB::singleStep > singleStepEvent
static std::map< std::string, GdbMultiLetterCommand > multiLetterMap
void send(const char *data)
void incomingConnection(int revent)
IncomingConnectionEvent * incomingConnectionEvent
void queryXfer(QuerySetCommand::Context &ctx)
void encodeBinaryData(const std::string &unencoded, std::string &encoded) const
void insertSoftBreak(Addr addr, size_t kind)
static std::map< std::string, QuerySetCommand > queryMap
virtual bool writeBlob(Addr vaddr, size_t size, const char *data)
bool cmdMemW(GdbCommand::Context &ctx)
void processCommands(int signum=0)
IncomingDataEvent * incomingDataEvent
bool cmdSetThread(GdbCommand::Context &ctx)
bool cmdClrHwBkpt(GdbCommand::Context &ctx)
bool cmdDumpPageTable(GdbCommand::Context &ctx)
static std::map< char, GdbCommand > commandMap
bool trap(ContextID id, int type)
void incomingData(int revent)
bool try_getbyte(uint8_t *c, int timeout=-1)
void sendSPacket(int errnum)
bool cmdAsyncStep(GdbCommand::Context &ctx)
virtual std::vector< std::string > availableFeatures() const
void queryFThreadInfo(QuerySetCommand::Context &ctx)
SocketEvent<&BaseRemoteGDB::incomingData > IncomingDataEvent
bool cmdSetHwBkpt(GdbCommand::Context &ctx)
bool cmdStep(GdbCommand::Context &ctx)
void recv(std::vector< char > &bp)
virtual bool getXferFeaturesRead(const std::string &annex, std::string &output)
Get an XML target description.
bool cmdRegW(GdbCommand::Context &ctx)
void queryAttached(QuerySetCommand::Context &ctx)
void encodeXferResponse(const std::string &unencoded, std::string &encoded, size_t offset, size_t unencoded_length) const
bool cmdSignal(GdbCommand::Context &ctx)
bool cmdMemR(GdbCommand::Context &ctx)
void descheduleInstCommitEvent(Event *ev)
Deschedule an instruction count based event.
bool read(Addr vaddr, size_t size, char *data)
void querySThreadInfo(QuerySetCommand::Context &ctx)
SocketEvent<&BaseRemoteGDB::incomingConnection > IncomingConnectionEvent
bool cmdRegR(GdbCommand::Context &ctx)
bool cmdIsThreadAlive(GdbCommand::Context &ctx)
void scheduleInstCommitEvent(Event *ev, int delta, ThreadContext *_tc)
Schedule an event which will be triggered "delta" instructions later.
virtual bool readBlob(Addr vaddr, size_t size, char *data)
void queryC(QuerySetCommand::Context &ctx)
virtual bool acc(Addr addr, size_t len)=0
gem5::BaseRemoteGDB::TrapEvent trapEvent
bool write(Addr vaddr, size_t size, const char *data)
bool cmdMultiUnsupported(GdbMultiLetterCommand::Context &ctx)
void querySupported(QuerySetCommand::Context &ctx)
bool cmdUnsupported(GdbCommand::Context &ctx)
void sendTPacket(int errnum, ContextID id, const std::string &stopReason)
friend class HardBreakpoint
bool cmdMultiLetter(GdbCommand::Context &ctx)
bool cmdVKill(GdbMultiLetterCommand::Context &ctx)
BaseGdbRegCache * regCachePtr
bool cmdAsyncCont(GdbCommand::Context &ctx)
void sendOPacket(const std::string message)
void removeSoftBreak(Addr addr, size_t kind)
void replaceThreadContext(ThreadContext *tc)
void insertHardBreak(Addr addr, size_t kind)
virtual BaseGdbRegCache * gdbRegs()=0
const std::string externalize() const
Dump all items in the pTable, to a concatenation of strings of the form Addr:Entry;.
const std::string name() const override
HardBreakpoint(BaseRemoteGDB *_gdb, PCEventScope *s, Addr pc)
void process(ThreadContext *tc) override
virtual bool listen(int port, bool reuse=true)
virtual int accept(bool nodelay=false)
static bool allDisabled()
virtual std::string name() const
This object is a proxy for a port or other object which implements the functional response protocol,...
void writeBlob(Addr addr, const void *p, int size) const
Same as tryWriteBlob, but insists on success.
void readBlob(Addr addr, void *p, int size) const
Higher level interfaces based on the above.
EmulationPageTable * pTable
ThreadContext is the external interface to all thread state for anything outside of the CPU.
virtual void descheduleInstCountEvent(Event *event)=0
virtual const PCStateBase & pcState() const =0
virtual Tick getCurrentInstCount()=0
virtual void scheduleInstCountEvent(Event *event, Tick count)=0
virtual Status status() const =0
virtual ContextID contextId() const =0
virtual Process * getProcessPtr()=0
This proxy attempts to translate virtual addresses using the TLBs.
bool scheduled() const
Determine if the current event is scheduled.
#define panic(...)
This implements a cprintf based panic() function.
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
void remove(PollEvent *event)
void schedule(PollEvent *event)
bool sendMessage(std::string message)
virtual char * data() const =0
Return the pointer to the raw bytes buffer containing the register values.
virtual void getRegs(ThreadContext *)=0
Fill the raw buffer from the registers in the ThreadContext.
virtual void setRegs(ThreadContext *) const =0
Set the ThreadContext's registers from the values in the raw buffer.
virtual size_t size() const =0
Return the size of the raw buffer, in bytes (i.e., half of the number of digits in the g/G packet).
void addThreadContext(ThreadContext *_tc)
BaseRemoteGDB(System *system, int _port)
Interface to other parts of the simulator.
void scheduleTrapEvent(ContextID id, int type, int delta, std::string stopReason)
bool selectThreadContext(ContextID id)
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
Tick curTick()
The universal simulation clock.
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
bool FullSystem
The FullSystem variable can be used to determine the current mode of simulation.
static void output(const char *filename)
static const char GDBBadP
int ContextID
Globally unique thread context ID.
static const char GDBGoodP
static const char GDBStart
void ccprintf(cp::Print &print)
PortProxy Object Declaration.
const GdbMultiLetterCommand * cmd
std::vector< std::string > args