Skip to content

Commit

Permalink
Destroy the controller via the FileMetadata
Browse files Browse the repository at this point in the history
  • Loading branch information
xusheng6 committed Feb 19, 2024
1 parent 6eb7670 commit 67ded6c
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 68 deletions.
2 changes: 2 additions & 0 deletions api/debuggerapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,8 @@ namespace BinaryNinjaDebuggerAPI {
DebuggerController(BNDebuggerController* controller);
static DbgRef<DebuggerController> GetController(Ref<BinaryNinja::BinaryView> data);
static bool ControllerExists(Ref<BinaryNinja::BinaryView> data);
static DbgRef<DebuggerController> GetController(Ref<BinaryNinja::FileMetadata> file);
static bool ControllerExists(Ref<BinaryNinja::FileMetadata> file);
void Destroy();
Ref<BinaryView> GetLiveView();
Ref<BinaryView> GetData();
Expand Down
22 changes: 22 additions & 0 deletions api/debuggercontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ using namespace std;

DbgRef<DebuggerController> DebuggerController::GetController(Ref<BinaryNinja::BinaryView> data)
{
if (!data)
return nullptr;

BNDebuggerController* controller = BNGetDebuggerController(data->GetObject());
if (!controller)
return nullptr;
Expand All @@ -30,6 +33,19 @@ DbgRef<DebuggerController> DebuggerController::GetController(Ref<BinaryNinja::Bi
}


DbgRef<DebuggerController> DebuggerController::GetController(Ref<BinaryNinja::FileMetadata> file)
{
if (!file)
return nullptr;

BNDebuggerController* controller = BNGetDebuggerControllerFromFile(file->GetObject());
if (!controller)
return nullptr;

return new DebuggerController(controller);
}


DebuggerController::DebuggerController(BNDebuggerController* controller)
{
m_object = controller;
Expand All @@ -42,6 +58,12 @@ bool DebuggerController::ControllerExists(Ref<BinaryNinja::BinaryView> data)
}


bool DebuggerController::ControllerExists(Ref<BinaryNinja::FileMetadata> file)
{
return BNDebuggerControllerExistsFromFile(file->GetObject());
}


void DebuggerController::Destroy()
{
BNDebuggerDestroyController(m_object);
Expand Down
3 changes: 3 additions & 0 deletions api/ffi.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ extern "C"
typedef struct BNDebuggerState BNDebuggerState;

typedef struct BNBinaryView BNBinaryView;
typedef struct BNFileMetadata BNFileMetadata;
typedef struct BNArchitecture BNArchitecture;
typedef struct BNDataBuffer BNDataBuffer;
typedef struct BNMetadata BNMetadata;
Expand Down Expand Up @@ -332,6 +333,8 @@ extern "C"
DEBUGGER_FFI_API BNDebuggerController* BNGetDebuggerController(BNBinaryView* data);
DEBUGGER_FFI_API void BNDebuggerDestroyController(BNDebuggerController* controller);
DEBUGGER_FFI_API bool BNDebuggerControllerExists(BNBinaryView* data);
DEBUGGER_FFI_API BNDebuggerController* BNGetDebuggerControllerFromFile(BNFileMetadata* file);
DEBUGGER_FFI_API bool BNDebuggerControllerExistsFromFile(BNFileMetadata* file);
DEBUGGER_FFI_API BNBinaryView* BNDebuggerGetLiveView(BNDebuggerController* controller);
DEBUGGER_FFI_API BNBinaryView* BNDebuggerGetData(BNDebuggerController* controller);
DEBUGGER_FFI_API void BNDebuggerSetData(BNDebuggerController* controller, BNBinaryView* data);
Expand Down
54 changes: 53 additions & 1 deletion core/debuggercontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1125,11 +1125,63 @@ bool DebuggerController::ControllerExists(BinaryViewRef data)
}


DbgRef<DebuggerController> DebuggerController::GetController(FileMetadataRef file)
{
for (size_t i = 0; i < g_controllerCount; i++)
{
DebuggerController* controller = g_debuggerControllers[i];
if (!controller)
continue;
if (controller->GetFile() == file)
return controller;
}

// You cannot create a controller from a file -- you must use a binary view for it
return nullptr;
}


bool DebuggerController::ControllerExists(FileMetadataRef file)
{
for (size_t i = 0; i < g_controllerCount; i++)
{
DbgRef<DebuggerController> controller = g_debuggerControllers[i];
if (!controller)
continue;
if (controller->GetFile() == file)
return true;
}

return false;
}


void DebuggerController::DeleteController(FileMetadataRef file)
{
for (size_t i = 0; i < g_controllerCount; i++)
{
DbgRef<DebuggerController> controller = g_debuggerControllers[i];
if (!controller)
continue;

if (controller->GetFile() == file)
{
g_debuggerControllers[i] = nullptr;
}
}
}


void DebuggerController::Destroy()
{
DebuggerController::DeleteController(GetData());
DebuggerController::DeleteController(GetFile());
m_file = nullptr;
m_liveView = nullptr;
if (m_state)
{
delete m_state;
m_state = nullptr;
}
}


Expand Down
6 changes: 6 additions & 0 deletions core/debuggercontroller.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,11 @@ namespace BinaryNinjaDebugger {
static DbgRef<DebuggerController> GetController(BinaryViewRef data);
static void DeleteController(BinaryViewRef data);
static bool ControllerExists(BinaryViewRef data);

static DbgRef<DebuggerController> GetController(FileMetadataRef file);
static void DeleteController(FileMetadataRef file);
static bool ControllerExists(FileMetadataRef file);

// Explicitly destroy the current controller, so a new controller on the same binaryview will be brand new.
// I am not super sure that this is the correct way of doing things, but it addresses the controller reuse
// problem.
Expand Down Expand Up @@ -252,6 +257,7 @@ namespace BinaryNinjaDebugger {
DebugAdapter* GetAdapter() { return m_adapter; }
DebuggerState* GetState() { return m_state; }
BinaryViewRef GetData() { return m_file->GetViewOfType(m_viewName); }
FileMetadataRef GetFile() { return m_file; }
void SetData(BinaryViewRef view) {}
BinaryViewRef GetLiveView() const { return m_liveView; }

Expand Down
24 changes: 24 additions & 0 deletions core/ffi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,30 @@ bool BNDebuggerControllerExists(BNBinaryView* data)
}


BNDebuggerController* BNGetDebuggerControllerFromFile(BNFileMetadata* file)
{
if (!file)
return nullptr;

Ref<FileMetadata> fileObject = new FileMetadata(BNNewFileReference(file));
DebuggerController* controller = DebuggerController::GetController(fileObject);
if (!controller)
return nullptr;

return DBG_API_OBJECT_REF(controller);
}


bool BNDebuggerControllerExistsFromFile(BNFileMetadata* file)
{
if (!file)
return false;

Ref<FileMetadata> fileObject = new FileMetadata(BNNewFileReference(file));
return DebuggerController::ControllerExists(fileObject);
}


BNBinaryView* BNDebuggerGetLiveView(BNDebuggerController* controller)
{
BinaryViewRef result = controller->object->GetLiveView();
Expand Down
102 changes: 35 additions & 67 deletions ui/uinotification.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,34 +78,6 @@ bool NotificationListener::OnBeforeSaveFile(UIContext* context, FileContext* fil
void NotificationListener::OnAfterSaveFile(UIContext* context, FileContext* file, ViewFrame* frame) {}


static void DestroyControllers(FileContext* file)
{
for (auto view : file->getAllDataViews())
{
if (DebuggerController::ControllerExists(view))
{
auto controller = DebuggerController::GetController(view);
if (controller)
controller->Destroy();
}
}
}


static void DestroyControllers(const std::vector<BinaryViewRef>& datas)
{
for (auto view : datas)
{
if (DebuggerController::ControllerExists(view))
{
auto controller = DebuggerController::GetController(view);
if (controller)
controller->Destroy();
}
}
}


bool NotificationListener::OnBeforeCloseFile(UIContext* context, FileContext* file, ViewFrame* frame)
{
auto mainWindow = context->mainWindow();
Expand All @@ -118,48 +90,44 @@ bool NotificationListener::OnBeforeCloseFile(UIContext* context, FileContext* fi
count++;
}

// This is the last tab of the file being closed. Check whether the debugger is connected
if (count == 1)
// If this is not the last tab of the file being closed, return
if (count != 1)
return true;

auto controller = DebuggerController::GetController(file->getMetadata());
if (!controller)
return true;

if (controller->IsConnected())
{
auto viewFrame = context->getCurrentViewFrame();
if (!viewFrame)
return true;
auto data = viewFrame->getCurrentBinaryView();
if (!data)
return true;
auto controller = DebuggerController::GetController(data);
if (controller && controller->IsConnected())
QMessageBox* msgBox = new QMessageBox(mainWindow);
msgBox->setAttribute(Qt::WA_DeleteOnClose);
msgBox->setIcon(QMessageBox::Question);
msgBox->setText(QObject::tr("The debugger file ") + file->getShortFileName(mainWindow)
+ QObject::tr(" is active. Do you want to stop it before closing?"));
msgBox->setWindowTitle(QObject::tr("Debugger Active"));
msgBox->setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
msgBox->setDefaultButton(QMessageBox::Yes);
msgBox->show();
msgBox->move(mainWindow->frameGeometry().center() - msgBox->rect().center());
msgBox->setAttribute(Qt::WA_KeyboardFocusChange);
int result = msgBox->exec();
if (result == QMessageBox::Cancel)
return false;
else if (result == QMessageBox::Yes)
{
QMessageBox* msgBox = new QMessageBox(mainWindow);
msgBox->setAttribute(Qt::WA_DeleteOnClose);
msgBox->setIcon(QMessageBox::Question);
msgBox->setText(QObject::tr("The debugger file ") + file->getShortFileName(mainWindow)
+ QObject::tr(" is active. Do you want to stop it before closing?"));
msgBox->setWindowTitle(QObject::tr("Debugger Active"));
msgBox->setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
msgBox->setDefaultButton(QMessageBox::Yes);
msgBox->show();
msgBox->move(mainWindow->frameGeometry().center() - msgBox->rect().center());
msgBox->setAttribute(Qt::WA_KeyboardFocusChange);
int result = msgBox->exec();
if (result == QMessageBox::Cancel)
return false;
else if (result == QMessageBox::Yes)
{
// Since the UIContext is not ref-counted, it would have been deleted when the thread we create below
// gets a chance to run. So we need to take all its data views and pass them as a parameter.
auto datas = file->getAllDataViews();
std::thread([=]() {
// Since we cannot wait for the target to stop on the main thread, we must create a new thread and
// wait from there.
controller->QuitAndWait();
DestroyControllers(datas);
}).detach();
return true;
}
std::thread([=]() {
// Since we cannot wait for the target to stop on the main thread, we must create a new thread and
// wait from there.
controller->QuitAndWait();
controller->Destroy();
}).detach();
return true;
}

DestroyControllers(file);
}
else
{
controller->Destroy();
}
return true;
}
Expand Down

0 comments on commit 67ded6c

Please sign in to comment.