summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOxore <oxore@protonmail.com>2022-10-02 00:49:39 +0300
committerOxore <oxore@protonmail.com>2022-10-02 00:59:23 +0300
commit15d14d36fc7ac30cdbde8c2a78e901ba2c47e94d (patch)
tree4606963389204dffa7a8cef51fb34ed80ecc01a3
parent72abe5f3e714df9cc8310a78bdfa648feb79c4d2 (diff)
Impl setting registers via GDB
-rw-r--r--emulator.cpp42
-rw-r--r--gdbremote_parser.cpp113
-rw-r--r--gdbremote_parser.hpp30
-rw-r--r--m68k_debugging.cpp1
-rw-r--r--m68k_debugging.hpp2
5 files changed, 154 insertions, 34 deletions
diff --git a/emulator.cpp b/emulator.cpp
index 7e6ad25..b5ad031 100644
--- a/emulator.cpp
+++ b/emulator.cpp
@@ -211,7 +211,7 @@ static std::string CreateResponse(
{
const M68KCPUState state = m68k_debug.GetCPUState();
std::string result{};
- for (size_t i = 0; i < state.registers_count ;i++)
+ for (size_t i = 0; i < state.registers_count; i++)
{
constexpr size_t value_size = std::string_view("12345678").length();
char value[value_size + 1]{};
@@ -221,6 +221,46 @@ static std::string CreateResponse(
}
return result;
}
+ case PacketType::kWriteGeneralRegisters:
+ {
+ const auto * const data =
+ static_cast<const PacketDataWriteGeneralRegisters*>(packet.data.get());
+ const auto& registers = data->registers;
+ for (size_t i = 0; i < registers.size(); i++) {
+ m68k_debug.SetRegister(static_cast<M68KRegister>(i), registers[i]);
+ }
+ return "OK";
+ }
+ break;
+ case PacketType::kReadRegister:
+ {
+ const auto * const data =
+ static_cast<const PacketDataReadRegister*>(packet.data.get());
+ const auto reg_id = static_cast<M68KRegister>(data->reg_id);
+ if (reg_id >= M68KRegister::kRegistersCount) {
+ return "E00";
+ }
+ const uint32_t value = m68k_debug.GetRegister(reg_id);
+ constexpr size_t value_size = std::string_view("12345678").length();
+ char value_str[value_size + 1]{};
+ const int ret = snprintf(value_str, value_size + 1, "%08x", value);
+ assert(ret == value_size);
+ return std::string(value_str, value_size);
+ }
+ break;
+ case PacketType::kWriteRegister:
+ {
+ const auto * const data =
+ static_cast<const PacketDataWriteRegister*>(packet.data.get());
+ const auto reg_id = static_cast<M68KRegister>(data->reg_id);
+ const auto value = data->value;
+ if (reg_id >= M68KRegister::kRegistersCount) {
+ return "E00";
+ }
+ m68k_debug.SetRegister(reg_id, value);
+ return "OK";
+ }
+ break;
case PacketType::kReadMemory:
{
const auto * const data =
diff --git a/gdbremote_parser.cpp b/gdbremote_parser.cpp
index 2c13668..8d70370 100644
--- a/gdbremote_parser.cpp
+++ b/gdbremote_parser.cpp
@@ -15,19 +15,21 @@ enum class TokenType: uint8_t {
kSeparatorComma,
kSeparatorColon,
kSeparatorSemicolon,
+ kSeparatorEquals,
kHexNumeric,
kArbitrary,
};
static inline bool isseparator(uint8_t byte)
{
- return ':' == byte || ';' == byte || ',' == byte;
+ return ':' == byte || ';' == byte || ',' == byte || '=' == byte;
}
static inline TokenType separatorTypeFromByte(uint8_t byte)
{
if (':' == byte) return TokenType::kSeparatorColon;
if (';' == byte) return TokenType::kSeparatorSemicolon;
+ if ('=' == byte) return TokenType::kSeparatorEquals;
return TokenType::kSeparatorComma;
}
@@ -49,6 +51,7 @@ struct Token {
for (; i < packet_data.length(); i++) {
assert(type != TokenType::kSeparatorColon);
assert(type != TokenType::kSeparatorSemicolon);
+ assert(type != TokenType::kSeparatorEquals);
assert(type != TokenType::kSeparatorComma);
const uint8_t byte = packet_data[i];
if (isseparator(byte)) {
@@ -90,48 +93,48 @@ static std::string DecodeBinaryHex(const std::string& data_hex)
struct Command {
std::string name;
- Packet (*parse)(const std::vector<Token>&&);
- static Packet parseNone(const std::vector<Token>&&)
+ Packet (*parse)(std::vector<Token>&&);
+ static Packet parseNone(std::vector<Token>&&)
{
return Packet::None();
}
- static Packet parseQuerySupported(const std::vector<Token>&&)
+ static Packet parseQuerySupported(std::vector<Token>&&)
{
// TODO arguments
return Packet{PacketType::kQuerySupported};
}
- static Packet parseQueryHaltReason(const std::vector<Token>&&)
+ static Packet parseQueryHaltReason(std::vector<Token>&&)
{
return Packet{PacketType::kQueryHaltReason};
}
- static Packet parseQueryC(const std::vector<Token>&&)
+ static Packet parseQueryC(std::vector<Token>&&)
{
// TODO arguments
return Packet{PacketType::kQueryC};
}
- static Packet parseQueryFThreadInfo(const std::vector<Token>&&)
+ static Packet parseQueryFThreadInfo(std::vector<Token>&&)
{
return Packet{PacketType::kQueryFThreadInfo};
}
- static Packet parseQuerySThreadInfo(const std::vector<Token>&&)
+ static Packet parseQuerySThreadInfo(std::vector<Token>&&)
{
return Packet{PacketType::kQuerySThreadInfo};
}
- static Packet parseQueryRTOSThreadInfo(const std::vector<Token>&&)
+ static Packet parseQueryRTOSThreadInfo(std::vector<Token>&&)
{
// TODO arguments
return Packet{PacketType::kQueryRTOSThreadInfo};
}
- static Packet parseQueryAttached(const std::vector<Token>&&)
+ static Packet parseQueryAttached(std::vector<Token>&&)
{
// TODO arguments
return Packet{PacketType::kQueryAttached};
}
- static Packet parseQueryTraceStatus(const std::vector<Token>&&)
+ static Packet parseQueryTraceStatus(std::vector<Token>&&)
{
return Packet{PacketType::kQueryTraceStatus};
}
- static Packet parseQueryRcmd(const std::vector<Token>&& tokens)
+ static Packet parseQueryRcmd(std::vector<Token>&& tokens)
{
if (tokens.size() < 3)
return Packet::None();
@@ -140,40 +143,38 @@ struct Command {
if (tokens[2].type != TokenType::kHexNumeric)
return Packet::None();
const std::string& data_encoded = tokens[2].data;
- const std::string data = DecodeBinaryHex(data_encoded);
- printf("%s\n", data.c_str());
return Packet{
PacketType::kQueryRcmd,
- std::make_unique<const PacketDataRcmd>(std::move(data)),
+ std::make_unique<const PacketDataRcmd>(std::move(DecodeBinaryHex(data_encoded))),
};
}
- static Packet parseQStartNoAckMode(const std::vector<Token>&&)
+ static Packet parseQStartNoAckMode(std::vector<Token>&&)
{
return Packet{PacketType::kQStartNoAckMode};
}
- static Packet parseSetThreadForCont(const std::vector<Token>&&)
+ static Packet parseSetThreadForCont(std::vector<Token>&&)
{
// TODO arguments
return Packet{PacketType::kSetThreadForCont};
}
- static Packet parseSetThreadForOps(const std::vector<Token>&&)
+ static Packet parseSetThreadForOps(std::vector<Token>&&)
{
// TODO arguments
return Packet{PacketType::kSetThreadForOps};
}
- static Packet parseMustReplyEmpty(const std::vector<Token>&&)
+ static Packet parseMustReplyEmpty(std::vector<Token>&&)
{
return Packet{PacketType::kVMustReplyEmpty};
}
- static Packet parseEnableExtendedMode(const std::vector<Token>&&)
+ static Packet parseEnableExtendedMode(std::vector<Token>&&)
{
return Packet{PacketType::kEnableExtendedMode};
}
- static Packet parseInterrupt(const std::vector<Token>&&)
+ static Packet parseInterrupt(std::vector<Token>&&)
{
return Packet{PacketType::kInterrupt};
}
- static Packet parseContinueVCont(const std::vector<Token>&& tokens)
+ static Packet parseContinueVCont(std::vector<Token>&& tokens)
{
const std::string first_arg = tokens.size() > 1 ? tokens[1].data : "";
// Check if it is "vCont?" command
@@ -183,11 +184,11 @@ struct Command {
// TODO arguments
return Packet{PacketType::kContinue};
}
- static Packet parseContinue(const std::vector<Token>&&)
+ static Packet parseContinue(std::vector<Token>&&)
{
return Packet{PacketType::kContinue};
}
- static Packet parseReadMemory(const std::vector<Token>&& tokens)
+ static Packet parseReadMemory(std::vector<Token>&& tokens)
{
if (tokens.size() < 4)
return Packet::None();
@@ -207,7 +208,7 @@ struct Command {
std::make_unique<const PacketDataReadMemory>(offset, lenght),
};
}
- static Packet parseWriteMemory(const std::vector<Token>&& tokens)
+ static Packet parseWriteMemory(std::vector<Token>&& tokens)
{
if (tokens.size() < 6)
return Packet::None();
@@ -239,15 +240,65 @@ struct Command {
std::make_unique<const PacketDataWriteMemory>(offset, lenght, std::move(data)),
};
}
- static Packet parseReadGeneralRegisters(const std::vector<Token>&&)
+ static Packet parseReadGeneralRegisters(std::vector<Token>&&)
{
return Packet{PacketType::kReadGeneralRegisters};
}
- static Packet parseStep(const std::vector<Token>&&)
+ static Packet parseWriteGeneralRegisters(std::vector<Token>&& tokens)
+ {
+ if (tokens.size() < 2)
+ return Packet::None();
+ if (tokens[1].type != TokenType::kHexNumeric)
+ return Packet::None();
+ const std::string& first = tokens[1].data;
+ constexpr size_t value_str_size = std::string_view("12345678").length();
+ std::vector<uint32_t> registers(first.length()/value_str_size);
+ for (size_t i = 0; i < first.length()/value_str_size; i++) {
+ const std::string value_str(first.substr(i * value_str_size, value_str_size));
+ registers[i] = strtol(value_str.c_str(), nullptr, 16);
+ }
+ return Packet{
+ PacketType::kWriteGeneralRegisters,
+ std::make_unique<const PacketDataWriteGeneralRegisters>(std::move(registers)),
+ };
+ }
+ static Packet parseReadRegister(std::vector<Token>&& tokens)
+ {
+ if (tokens.size() < 2)
+ return Packet::None();
+ if (tokens[1].type != TokenType::kHexNumeric)
+ return Packet::None();
+ const std::string& first = tokens[1].data;
+ const uint32_t reg_id = strtol(first.c_str(), nullptr, 16);
+ return Packet{
+ PacketType::kReadRegister,
+ std::make_unique<const PacketDataReadRegister>(reg_id),
+ };
+ }
+ static Packet parseWriteRegister(std::vector<Token>&& tokens)
+ {
+ if (tokens.size() < 4)
+ return Packet::None();
+ if (tokens[1].type != TokenType::kHexNumeric)
+ return Packet::None();
+ if (tokens[2].type != TokenType::kSeparatorEquals)
+ return Packet::None();
+ if (tokens[3].type != TokenType::kHexNumeric)
+ return Packet::None();
+ const std::string& first = tokens[1].data;
+ const std::string& second = tokens[3].data;
+ const uint32_t reg_id = strtol(first.c_str(), nullptr, 16);
+ const uint32_t value = strtol(second.c_str(), nullptr, 16);
+ return Packet{
+ PacketType::kWriteRegister,
+ std::make_unique<const PacketDataWriteRegister>(reg_id, value),
+ };
+ }
+ static Packet parseStep(std::vector<Token>&&)
{
return Packet{PacketType::kStep};
}
- static Packet parseSetOrDeleteBreakpoint(const std::vector<Token>&& tokens)
+ static Packet parseSetOrDeleteBreakpoint(std::vector<Token>&& tokens)
{
if (tokens.size() < 6)
return Packet::None();
@@ -302,6 +353,9 @@ static const Command commands[] = {
{ "m", Command::parseReadMemory },
{ "M", Command::parseWriteMemory },
{ "g", Command::parseReadGeneralRegisters },
+ { "G", Command::parseWriteGeneralRegisters },
+ { "p", Command::parseReadRegister },
+ { "P", Command::parseWriteRegister },
{ "s", Command::parseStep },
{ "Z", Command::parseSetOrDeleteBreakpoint },
{ "z", Command::parseSetOrDeleteBreakpoint },
@@ -313,8 +367,7 @@ Packet Packet::Parse(std::string packet_data)
const auto cmdlen = command.name.length();
const auto packetlen = packet_data.length();
if (cmdlen <= packetlen && 0 == memcmp(&command.name[0], &packet_data[0], cmdlen)) {
- const auto tokens = Token::Tokenize(packet_data, command.name);
- return command.parse(std::move(tokens));
+ return command.parse(std::move(Token::Tokenize(packet_data, command.name)));
}
}
return Packet::None();
diff --git a/gdbremote_parser.hpp b/gdbremote_parser.hpp
index d35d78e..856206a 100644
--- a/gdbremote_parser.hpp
+++ b/gdbremote_parser.hpp
@@ -61,6 +61,9 @@ enum class PacketType: int {
kContinue,
kContinueAskSupported,
kReadGeneralRegisters,
+ kWriteGeneralRegisters,
+ kReadRegister,
+ kWriteRegister,
kReadMemory,
kWriteMemory,
kStep,
@@ -97,7 +100,7 @@ struct PacketDataWriteMemory: public PacketData {
};
struct PacketDataRcmd: public PacketData {
- PacketDataRcmd(const std::string&& a_data): data(std::move(a_data)) {}
+ PacketDataRcmd(std::string&& a_data): data(std::move(a_data)) {}
std::string data{};
virtual ~PacketDataRcmd() {}
};
@@ -120,6 +123,25 @@ struct PacketDataBreakpoint: public PacketData {
virtual ~PacketDataBreakpoint() {}
};
+struct PacketDataWriteGeneralRegisters: public PacketData {
+ PacketDataWriteGeneralRegisters(std::vector<uint32_t>&& regs): registers(std::move(regs)) {}
+ std::vector<uint32_t> registers{};
+ virtual ~PacketDataWriteGeneralRegisters() {}
+};
+
+struct PacketDataReadRegister: public PacketData {
+ PacketDataReadRegister(uint32_t a_reg_id): reg_id(a_reg_id) {}
+ uint32_t reg_id{};
+ virtual ~PacketDataReadRegister() {}
+};
+
+struct PacketDataWriteRegister: public PacketData {
+ PacketDataWriteRegister(uint32_t a_reg_id, uint32_t a_value)
+ : reg_id(a_reg_id), value(a_value) {}
+ uint32_t reg_id{}, value{};
+ virtual ~PacketDataWriteRegister() {}
+};
+
struct Packet {
const PacketType type{};
const std::unique_ptr<const PacketData> data{nullptr};
@@ -174,6 +196,12 @@ struct Packet {
return "vCont?";
case PacketType::kReadGeneralRegisters:
return "g";
+ case PacketType::kWriteGeneralRegisters:
+ return "G";
+ case PacketType::kReadRegister:
+ return "p";
+ case PacketType::kWriteRegister:
+ return "P";
case PacketType::kReadMemory:
return "m";
case PacketType::kWriteMemory:
diff --git a/m68k_debugging.cpp b/m68k_debugging.cpp
index 2e64417..5bae0d0 100644
--- a/m68k_debugging.cpp
+++ b/m68k_debugging.cpp
@@ -56,7 +56,6 @@ static inline m68k_register_t ConvertRegisterId(const M68KRegister register_id)
case M68KRegister::kFPC:
case M68KRegister::kFPS:
case M68KRegister::kFPI:
- case M68KRegister::kRegistersCount:
assert(!"Unsupported register_id");
break;
}
diff --git a/m68k_debugging.hpp b/m68k_debugging.hpp
index 1aa3bfc..7141809 100644
--- a/m68k_debugging.hpp
+++ b/m68k_debugging.hpp
@@ -29,11 +29,11 @@ enum class M68KRegister: size_t {
kSP = kA7,
kPS = 16, /* Processor status (Condition code register) */
kPC = 17, /* Program counter */
+ kRegistersCount,
kFP0 = 18, /* Floating point register 0 */
kFPC = 26, /* 68881 control register */
kFPS = 27, /* 68881 status register */
kFPI = 28, /* Floating point register 1 */
- kRegistersCount,
};
struct M68KCPUState {