Skip to content

Commit 7ecb5ed

Browse files
committed
Support viewing the process list and select a process to debug with esReven adapter
1 parent 8bc88f8 commit 7ecb5ed

2 files changed

Lines changed: 167 additions & 5 deletions

File tree

core/adapters/esrevenadapter.cpp

Lines changed: 166 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,57 @@ bool EsrevenAdapter::ExecuteWithArgs(const std::string &path, const std::string
7979

8080
bool EsrevenAdapter::Attach(std::uint32_t pid)
8181
{
82-
LogWarn("EsrevenAdapter does not support Attach()");
83-
return false;
82+
if (!m_rspConnector)
83+
{
84+
LogWarn("EsrevenAdapter::Attach called without an active connection. "
85+
"Please connect to the debug server first.");
86+
return false;
87+
}
88+
89+
// Send rvn:select-process to activate process filtering at runtime
90+
auto response = m_rspConnector->TransmitAndReceive(
91+
RspData(fmt::format("rvn:select-process:{}", pid)));
92+
std::string responseStr = response.AsString();
93+
94+
if (responseStr != "OK")
95+
{
96+
LogWarn("Failed to select process %u: %s", pid, responseStr.c_str());
97+
DebuggerEvent event;
98+
event.type = LaunchFailureEventType;
99+
event.data.errorData.shortError = "Process selection failed";
100+
event.data.errorData.error =
101+
fmt::format("Failed to select process with PID {}: {}", pid, responseStr);
102+
PostDebuggerEvent(event);
103+
return false;
104+
}
105+
106+
m_processPid = pid;
107+
InvalidateCache();
108+
ClearCachedBreakpoints();
109+
110+
// Query the initial stop reason after selecting the process
111+
const auto reply = m_rspConnector->TransmitAndReceive(RspData("?"));
112+
auto map = RspConnector::PacketToUnorderedMap(reply);
113+
m_lastActiveThreadId = (uint32_t)map["thread"];
114+
m_isTargetRunning = false;
115+
116+
// Apply any pending breakpoints
117+
BNSettingsScope scope = SettingsResourceScope;
118+
auto data = GetData();
119+
auto adapterSettings = GetAdapterSettings();
120+
auto inputFile = adapterSettings->Get<std::string>("common.inputFile", data, &scope);
121+
122+
CheckApplyPendingBreakpoints();
123+
124+
if (Settings::Instance()->Get<bool>("debugger.stopAtEntryPoint") && m_hasEntryFunction)
125+
AddBreakpoint(ModuleNameAndOffset(inputFile, m_entryPoint - m_start));
126+
127+
DebuggerEvent dbgevt;
128+
dbgevt.type = AdapterStoppedEventType;
129+
dbgevt.data.targetStoppedData.reason = InitialBreakpoint;
130+
PostDebuggerEvent(dbgevt);
131+
132+
return true;
84133
}
85134

86135
bool EsrevenAdapter::LoadRegisterInfo()
@@ -297,8 +346,90 @@ bool EsrevenAdapter::Connect(const std::string& server, std::uint32_t port)
297346

298347
bool EsrevenAdapter::ConnectToDebugServer(const std::string &server, std::uint32_t port)
299348
{
300-
LogWarn("DbgAdapter does not support connecting to a debug server, please use connect to remote process instead");
301-
return false;
349+
m_canReverseContinue = false;
350+
m_canReverseStep = false;
351+
352+
BNSettingsScope scope = SettingsResourceScope;
353+
auto data = GetData();
354+
auto adapterSettings = GetAdapterSettings();
355+
scope = SettingsResourceScope;
356+
auto ipAddress = adapterSettings->Get<std::string>("debugServer.ipAddress", data, &scope);
357+
scope = SettingsResourceScope;
358+
auto serverPort = adapterSettings->Get<uint64_t>("debugServer.port", data, &scope);
359+
360+
bool connected = false;
361+
for (std::uint8_t index{}; index < 30; index++)
362+
{
363+
this->m_socket = new Socket(AF_INET, SOCK_STREAM, 0);
364+
365+
sockaddr_in address{};
366+
address.sin_family = (u_short)AF_INET;
367+
address.sin_addr.s_addr = inet_addr(ipAddress.c_str());
368+
address.sin_port = htons((u_short)serverPort);
369+
370+
if (this->m_socket->Connect(address))
371+
{
372+
connected = true;
373+
break;
374+
}
375+
376+
m_socket->Close();
377+
std::this_thread::sleep_for(std::chrono::milliseconds(500));
378+
}
379+
380+
if (!connected)
381+
{
382+
DebuggerEvent event;
383+
event.type = LaunchFailureEventType;
384+
event.data.errorData.shortError = "Connection failed";
385+
event.data.errorData.error =
386+
fmt::format("Failed to connect to debug server at {}:{}", ipAddress, serverPort);
387+
PostDebuggerEvent(event);
388+
return false;
389+
}
390+
391+
this->m_rspConnector = new RspConnector(this->m_socket);
392+
this->m_rspConnector->TransmitAndReceive(RspData("Hg0"));
393+
this->m_rspConnector->NegotiateCapabilities(
394+
{ "swbreak+", "hwbreak+", "qRelocInsn+", "fork-events+", "vfork-events+", "exec-events+",
395+
"vContSupported+", "QThreadEvents+", "no-resumed+", "xmlRegisters=i386" });
396+
397+
auto capacities = m_rspConnector->GetServerCapabilities();
398+
if (std::find(capacities.begin(), capacities.end(), "ReverseContinue") != capacities.end())
399+
m_canReverseContinue = true;
400+
if (std::find(capacities.begin(), capacities.end(), "ReverseStep") != capacities.end())
401+
m_canReverseStep = true;
402+
403+
if (!this->LoadRegisterInfo())
404+
{
405+
DebuggerEvent event;
406+
event.type = LaunchFailureEventType;
407+
event.data.errorData.shortError = "Invalid Register Info";
408+
event.data.errorData.error = fmt::format("Failed to read register info from the server");
409+
PostDebuggerEvent(event);
410+
return false;
411+
}
412+
413+
m_isTargetRunning = false;
414+
return true;
415+
}
416+
417+
418+
bool EsrevenAdapter::DisconnectDebugServer()
419+
{
420+
if (!m_rspConnector)
421+
return true;
422+
423+
this->m_rspConnector->SendPayload(RspData("D"));
424+
this->m_socket->Kill();
425+
m_isTargetRunning = false;
426+
InvalidateCache();
427+
ClearCachedBreakpoints();
428+
429+
delete m_rspConnector;
430+
m_rspConnector = nullptr;
431+
432+
return true;
302433
}
303434

304435
bool EsrevenAdapter::Detach()
@@ -2596,7 +2727,9 @@ bool EsrevenAdapterType::CanConnect(BinaryNinja::BinaryView *data)
25962727

25972728
bool EsrevenAdapterType::CanExecute(BinaryNinja::BinaryView *data)
25982729
{
2599-
return false;
2730+
// Return true so that the "Attach to Process..." button is enabled in the UI,
2731+
// allowing the two-step workflow: Connect to Debug Server → Attach to Process.
2732+
return true;
26002733
}
26012734

26022735
void BinaryNinjaDebugger::InitEsrevenAdapterType()
@@ -2656,6 +2789,34 @@ Ref<Settings> EsrevenAdapterType::RegisterAdapterSettings()
26562789
"readOnly" : false
26572790
})");
26582791

2792+
settings->RegisterSetting("attach.pid",
2793+
R"({
2794+
"title" : "PID to attach to",
2795+
"type" : "number",
2796+
"default" : 0,
2797+
"description" : "PID of the process to attach to",
2798+
"readOnly" : false
2799+
})");
2800+
2801+
settings->RegisterSetting("debugServer.ipAddress",
2802+
R"({
2803+
"title" : "Debug Server IP Address",
2804+
"type" : "string",
2805+
"default" : "127.0.0.1",
2806+
"description" : "IP address of the REVEN GDB stub to connect to",
2807+
"readOnly" : false
2808+
})");
2809+
settings->RegisterSetting("debugServer.port",
2810+
R"({
2811+
"title" : "Debug Server Port",
2812+
"type" : "number",
2813+
"default" : 31337,
2814+
"minValue" : 0,
2815+
"maxValue" : 65535,
2816+
"description" : "Port of the REVEN GDB stub to connect to",
2817+
"readOnly" : false
2818+
})");
2819+
26592820
settings->RegisterSetting("ttd.queryTimeout",
26602821
R"JSON({
26612822
"title" : "TTD Query Timeout",

core/adapters/esrevenadapter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ namespace BinaryNinjaDebugger
113113
bool Attach(std::uint32_t pid) override;
114114
bool Connect(const std::string& server, std::uint32_t port) override;
115115
bool ConnectToDebugServer(const std::string& server, std::uint32_t port) override;
116+
bool DisconnectDebugServer() override;
116117

117118
bool Detach() override;
118119
bool Quit() override;

0 commit comments

Comments
 (0)