Skip to content

Commit cbd5258

Browse files
committed
dev: starting ai decompiler feature
1 parent 5493fbd commit cbd5258

3 files changed

Lines changed: 91 additions & 38 deletions

File tree

revengai/features/__init__.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,13 @@
77
from .view_function_in_portal import ViewFunctionInPortalFeature
88
from .ai_decompiler import AIDecompilerFeature
99

10-
__all__ = ['ConfigurationFeature', 'UploadFeature', 'AutoUnstripFeature', 'ChooseSourceFeature', 'MatchFunctionsFeature', 'MatchCurrentFunctionFeature', 'ViewFunctionInPortalFeature', 'AIDecompilerFeature']
10+
__all__ = [
11+
'ConfigurationFeature',
12+
'UploadFeature',
13+
'AutoUnstripFeature',
14+
'ChooseSourceFeature',
15+
'MatchFunctionsFeature',
16+
'MatchCurrentFunctionFeature',
17+
'ViewFunctionInPortalFeature',
18+
'AIDecompilerFeature'
19+
]

revengai/features/ai_decompiler/__init__.py

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
1-
from binaryninja import PluginCommand, log_info, BinaryView
1+
from binaryninja import PluginCommand, log_info, BinaryView, log_error
2+
from PySide6.QtWidgets import QWidget, QVBoxLayout, QTabWidget, QLabel, QDockWidget
23
from .ai_decompiler import AIDecompiler
4+
from binaryninjaui import UIContext
5+
from PySide6.QtCore import Qt
36
from .ai_decompiler_dialog import AIDecompilerDialog
47
from revengai.utils import BaseAuthFeature
58

69
class AIDecompilerFeature(BaseAuthFeature):
710
def __init__(self, config=None):
811
super().__init__(config)
912
self.ai_decompiler = AIDecompiler(config)
13+
self.dock_widget = None
14+
self.widget = None
1015
log_info("RevEng.AI | AIDecompiler Feature initialized")
1116

1217
def register(self):
@@ -19,9 +24,43 @@ def register(self):
1924
log_info("RevEng.AI | AIDecompiler Feature registered")
2025

2126
def show_ai_decompiler_dialog(self, bv: BinaryView, func):
22-
log_info("RevEng.AI | Opening MatchCurrentFunction dialog")
23-
dialog = AIDecompilerDialog(self.config, self.ai_decompiler, bv, func)
24-
dialog.exec_()
27+
try:
28+
log_info("RevEng.AI | Opening AI Decompiler Dock")
29+
30+
ctx = UIContext.activeContext()
31+
if not ctx:
32+
log_error("RevEng.AI | No active UI context.")
33+
return
34+
35+
main_win = ctx.mainWindow()
36+
if not main_win:
37+
log_error("RevEng.AI | No main window found.")
38+
return
39+
40+
if self.dock_widget is not None and self.dock_widget.parent() is not None:
41+
self.dock_widget.raise_()
42+
log_info(f"RevEng.AI | AI Decompiler Dock already open, adding tab 0x{func:x}")
43+
if self.widget is not None:
44+
self.widget.add_tab(func)
45+
return
46+
47+
self.dock_widget = QDockWidget("RevEng.AI | AI Decompiler", main_win)
48+
self.widget = AIDecompilerDialog(self.config, self.ai_decompiler, bv, func)
49+
self.dock_widget.setObjectName("RevEng.AI | AI Decompiler")
50+
self.dock_widget.setWidget(self.widget)
51+
main_win.addDockWidget(Qt.RightDockWidgetArea, self.dock_widget)
52+
self.dock_widget.raise_()
53+
54+
self.dock_widget.visibilityChanged.connect(self.on_dock_closed)
55+
log_info("RevEng.AI | AI Decompiler Dock displayed.")
56+
57+
except Exception as e:
58+
log_error(f"RevEng.AI | Error opening AI Decompiler Dock: {e}")
59+
return
60+
61+
def on_dock_closed(self, visible):
62+
if not visible:
63+
self.dock_widget = None
2564

2665
def is_valid(self, bv: BinaryView, func):
2766
return self.config.is_configured == True
Lines changed: 38 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,59 @@
1-
from binaryninja import log_error
1+
from binaryninja import log_error, log_info
22
from PySide6.QtWidgets import (QDockWidget, QVBoxLayout, QHBoxLayout,
3-
QPushButton, QLabel, QCheckBox, QWidget)
3+
QPushButton, QLabel, QCheckBox, QWidget, QTabWidget)
44
from PySide6.QtCore import Qt
55
from PySide6.QtGui import QPixmap
6+
from PySide6.QtWidgets import QWidget
67
from PySide6.QtCore import QCoreApplication
78
from PySide6.QtWidgets import QMessageBox
89
from PySide6.QtWidgets import QProgressBar
910
from revengai.utils import create_progress_dialog
1011
from revengai.utils.data_thread import DataThread
1112
import os
1213

13-
class AIDecompilerDialog(QDockWidget):
14+
class AIDecompilerDialog(QWidget):
1415
def __init__(self, config, ai_decompiler, bv, func):
1516
super().__init__()
1617
self.config = config
1718
self.ai_decompiler = ai_decompiler
1819
self.bv = bv
1920
self.func = func
20-
self.init_ui()
21+
self.tabs = QTabWidget()
22+
self.init_ui(func)
2123

22-
def init_ui(self):
24+
def init_ui(self, func):
2325
self.setWindowTitle("RevEng.AI: AI Decompiler")
24-
25-
# Create a widget to hold the layout
26-
content_widget = QWidget()
27-
layout = QVBoxLayout(content_widget)
28-
29-
title_label = QLabel("Getting AI decompiler...")
30-
title_label.setStyleSheet("font-size: 18px;")
31-
layout.addWidget(title_label)
26+
layout = QVBoxLayout()
27+
self.setLayout(layout)
28+
layout.addWidget(self.tabs)
29+
self.add_tab(func)
30+
self.tabs.tabCloseRequested.connect(self.close_tab)
31+
32+
def add_tab(self, tab_name):
33+
tab_name = str(f"0x{tab_name:x}")
34+
for i in range(self.tabs.count()):
35+
log_info(f"RevEng.AI | Tab {self.tabs.tabText(i)} == {tab_name}")
36+
if self.tabs.tabText(i) == tab_name:
37+
self.tabs.setCurrentIndex(i)
38+
return
39+
40+
log_info(f"RevEng.AI | Adding tab {tab_name}")
41+
tab = QWidget()
42+
layout = QVBoxLayout()
43+
layout.addWidget(QLabel(f"{tab_name} UI goes here"))
44+
tab.setLayout(layout)
45+
index = self.tabs.addTab(tab, tab_name)
46+
self.tabs.setCurrentIndex(index)
47+
48+
if self.tabs.count() > 1:
49+
self.tabs.setTabsClosable(True)
50+
51+
def close_tab(self, index):
52+
log_info(f"RevEng.AI | Closing tab {index} of {self.tabs.count()} tabs")
53+
self.tabs.removeTab(index)
54+
if self.tabs.count() == 1:
55+
self.tabs.setTabsClosable(False)
3256

33-
progress_bar = QProgressBar()
34-
progress_bar.setMinimumWidth(250)
35-
progress_bar.setMinimumHeight(20)
36-
layout.addWidget(progress_bar)
3757

38-
# Set the content widget
39-
self.setWidget(content_widget)
4058

41-
self.setStyleSheet("""
42-
QProgressBar {
43-
border: 1px solid #cccccc;
44-
border-radius: 4px;
45-
text-align: center;
46-
background-color: #f0f0f0;
47-
min-width: 250px;
48-
min-height: 20px;
49-
}
50-
QProgressBar::chunk {
51-
background-color: #007bff;
52-
border-radius: 3px;
53-
}
54-
""")
59+

0 commit comments

Comments
 (0)