summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api-docs/source/conf.py12
-rw-r--r--binaryninjaapi.h15
-rw-r--r--binaryninjacore.h4
-rw-r--r--binaryviewtype.cpp8
-rw-r--r--docs/getting-started.md9
-rw-r--r--docs/guide/debugger.md280
-rw-r--r--docs/img/debugger/adaptersettings.pngbin0 -> 26620 bytes
-rw-r--r--docs/img/debugger/breakpointwidget.pngbin0 -> 7118 bytes
-rw-r--r--docs/img/debugger/contextmenu.pngbin0 -> 56154 bytes
-rw-r--r--docs/img/debugger/controlbuttons.pngbin0 -> 6166 bytes
-rw-r--r--docs/img/debugger/debuggerconsole.pngbin0 -> 82873 bytes
-rw-r--r--docs/img/debugger/debuggerview.pngbin0 -> 14746 bytes
-rw-r--r--docs/img/debugger/modulewidget.pngbin0 -> 38517 bytes
-rw-r--r--docs/img/debugger/registerwidget.pngbin0 -> 11359 bytes
-rw-r--r--docs/img/debugger/stacktracewidget.pngbin0 -> 22468 bytes
-rw-r--r--docs/img/debugger/stackvariable.pngbin0 -> 94179 bytes
-rw-r--r--docs/img/debugger/statuswidget.pngbin0 -> 3149 bytes
-rw-r--r--docs/img/debugger/statuswidget2.pngbin0 -> 2942 bytes
-rw-r--r--docs/img/debugger/syncgroup.pngbin0 -> 10805 bytes
-rw-r--r--docs/img/debugger/targetterminal.pngbin0 -> 17494 bytes
-rw-r--r--docs/img/debugger/ui.pngbin0 -> 643280 bytes
-rw-r--r--filemetadata.cpp15
-rw-r--r--mkdocs-stable.yml1
-rw-r--r--mkdocs.yml1
-rw-r--r--python/binaryview.py16
-rw-r--r--python/scriptingprovider.py12
-rw-r--r--rust/src/custombinaryview.rs17
-rwxr-xr-xsuite/generator.py13
28 files changed, 396 insertions, 7 deletions
diff --git a/api-docs/source/conf.py b/api-docs/source/conf.py
index 27e12c8f..3fc64ade 100644
--- a/api-docs/source/conf.py
+++ b/api-docs/source/conf.py
@@ -37,16 +37,18 @@ sys.path.insert(0, bnpath)
os.environ["BN_DISABLE_USER_SETTINGS"] = "True"
os.environ["BN_DISABLE_USER_PLUGINS"] = "True"
os.environ["BN_DISABLE_REPOSITORY_PLUGINS"] = "True"
+os.environ["BN_EXPERIMENTAL_DEBUGGER"] = "True"
import binaryninja
def modulelist(modulename):
modules = inspect.getmembers(modulename, inspect.ismodule)
+ # We block the module named "debugger", because it is the folder that contains all debugger Python files
moduleblacklist = ["abc", "atexit", "binaryninja", "builtins", "ctypes",
"core", "struct", "sys", "_binaryninjacore", "traceback", "code", "enum",
"json", "numbers", "threading", "re", "requests", "os", "startup",
"associateddatastore", "range", "pyNativeStr", "cstr", "fnsignature",
"get_class_members", "datetime", "inspect", "subprocess", "site",
- "string", "random", "uuid", "queue", "collections"]
+ "string", "random", "uuid", "queue", "collections", "dbgcore", "debugger"]
return sorted(set(x for x in modules if x[0] not in moduleblacklist))
def classlist(module):
@@ -91,7 +93,9 @@ Full Class List
''')
for modulename, module in modulelist(binaryninja):
- filename = f"binaryninja.{modulename}-module.rst"
+ # Since we put debugger python files in a folder, binaryninja.{modulename} is no longer the
+ # correct name of the module
+ filename = f"{module.__name__}-module.rst"
pythonrst.write(f" {modulename} <{filename}>\n")
modulefile = open(filename, "w")
underline = "="*len(f"{modulename} module")
@@ -104,12 +108,12 @@ Full Class List
''')
for (classname, classref) in classlist(module):
- modulefile.write(f" binaryninja.{modulename}.{classname}\n")
+ modulefile.write(f" {module.__name__}.{classname}\n")
modulefile.write('''\n.. toctree::
:maxdepth: 2\n''')
- modulefile.write(f'''\n\n.. automodule:: binaryninja.{modulename}
+ modulefile.write(f'''\n\n.. automodule:: {module.__name__}
:members:
:undoc-members:
:show-inheritance:''')
diff --git a/binaryninjaapi.h b/binaryninjaapi.h
index 95a3a677..763eb02c 100644
--- a/binaryninjaapi.h
+++ b/binaryninjaapi.h
@@ -1061,6 +1061,9 @@ namespace BinaryNinja {
bool Rebase(BinaryView* data, uint64_t address);
bool Rebase(BinaryView* data, uint64_t address,
const std::function<bool(size_t progress, size_t total)>& progressCallback);
+ bool CreateSnapshotedView(BinaryView* data, const std::string& viewName);
+ bool CreateSnapshotedView(BinaryView* data, const std::string& viewName,
+ const std::function<bool(size_t progress, size_t total)>& progressCallback);
MergeResult MergeUserAnalysis(const std::string& name, const std::function<bool(size_t, size_t)>& progress,
const std::vector<std::string> excludedHashes = {});
@@ -2267,6 +2270,7 @@ namespace BinaryNinja {
static BNBinaryView* CreateCallback(void* ctxt, BNBinaryView* data);
static BNBinaryView* ParseCallback(void* ctxt, BNBinaryView* data);
static bool IsValidCallback(void* ctxt, BNBinaryView* data);
+ static bool IsDeprecatedCallback(void* ctxt);
static BNSettings* GetSettingsCallback(void* ctxt, BNBinaryView* data);
BinaryViewType(BNBinaryViewType* type);
@@ -2297,7 +2301,7 @@ namespace BinaryNinja {
std::string GetName();
std::string GetLongName();
- bool IsDeprecated();
+ virtual bool IsDeprecated();
virtual BinaryView* Create(BinaryView* data) = 0;
virtual BinaryView* Parse(BinaryView* data) = 0;
@@ -3587,6 +3591,15 @@ namespace BinaryNinja {
Confidence<Ref<Type>> type;
std::string name;
bool autoDefined;
+
+ bool operator==(const VariableNameAndType& a)
+ {
+ return (var == a.var) && (type == a.type) && (name == a.name) && (autoDefined == a.autoDefined);
+ }
+ bool operator!=(const VariableNameAndType& a)
+ {
+ return !(*this == a);
+ }
};
struct StackVariableReference
diff --git a/binaryninjacore.h b/binaryninjacore.h
index b4b5dd3f..fd004a27 100644
--- a/binaryninjacore.h
+++ b/binaryninjacore.h
@@ -1403,6 +1403,7 @@ extern "C"
BNBinaryView* (*create)(void* ctxt, BNBinaryView* data);
BNBinaryView* (*parse)(void* ctxt, BNBinaryView* data);
bool (*isValidForData)(void* ctxt, BNBinaryView* data);
+ bool (*isDeprecated)(void* ctxt);
BNSettings* (*getLoadSettingsForData)(void* ctxt, BNBinaryView* data);
};
@@ -3017,6 +3018,9 @@ extern "C"
BINARYNINJACOREAPI bool BNRebase(BNBinaryView* data, uint64_t address);
BINARYNINJACOREAPI bool BNRebaseWithProgress(
BNBinaryView* data, uint64_t address, void* ctxt, bool (*progress)(void* ctxt, size_t progress, size_t total));
+ BINARYNINJACOREAPI bool BNCreateSnapshotedView(BNBinaryView* data, const char* viewName);
+ BINARYNINJACOREAPI bool BNCreateSnapshotedViewWithProgress(BNBinaryView* data, const char* viewName, void* ctxt,
+ bool (*progress)(void* ctxt, size_t progress, size_t total));
BINARYNINJACOREAPI BNMergeResult BNMergeUserAnalysis(BNFileMetadata* file, const char* name, void* ctxt,
bool (*progress)(void* ctxt, size_t progress, size_t total), char** excludedHashes, size_t excludedHashesCount);
diff --git a/binaryviewtype.cpp b/binaryviewtype.cpp
index cb8abea8..657970a6 100644
--- a/binaryviewtype.cpp
+++ b/binaryviewtype.cpp
@@ -54,6 +54,13 @@ bool BinaryViewType::IsValidCallback(void* ctxt, BNBinaryView* data)
}
+bool BinaryViewType::IsDeprecatedCallback(void* ctxt)
+{
+ BinaryViewType* type = (BinaryViewType*)ctxt;
+ return type->IsDeprecated();
+}
+
+
BNSettings* BinaryViewType::GetSettingsCallback(void* ctxt, BNBinaryView* data)
{
BinaryViewType* type = (BinaryViewType*)ctxt;
@@ -85,6 +92,7 @@ void BinaryViewType::Register(BinaryViewType* type)
callbacks.create = CreateCallback;
callbacks.parse = ParseCallback;
callbacks.isValidForData = IsValidCallback;
+ callbacks.isDeprecated = IsDeprecatedCallback;
callbacks.getLoadSettingsForData = GetSettingsCallback;
type->AddRefForRegistration();
diff --git a/docs/getting-started.md b/docs/getting-started.md
index 8f183d3f..85a13cee 100644
--- a/docs/getting-started.md
+++ b/docs/getting-started.md
@@ -610,6 +610,14 @@ Binary Ninja supports loading PDB files through a built in PDB loader. When sele
3. Attempt to connect and download the PDB from the list of symbol servers specified in setting `symbol-server-list`.
4. Prompt the user for the PDB.
+## Debugger Plugin (Beta)
+
+Binary Ninja now comes with the debugger plugin that can debug executables on Windows, Linux, and macOS.
+
+The debugger is currently in Beta, so it needs to be manually turned on. The relevant setting is in "Settings" -> "corePlugins" -> "Debugger Plugin (Beta)".
+
+For more detailed information on plugins, see the [debugger guide](guide/debugger.md).
+
## Settings
![settings >](img/settings.png "Settings")
@@ -692,6 +700,7 @@ Here's a list of all built-in settings currently available from the UI:
|corePlugins|PowerPC Architecture|Enable the built-in PowerPC architecture module.|`boolean`|`True`|[`SettingsUserScope`]|<a id='corePlugins.architectures.powerpc'>corePlugins.architectures.powerpc</a>|
|corePlugins|x86/x86_64 Architecture|Enable the built-in x86/x86_64 architecture module.|`boolean`|`True`|[`SettingsUserScope`]|<a id='corePlugins.architectures.x86'>corePlugins.architectures.x86</a>|
|corePlugins|Crypto Plugin|Enable the built-in crypto plugin.|`boolean`|`True`|[`SettingsUserScope`]|<a id='corePlugins.crypto'>corePlugins.crypto</a>|
+|corePlugins|Debugger Plugin (Beta)|Enable the built-in debugger plugin.|`boolean`|`False`|[`SettingsUserScope`]|<a id='corePlugins.debugger'>corePlugins.debugger</a>|
|corePlugins|PDB Loader|Enable the built-in PDB loader plugin.|`boolean`|`True`|[`SettingsUserScope`]|<a id='corePlugins.pdb'>corePlugins.pdb</a>|
|corePlugins|DECREE Platform|Enable the built-in DECREE platform module.|`boolean`|`True`|[`SettingsUserScope`]|<a id='corePlugins.platforms.decree'>corePlugins.platforms.decree</a>|
|corePlugins|FreeBSD Platform|Enable the built-in FreeBSD platform module.|`boolean`|`True`|[`SettingsUserScope`]|<a id='corePlugins.platforms.freebsd'>corePlugins.platforms.freebsd</a>|
diff --git a/docs/guide/debugger.md b/docs/guide/debugger.md
new file mode 100644
index 00000000..6abf7f90
--- /dev/null
+++ b/docs/guide/debugger.md
@@ -0,0 +1,280 @@
+# Debugger (Beta)
+
+Binary Ninja Debugger is a plugin that can debug executables on Windows, Linux, and macOS.
+
+The debugger plugin is shipped with Binary Ninja. However, it is currently in Beta, so it needs to be manually turned on. The relevant setting is in "Settings" -> "corePlugins" -> "Debugger Plugin (Beta)".
+
+Alternatively, one can set the environment variable BN_EXPERIMENTAL_DEBUGGER (to anything), which also enables the debugger.
+
+After enabling the debugger plugin, restart Binary Ninja to use it.
+
+The debugger is open-source at https://github.com/Vector35/debugger with Apache License 2.0. Bug reports and pull requests are welcome!
+
+
+## UI
+
+<img src="../img/debugger/ui.png" width="1000"/>
+
+The debugger UI mainly consists of five parts:
+
+- debugger sidebar
+- global area panels
+- debugger status widget
+- debugger context menu
+- stack variable annotations
+
+The current UI should accommodate common operations within the debugger. And it is set to receive huge improvements over this summer.
+
+### Debugger Sidebar
+
+The debugger sidebar locates inside the sidebar, which is on the left side of the main window. It can be enabled by clicking the button that looks like a bug.
+
+The debugger sidebar contains four widgets, the control buttons, the register widget, the breakpoint widget, and the module widget.
+
+#### Control Buttons
+
+![](../img/debugger/controlbuttons.png)
+
+There is a row of buttons at the top of the debugger Sidebar. They control the execution of the target. The behavior of the button is hopefully sensible from its icon. One can also hover over the button to get the name of the icon.
+
+Buttons that do not work for the current target status are disabled. For example, before launching the target, the `Step Into` button is disabled.
+
+A typical scenario is to click the left-most button to launch the target, and then use the buttons on the right to resume the target, step into/over/return. The `Pause` button can be used to break into the target while it is running.
+
+There is a Settings button on the right of the buttons. Clicking it will pop up a Debug Adapter Settings dialog, which allows the selection of a DebugAdapter, as well as the configuration of useful things like command-line arguments or the working directory.
+
+For `Step Into` and `Step Over`, if the current view is viewing an IL function, then the operation appears to be performed on that IL, offering a source-code debugging-like experience. However, the underlying operation is still performed at the disassembly level because that is the only thing the backend understands. The high-level operations are simulated, i.e., the debugger may decide to step the target multiple times before finally yielding the control. These are transparent to the users.
+
+![](../img/debugger/adaptersettings.png)
+
+
+#### Register Widget
+
+![](../img/debugger/registerwidget.png)
+
+Register widget lists registers and their values. A hint column presents anything interesting pointed to by the register. Currently, only strings and pointers to strings are considered. In the future, we would also annotate variables.
+
+Double-clicking a value enters editing mode, and the user can type in new values for the register. The new value is parsed as hex.
+
+The Register widget tracks the last seen value of registers and provides visual feedback. Unchanged values are colored white, changed values are colored blue. User-edited values are colored orange.
+
+An experimental feature is added to shorten the list: registers with a value of zero are not shown in the list. We will evaluate how well it works, and probably going to offer it as a configurable option.
+
+
+#### Breakpoint Widget
+
+![](../img/debugger/breakpointwidget.png)
+
+The breakpoint widget lists breakpoints in the target. There are two columns in it, the left one shows the address in the format of `module + offset`, and the right column shows the absolute address.
+
+The context menu of the widget offers to delete a breakpoint or to jump to the address of a breakpoint.
+
+#### Module Widget
+
+![](../img/debugger/modulewidget.png)
+
+The module widget shows the address, size, name, and path information of the target's modules.
+
+Note: the bizarrely huge size is caused by dyld_shared_cache on macOS, which will be addressed in the future. The size of the main executable is still calculated correctly.
+
+
+
+### Global Area Panels
+
+The debugger adds three new global area widgets, i.e., target terminal, debugger console, and stack trace.
+
+#### Target Terminal
+
+![](../img/debugger/targetterminal.png)
+
+The target terminal simulates a terminal for the target. If the process writes to stdout, the content will be printed here. There is a line input at the bottom, and all input to it will be sent to the target's stdin.
+
+Due to a backend limitation, this feature only works on macOS and Linux. On Windows, the target always runs in its terminal, and all input/output happens there.
+
+On macOS and Linux, the default setting redirects the stdin/stdout here. However, if the user configures the target to run in its terminal (by calling `dbg.request_terminal_emulator = True`), then the stdin/stdout will not be redirected, and need to be accessed in the target's terminal.
+
+#### Debugger Console
+
+![](../img/debugger/debuggerconsole.png)
+
+The debugger console allows the user to execute a backend command and get the result.
+
+On Linux and macOS, the backend is based on LLDB and the syntax follows LLDB command syntax.
+
+On Windows, the backend is based on Windows Debugger Engine, which supports Windbg command syntax.
+
+Note, however, one should NOT execute any command that changes the execution status of the target, E.g., resume/step the target, or launch/quit the target. It will cause the UI to de-synchronize with the backend, or even hang. We have given a high priority to fixing this issue.
+
+#### Stack Trace
+
+![](../img/debugger/stacktracewidget.png)
+
+The stack trace widget lists all the threads along with the stack frames of the active thread.
+
+The dropdown menu is a thread selector, which can be used to switch between threads. The selected thread will become the active thread, and its stack frames will be shown below.
+
+Double-clicking an item in the stack frames list navigates to the return address of the frame.
+
+
+
+
+### Debugger Status Widget
+
+![](../img/debugger/statuswidget.png)
+
+![](../img/debugger/statuswidget2.png)
+
+A debugger status widget is added to the main window's status bar. It indicates the current status of the target.
+
+For example, when the target stops, it will include the reason for the stop. When the target exists, the exit code is reported. When an error occurs during certain operations, an error message will also be displayed here.
+
+The widget always shows the status of the debugger for the current binary view. If you switch to a tab that views a different binary, it will show the status of the debugger for that binary, which might be inactive.
+
+
+### Context menu
+
+![](../img/debugger/contextmenu.png)
+
+The debugger registers a series of useful actions, along with keyboard shortcuts. These shortcuts can be customized using Binary Ninja's keybindings support.
+
+Among these actions, target control actions, e.g., `Run`/`Step Into` have the same effect as the control buttons in the sidebar.
+
+`Toggle Breakpoint` adds a breakpoint at the current location if there is no breakpoint; otherwise, the existing breakpoint is removed.
+
+`Run To Here` lets the target execute until the current line is hit.
+
+`Make Code` is an experimental feature that displays the selected region as code. If the region is indeed code, the user can then hit `P` to create a function there.
+
+### Stack variable annotation
+
+![](../img/debugger/stackvariable.png)
+
+When the target breaks and a stack trace is available, the debugger annotates the stack variables in the linear view as data variables.
+
+The above image shows the annotated stack with three stack frames. The start and end of each stack frame are marked, and stack variables are defined according to the stack variables in the functions.
+
+To view the stack variable annotations, switch to the linear view of the Debugger binary view, and then navigate to the stack pointer address.
+
+A useful setup is a split view that shows the code on the left, and the stack on the right. If the user adopts this layout, remember to put the linear view that shows the stack region on a different sync group, so executing the target would not lead to navigation of the linear view. This way, we can observe how variables on the stack change.
+
+In the future, we will offer a way to set up this side-by-side view in one click.
+
+Only the stack frames and variables of the current (active) thread are annotated to avoid confusion. If you wish to view stack variables from a different thread, first switch to that thread in the `Stack Trace` global area panel.
+
+The annotation is done only when there are at least two frames in the stack trace. This is a known limitation, and we will address it later.
+
+
+### Other UI elements
+
+On every line that has a breakpoint, there are two visual indicators:
+
+- the line is highlighted in red
+- a red breakpoint tag is added to the left
+
+On the line where the program counter is at, there are two visual indicators:
+
+- the line is highlighted in blue
+- a program counter tag is added to the left
+
+
+## Design
+
+### Debug Adapters
+
+The goal of the Binary Ninja debugger is to provide a unified way of debugging programs on different platforms (e.g., Windows, Linux, macOS, etc). However, this is not an easy task, because each platform has its way of supporting debugging and it varies considerably.
+
+To deal with this, we abstract the core functionalities of a debugger into a class `DebugAdapter`. Each debug adapter is a subclass of the `DebugAdapter` with the platform-dependent implementation of each method.
+
+The debugger then **drives** the various adapters, creating a unified debugging experience, both in GUI and API.
+
+Right now, the debugger comes with two debug adapters. The `LLDBAdapter` uses [LLDB](https://lldb.llvm.org/) as its backend and debugs programs on macOS and Linux. The `DbgEngAdapter` uses [Windows debugger engine](https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/introduction), and debugs programs on Windows.
+
+New debug adapters can be created by subclassing `DebugAdapter` to support other targets.
+
+Remote debugging is a planned feature. Specifically, the capacity to connect to a target via [RSP protocol](https://sourceware.org/gdb/current/onlinedocs/gdb/Remote-Protocol.html) is already baked into the LLDBAdapter, though not tested.
+
+
+### The Debugger BinaryView
+
+To represent the memory space of the target, the debugger creates a specialized `BinaryView` called `DebugProcessView`. Throughout this document, it is also called the `Debugger` BinaryView.
+
+[//]: # (On the other hand, there is a `base` BinaryView that is the BinaryView used to create the debugger. The base binaryView gets rebased to the correct location when the target launches. )
+
+The Debugger BinaryView reads and writes its memory from the connected `DebugAdapter`. To save on data transfer, the debugger caches all read operations from the adapter. Whenever the debugger executes instructions or writes data, the cached data is cleared.
+
+When the target is launched, the debugger automatically switches the view to the Debugger BinaryView.
+
+![](../img/debugger/debuggerview.png)
+
+The debugger automatically applies all analysis data to the Debugger BinaryView, including functions and types, etc. This means the user can conveniently use types that are present in the static analysis.
+
+The Debugger BinaryView can be accessed by `dbg.live_view`, which should not be None once the target is launched. One can read/write to it in the normal way. Writing to it will also cause the target's memory to change.
+
+Right now, the Debugger BinaryView is discarded once the target exits. It cannot be easily reused due to ASLR, which makes the base of the program different in each run. As a result, any changes the user made to the Debugger BinaryView is also gone after the target exits. In the future, we will provide a way to let the user to selectively commit the changes made to the original view.
+
+## API
+
+The debugger exposes its functionality in both Python and C++ API. The Python documentation can be accessed [online](https://api.binary.ninja/binaryninja.debugger.debuggercontroller-module.html).
+
+The API is centered around the [`DebuggerController`](https://api.binary.ninja/binaryninja.debugger.debuggercontroller-module.html#binaryninja.debugger.debuggercontroller.DebuggerController) class, which provides all functionalities of the debugger. There is no need to directly access the `DebugAdapter` classes.
+
+When the debugger is used within the UI, the `dbg` variable is injected into the Python interpreter. It always represents the debugger for the currently active Binary View. One can think of it as being created by
+
+```Python
+dbg = DebuggerController(bv)
+```
+
+where `bv` is another magic variable that always represents the current BinaryView.
+
+One can simply run `dbg.launch()` in the Python console to launch the target.
+
+
+
+## How-to Guide
+
+Here is an incomplete guide on how to get started with the debugger. It covers the most basics operations in the debugger.
+
+### Launch and Control the Target
+
+There are several ways to launch the target:
+
+- Use the control buttons at the top of the debugger sidebar
+- Use the debugger context menu or its keybindings
+- run `dbg.run()`, `dbg.step_into()`, etc. in the Python console.
+
+Note, one should never issue any command that changes the execution status of the target in the `Debugger Console`, which causes the UI to go out of sync with the backend.
+
+
+### Configure Launch Parameters
+
+- Click the Settings button which is on the right side of the control buttons widget, and edit parameters in the dialog
+- directly set the value of `dbg.cmd_line`, `dbg.working_directory`, `dbg.working_dir`, etc
+
+
+### Add/Remove Breakpoints
+
+- Select the line, use the `Toggle Breakpoint` context menu
+- Right-click a line in the Breakpoint widget in the sidebar, and select `Remove Breakpoint`
+- run `dbg.add_breakpoint(address)` or `dbg.delete_breakpoint(address)` in the Python console.
+
+
+### Modify Register Values
+
+- Double-click a value item in the Register widget, type in the new value, and hit enter
+- run `dbg.set_reg_value(reg_name, value)` in the Python console.
+
+
+### View/Edit Memory
+
+- Switch to Linear or hex view of the Debugger BinaryView, and view/edit in the normal way
+- get the Debugger BinaryView by `dbg.live_view`, and read/write it in the normal way
+
+
+## Open-Source
+
+Vector 35 is grateful for the following open source packages that are used in Binary Ninja debugger:
+
+- [fmt](https://github.com/fmtlib/fmt) ([fmt license](https://github.com/fmtlib/fmt/blob/master/LICENSE.rst) - MIT)
+- [pugixml](https://pugixml.org/) ([pugixml license](https://pugixml.org/license.html) - MIT)
+- [gdb](https://www.gnu.org/software/gdb) ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.html))
+- [lldb](https://lldb.llvm.org/) ([Apache 2.0 License with LLVM exceptions](https://llvm.org/docs/DeveloperPolicy.html#new-llvm-project-license-framework))
diff --git a/docs/img/debugger/adaptersettings.png b/docs/img/debugger/adaptersettings.png
new file mode 100644
index 00000000..f9d3c9c6
--- /dev/null
+++ b/docs/img/debugger/adaptersettings.png
Binary files differ
diff --git a/docs/img/debugger/breakpointwidget.png b/docs/img/debugger/breakpointwidget.png
new file mode 100644
index 00000000..9186b3dc
--- /dev/null
+++ b/docs/img/debugger/breakpointwidget.png
Binary files differ
diff --git a/docs/img/debugger/contextmenu.png b/docs/img/debugger/contextmenu.png
new file mode 100644
index 00000000..c3af7c03
--- /dev/null
+++ b/docs/img/debugger/contextmenu.png
Binary files differ
diff --git a/docs/img/debugger/controlbuttons.png b/docs/img/debugger/controlbuttons.png
new file mode 100644
index 00000000..1840471f
--- /dev/null
+++ b/docs/img/debugger/controlbuttons.png
Binary files differ
diff --git a/docs/img/debugger/debuggerconsole.png b/docs/img/debugger/debuggerconsole.png
new file mode 100644
index 00000000..c101328b
--- /dev/null
+++ b/docs/img/debugger/debuggerconsole.png
Binary files differ
diff --git a/docs/img/debugger/debuggerview.png b/docs/img/debugger/debuggerview.png
new file mode 100644
index 00000000..c2446a6b
--- /dev/null
+++ b/docs/img/debugger/debuggerview.png
Binary files differ
diff --git a/docs/img/debugger/modulewidget.png b/docs/img/debugger/modulewidget.png
new file mode 100644
index 00000000..0c79b0af
--- /dev/null
+++ b/docs/img/debugger/modulewidget.png
Binary files differ
diff --git a/docs/img/debugger/registerwidget.png b/docs/img/debugger/registerwidget.png
new file mode 100644
index 00000000..8b03cbe9
--- /dev/null
+++ b/docs/img/debugger/registerwidget.png
Binary files differ
diff --git a/docs/img/debugger/stacktracewidget.png b/docs/img/debugger/stacktracewidget.png
new file mode 100644
index 00000000..bdf0bfd4
--- /dev/null
+++ b/docs/img/debugger/stacktracewidget.png
Binary files differ
diff --git a/docs/img/debugger/stackvariable.png b/docs/img/debugger/stackvariable.png
new file mode 100644
index 00000000..a32edc1b
--- /dev/null
+++ b/docs/img/debugger/stackvariable.png
Binary files differ
diff --git a/docs/img/debugger/statuswidget.png b/docs/img/debugger/statuswidget.png
new file mode 100644
index 00000000..1daed964
--- /dev/null
+++ b/docs/img/debugger/statuswidget.png
Binary files differ
diff --git a/docs/img/debugger/statuswidget2.png b/docs/img/debugger/statuswidget2.png
new file mode 100644
index 00000000..26e2c976
--- /dev/null
+++ b/docs/img/debugger/statuswidget2.png
Binary files differ
diff --git a/docs/img/debugger/syncgroup.png b/docs/img/debugger/syncgroup.png
new file mode 100644
index 00000000..d6764c36
--- /dev/null
+++ b/docs/img/debugger/syncgroup.png
Binary files differ
diff --git a/docs/img/debugger/targetterminal.png b/docs/img/debugger/targetterminal.png
new file mode 100644
index 00000000..8e244c70
--- /dev/null
+++ b/docs/img/debugger/targetterminal.png
Binary files differ
diff --git a/docs/img/debugger/ui.png b/docs/img/debugger/ui.png
new file mode 100644
index 00000000..d8297100
--- /dev/null
+++ b/docs/img/debugger/ui.png
Binary files differ
diff --git a/filemetadata.cpp b/filemetadata.cpp
index 57ebcc2d..cdcee292 100644
--- a/filemetadata.cpp
+++ b/filemetadata.cpp
@@ -268,6 +268,21 @@ bool FileMetadata::Rebase(
}
+bool FileMetadata::CreateSnapshotedView(BinaryView *data, const std::string &viewName)
+{
+ return BNCreateSnapshotedView(data->GetObject(), viewName.c_str());
+}
+
+
+bool FileMetadata::CreateSnapshotedView(BinaryView* data, const std::string& viewName,
+ const function<bool(size_t progress, size_t total)>& progressCallback)
+{
+ DatabaseProgressCallbackContext cb;
+ cb.func = progressCallback;
+ return BNCreateSnapshotedViewWithProgress(data->GetObject(), viewName.c_str(), &cb, DatabaseProgressCallback);
+}
+
+
MergeResult FileMetadata::MergeUserAnalysis(
const std::string& name, const std::function<bool(size_t, size_t)>& progress, std::vector<string> excludedHashes)
{
diff --git a/mkdocs-stable.yml b/mkdocs-stable.yml
index 3a5196e2..59445176 100644
--- a/mkdocs-stable.yml
+++ b/mkdocs-stable.yml
@@ -45,6 +45,7 @@ nav:
- Using Plugins: 'guide/plugins.md'
- Troubleshooting: 'guide/troubleshooting.md'
- Working with Types: 'guide/type.md'
+ - Using Debugger (Beta): 'guide/debugger.md'
- Developer Guide:
- Using the API: 'dev/api.md'
- Writing Python Plugins: 'dev/plugins.md'
diff --git a/mkdocs.yml b/mkdocs.yml
index 39b85c8c..17c97d08 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -38,6 +38,7 @@ nav:
- Using Plugins: 'guide/plugins.md'
- Troubleshooting: 'guide/troubleshooting.md'
- Working with Types: 'guide/type.md'
+ - Using Debugger (Beta): 'guide/debugger.md'
- Developer Guide:
- Using the API: 'dev/api.md'
- Writing Python Plugins: 'dev/plugins.md'
diff --git a/python/binaryview.py b/python/binaryview.py
index 625a22a4..cdda228f 100644
--- a/python/binaryview.py
+++ b/python/binaryview.py
@@ -900,7 +900,7 @@ class BinaryViewType(metaclass=_BinaryViewTypeMetaclass):
if available.name == "Universal":
universal_bvt = available
continue
- if bvt is None and available.name != "Raw":
+ if bvt is None and available.name not in ["Raw", "Debugger"]:
bvt = available
if bvt is None:
@@ -1935,6 +1935,7 @@ class BinaryView:
cls._registered_cb.create = cls._registered_cb.create.__class__(cls._create)
cls._registered_cb.parse = cls._registered_cb.parse.__class__(cls._parse)
cls._registered_cb.isValidForData = cls._registered_cb.isValidForData.__class__(cls._is_valid_for_data)
+ cls._registered_cb.isDeprecated = cls._registered_cb.isDeprecated.__class__(cls._is_deprecated)
cls._registered_cb.getLoadSettingsForData = cls._registered_cb.getLoadSettingsForData.__class__(
cls._get_load_settings_for_data
)
@@ -1991,6 +1992,19 @@ class BinaryView:
return False
@classmethod
+ def _is_deprecated(cls, ctxt):
+ # Since the is_deprecated() method is newly added, existing code may not have it at all
+ # So here we do not consider it as an error
+ if not callable(getattr(cls, 'is_deprecated', None)):
+ return False
+
+ try:
+ return cls.is_deprecated() # type: ignore
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ @classmethod
def _get_load_settings_for_data(cls, ctxt, data):
try:
attr = getattr(cls, "get_load_settings_for_data", None)
diff --git a/python/scriptingprovider.py b/python/scriptingprovider.py
index 8dfe3553..11707240 100644
--- a/python/scriptingprovider.py
+++ b/python/scriptingprovider.py
@@ -43,6 +43,7 @@ from . import function
from .log import log_info, log_error, is_output_redirected_to_log
from .pluginmanager import RepositoryManager
from .enums import ScriptingProviderExecuteResult, ScriptingProviderInputReadyState
+from .debugger import *
class _ThreadActionContext:
@@ -585,7 +586,7 @@ class PythonScriptingInstance(ScriptingInstance):
# Note: "current_address" and "here" are interactive auto-variables (i.e. can be set by user and programmatically)
blacklisted_vars = {
"current_view", "bv", "current_function", "current_basic_block", "current_selection", "current_llil",
- "current_mlil", "current_hlil"
+ "current_mlil", "current_hlil", "dbg"
}
self.locals = BlacklistedDict(
blacklisted_vars, {"__name__": "__console__", "__doc__": None, "binaryninja": sys.modules[__name__]}
@@ -601,6 +602,7 @@ class PythonScriptingInstance(ScriptingInstance):
self.current_addr = 0
self.current_selection_begin = 0
self.current_selection_end = 0
+ self.current_dbg = None
# Selections that were current as of last issued command
self.active_view = None
@@ -609,6 +611,7 @@ class PythonScriptingInstance(ScriptingInstance):
self.active_addr = 0
self.active_selection_begin = 0
self.active_selection_end = 0
+ self.active_dbg = None
self.locals["get_selected_data"] = self.get_selected_data
self.locals["write_at_cursor"] = self.write_at_cursor
@@ -724,6 +727,7 @@ from binaryninja import *
self.active_addr = self.current_addr
self.active_selection_begin = self.current_selection_begin
self.active_selection_end = self.current_selection_end
+ self.active_dbg = self.current_dbg
self.locals.blacklist_enabled = False
self.locals["current_thread"] = self.interpreter
@@ -734,6 +738,7 @@ from binaryninja import *
self.locals["current_address"] = self.active_addr
self.locals["here"] = self.active_addr
self.locals["current_selection"] = (self.active_selection_begin, self.active_selection_end)
+ self.locals["dbg"] = self.active_dbg
if self.active_func is None:
self.locals["current_llil"] = None
self.locals["current_mlil"] = None
@@ -812,6 +817,11 @@ from binaryninja import *
@abc.abstractmethod
def perform_set_current_binary_view(self, view):
self.interpreter.current_view = view
+ if settings.Settings().get_bool('corePlugins.debugger'):
+ if view is not None:
+ self.interpreter.current_dbg = DebuggerController(view)
+ else:
+ self.interpreter.current_dbg = None
@abc.abstractmethod
def perform_set_current_function(self, func):
diff --git a/rust/src/custombinaryview.rs b/rust/src/custombinaryview.rs
index 3afc6dc6..d547c388 100644
--- a/rust/src/custombinaryview.rs
+++ b/rust/src/custombinaryview.rs
@@ -55,6 +55,16 @@ where
})
}
+ extern "C" fn cb_deprecated<T>(ctxt: *mut c_void) -> bool
+ where
+ T: CustomBinaryViewType,
+ {
+ ffi_wrap!("BinaryViewTypeBase::is_deprecated", unsafe {
+ let view_type = &*(ctxt as *mut T);
+ view_type.is_deprecated()
+ })
+ }
+
extern "C" fn cb_create<T>(ctxt: *mut c_void, data: *mut BNBinaryView) -> *mut BNBinaryView
where
T: CustomBinaryViewType,
@@ -117,6 +127,7 @@ where
create: Some(cb_create::<T>),
parse: Some(cb_parse::<T>),
isValidForData: Some(cb_valid::<T>),
+ isDeprecated: Some(cb_deprecated::<T>),
getLoadSettingsForData: Some(cb_load_settings::<T>),
};
@@ -141,6 +152,8 @@ where
pub trait BinaryViewTypeBase: AsRef<BinaryViewType> {
fn is_valid_for(&self, data: &BinaryView) -> bool;
+ fn is_deprecated(&self) -> bool;
+
fn load_settings_for_data(&self, data: &BinaryView) -> Result<Ref<Settings>> {
let settings_handle =
unsafe { BNGetBinaryViewDefaultLoadSettingsForData(self.as_ref().0, data.handle) };
@@ -233,6 +246,10 @@ impl BinaryViewTypeBase for BinaryViewType {
unsafe { BNIsBinaryViewTypeValidForData(self.0, data.handle) }
}
+ fn is_deprecated(&self) -> bool {
+ unsafe { BNIsBinaryViewTypeDeprecated(self.0) }
+ }
+
fn load_settings_for_data(&self, data: &BinaryView) -> Result<Ref<Settings>> {
let settings_handle =
unsafe { BNGetBinaryViewDefaultLoadSettingsForData(self.as_ref().0, data.handle) };
diff --git a/suite/generator.py b/suite/generator.py
index ca7b362f..0fbc6346 100755
--- a/suite/generator.py
+++ b/suite/generator.py
@@ -11,6 +11,7 @@ import time
os.environ["BN_DISABLE_USER_PLUGINS"] = "True"
os.environ["BN_DISABLE_USER_SETTINGS"] = "True"
os.environ["BN_DISABLE_REPOSITORY_PLUGINS"] = "True"
+os.environ["BN_EXPERIMENTAL_DEBUGGER"] = "True"
if sys.version_info.major == 2:
print("Generate unit tests on Python 3. Python 2 is not compatible.")
@@ -30,15 +31,22 @@ from collections import Counter
os.environ["BN_DISABLE_USER_PLUGINS"] = "True"
os.environ["BN_DISABLE_USER_SETTINGS"] = "True"
os.environ["BN_DISABLE_REPOSITORY_PLUGINS"] = "True"
+os.environ["BN_EXPERIMENTAL_DEBUGGER"] = "True"
api_suite_path = os.path.realpath(os.path.join(os.path.dirname(os.path.realpath(__file__)), {4}))
sys.path.append(api_suite_path)
# support direct invocation of configuration unit.py
commondir = os.path.realpath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "..", ".."))
sys.path.append(commondir)
+
+debugger_suite_path = os.path.realpath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "..", "..", "..",
+ "public", "debugger", "test"))
+sys.path.append(debugger_suite_path)
+
import config
import testcommon
import api_test
+import debugger_test
class TestBinaryNinja(unittest.TestCase):
@@ -148,6 +156,8 @@ def main():
config.verbose = True
elif sys.argv[i] == '--api-only':
config.api_only = True
+ elif sys.argv[i] == '--debugger-only':
+ config.debugger_only = True
else:
# otherwise the argument is taken as a test case search keyword
test_keyword = sys.argv[i]
@@ -155,6 +165,9 @@ def main():
if config.api_only:
runner = unittest.TextTestRunner(verbosity=2)
test_suite = unittest.defaultTestLoader.loadTestsFromModule(api_test)
+ elif config.debugger_only:
+ runner = unittest.TextTestRunner(verbosity=2)
+ test_suite = unittest.defaultTestLoader.loadTestsFromModule(debugger_test)
else:
runner = unittest.TextTestRunner(verbosity=2)
test_suite = unittest.defaultTestLoader.loadTestsFromTestCase(TestBinaryNinja)