sim,cpu: Move the remote GDB stub into the workload.
There are two user visible effects of this change. First, all of the threads for a particular workload are moved under a single GDB instance. The GDB session can see all the threads at once, and can let you move between them as you want. Second, since there is a GDB instance per workload and not per CPU, the wait_for_gdb parameter was moved to the workload. Change-Id: I510410c3cbb56e445b0fbb1def94c769d3a7b2e3 Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/44617 Reviewed-by: Daniel Carvalho <odanrc@yahoo.com.br> Maintainer: Gabe Black <gabe.black@gmail.com> Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
@@ -146,9 +146,6 @@ class BaseCPU(ClockedObject):
|
||||
do_statistics_insts = Param.Bool(True,
|
||||
"enable statistics pseudo instructions")
|
||||
|
||||
wait_for_remote_gdb = Param.Bool(False,
|
||||
"Wait for a remote GDB connection");
|
||||
|
||||
workload = VectorParam.Process([], "processes to run")
|
||||
|
||||
mmu = Param.BaseMMU(ArchMMU(), "CPU memory management unit")
|
||||
|
||||
@@ -725,12 +725,6 @@ BaseCPU::traceFunctionsInternal(Addr pc)
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
BaseCPU::waitForRemoteGDB() const
|
||||
{
|
||||
return params().wait_for_remote_gdb;
|
||||
}
|
||||
|
||||
|
||||
BaseCPU::GlobalStats::GlobalStats(::Stats::Group *parent)
|
||||
: ::Stats::Group(parent),
|
||||
|
||||
@@ -609,8 +609,6 @@ class BaseCPU : public ClockedObject
|
||||
return &addressMonitor[tid];
|
||||
}
|
||||
|
||||
bool waitForRemoteGDB() const;
|
||||
|
||||
Cycles syscallRetryLatency;
|
||||
|
||||
// Enables CPU to enter power gating on a configurable cycle count
|
||||
|
||||
@@ -33,6 +33,9 @@ class Workload(SimObject):
|
||||
cxx_header = "sim/workload.hh"
|
||||
abstract = True
|
||||
|
||||
wait_for_remote_gdb = Param.Bool(False,
|
||||
"Wait for a remote GDB connection");
|
||||
|
||||
class KernelWorkload(Workload):
|
||||
type = 'KernelWorkload'
|
||||
cxx_header = "sim/kernel_workload.hh"
|
||||
|
||||
@@ -43,7 +43,6 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "arch/remote_gdb.hh"
|
||||
#include "base/compiler.hh"
|
||||
#include "base/loader/object_file.hh"
|
||||
#include "base/loader/symtab.hh"
|
||||
@@ -124,13 +123,6 @@ System::Threads::insert(ThreadContext *tc, ContextID id)
|
||||
// been reallocated.
|
||||
t.resumeEvent = new EventFunctionWrapper(
|
||||
[this, id](){ thread(id).resume(); }, sys->name());
|
||||
# if THE_ISA != NULL_ISA
|
||||
int port = getRemoteGDBPort();
|
||||
if (port) {
|
||||
t.gdb = new TheISA::RemoteGDB(sys, tc, port + id);
|
||||
t.gdb->listen();
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
void
|
||||
@@ -138,8 +130,6 @@ System::Threads::replace(ThreadContext *tc, ContextID id)
|
||||
{
|
||||
auto &t = thread(id);
|
||||
panic_if(!t.context, "Can't replace a context which doesn't exist.");
|
||||
if (t.gdb)
|
||||
t.gdb->replaceThreadContext(tc);
|
||||
# if THE_ISA != NULL_ISA
|
||||
if (t.resumeEvent->scheduled()) {
|
||||
Tick when = t.resumeEvent->when();
|
||||
@@ -277,26 +267,6 @@ System::~System()
|
||||
delete workItemStats[j];
|
||||
}
|
||||
|
||||
void
|
||||
System::startup()
|
||||
{
|
||||
SimObject::startup();
|
||||
|
||||
// Now that we're about to start simulation, wait for GDB connections if
|
||||
// requested.
|
||||
#if THE_ISA != NULL_ISA
|
||||
for (int i = 0; i < threads.size(); i++) {
|
||||
auto *gdb = threads.thread(i).gdb;
|
||||
auto *cpu = threads[i]->getCpuPtr();
|
||||
if (gdb && cpu->waitForRemoteGDB()) {
|
||||
inform("%s: Waiting for a remote GDB connection on port %d.",
|
||||
cpu->name(), gdb->port());
|
||||
gdb->connect();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Port &
|
||||
System::getPort(const std::string &if_name, PortID idx)
|
||||
{
|
||||
@@ -520,11 +490,7 @@ System::workItemEnd(uint32_t tid, uint32_t workid)
|
||||
bool
|
||||
System::trapToGdb(int signal, ContextID ctx_id) const
|
||||
{
|
||||
auto *gdb = threads.thread(ctx_id).gdb;
|
||||
if (!gdb)
|
||||
return false;
|
||||
gdb->trap(ctx_id, signal);
|
||||
return true;
|
||||
return workload && workload->trapToGdb(signal, ctx_id);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -119,7 +119,6 @@ class System : public SimObject, public PCEventScope
|
||||
{
|
||||
ThreadContext *context = nullptr;
|
||||
bool active = false;
|
||||
BaseRemoteGDB *gdb = nullptr;
|
||||
Event *resumeEvent = nullptr;
|
||||
|
||||
void resume();
|
||||
@@ -231,8 +230,6 @@ class System : public SimObject, public PCEventScope
|
||||
const_iterator end() const { return const_iterator(*this, size()); }
|
||||
};
|
||||
|
||||
void startup() override;
|
||||
|
||||
/**
|
||||
* Get a reference to the system port that can be used by
|
||||
* non-structural simulation objects like processes or threads, or
|
||||
|
||||
@@ -27,7 +27,10 @@
|
||||
|
||||
#include "sim/workload.hh"
|
||||
|
||||
#include "arch/remote_gdb.hh"
|
||||
#include "config/the_isa.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
#include "sim/debug.hh"
|
||||
|
||||
void
|
||||
Workload::registerThreadContext(ThreadContext *tc)
|
||||
@@ -37,6 +40,16 @@ Workload::registerThreadContext(ThreadContext *tc)
|
||||
std::tie(it, success) = threads.insert(tc);
|
||||
panic_if(!success, "Failed to add thread context %d.",
|
||||
tc->contextId());
|
||||
|
||||
# if THE_ISA != NULL_ISA
|
||||
int port = getRemoteGDBPort();
|
||||
if (port && !gdb) {
|
||||
gdb = new TheISA::RemoteGDB(system, tc, port);
|
||||
gdb->listen();
|
||||
} else if (gdb) {
|
||||
gdb->addThreadContext(tc);
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
void
|
||||
@@ -54,7 +67,39 @@ Workload::replaceThreadContext(ThreadContext *tc)
|
||||
std::tie(it, success) = threads.insert(tc);
|
||||
panic_if(!success,
|
||||
"Failed to insert replacement thread context %d.", id);
|
||||
|
||||
if (gdb)
|
||||
gdb->replaceThreadContext(tc);
|
||||
|
||||
return;
|
||||
}
|
||||
panic("Replacement thread context %d doesn't match any known id.", id);
|
||||
}
|
||||
|
||||
bool
|
||||
Workload::trapToGdb(int signal, ContextID ctx_id)
|
||||
{
|
||||
# if THE_ISA != NULL_ISA
|
||||
if (gdb) {
|
||||
gdb->trap(ctx_id, signal);
|
||||
return true;
|
||||
}
|
||||
# endif
|
||||
return false;
|
||||
};
|
||||
|
||||
void
|
||||
Workload::startup()
|
||||
{
|
||||
SimObject::startup();
|
||||
|
||||
# if THE_ISA != NULL_ISA
|
||||
// Now that we're about to start simulation, wait for GDB connections if
|
||||
// requested.
|
||||
if (gdb && waitForRemoteGDB) {
|
||||
inform("%s: Waiting for a remote GDB connection on port %d.", name(),
|
||||
gdb->port());
|
||||
gdb->connect();
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "sim/sim_object.hh"
|
||||
#include "sim/stats.hh"
|
||||
|
||||
class BaseRemoteGDB;
|
||||
class System;
|
||||
class ThreadContext;
|
||||
|
||||
@@ -66,20 +67,29 @@ class Workload : public SimObject
|
||||
{}
|
||||
} stats;
|
||||
|
||||
BaseRemoteGDB *gdb = nullptr;
|
||||
bool waitForRemoteGDB = false;
|
||||
std::set<ThreadContext *> threads;
|
||||
|
||||
public:
|
||||
Workload(const WorkloadParams ¶ms) : SimObject(params), stats(this)
|
||||
Workload(const WorkloadParams ¶ms) : SimObject(params), stats(this),
|
||||
waitForRemoteGDB(params.wait_for_remote_gdb)
|
||||
{}
|
||||
|
||||
void recordQuiesce() { stats.instStats.quiesce++; }
|
||||
void recordArm() { stats.instStats.arm++; }
|
||||
|
||||
// Once trapping into GDB is no longer a special case routed through the
|
||||
// system object, this helper can be removed.
|
||||
bool trapToGdb(int signal, ContextID ctx_id);
|
||||
|
||||
System *system = nullptr;
|
||||
|
||||
virtual void registerThreadContext(ThreadContext *tc);
|
||||
virtual void replaceThreadContext(ThreadContext *tc);
|
||||
|
||||
void startup() override;
|
||||
|
||||
virtual Addr getEntry() const = 0;
|
||||
virtual Loader::Arch getArch() const = 0;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user