/*
- * Copyright (c) 2010, 2013 ARM Limited
+ * Copyright 2015 LabWare
+ * Copyright 2014 Google Inc.
+ * Copyright (c) 2010, 2013, 2016, 2018-2019 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
*
* Authors: Nathan Binkert
* William Wang
+ * Boris Shingarov
*/
/*
* "Stub" to allow remote cpu to debug over a serial line using gdb.
*/
+#include "arch/arm/remote_gdb.hh"
+
#include <sys/signal.h>
#include <unistd.h>
#include "arch/arm/decoder.hh"
#include "arch/arm/pagetable.hh"
#include "arch/arm/registers.hh"
-#include "arch/arm/remote_gdb.hh"
#include "arch/arm/system.hh"
#include "arch/arm/utility.hh"
#include "arch/arm/vtophys.hh"
+#include "base/chunk_generator.hh"
#include "base/intmath.hh"
#include "base/remote_gdb.hh"
#include "base/socket.hh"
#include "base/trace.hh"
+#include "blobs/gdb_xml_aarch64_core.hh"
+#include "blobs/gdb_xml_aarch64_fpu.hh"
+#include "blobs/gdb_xml_aarch64_target.hh"
+#include "blobs/gdb_xml_arm_core.hh"
+#include "blobs/gdb_xml_arm_target.hh"
+#include "blobs/gdb_xml_arm_vfpv3.hh"
#include "cpu/static_inst.hh"
#include "cpu/thread_context.hh"
#include "cpu/thread_state.hh"
using namespace std;
using namespace ArmISA;
-RemoteGDB::RemoteGDB(System *_system, ThreadContext *tc)
- : BaseRemoteGDB(_system, tc, MAX_NUMREGS), notTakenBkpt(0), takenBkpt(0)
+RemoteGDB::RemoteGDB(System *_system, ThreadContext *tc, int _port)
+ : BaseRemoteGDB(_system, tc, _port), regCache32(this), regCache64(this)
{
}
RemoteGDB::acc(Addr va, size_t len)
{
if (FullSystem) {
- Addr last_va;
- va = truncPage(va);
- last_va = roundPage(va + len);
-
- do {
- if (virtvalid(context, va)) {
- return true;
+ for (ChunkGenerator gen(va, len, PageBytes); !gen.done(); gen.next()) {
+ if (!virtvalid(context(), gen.addr())) {
+ DPRINTF(GDBAcc, "acc: %#x mapping is invalid\n", va);
+ return false;
}
- va += PageBytes;
- } while (va < last_va);
+ }
DPRINTF(GDBAcc, "acc: %#x mapping is valid\n", va);
return true;
} 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;
- return false;
+ // Check to make sure the first byte is mapped into the processes
+ // address space.
+ return context()->getProcessPtr()->pTable->lookup(va) != nullptr;
}
}
-/*
- * Translate the kernel debugger register format into the GDB register
- * format.
- */
void
-RemoteGDB::getregs()
+RemoteGDB::AArch64GdbRegCache::getRegs(ThreadContext *context)
{
- DPRINTF(GDBAcc, "getregs in remotegdb \n");
-
- memset(gdbregs.regs, 0, gdbregs.bytes());
-
- if (inAArch64(context)) { // AArch64
- // x0-x31
- for (int i = 0; i < 32; ++i) {
- gdbregs.regs[REG_X0 + i] = context->readIntReg(INTREG_X0 + i);
+ DPRINTF(GDBAcc, "getRegs in remotegdb \n");
+
+ for (int i = 0; i < 31; ++i)
+ r.x[i] = context->readIntReg(INTREG_X0 + i);
+ r.spx = context->readIntReg(INTREG_SPX);
+ r.pc = context->pcState().pc();
+ r.cpsr = context->readMiscRegNoEffect(MISCREG_CPSR);
+
+ size_t base = 0;
+ for (int i = 0; i < NumVecV8ArchRegs; i++) {
+ auto v = (context->readVecReg(RegId(VecRegClass, i))).as<VecElem>();
+ for (size_t j = 0; j < NumVecElemPerNeonVecReg; j++) {
+ r.v[base] = v[j];
+ base++;
}
- // pc
- gdbregs.regs[REG_PC_64] = context->pcState().pc();
- // cpsr
- gdbregs.regs[REG_CPSR_64] = context->readMiscRegNoEffect(MISCREG_CPSR);
- // v0-v31
- for (int i = 0; i < 32; ++i) {
- gdbregs.regs[REG_V0 + 2 * i] = static_cast<uint64_t>(
- context->readFloatRegBits(i * 4 + 3)) << 32 |
- context->readFloatRegBits(i * 4 + 2);
- gdbregs.regs[REG_V0 + 2 * i + 1] = static_cast<uint64_t>(
- context->readFloatRegBits(i * 4 + 1)) << 32 |
- context->readFloatRegBits(i * 4 + 0);
- }
- } else { // AArch32
- // R0-R15 supervisor mode
- // arm registers are 32 bits wide, gdb registers are 64 bits wide two
- // arm registers are packed into one gdb register (little endian)
- gdbregs.regs[REG_R0 + 0] = context->readIntReg(INTREG_R1) << 32 |
- context->readIntReg(INTREG_R0);
- gdbregs.regs[REG_R0 + 1] = context->readIntReg(INTREG_R3) << 32 |
- context->readIntReg(INTREG_R2);
- gdbregs.regs[REG_R0 + 2] = context->readIntReg(INTREG_R5) << 32 |
- context->readIntReg(INTREG_R4);
- gdbregs.regs[REG_R0 + 3] = context->readIntReg(INTREG_R7) << 32 |
- context->readIntReg(INTREG_R6);
- gdbregs.regs[REG_R0 + 4] = context->readIntReg(INTREG_R9) << 32 |
- context->readIntReg(INTREG_R8);
- gdbregs.regs[REG_R0 + 5] = context->readIntReg(INTREG_R11) << 32|
- context->readIntReg(INTREG_R10);
- gdbregs.regs[REG_R0 + 6] = context->readIntReg(INTREG_SP) << 32 |
- context->readIntReg(INTREG_R12);
- gdbregs.regs[REG_R0 + 7] = context->pcState().pc() << 32 |
- context->readIntReg(INTREG_LR);
-
- // CPSR
- gdbregs.regs[REG_CPSR] = context->readMiscRegNoEffect(MISCREG_CPSR);
-
- // vfpv3/neon floating point registers (32 double or 64 float)
-
- gdbregs.regs[REG_F0] =
- static_cast<uint64_t>(context->readFloatRegBits(0)) << 32 |
- gdbregs.regs[REG_CPSR];
-
- for (int i = 1; i < (NumFloatV7ArchRegs>>1); ++i) {
- gdbregs.regs[i + REG_F0] =
- static_cast<uint64_t>(context->readFloatRegBits(2*i)) << 32 |
- context->readFloatRegBits(2*i-1);
- }
-
- // FPSCR
- gdbregs.regs[REG_FPSCR] = static_cast<uint64_t>(
- context->readMiscRegNoEffect(MISCREG_FPSCR)) << 32 |
- context->readFloatRegBits(NumFloatV7ArchRegs - 1);
}
+ r.fpsr = context->readMiscRegNoEffect(MISCREG_FPSR);
+ r.fpcr = context->readMiscRegNoEffect(MISCREG_FPCR);
}
-/*
- * Translate the GDB register format into the kernel debugger register
- * format.
- */
void
-RemoteGDB::setregs()
+RemoteGDB::AArch64GdbRegCache::setRegs(ThreadContext *context) const
{
-
- DPRINTF(GDBAcc, "setregs in remotegdb \n");
- if (inAArch64(context)) { // AArch64
- // x0-x31
- for (int i = 0; i < 32; ++i) {
- context->setIntReg(INTREG_X0 + i, gdbregs.regs[REG_X0 + i]);
- }
- // pc
- context->pcState(gdbregs.regs[REG_PC_64]);
- // cpsr
- context->setMiscRegNoEffect(MISCREG_CPSR, gdbregs.regs[REG_CPSR_64]);
- // v0-v31
- for (int i = 0; i < 32; ++i) {
- context->setFloatRegBits(i * 4 + 3,
- gdbregs.regs[REG_V0 + 2 * i] >> 32);
- context->setFloatRegBits(i * 4 + 2,
- gdbregs.regs[REG_V0 + 2 * i]);
- context->setFloatRegBits(i * 4 + 1,
- gdbregs.regs[REG_V0 + 2 * i + 1] >> 32);
- context->setFloatRegBits(i * 4 + 0,
- gdbregs.regs[REG_V0 + 2 * i + 1]);
+ DPRINTF(GDBAcc, "setRegs in remotegdb \n");
+
+ for (int i = 0; i < 31; ++i)
+ context->setIntReg(INTREG_X0 + i, r.x[i]);
+ auto pc_state = context->pcState();
+ pc_state.set(r.pc);
+ context->pcState(pc_state);
+ context->setMiscRegNoEffect(MISCREG_CPSR, r.cpsr);
+ // Update the stack pointer. This should be done after
+ // updating CPSR/PSTATE since that might affect how SPX gets
+ // mapped.
+ context->setIntReg(INTREG_SPX, r.spx);
+
+ size_t base = 0;
+ for (int i = 0; i < NumVecV8ArchRegs; i++) {
+ auto v = (context->getWritableVecReg(
+ RegId(VecRegClass, i))).as<VecElem>();
+ for (size_t j = 0; j < NumVecElemPerNeonVecReg; j++) {
+ v[j] = r.v[base];
+ base++;
}
- } else { // AArch32
- // R0-R15 supervisor mode
- // arm registers are 32 bits wide, gdb registers are 64 bits wide
- // two arm registers are packed into one gdb register (little endian)
- context->setIntReg(INTREG_R0 , bits(gdbregs.regs[REG_R0 + 0], 31, 0));
- context->setIntReg(INTREG_R1 , bits(gdbregs.regs[REG_R0 + 0], 63, 32));
- context->setIntReg(INTREG_R2 , bits(gdbregs.regs[REG_R0 + 1], 31, 0));
- context->setIntReg(INTREG_R3 , bits(gdbregs.regs[REG_R0 + 1], 63, 32));
- context->setIntReg(INTREG_R4 , bits(gdbregs.regs[REG_R0 + 2], 31, 0));
- context->setIntReg(INTREG_R5 , bits(gdbregs.regs[REG_R0 + 2], 63, 32));
- context->setIntReg(INTREG_R6 , bits(gdbregs.regs[REG_R0 + 3], 31, 0));
- context->setIntReg(INTREG_R7 , bits(gdbregs.regs[REG_R0 + 3], 63, 32));
- context->setIntReg(INTREG_R8 , bits(gdbregs.regs[REG_R0 + 4], 31, 0));
- context->setIntReg(INTREG_R9 , bits(gdbregs.regs[REG_R0 + 4], 63, 32));
- context->setIntReg(INTREG_R10, bits(gdbregs.regs[REG_R0 + 5], 31, 0));
- context->setIntReg(INTREG_R11, bits(gdbregs.regs[REG_R0 + 5], 63, 32));
- context->setIntReg(INTREG_R12, bits(gdbregs.regs[REG_R0 + 6], 31, 0));
- context->setIntReg(INTREG_SP , bits(gdbregs.regs[REG_R0 + 6], 63, 32));
- context->setIntReg(INTREG_LR , bits(gdbregs.regs[REG_R0 + 7], 31, 0));
- context->pcState(bits(gdbregs.regs[REG_R0 + 7], 63, 32));
-
- //CPSR
- context->setMiscRegNoEffect(MISCREG_CPSR, gdbregs.regs[REG_CPSR]);
-
- //vfpv3/neon floating point registers (32 double or 64 float)
- context->setFloatRegBits(0, gdbregs.regs[REG_F0]>>32);
-
- for (int i = 1; i < NumFloatV7ArchRegs; ++i) {
- if (i%2) {
- int j = (i+1)/2;
- context->setFloatRegBits(i, bits(gdbregs.regs[j + REG_F0], 31, 0));
- } else {
- int j = i/2;
- context->setFloatRegBits(i, gdbregs.regs[j + REG_F0]>>32);
- }
- }
-
- //FPSCR
- context->setMiscReg(MISCREG_FPSCR, gdbregs.regs[REG_FPSCR]>>32);
}
+ context->setMiscRegNoEffect(MISCREG_FPSR, r.fpsr);
+ context->setMiscRegNoEffect(MISCREG_FPCR, r.fpcr);
}
void
-RemoteGDB::clearSingleStep()
+RemoteGDB::AArch32GdbRegCache::getRegs(ThreadContext *context)
{
- DPRINTF(GDBMisc, "clearSingleStep bt_addr=%#x nt_addr=%#x\n",
- takenBkpt, notTakenBkpt);
-
- if (takenBkpt != 0)
- clearTempBreakpoint(takenBkpt);
-
- if (notTakenBkpt != 0)
- clearTempBreakpoint(notTakenBkpt);
+ DPRINTF(GDBAcc, "getRegs in remotegdb \n");
+
+ r.gpr[0] = context->readIntReg(INTREG_R0);
+ r.gpr[1] = context->readIntReg(INTREG_R1);
+ r.gpr[2] = context->readIntReg(INTREG_R2);
+ r.gpr[3] = context->readIntReg(INTREG_R3);
+ r.gpr[4] = context->readIntReg(INTREG_R4);
+ r.gpr[5] = context->readIntReg(INTREG_R5);
+ r.gpr[6] = context->readIntReg(INTREG_R6);
+ r.gpr[7] = context->readIntReg(INTREG_R7);
+ r.gpr[8] = context->readIntReg(INTREG_R8);
+ r.gpr[9] = context->readIntReg(INTREG_R9);
+ r.gpr[10] = context->readIntReg(INTREG_R10);
+ r.gpr[11] = context->readIntReg(INTREG_R11);
+ r.gpr[12] = context->readIntReg(INTREG_R12);
+ r.gpr[13] = context->readIntReg(INTREG_SP);
+ r.gpr[14] = context->readIntReg(INTREG_LR);
+ r.gpr[15] = context->pcState().pc();
+ r.cpsr = context->readMiscRegNoEffect(MISCREG_CPSR);
+
+ // One day somebody will implement transfer of FPRs correctly.
+ for (int i = 0; i < 32; i++)
+ r.fpr[i] = 0;
+
+ r.fpscr = context->readMiscRegNoEffect(MISCREG_FPSCR);
}
void
-RemoteGDB::setSingleStep()
+RemoteGDB::AArch32GdbRegCache::setRegs(ThreadContext *context) const
{
- PCState pc = context->pcState();
- PCState bpc;
- bool set_bt = false;
-
- // User was stopped at pc, e.g. the instruction at pc was not
- // executed.
- MachInst inst = read<MachInst>(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());
+ DPRINTF(GDBAcc, "setRegs in remotegdb \n");
+
+ context->setIntReg(INTREG_R0, r.gpr[0]);
+ context->setIntReg(INTREG_R1, r.gpr[1]);
+ context->setIntReg(INTREG_R2, r.gpr[2]);
+ context->setIntReg(INTREG_R3, r.gpr[3]);
+ context->setIntReg(INTREG_R4, r.gpr[4]);
+ context->setIntReg(INTREG_R5, r.gpr[5]);
+ context->setIntReg(INTREG_R6, r.gpr[6]);
+ context->setIntReg(INTREG_R7, r.gpr[7]);
+ context->setIntReg(INTREG_R8, r.gpr[8]);
+ context->setIntReg(INTREG_R9, r.gpr[9]);
+ context->setIntReg(INTREG_R10, r.gpr[10]);
+ context->setIntReg(INTREG_R11, r.gpr[11]);
+ context->setIntReg(INTREG_R12, r.gpr[12]);
+ context->setIntReg(INTREG_SP, r.gpr[13]);
+ context->setIntReg(INTREG_LR, r.gpr[14]);
+ auto pc_state = context->pcState();
+ pc_state.set(r.gpr[15]);
+ context->pcState(pc_state);
+
+ // One day somebody will implement transfer of FPRs correctly.
+
+ context->setMiscReg(MISCREG_FPSCR, r.fpscr);
+ context->setMiscRegNoEffect(MISCREG_CPSR, r.cpsr);
}
-// Write bytes to kernel address space for debugger.
bool
-RemoteGDB::write(Addr vaddr, size_t size, const char *data)
+RemoteGDB::getXferFeaturesRead(const std::string &annex, std::string &output)
{
- return BaseRemoteGDB::write(vaddr, size, data);
+#define GDB_XML(x, s) \
+ { x, std::string(reinterpret_cast<const char *>(Blobs::s), \
+ Blobs::s ## _len) }
+ static const std::map<std::string, std::string> annexMap32{
+ GDB_XML("target.xml", gdb_xml_arm_target),
+ GDB_XML("arm-core.xml", gdb_xml_arm_core),
+ GDB_XML("arm-vfpv3.xml", gdb_xml_arm_vfpv3),
+ };
+ static const std::map<std::string, std::string> annexMap64{
+ GDB_XML("target.xml", gdb_xml_aarch64_target),
+ GDB_XML("aarch64-core.xml", gdb_xml_aarch64_core),
+ GDB_XML("aarch64-fpu.xml", gdb_xml_aarch64_fpu),
+ };
+#undef GDB_XML
+ auto& annexMap = inAArch64(context()) ? annexMap64 : annexMap32;
+ auto it = annexMap.find(annex);
+ if (it == annexMap.end())
+ return false;
+ output = it->second;
+ return true;
}
+BaseGdbRegCache*
+RemoteGDB::gdbRegs()
+{
+ if (inAArch64(context()))
+ return ®Cache64;
+ else
+ return ®Cache32;
+}