mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-18 19:23:56 +00:00
Support threads in gdb
This commit is contained in:
@@ -115,6 +115,28 @@ namespace gdb_stub
|
||||
{
|
||||
connection.send_reply("OK");
|
||||
}
|
||||
else if (name == "C")
|
||||
{
|
||||
const auto thread_id = handler.get_current_thread_id();
|
||||
connection.send_reply("QC" + utils::string::to_hex_number(thread_id));
|
||||
}
|
||||
else if (name == "sThreadInfo")
|
||||
{
|
||||
connection.send_reply("l");
|
||||
}
|
||||
else if (name == "fThreadInfo")
|
||||
{
|
||||
std::string reply{};
|
||||
const auto ids = handler.get_thread_ids();
|
||||
|
||||
for (const auto id : ids)
|
||||
{
|
||||
reply.push_back(reply.empty() ? 'm' : ',');
|
||||
reply.append(utils::string::to_hex_number(id));
|
||||
}
|
||||
|
||||
connection.send_reply(reply);
|
||||
}
|
||||
else
|
||||
{
|
||||
connection.send_reply({});
|
||||
@@ -389,6 +411,29 @@ namespace gdb_stub
|
||||
connection.send_reply("OK");
|
||||
}
|
||||
|
||||
void switch_to_thread(connection_handler& connection, debugging_handler& handler,
|
||||
const std::string_view payload)
|
||||
{
|
||||
if (payload.size() < 2)
|
||||
{
|
||||
connection.send_reply({});
|
||||
return;
|
||||
}
|
||||
|
||||
const auto operation = payload[0];
|
||||
if (operation != 'g')
|
||||
{
|
||||
connection.send_reply("OK");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t id{};
|
||||
rt_assert(sscanf_s(std::string(payload.substr(1)).c_str(), "%x", &id) == 1);
|
||||
|
||||
const auto res = id == 0 || handler.switch_to_thread(id);
|
||||
connection.send_reply(res ? "OK" : "E01");
|
||||
}
|
||||
|
||||
void handle_command(connection_handler& connection, async_handler& async, debugging_handler& handler,
|
||||
const uint8_t command, const std::string_view data)
|
||||
{
|
||||
@@ -453,6 +498,10 @@ namespace gdb_stub
|
||||
write_x_memory(connection, handler, data);
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
switch_to_thread(connection, handler, data);
|
||||
break;
|
||||
|
||||
default:
|
||||
connection.send_reply({});
|
||||
break;
|
||||
|
||||
@@ -43,6 +43,11 @@ namespace gdb_stub
|
||||
virtual void on_interrupt() = 0;
|
||||
|
||||
virtual std::string get_target_description(std::string_view file) = 0;
|
||||
|
||||
virtual bool switch_to_thread(uint32_t thread_id) = 0;
|
||||
|
||||
virtual uint32_t get_current_thread_id() = 0;
|
||||
virtual std::vector<uint32_t> get_thread_ids() = 0;
|
||||
};
|
||||
|
||||
bool run_gdb_stub(const network::address& bind_address, debugging_handler& handler);
|
||||
|
||||
@@ -40,6 +40,34 @@ class win_x64_gdb_stub_handler : public x64_gdb_stub_handler
|
||||
return gdb_stub::action::resume;
|
||||
}
|
||||
|
||||
uint32_t get_current_thread_id() override
|
||||
{
|
||||
return this->win_emu_->current_thread().id;
|
||||
}
|
||||
|
||||
std::vector<uint32_t> get_thread_ids() override
|
||||
{
|
||||
const auto& threads = this->win_emu_->process().threads;
|
||||
|
||||
std::vector<uint32_t> ids{};
|
||||
ids.reserve(threads.size());
|
||||
|
||||
for (const auto& t : threads | std::views::values)
|
||||
{
|
||||
if (!t.is_terminated())
|
||||
{
|
||||
ids.push_back(t.id);
|
||||
}
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
bool switch_to_thread(const uint32_t thread_id) override
|
||||
{
|
||||
return this->win_emu_->activate_thread(thread_id);
|
||||
}
|
||||
|
||||
private:
|
||||
windows_emulator* win_emu_{};
|
||||
};
|
||||
|
||||
@@ -250,6 +250,16 @@ class x64_gdb_stub_handler : public gdb_stub::debugging_handler
|
||||
return entry->second;
|
||||
}
|
||||
|
||||
uint32_t get_current_thread_id() override
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::vector<uint32_t> get_thread_ids() override
|
||||
{
|
||||
return {this->get_current_thread_id()};
|
||||
}
|
||||
|
||||
private:
|
||||
x64_emulator* emu_{};
|
||||
|
||||
|
||||
@@ -525,14 +525,39 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
bool switch_to_thread(windows_emulator& win_emu, emulator_thread& thread)
|
||||
emulator_thread* get_thread_by_id(process_context& process, const uint32_t id)
|
||||
{
|
||||
for (auto& t : process.threads | std::views::values)
|
||||
{
|
||||
if (t.id == id)
|
||||
{
|
||||
return &t;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool switch_to_thread(windows_emulator& win_emu, emulator_thread& thread, const bool force = false)
|
||||
{
|
||||
if (thread.is_terminated())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& emu = win_emu.emu();
|
||||
auto& context = win_emu.process();
|
||||
|
||||
if (!thread.is_thread_ready(win_emu))
|
||||
const auto is_ready = thread.is_thread_ready(win_emu);
|
||||
|
||||
if (!is_ready)
|
||||
{
|
||||
return false;
|
||||
if (!force)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
win_emu.yield_thread();
|
||||
}
|
||||
|
||||
auto* active_thread = context.active_thread;
|
||||
@@ -553,7 +578,6 @@ namespace
|
||||
|
||||
thread.restore(emu);
|
||||
thread.setup_if_necessary(emu, context);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -863,6 +887,17 @@ void windows_emulator::perform_thread_switch()
|
||||
}
|
||||
}
|
||||
|
||||
bool windows_emulator::activate_thread(const uint32_t id)
|
||||
{
|
||||
const auto thread = get_thread_by_id(this->process(), id);
|
||||
if (!thread)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return switch_to_thread(*this, *thread, true);
|
||||
}
|
||||
|
||||
void windows_emulator::on_instruction_execution(const uint64_t address)
|
||||
{
|
||||
auto& process = this->process();
|
||||
|
||||
@@ -124,6 +124,7 @@ class windows_emulator
|
||||
|
||||
void yield_thread();
|
||||
void perform_thread_switch();
|
||||
bool activate_thread(uint32_t id);
|
||||
|
||||
bool time_is_relative() const
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user