Go to the documentation of this file.
132 #include <sys/select.h>
133 #include <sys/time.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)
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);
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;
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) {
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>
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();
void incomingData(int revent)
const ListenSocket & hostSocket() const
bool cmdUnsupported(GdbCommand::Context &ctx)
bool sendMessage(std::string message)
bool cmdVKill(GdbMultiLetterCommand::Context &ctx)
void scheduleTrapEvent(ContextID id, GDBSignal type, int delta, std::string stopReason)
static const char GDBStart
static std::map< std::string, GdbMultiLetterCommand > multiLetterMap
bool cmdDumpPageTable(GdbCommand::Context &ctx)
const std::string name() const override
void writeBlob(Addr addr, const void *p, int size) const
Same as tryWriteBlob, but insists on success.
bool cmdMultiLetter(GdbCommand::Context &ctx)
friend class HardBreakpoint
bool cmdSetThread(GdbCommand::Context &ctx)
void sendOPacket(const std::string message)
bool querySymbol(QuerySetCommand::Context &ctx)
bool cmdMultiUnsupported(GdbMultiLetterCommand::Context &ctx)
void insertSoftBreak(Addr addr, size_t kind)
virtual BaseGdbRegCache * gdbRegs()=0
bool cmdRegR(GdbCommand::Context &ctx)
static void output(const char *filename)
bool cmdIsThreadAlive(GdbCommand::Context &ctx)
void encodeBinaryData(const std::string &unencoded, std::string &encoded) const
void scheduleInstCommitEvent(Event *ev, int delta, ThreadContext *_tc)
Schedule an event which will be triggered "delta" instructions later.
virtual const PCStateBase & pcState() const =0
const std::string externalize() const
Dump all items in the pTable, to a concatenation of strings of the form Addr:Entry;.
void removeHardBreak(Addr addr, size_t kind)
static std::map< char, GdbCommand > commandMap
void insertHardBreak(Addr addr, size_t kind)
virtual ContextID contextId() const =0
virtual bool acc(Addr addr, size_t len)=0
bool read(Addr vaddr, size_t size, char *data)
MemberEventWrapper<&BaseRemoteGDB::singleStep > singleStepEvent
MemberEventWrapper<&BaseRemoteGDB::connect > connectEvent
bool cmdMemW(GdbCommand::Context &ctx)
bool cmdStep(GdbCommand::Context &ctx)
void stopReason(std::string s)
void remove(PollEvent *event)
ListenSocketPtr build(const std::string &name) const
void sendTPacket(GDBSignal sig, ContextID id, const std::string &stopReason)
bool queryXfer(QuerySetCommand::Context &ctx)
virtual Status status() const =0
BaseRemoteGDB(System *system, ListenSocketConfig _listen_config)
Interface to other parts of the simulator.
bool queryC(QuerySetCommand::Context &ctx)
This proxy attempts to translate virtual addresses using the TLBs.
bool queryRcmd(QuerySetCommand::Context &ctx)
virtual void getRegs(ThreadContext *)=0
Fill the raw buffer from the registers in the ThreadContext.
virtual Tick getCurrentInstCount()=0
IncomingDataEvent * incomingDataEvent
void encodeXferResponse(const std::string &unencoded, std::string &encoded, size_t offset, size_t unencoded_length) const
virtual std::vector< std::string > availableFeatures() const
IncomingConnectionEvent * incomingConnectionEvent
ThreadContext is the external interface to all thread state for anything outside of the CPU.
virtual bool writeBlob(Addr vaddr, size_t size, const char *data)
virtual std::string name() const
const GdbMultiLetterCommand * cmd
bool cmdSignal(GdbCommand::Context &ctx)
EmulationPageTable * pTable
void process(ThreadContext *tc) override
HardBreakpoint(BaseRemoteGDB *_gdb, PCEventScope *s, Addr pc)
bool cmdAsyncCont(GdbCommand::Context &ctx)
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).
This object is a proxy for a port or other object which implements the functional response protocol,...
MonitorCallEvent(BaseRemoteGDB &gdb, ContextID id, const std::string &_cause, int code)
static const char GDBGoodP
bool queryAttached(QuerySetCommand::Context &ctx)
virtual char * data() const =0
Return the pointer to the raw bytes buffer containing the register values.
void schedule(PollEvent *event)
bool querySupported(QuerySetCommand::Context &ctx)
gem5::BaseRemoteGDB::TrapEvent trapEvent
void readBlob(Addr addr, void *p, int size) const
Higher level interfaces based on the above.
bool querySThreadInfo(QuerySetCommand::Context &ctx)
void replaceThreadContext(ThreadContext *tc)
bool cmdRegW(GdbCommand::Context &ctx)
static bool allDisabled()
virtual bool getXferFeaturesRead(const std::string &annex, std::string &output)
Get an XML target description.
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
void removeSoftBreak(Addr addr, size_t kind)
SocketEvent<&BaseRemoteGDB::incomingData > IncomingDataEvent
bool write(Addr vaddr, size_t size, const char *data)
bool queryFThreadInfo(QuerySetCommand::Context &ctx)
#define DDUMP(x, data, count)
DPRINTF is a debugging trace facility that allows one to selectively enable tracing statements.
virtual void scheduleInstCountEvent(Event *event, Tick count)=0
SocketEvent<&BaseRemoteGDB::incomingConnection > IncomingConnectionEvent
virtual Process * getProcessPtr()=0
bool FullSystem
The FullSystem variable can be used to determine the current mode of simulation.
BaseGdbRegCache * regCachePtr
MemberEventWrapper<&BaseRemoteGDB::detach > disconnectEvent
void processCommands(GDBSignal sig=GDBSignal::ZERO)
bool selectThreadContext(ContextID id)
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
bool trap(ContextID id, int type)
bool cmdClrHwBkpt(GdbCommand::Context &ctx)
bool cmdSetHwBkpt(GdbCommand::Context &ctx)
virtual void setRegs(ThreadContext *) const =0
Set the ThreadContext's registers from the values in the raw buffer.
void send(const char *data)
virtual void descheduleInstCountEvent(Event *event)=0
void descheduleInstCommitEvent(Event *ev)
Deschedule an instruction count based event.
bool cmdReplyEmpty(GdbMultiLetterCommand::Context &ctx)
static std::map< std::string, QuerySetCommand > queryMap
void recv(std::vector< char > &bp)
bool cmdDetach(GdbCommand::Context &ctx)
int ContextID
Globally unique thread context ID.
void addThreadContext(ThreadContext *_tc)
std::vector< std::string > args
bool cmdMemR(GdbCommand::Context &ctx)
void sendSPacket(GDBSignal sig)
void incomingConnection(int revent)
bool cmdCont(GdbCommand::Context &ctx)
std::map< ContextID, ThreadContext * > threads
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
bool try_getbyte(uint8_t *c, int timeout=-1)
virtual bool readBlob(Addr vaddr, size_t size, char *data)
bool cmdAsyncStep(GdbCommand::Context &ctx)
bool cmdQueryVar(GdbCommand::Context &ctx)
static const char GDBBadP
bool scheduled() const
Determine if the current event is scheduled.
#define panic(...)
This implements a cprintf based panic() function.
virtual bool checkBpKind(size_t kind)
Generated on Sun Jul 30 2023 01:56:47 for gem5 by doxygen 1.8.17