132#include <sys/select.h>
153#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)
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);
237hex2c(
char c0,
char c1)
239 char temp[3] = {c0,c1,
'\0'};
240 return std::stoi(temp,0,16);
246hexS2string(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]));
257string2hexS(std::string in)
259 std::string out =
"";
262 std::snprintf(temp,3,
"%02hhx",ch);
272 return "0123456789abcdef"[
n & 0x0f];
277mem2hex(
char *vdst,
const char *vsrc,
int len)
280 const char *src = vsrc;
283 *dst++ = i2digit(*src >> 4);
284 *dst++ = i2digit(*src++);
294hex2mem(
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;
315hex2i(
const char **srcp)
317 const char *src = *srcp;
321 while ((nibble = digit2i(*src)) >= 0) {
331parseThreadId(
const char **srcp,
bool &
all,
bool &any,
ContextID &tid)
335 const char *src = *srcp;
367enum 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";
389std::map<Addr, HardBreakpoint *> hardBreakMap;
395 incomingConnectionEvent(nullptr), incomingDataEvent(nullptr),
396 fd(-1), sys(_system), connectEvent(*this), disconnectEvent(*this),
397 trapEvent(this), singleStepEvent(*this)
411 return sys->
name() +
".remote_gdb";
418 warn_once(
"Sockets disabled, not accepting gdb connections");
433 "Can't accept GDB connections without any threads!");
451 "Remote GDB socket is unknown until listen() has been called.");
509 assert(it_success.second);
558 DPRINTF(GDBMisc,
"Finishing thread switch");
567 if (stopReason==
"monitor_return"){
587 DPRINTF(GDBMisc,
"passing message %s\n", message);
596 warn(
"GDB connect event has already been scheduled!");
600 if (revent & POLLIN) {
609 warn(
"GDB trap event has already been scheduled!");
613 if (revent & POLLIN) {
615 }
else if (revent & POLLNVAL) {
633 panic(
"try_getbyte called with a null pointer as c");
643 struct timeval tv;
struct timeval* tv_ptr;
644 if (timeout_ms >= 0){
645 tv.tv_sec = timeout_ms/1000;
646 tv.tv_usec = timeout_ms%1000;
655 retval = ::select(
fd + 1, &rfds, NULL, NULL, tv_ptr);
656 if (retval < 0 && errno != EINTR){
657 DPRINTF(GDBMisc,
"getbyte failed errno=%i retval=%i\n",
659 throw BadClient(
"Couldn't read data from debugger.");
663 }
while (errno == EINTR);
668 if (res ==
sizeof(*
c))
679 throw BadClient(
"Couldn't write data to the debugger.");
710 csum -= digit2i(
getbyte()) * 16;
718 if (bp.size() > 2 && bp[2] ==
':') {
721 auto begin = std::begin(bp);
722 bp.erase(begin, std::next(begin, 3));
731 DPRINTF(GDBRecv,
"recv: %s\n", bp.data());
741 DPRINTF(GDBSend,
"send: %s\n", bp);
749 for (csum = 0; (
c = *
p);
p++) {
762 DPRINTF(GDBSend,
"PacketError\n");
780 if (
data.size() == 1)
789 DPRINTF(GDBMisc,
"Unknown command: %c(%#x)\n",
793 cmd_ctx.
cmd = &(cmd_it->second);
795 if (!(this->*(cmd_ctx.
cmd->
func))(cmd_ctx))
798 }
catch (BadClient &
e) {
803 }
catch (Unsupported &
e) {
805 }
catch (CmdError &
e) {
807 }
catch (std::exception &
e) {
808 panic(
"Unrecognized GDB exception: %s",
e.what());
810 panic(
"Unrecognized GDB exception.");
841 DPRINTF(GDBRead,
"read: addr=%#x, size=%d",
vaddr, size);
849 if (debug::GDBRead) {
850 if (debug::GDBExtra) {
852 mem2hex(buf,
data, size);
866 if (debug::GDBWrite) {
868 if (debug::GDBExtra) {
870 mem2hex(buf,
data, size);
903 throw BadClient(
"Invalid breakpoint kind.\n");
912 throw BadClient(
"Invalid breakpoint kind.\n");
921 throw BadClient(
"Invalid breakpoint kind.\n");
923 DPRINTF(GDBMisc,
"Inserting hardware breakpoint at %#x\n",
addr);
936 throw BadClient(
"Invalid breakpoint kind.\n");
938 DPRINTF(GDBMisc,
"Removing hardware breakpoint at %#x\n",
addr);
940 auto i = hardBreakMap.find(
addr);
941 if (
i == hardBreakMap.end())
942 throw CmdError(
"E0C");
947 hardBreakMap.erase(
i);
953 const std::string& stopReason)
955 if (!stopReason.empty()){
956 send(
"T%02xcore:%x;thread:%x;%s;",
957 (uint8_t)sig,
id + 1,
id + 1,stopReason);
959 send(
"T%02xcore:%x;thread:%x;",
960 (uint8_t)sig,
id + 1,
id + 1);
965 send(
"S%02x",(uint8_t)sig);
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) {
1279std::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();
1313splitAt(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));
1325std::map<std::string, BaseRemoteGDB::QuerySetCommand>
1347 std::ostringstream oss;
1351 oss <<
"PacketSize=1024";
1353 oss <<
';' << feature;
1361 auto split = splitAt(ctx.
args.at(0),
":");
1362 auto object = split.first;
1364 split = splitAt(split.second,
":");
1365 auto operation = split.first;
1368 if (
object !=
"features" || operation !=
"read")
1369 throw Unsupported();
1372 split = splitAt(split.second,
":");
1373 auto annex = split.first;
1376 std::string content;
1378 throw CmdError(
"E00");
1381 split = splitAt(split.second,
",");
1382 auto offset_str = split.first;
1383 auto length_str = split.second;
1385 const char *offset_ptr = offset_str.c_str();
1386 const char *length_ptr = length_str.c_str();
1387 auto offset = hex2i(&offset_ptr);
1388 auto length = hex2i(&length_ptr);
1389 if (offset_ptr != offset_str.c_str() + offset_str.length() ||
1390 length_ptr != length_str.c_str() + length_str.length()) {
1391 throw CmdError(
"E00");
1394 std::string encoded;
1410 if (!ctx.
args.empty() && !ctx.
args[0].empty()){
1413 DPRINTF(GDBMisc,
"QAttached : pid=%s\n",pid);
1435 gdb.
trap(
id,GDBSignal::ZERO,
"monitor_return");
1445 std::string message=hexS2string(ctx.
args[0]);
1446 DPRINTF(GDBMisc,
"Rcmd Query: %s => %s\n", ctx.
args[0],message);
1469 send(
"m%x", encodeThreadId(it->second->contextId()));
1479 auto query_split = splitAt({ ctx.
data, (size_t)ctx.
len },
":,");
1480 const auto &query_str = query_split.first;
1483 auto query_it =
queryMap.find(query_str);
1485 DPRINTF(GDBMisc,
"Unknown query %s\n",
s);
1486 throw Unsupported();
1492 const auto &query = query_it->second;
1493 auto remaining = std::move(query_split.second);
1494 if (!query.argSep) {
1495 qctx.
args.emplace_back(std::move(remaining));
1497 while (remaining !=
"") {
1498 auto arg_split = splitAt(remaining, query.argSep);
1499 qctx.
args.emplace_back(std::move(arg_split.first));
1500 remaining = std::move(arg_split.second);
1505 return (this->*(query.func))(qctx);
1516 const std::string &annex, std::string &
output)
1523 const std::string &unencoded, std::string &encoded)
const
1525 for (
const char&
c : unencoded) {
1526 if (
c ==
'$' ||
c ==
'#' ||
c ==
'}' ||
c ==
'*') {
1528 encoded +=
c ^ 0x20;
1537 std::string &encoded,
size_t offset,
size_t unencoded_length)
const
1539 if (
offset + unencoded_length < unencoded.length())
1556 const char *
p = ctx.
data;
1559 Addr new_pc = hex2i(&
p);
1570 const char *
p = ctx.
data;
1571 Addr new_pc = hex2i(&
p);
1581 const char *
p = ctx.
data;
1582 char sub_cmd = *
p++;
1584 throw CmdError(
"E0D");
1587 throw CmdError(
"E0D");
1588 size_t kind = hex2i(&
p);
1590 DPRINTF(GDBMisc,
"clear %s, addr=%#x, kind=%d\n",
1591 breakType(sub_cmd),
addr, kind);
1604 throw Unsupported();
1614 const char *
p = ctx.
data;
1615 char sub_cmd = *
p++;
1617 throw CmdError(
"E0D");
1620 throw CmdError(
"E0D");
1621 size_t kind = hex2i(&
p);
1623 DPRINTF(GDBMisc,
"set %s, addr=%#x, kind=%d\n",
1624 breakType(sub_cmd),
addr, kind);
1637 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)
bool queryAttached(QuerySetCommand::Context &ctx)
std::map< ContextID, ThreadContext * > threads
bool cmdQueryVar(GdbCommand::Context &ctx)
bool cmdCont(GdbCommand::Context &ctx)
virtual bool checkBpKind(size_t kind)
MemberEventWrapper<&BaseRemoteGDB::singleStep > singleStepEvent
bool cmdDetach(GdbCommand::Context &ctx)
bool cmdReplyEmpty(GdbMultiLetterCommand::Context &ctx)
static std::map< std::string, GdbMultiLetterCommand > multiLetterMap
void send(const char *data)
void incomingConnection(int revent)
IncomingConnectionEvent * incomingConnectionEvent
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)
bool querySupported(QuerySetCommand::Context &ctx)
bool queryRcmd(QuerySetCommand::Context &ctx)
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)
bool cmdAsyncStep(GdbCommand::Context &ctx)
virtual std::vector< std::string > availableFeatures() const
MemberEventWrapper<&BaseRemoteGDB::connect > connectEvent
void sendTPacket(GDBSignal sig, ContextID id, const std::string &stopReason)
MemberEventWrapper<&BaseRemoteGDB::detach > disconnectEvent
SocketEvent<&BaseRemoteGDB::incomingData > IncomingDataEvent
bool cmdSetHwBkpt(GdbCommand::Context &ctx)
bool querySThreadInfo(QuerySetCommand::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 encodeXferResponse(const std::string &unencoded, std::string &encoded, size_t offset, size_t unencoded_length) const
bool cmdSignal(GdbCommand::Context &ctx)
void sendSPacket(GDBSignal sig)
bool cmdMemR(GdbCommand::Context &ctx)
void descheduleInstCommitEvent(Event *ev)
Deschedule an instruction count based event.
bool read(Addr vaddr, size_t size, char *data)
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)
virtual bool acc(Addr addr, size_t len)=0
virtual BaseGdbRegCache * gdbRegs()=0
gem5::BaseRemoteGDB::TrapEvent trapEvent
bool write(Addr vaddr, size_t size, const char *data)
bool cmdMultiUnsupported(GdbMultiLetterCommand::Context &ctx)
bool cmdUnsupported(GdbCommand::Context &ctx)
friend class HardBreakpoint
bool cmdMultiLetter(GdbCommand::Context &ctx)
bool queryXfer(QuerySetCommand::Context &ctx)
bool cmdVKill(GdbMultiLetterCommand::Context &ctx)
BaseGdbRegCache * regCachePtr
bool cmdAsyncCont(GdbCommand::Context &ctx)
void sendOPacket(const std::string message)
bool querySymbol(QuerySetCommand::Context &ctx)
bool queryFThreadInfo(QuerySetCommand::Context &ctx)
void removeSoftBreak(Addr addr, size_t kind)
void processCommands(GDBSignal sig=GDBSignal::ZERO)
void replaceThreadContext(ThreadContext *tc)
bool queryC(QuerySetCommand::Context &ctx)
void insertHardBreak(Addr addr, size_t kind)
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
ListenSocketPtr build(const std::string &name) const
static bool allDisabled()
MonitorCallEvent(BaseRemoteGDB &gdb, ContextID id, const std::string &_cause, int code)
virtual std::string name() const
This object is a proxy for a port or other object which implements the functional response protocol,...
void readBlob(Addr addr, void *p, uint64_t size) const
Higher level interfaces based on the above.
void writeBlob(Addr addr, const void *p, uint64_t size) const
Same as tryWriteBlob, but insists on success.
EmulationPageTable * pTable
ThreadContext is the external interface to all thread state for anything outside of the CPU.
virtual void descheduleInstCountEvent(Event *event)=0
virtual Tick getCurrentInstCount()=0
virtual void scheduleInstCountEvent(Event *event, Tick count)=0
virtual const PCStateBase & pcState() const =0
virtual Status status() const =0
virtual Process * getProcessPtr()=0
virtual ContextID contextId() const =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 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.
const ListenSocket & hostSocket() const
void scheduleTrapEvent(ContextID id, GDBSignal type, int delta, std::string stopReason)
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).
virtual char * data() const =0
Return the pointer to the raw bytes buffer containing the register values.
void addThreadContext(ThreadContext *_tc)
BaseRemoteGDB(System *system, ListenSocketConfig _listen_config)
Interface to other parts of the simulator.
bool selectThreadContext(ContextID id)
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
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
PortProxy Object Declaration.
const GdbMultiLetterCommand * cmd
std::vector< std::string > args