# Node ID 209b75a0b6f13f741d8d111092f6b72e58dbe9ed # Parent 2a1d75864ad2dbb6d381e9e98c77b0c7284ae324 diff --git a/configs/common/Options.py b/configs/common/Options.py --- a/configs/common/Options.py +++ b/configs/common/Options.py @@ -117,6 +117,9 @@ # Enable Ruby parser.add_option("--ruby", action="store_true") + # Enable remote debugging with GDB + parser.add_option("--rgdb-wait", action="store_true") + # Run duration options parser.add_option("-m", "--abs-max-tick", type="int", default=m5.MaxTick, metavar="TICKS", help="Run to absolute simulated tick " \ diff --git a/configs/example/fs.py b/configs/example/fs.py --- a/configs/example/fs.py +++ b/configs/example/fs.py @@ -192,6 +192,8 @@ if options.checker: test_sys.cpu[i].addCheckerCpu() test_sys.cpu[i].createThreads() + if options.rgdb_wait: + test_sys.cpu[i].rgdb_wait = True CacheConfig.config_cache(options, test_sys) MemConfig.config_mem(options, test_sys) diff --git a/configs/example/se.py b/configs/example/se.py --- a/configs/example/se.py +++ b/configs/example/se.py @@ -221,6 +221,9 @@ system.cpu[i].createThreads() + if options.rgdb_wait: + system.cpu[i].rgdb_wait = True + if options.ruby: if not (options.cpu_type == "detailed" or options.cpu_type == "timing"): print >> sys.stderr, "Ruby requires TimingSimpleCPU or O3CPU!!" diff --git a/src/arch/x86/faults.cc b/src/arch/x86/faults.cc --- a/src/arch/x86/faults.cc +++ b/src/arch/x86/faults.cc @@ -47,6 +47,8 @@ #include "cpu/thread_context.hh" #include "debug/Faults.hh" #include "sim/full_system.hh" +#include "sim/system.hh" +#include "base/remote_gdb.hh" namespace X86ISA { @@ -149,6 +151,7 @@ tc->setMiscReg(MISCREG_CR2, (uint32_t)addr); } } else { + PageFaultErrorCode code = errorCode; const char *modeStr = ""; if (code.fetch) diff --git a/src/arch/x86/remote_gdb.hh b/src/arch/x86/remote_gdb.hh --- a/src/arch/x86/remote_gdb.hh +++ b/src/arch/x86/remote_gdb.hh @@ -53,8 +53,14 @@ protected: enum RegisterContants { + /* + * These are all based on x86-64 + */ + RegRax, RegRbx, RegRcx, RegRdx, RegRsi, RegRdi, RegRbp, RegRsp, + RegR8, RegR9, RegR10, RegR11, RegR12, RegR13, RegR14, RegR15, RegRip, + RegEflags_Cs, RegSs_Ds, RegEs_Fs, RegGs, + NumGDBRegs - //XXX fill this in }; public: @@ -70,6 +76,8 @@ void setSingleStep(); Addr nextBkpt; + Addr notTakenBkpt; + Addr takenBkpt; }; } diff --git a/src/arch/x86/remote_gdb.cc b/src/arch/x86/remote_gdb.cc --- a/src/arch/x86/remote_gdb.cc +++ b/src/arch/x86/remote_gdb.cc @@ -42,12 +42,22 @@ #include +#include "arch/x86/regs/float.hh" +#include "arch/x86/decoder.hh" #include "arch/x86/remote_gdb.hh" +#include "arch/x86/utility.hh" #include "arch/vtophys.hh" #include "base/remote_gdb.hh" #include "base/socket.hh" #include "base/trace.hh" +#include "cpu/static_inst.hh" #include "cpu/thread_context.hh" +#include "debug/GDBAcc.hh" +#include "debug/GDBMisc.hh" +#include "mem/page_table.hh" +#include "sim/full_system.hh" +#include "sim/process.hh" +#include "sim/system.hh" using namespace std; using namespace X86ISA; @@ -56,27 +66,111 @@ : BaseRemoteGDB(_system, c, NumGDBRegs) {} -bool RemoteGDB::acc(Addr va, size_t len) +/* + * Determine if the mapping at va..(va+len) is valid. + */ +bool +RemoteGDB::acc(Addr va, size_t len) { - panic("Remote gdb acc not implemented in x86!\n"); + if (FullSystem) { + if(va) + return true; + return false; + } else { + TlbEntry entry; + //Check to make sure the first byte is mapped into the processes address + //space. + if (context->getProcessPtr()->pTable->lookup(va, entry)) { + return true; + } + DPRINTF(GDBMisc, "Page table lookup %lu failed\n", va); + return false; + } } -void RemoteGDB::getregs() +void +RemoteGDB::getregs() { - panic("Remote gdb getregs not implemented in x86!\n"); + memset(gdbregs.regs, 0, gdbregs.bytes()); + + // These are 64-bit registers + gdbregs.regs[RegRax] = context->readIntReg(INTREG_RAX); + gdbregs.regs[RegRcx] = context->readIntReg(INTREG_RCX); + gdbregs.regs[RegRdx] = context->readIntReg(INTREG_RDX); + gdbregs.regs[RegRbx] = context->readIntReg(INTREG_RBX); + gdbregs.regs[RegRsp] = context->readIntReg(INTREG_RSP); + gdbregs.regs[RegRbp] = context->readIntReg(INTREG_RBP); + gdbregs.regs[RegRsi] = context->readIntReg(INTREG_RSI); + gdbregs.regs[RegRdi] = context->readIntReg(INTREG_RDI); + gdbregs.regs[RegR8] = context->readIntReg(INTREG_R8); + gdbregs.regs[RegR9] = context->readIntReg(INTREG_R9); + gdbregs.regs[RegR10] = context->readIntReg(INTREG_R10); + gdbregs.regs[RegR11] = context->readIntReg(INTREG_R11); + gdbregs.regs[RegR12] = context->readIntReg(INTREG_R12); + gdbregs.regs[RegR13] = context->readIntReg(INTREG_R13); + gdbregs.regs[RegR14] = context->readIntReg(INTREG_R14); + gdbregs.regs[RegR15] = context->readIntReg(INTREG_R15); + gdbregs.regs[RegRip] = context->pcState().pc(); + + // these x86 registers are 32 bits, gdb registers are 64 bits + // so pack two of them into one gdb register + gdbregs.regs[RegEflags_Cs] = getRFlags(context) << 32 | + context->readMiscRegNoEffect(MISCREG_CS_EFF_BASE); + + gdbregs.regs[RegSs_Ds] = + context->readMiscRegNoEffect(MISCREG_SS_EFF_BASE) << 32 | + context->readMiscRegNoEffect(MISCREG_DS_EFF_BASE); + + gdbregs.regs[RegEs_Fs] = + context->readMiscRegNoEffect(MISCREG_ES_EFF_BASE) << 32 | + context->readMiscRegNoEffect(MISCREG_FS); + + gdbregs.regs[RegGs] = + context->readMiscRegNoEffect(MISCREG_GS_EFF_BASE) << 32; } -void RemoteGDB::setregs() +void +RemoteGDB::setregs() { - panic("Remote gdb setregs not implemented in x86!\n"); + DPRINTF(GDBAcc, "setregs in remote gdb\n"); } -void RemoteGDB::clearSingleStep() +void +RemoteGDB::clearSingleStep() { - panic("Remote gdb clearSingleStep not implemented in x86!\n"); + DPRINTF(GDBMisc, "clearSingleStep bt_addr=%#x nt_addr=%#x\n", + takenBkpt, notTakenBkpt); + + if (takenBkpt != 0) + clearTempBreakpoint(takenBkpt); + + if (notTakenBkpt != 0) + clearTempBreakpoint(notTakenBkpt); } -void RemoteGDB::setSingleStep() +void +RemoteGDB::setSingleStep() { - panic("Remoge gdb setSingleStep not implemented in x86!\n"); + PCState pc = context->pcState(); + PCState bpc; + bool set_bt = false; + + // User was stopped at pc, e.g. the instruction at pc was not + // executed. + ExtMachInst inst = read(pc.pc()); + StaticInstPtr si = context->getDecoderPtr()->decode(inst, pc.pc()); + if (si->hasBranchTarget(pc, context, bpc)) { + // Don't bother setting a breakpoint on the taken branch if it + // is the same as the next pc + if (bpc.pc() != pc.npc()) + set_bt = true; + } + + DPRINTF(GDBMisc, "setSingleStep bt_addr=%#x nt_addr=%#x\n", + takenBkpt, notTakenBkpt); + + setTempBreakpoint(notTakenBkpt = pc.npc()); + + if (set_bt) + setTempBreakpoint(takenBkpt = bpc.pc()); } diff --git a/src/base/misc.cc b/src/base/misc.cc --- a/src/base/misc.cc +++ b/src/base/misc.cc @@ -52,6 +52,9 @@ #include "base/trace.hh" #include "base/types.hh" #include "sim/core.hh" +#include "sim/full_system.hh" +#include "sim/system.hh" +#include "base/remote_gdb.hh" using namespace std; @@ -82,6 +85,19 @@ const char *func, const char *file, int line, const char *format) { + if (prefix != NULL) { + if ((strcmp(prefix, "fatal") == 0) && !FullSystem) { + // @todo determine which system caused this exit + System * system = System::systemList[0]; + + if (system) { + // @todo determine which cpu caused this exit + if (system->remoteGDB.size()) + system->remoteGDB[0]->trap(SIGINT); + } + } + } + newline_if_needed(std::cerr, format); ccprintf(std::cerr, diff --git a/src/base/remote_gdb.cc b/src/base/remote_gdb.cc --- a/src/base/remote_gdb.cc +++ b/src/base/remote_gdb.cc @@ -148,7 +148,9 @@ void debugger() { - static int current_debugger = -1; + // set this to zero to make it listen for the remote debugger + static int current_debugger = 0; + if (current_debugger >= 0 && current_debugger < (int)debuggers.size()) { BaseRemoteGDB *gdb = debuggers[current_debugger]; if (!gdb->isattached()) @@ -539,8 +541,11 @@ bool BaseRemoteGDB::insertSoftBreak(Addr addr, size_t len) { - if (len != sizeof(TheISA::MachInst)) + +#if THE_ISA != X86_ISA + if (len != sizeof(MachInst)) panic("invalid length\n"); +#endif // X86_ISA return insertHardBreak(addr, len); } @@ -548,8 +553,11 @@ bool BaseRemoteGDB::removeSoftBreak(Addr addr, size_t len) { + +#if THE_ISA != X86_ISA if (len != sizeof(MachInst)) panic("invalid length\n"); +#endif // X86_ISA return removeHardBreak(addr, len); } @@ -557,8 +565,11 @@ bool BaseRemoteGDB::insertHardBreak(Addr addr, size_t len) { + +#if THE_ISA != X86_ISA if (len != sizeof(MachInst)) panic("invalid length\n"); +#endif // X86_ISA DPRINTF(GDBMisc, "inserting hardware breakpoint at %#x\n", addr); @@ -574,8 +585,11 @@ bool BaseRemoteGDB::removeHardBreak(Addr addr, size_t len) { + +#if THE_ISA != X86_ISA if (len != sizeof(MachInst)) panic("invalid length\n"); +#endif //X86_ISA DPRINTF(GDBMisc, "removing hardware breakpoint at %#x\n", addr); diff --git a/src/cpu/BaseCPU.py b/src/cpu/BaseCPU.py --- a/src/cpu/BaseCPU.py +++ b/src/cpu/BaseCPU.py @@ -130,6 +130,7 @@ cpu_id = Param.Int(-1, "CPU identifier") socket_id = Param.Unsigned(0, "Physical Socket identifier") numThreads = Param.Unsigned(1, "number of HW thread contexts") + rgdb_wait = Param.Bool(False, "Enable remote debugging") function_trace = Param.Bool(False, "Enable function trace") function_trace_start = Param.Tick(0, "Tick to start function trace") diff --git a/src/cpu/base.hh b/src/cpu/base.hh --- a/src/cpu/base.hh +++ b/src/cpu/base.hh @@ -108,6 +108,11 @@ */ const uint32_t _socketId; + /** Allow remote debugging of the kernel in FS mode, or the user programs + * in SE mode. Doesn't yet support multiple cpus + */ + bool _rgdbWait; + /** instruction side request id that must be placed in all requests */ MasterID _instMasterId; @@ -155,6 +160,8 @@ /** Reads this CPU's Socket ID. */ uint32_t socketId() const { return _socketId; } + bool rgdbWait() const { return _rgdbWait; } + /** Reads this CPU's unique data requestor ID */ MasterID dataMasterId() { return _dataMasterId; } /** Reads this CPU's unique instruction requestor ID */ diff --git a/src/cpu/base.cc b/src/cpu/base.cc --- a/src/cpu/base.cc +++ b/src/cpu/base.cc @@ -118,6 +118,7 @@ BaseCPU::BaseCPU(Params *p, bool is_checker) : MemObject(p), instCnt(0), _cpuId(p->cpu_id), _socketId(p->socket_id), + _rgdbWait(p->rgdb_wait), _instMasterId(p->system->getMasterId(name() + ".inst")), _dataMasterId(p->system->getMasterId(name() + ".data")), _taskId(ContextSwitchTaskId::Unknown), _pid(Request::invldPid), diff --git a/src/sim/faults.cc b/src/sim/faults.cc --- a/src/sim/faults.cc +++ b/src/sim/faults.cc @@ -45,7 +45,7 @@ DPRINTF(Fault, "Fault %s at PC: %s\n", name(), tc->pcState()); assert(!tc->misspeculating()); } else { - panic("fault (%s) detected @ PC %s", name(), tc->pcState()); + fatal("fault (%s) detected @ PC %s", name(), tc->pcState()); } } @@ -67,7 +67,7 @@ handled = p->fixupStackFault(vaddr); } if (!handled) - panic("Page table fault when accessing virtual address %#x\n", vaddr); + fatal("Page table fault when accessing virtual address %#x\n", vaddr); } diff --git a/src/sim/system.cc b/src/sim/system.cc --- a/src/sim/system.cc +++ b/src/sim/system.cc @@ -53,6 +53,7 @@ #include "base/str.hh" #include "base/trace.hh" #include "config/the_isa.hh" +#include "cpu/base.hh" #include "cpu/thread_context.hh" #include "debug/Loader.hh" #include "debug/WorkItems.hh" @@ -197,13 +198,6 @@ return false; } -/** - * Setting rgdb_wait to a positive integer waits for a remote debugger to - * connect to that context ID before continuing. This should really - be a parameter on the CPU object or something... - */ -int rgdb_wait = -1; - int System::registerThreadContext(ThreadContext *tc, int assigned) { @@ -235,7 +229,10 @@ GDBListener *gdbl = new GDBListener(rgdb, port + id); gdbl->listen(); - if (rgdb_wait != -1 && rgdb_wait == id) + /* allow debugging for a single cpu. How should we enable this on the + * command line for multiple cpus? + */ + if(tc->getCpuPtr()->rgdbWait() && id == 0 ) gdbl->accept(); if (remoteGDB.size() <= id) {