from PySide2 import QtCore from PySide2.QtCore import Qt, QSize from PySide2.QtWidgets import QApplication, QHBoxLayout, QVBoxLayout, QLabel, QWidget, QPushButton, QLineEdit, QTextEdit from PySide2.QtGui import QTextCursor import binaryninja from binaryninjaui import DockHandler, DockContextHandler, UIActionHandler, getMonospaceFont from .. import binjaplug class DebugConsoleWidget(QWidget, DockContextHandler): def __init__(self, parent, name, data): if not type(data) == binaryninja.binaryview.BinaryView: raise Exception('expected widget data to be a BinaryView') self.bv = data QWidget.__init__(self, parent) DockContextHandler.__init__(self, self, name) self.actionHandler = UIActionHandler() self.actionHandler.setupActionHandler(self) layout = QVBoxLayout() self.consoleText = QTextEdit(self) self.consoleText.setReadOnly(True) self.consoleText.setFont(getMonospaceFont(self)) layout.addWidget(self.consoleText, 1) inputLayout = QHBoxLayout() inputLayout.setContentsMargins(4, 4, 4, 4) promptLayout = QVBoxLayout() promptLayout.setContentsMargins(0, 5, 0, 5) inputLayout.addLayout(promptLayout) self.consoleEntry = QLineEdit(self) inputLayout.addWidget(self.consoleEntry, 1) self.entryLabel = QLabel("dbg>>> ", self) self.entryLabel.setFont(getMonospaceFont(self)) promptLayout.addWidget(self.entryLabel) promptLayout.addStretch(1) self.consoleEntry.returnPressed.connect(lambda: self.sendLine()) layout.addLayout(inputLayout) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) self.setLayout(layout) def sizeHint(self): return QSize(300, 100) def canWrite(self): debug_state = binjaplug.get_state(self.bv) try: return debug_state.adapter.stdin_is_writable() except: return False def sendLine(self): if not self.canWrite(): return line = self.consoleEntry.text() self.consoleEntry.setText("") debug_state = binjaplug.get_state(self.bv) try: debug_state.send_console_input(line) except Exception as e: self.notifyStdout("Error sending input: {} {}\n".format(type(e).__name__, ' '.join(e.args))) def notifyStdout(self, line): self.consoleText.insertPlainText(line) # Scroll down cursor = self.consoleText.textCursor() cursor.clearSelection() cursor.movePosition(QTextCursor.End) self.consoleText.setTextCursor(cursor) self.updateEnabled() def updateEnabled(self): enabled = self.canWrite() self.consoleEntry.setEnabled(enabled) self.entryLabel.setText("stdin>>> " if enabled else "stdin (unavailable) ") #-------------------------------------------------------------------------- # callbacks to us api/ui/dockhandler.h #-------------------------------------------------------------------------- def notifyOffsetChanged(self, offset): self.updateEnabled() def notifyViewChanged(self, view_frame): self.updateEnabled() def contextMenuEvent(self, event): self.m_contextMenuManager.show(self.m_menu, self.actionHandler) def shouldBeVisible(self, view_frame): if view_frame is None: return False else: return True