base,sim: Adding monitor function to GDB

The remote protocol provides a monitor query. This query allows to
provide a implementation defined behavior in the stub.

I proposed to use this command as a way to quit simulation with a
message provided by the GDB client.

Thus calling "monitor my_message" in the client will exit the
simulation with the exit message "GDB_MONITOR:my_message".

This is implemented through a derived class based on
GlobalSimLoopExitEvent and a small addition to the based class that adds
a clean method that will be called when returning siumation after the
Event.

Change-Id: Ib5fda569edcf6733cbcc6240ef6d2ec4dc6502ec
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/63538
Maintainer: Bobby Bruce <bbruce@ucdavis.edu>
Reviewed-by: Bobby Bruce <bbruce@ucdavis.edu>
Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
Quentin Forcioli
2022-08-16 17:43:31 +02:00
parent 7230a3e7f0
commit d401b1fbad
5 changed files with 52 additions and 8 deletions

View File

@@ -157,6 +157,7 @@
#include "mem/translating_port_proxy.hh"
#include "sim/full_system.hh"
#include "sim/process.hh"
#include "sim/sim_events.hh"
#include "sim/system.hh"
namespace gem5
@@ -241,7 +242,7 @@ hex2c(char c0,char c1)
//this function will be used in a future patch
//convert a encoded string to a string
[[maybe_unused]] std::string
std::string
hexS2string(std::string hex_in)
{
std::string out="";
@@ -554,7 +555,6 @@ BaseRemoteGDB::trap(ContextID id, GDBSignal sig,const std::string& stopReason)
return;
if (tc->contextId() != id) {
//prevent thread switch when single stepping
if (singleStepEvent.scheduled()){
return;
@@ -564,11 +564,14 @@ BaseRemoteGDB::trap(ContextID id, GDBSignal sig,const std::string& stopReason)
return;
}
DPRINTF(GDBMisc, "trap: PC=%s\n", tc->pcState());
clearSingleStep();
if (threadSwitching) {
if (stopReason=="monitor_return"){
//should wnot send any Tpacket here
send("OK");
}else if (threadSwitching) {
threadSwitching = false;
// Tell GDB the thread switch has completed.
send("OK");
@@ -1326,6 +1329,7 @@ splitAt(std::string str, const char * const delim)
std::map<std::string, BaseRemoteGDB::QuerySetCommand>
BaseRemoteGDB::queryMap = {
{ "C", { &BaseRemoteGDB::queryC } },
{ "Rcmd", { &BaseRemoteGDB::queryRcmd} },
{ "Attached", { &BaseRemoteGDB::queryAttached} },
{ "Supported", { &BaseRemoteGDB::querySupported, ";" } },
{ "Xfer", { &BaseRemoteGDB::queryXfer } },
@@ -1416,6 +1420,38 @@ BaseRemoteGDB::queryAttached(QuerySetCommand::Context &ctx)
return true;
}
class MonitorCallEvent : public GlobalSimLoopExitEvent
{
BaseRemoteGDB& gdb;
ContextID id;
public:
MonitorCallEvent(BaseRemoteGDB& gdb,ContextID id,const std::string &_cause,
int code):
GlobalSimLoopExitEvent(_cause,code), gdb(gdb),id(id)
{};
void process() override{
GlobalSimLoopExitEvent::process();
}
void clean() override{
//trapping now
//this is the only point in time when we can call trap
//before any breakpoint triggers
gdb.trap(id,GDBSignal::ZERO,"monitor_return");
delete this;
}
~MonitorCallEvent(){
DPRINTF(Event,"MonitorCallEvent destructed\n");;
}
};
bool
BaseRemoteGDB::queryRcmd(QuerySetCommand::Context &ctx){
std::string message=hexS2string(ctx.args[0]);
DPRINTF(GDBMisc, "Rcmd Query: %s => %s\n", ctx.args[0],message);
//Tick when = curTick();
new MonitorCallEvent(*this,tc->contextId(),"GDB_MONITOR:"+ message, 0);
return false;
}
bool
BaseRemoteGDB::queryFThreadInfo(QuerySetCommand::Context &ctx)
@@ -1444,7 +1480,7 @@ BaseRemoteGDB::cmdQueryVar(GdbCommand::Context &ctx)
{
// The query command goes until the first ':', or the end of the string.
std::string s(ctx.data, ctx.len);
auto query_split = splitAt({ ctx.data, (size_t)ctx.len }, ":");
auto query_split = splitAt({ ctx.data, (size_t)ctx.len }, ":,");
const auto &query_str = query_split.first;
// Look up the query command, and report if it isn't found.

View File

@@ -433,6 +433,7 @@ class BaseRemoteGDB
bool querySupported(QuerySetCommand::Context &ctx);
bool queryXfer(QuerySetCommand::Context &ctx);
bool querySymbol(QuerySetCommand::Context &ctx);
bool queryRcmd(QuerySetCommand::Context &ctx);
bool queryAttached(QuerySetCommand::Context &ctx);
size_t threadInfoIdx = 0;

View File

@@ -46,6 +46,7 @@
#include "base/debug.hh"
#include "base/flags.hh"
#include "base/trace.hh"
#include "base/types.hh"
#include "base/uncontended_mutex.hh"
#include "debug/Event.hh"

View File

@@ -68,8 +68,11 @@ class GlobalSimLoopExitEvent : public GlobalEvent
const std::string getCause() const { return cause; }
int getCode() const { return code; }
void process(); // process event
virtual void process();// process event
virtual void clean(){};//cleaning event
~GlobalSimLoopExitEvent (){
DPRINTF(Event,"GlobalSimLoopExitEvent destructed\n");
};
virtual const char *description() const;
};

View File

@@ -184,9 +184,12 @@ struct DescheduleDeleter
* terminate the loop. Exported to Python.
* @return The SimLoopExitEvent that caused the loop to exit.
*/
GlobalSimLoopExitEvent *global_exit_event= nullptr;
GlobalSimLoopExitEvent *
simulate(Tick num_cycles)
{
if (global_exit_event)//cleaning last global exit event
global_exit_event->clean();
std::unique_ptr<GlobalSyncEvent, DescheduleDeleter> quantum_event;
const Tick exit_tick = num_cycles < MaxTick - curTick() ?
curTick() + num_cycles : MaxTick;
@@ -224,7 +227,7 @@ simulate(Tick num_cycles)
BaseGlobalEvent *global_event = local_event->globalEvent();
assert(global_event);
GlobalSimLoopExitEvent *global_exit_event =
global_exit_event =
dynamic_cast<GlobalSimLoopExitEvent *>(global_event);
assert(global_exit_event);