Skip to content

Commit

Permalink
Add support for DbgEng TTD into the debugger
Browse files Browse the repository at this point in the history
  • Loading branch information
xusheng6 committed Jun 19, 2023
1 parent 7fcdfe8 commit 416ff54
Show file tree
Hide file tree
Showing 8 changed files with 407 additions and 39 deletions.
7 changes: 6 additions & 1 deletion core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@ file(GLOB ADAPTER_SOURCES
)

if(WIN32)
set(SOURCES ${COMMON_SOURCES} ${ADAPTER_SOURCES} adapters/dbgengadapter.cpp adapters/dbgengadapter.h)
set(SOURCES ${COMMON_SOURCES} ${ADAPTER_SOURCES}
adapters/dbgengadapter.cpp
adapters/dbgengadapter.h
adapters/dbgengttdadapter.cpp
adapters/dbgengttdadapter.h
)
else()
set(SOURCES ${COMMON_SOURCES} ${ADAPTER_SOURCES})
endif()
Expand Down
59 changes: 31 additions & 28 deletions core/adapters/dbgengadapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,6 @@ limitations under the License.
using namespace BinaryNinjaDebugger;
using namespace std;

#define QUERY_DEBUG_INTERFACE(query, out) \
if (const auto result = this->m_debugClient->QueryInterface(__uuidof(query), reinterpret_cast<void**>(out)); \
result != S_OK) \
throw std::runtime_error("Failed to create " #query)

static bool IsValidDbgEngPaths(const std::string& path)
{
if (path.empty())
Expand Down Expand Up @@ -104,7 +99,7 @@ std::string DbgEngAdapter::GetDbgEngPath(const std::string& arch)

bool DbgEngAdapter::LoadDngEngLibraries()
{
auto enginePath = GetDbgEngPath();
auto enginePath = GetDbgEngPath("x64");
if (!enginePath.empty())
{
LogDebug("DbgEng libraries in path %s", enginePath.c_str());
Expand Down Expand Up @@ -196,11 +191,11 @@ bool DbgEngAdapter::ConnectToDebugServerInternal(const std::string& connectionSt
if (DebugCreate == nullptr)
return false;

if (const auto result = DebugCreate(__uuidof(IDebugClient5), reinterpret_cast<void**>(&this->m_debugClient));
if (const auto result = DebugCreate(__uuidof(IDebugClient7), reinterpret_cast<void**>(&this->m_debugClient));
result != S_OK)
throw std::runtime_error("Failed to create IDebugClient5");
throw std::runtime_error("Failed to create IDebugClient7");

QUERY_DEBUG_INTERFACE(IDebugControl5, &this->m_debugControl);
QUERY_DEBUG_INTERFACE(IDebugControl7, &this->m_debugControl);
QUERY_DEBUG_INTERFACE(IDebugDataSpaces, &this->m_debugDataSpaces);
QUERY_DEBUG_INTERFACE(IDebugRegisters, &this->m_debugRegisters);
QUERY_DEBUG_INTERFACE(IDebugSymbols3, &this->m_debugSymbols);
Expand Down Expand Up @@ -271,14 +266,6 @@ bool DbgEngAdapter::Start()
return true;
}

#undef QUERY_DEBUG_INTERFACE

#define SAFE_RELEASE(ptr) \
if (ptr) \
{ \
ptr->Release(); \
ptr = nullptr; \
}

void DbgEngAdapter::Reset()
{
Expand All @@ -305,27 +292,32 @@ void DbgEngAdapter::Reset()
m_connectedToDebugServer = false;
m_server = 0;
}

SAFE_RELEASE(this->m_debugClient);
}

this->m_debugActive = false;
}

#undef SAFE_RELEASE

DbgEngAdapter::DbgEngAdapter(BinaryView* data) : DebugAdapter(data)
{
auto metadata = data->QueryMetadata("PDB_FILENAME");
if (metadata && metadata->IsString())
m_pdbFileName = metadata->GetString();
LoadDngEngLibraries();
}

DbgEngAdapter::~DbgEngAdapter()
{
this->Reset();
}


bool DbgEngAdapter::Init()
{
return LoadDngEngLibraries();
}


bool DbgEngAdapter::Execute(const std::string& path, const LaunchConfigurations& configs)
{
return this->ExecuteWithArgs(path, "", "", {});
Expand Down Expand Up @@ -496,15 +488,25 @@ void DbgEngAdapter::EngineLoop()
// TODO: add step branch and step backs
else if ((execution_status == DEBUG_STATUS_GO) || (execution_status == DEBUG_STATUS_STEP_INTO)
|| (execution_status == DEBUG_STATUS_STEP_OVER) || (execution_status == DEBUG_STATUS_GO_HANDLED)
|| (execution_status == DEBUG_STATUS_GO_NOT_HANDLED))
|| (execution_status == DEBUG_STATUS_STEP_BRANCH)
|| (execution_status == DEBUG_STATUS_GO_NOT_HANDLED) || (execution_status == DEBUG_STATUS_REVERSE_GO)
|| (execution_status == DEBUG_STATUS_REVERSE_STEP_OVER)
|| (execution_status == DEBUG_STATUS_REVERSE_STEP_INTO)
|| (execution_status == DEBUG_STATUS_REVERSE_STEP_BRANCH))
{
DebuggerEvent dbgevt;
if (execution_status == DEBUG_STATUS_GO)
if ((execution_status == DEBUG_STATUS_GO) || (execution_status == DEBUG_STATUS_REVERSE_GO)
|| ((execution_status == DEBUG_STATUS_GO_HANDLED))
|| (execution_status == DEBUG_STATUS_GO_NOT_HANDLED))
{
dbgevt.type = ResumeEventType;
PostDebuggerEvent(dbgevt);
}
else if ((execution_status == DEBUG_STATUS_STEP_INTO) || (execution_status == DEBUG_STATUS_STEP_OVER))
else if ((execution_status == DEBUG_STATUS_STEP_INTO) || (execution_status == DEBUG_STATUS_STEP_OVER)
|| (execution_status == DEBUG_STATUS_STEP_BRANCH)
|| (execution_status == DEBUG_STATUS_REVERSE_STEP_OVER)
|| (execution_status == DEBUG_STATUS_REVERSE_STEP_INTO)
|| (execution_status == DEBUG_STATUS_REVERSE_STEP_BRANCH))
{
dbgevt.type = StepIntoEventType;
PostDebuggerEvent(dbgevt);
Expand Down Expand Up @@ -782,10 +784,11 @@ DebugBreakpoint DbgEngAdapter::AddBreakpoint(const std::uintptr_t address, unsig
{
IDebugBreakpoint2* debug_breakpoint {};

/* attempt to read/write at breakpoint location to confirm its valid */
/* attempt to read at breakpoint location to confirm its valid */
/* DbgEng won't tell us if its valid until continue/go so this is a hacky fix */
auto val = this->ReadMemory(address, sizeof(std::uint16_t));
if (!this->WriteMemory(address, val))
/* Note we cannot write to it if we are replaying TTD trace */
auto val = this->ReadMemory(address, 1);
if (val.GetLength() != 1)
return {};

if (const auto result =
Expand Down Expand Up @@ -1132,7 +1135,7 @@ bool DbgEngAdapter::Wait(std::chrono::milliseconds timeout)
std::memset(&DbgEngAdapter::ProcessCallbackInfo.m_lastBreakpoint, 0, sizeof(DbgEngAdapter::ProcessCallbackInfo.m_lastBreakpoint));
std::memset(&DbgEngAdapter::ProcessCallbackInfo.m_lastException, 0, sizeof(DbgEngAdapter::ProcessCallbackInfo.m_lastException));

const auto wait_result = this->m_debugControl->WaitForEvent(0, timeout.count());
const auto wait_result = this->m_debugControl->WaitForEvent(0, INFINITE);
return wait_result == S_OK;
}

Expand Down Expand Up @@ -1439,7 +1442,7 @@ HRESULT DbgEngInputCallbacks::QueryInterface(const IID& interface_id, void** _in
return S_OK;
}

void DbgEngInputCallbacks::SetDbgControl(IDebugControl5* control)
void DbgEngInputCallbacks::SetDbgControl(IDebugControl7* control)
{
m_control = control;
}
Expand Down
31 changes: 23 additions & 8 deletions core/adapters/dbgengadapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,18 @@ limitations under the License.
#include <chrono>

namespace BinaryNinjaDebugger {
#define SAFE_RELEASE(ptr) \
if (ptr) \
{ \
ptr->Release(); \
ptr = nullptr; \
}

#define QUERY_DEBUG_INTERFACE(query, out) \
if (const auto result = this->m_debugClient->QueryInterface(__uuidof(query), reinterpret_cast<void**>(out)); \
result != S_OK) \
throw std::runtime_error("Failed to create " #query)

struct ProcessCallbackInformation
{
DebugBreakpoint m_lastBreakpoint {};
Expand All @@ -48,15 +60,15 @@ namespace BinaryNinjaDebugger {
class DbgEngInputCallbacks : public IDebugInputCallbacks
{
private:
IDebugControl5* m_control;
IDebugControl7* m_control;

public:
CALLBACK_METHOD(unsigned long) AddRef() override;
CALLBACK_METHOD(unsigned long) Release() override;
CALLBACK_METHOD(HRESULT) QueryInterface(const IID& interface_id, void** _interface) override;
CALLBACK_METHOD(HRESULT) StartInput(ULONG BufferSize);
CALLBACK_METHOD(HRESULT) EndInput();
void SetDbgControl(IDebugControl5* control);
void SetDbgControl(IDebugControl7* control);
};

class DbgEngAdapter;
Expand Down Expand Up @@ -106,19 +118,20 @@ namespace BinaryNinjaDebugger {

class DbgEngAdapter : public DebugAdapter
{
public:
DbgEngEventCallbacks m_debugEventCallbacks {};
DbgEngOutputCallbacks m_outputCallbacks {};
DbgEngInputCallbacks m_inputCallbacks {};
IDebugClient5* m_debugClient {nullptr};
IDebugControl5* m_debugControl {nullptr};
IDebugClient7* m_debugClient {nullptr};
IDebugControl7* m_debugControl {nullptr};
IDebugDataSpaces* m_debugDataSpaces {nullptr};
IDebugRegisters* m_debugRegisters {nullptr};
IDebugSymbols3* m_debugSymbols {nullptr};
IDebugSystemObjects* m_debugSystemObjects {nullptr};
bool m_debugActive {false};

bool Start();
void Reset();
virtual bool Start();
virtual void Reset();

std::vector<DebugBreakpoint> m_debug_breakpoints {};
bool m_lastOperationIsStepInto = false;
Expand All @@ -144,10 +157,12 @@ namespace BinaryNinjaDebugger {
DbgEngAdapter(BinaryView* data);
~DbgEngAdapter();

bool Init() override;

[[nodiscard]] bool Execute(const std::string& path, const LaunchConfigurations& configs = {}) override;
[[nodiscard]] bool ExecuteWithArgs(const std::string& path, const std::string& args,
const std::string& workingDir, const LaunchConfigurations& configs = {}) override;
[[nodiscard]] bool ExecuteWithArgsInternal(const std::string& path, const std::string& args,
[[nodiscard]] virtual bool ExecuteWithArgsInternal(const std::string& path, const std::string& args,
const std::string& workingDir, const LaunchConfigurations& configs = {});
[[nodiscard]] bool Attach(std::uint32_t pid) override;
[[nodiscard]] bool AttachInternal(std::uint32_t pid);
Expand Down Expand Up @@ -216,7 +231,7 @@ namespace BinaryNinjaDebugger {

void ApplyBreakpoints();

std::string GetDbgEngPath(const std::string& arch = "x64");
virtual std::string GetDbgEngPath(const std::string& arch);

bool LoadDngEngLibraries();

Expand Down
Loading

0 comments on commit 416ff54

Please sign in to comment.