Merge branch 'NationalSecurityAgency:master' into armv8-splimit

This commit is contained in:
Behrang 2024-12-08 13:11:17 +00:00 committed by GitHub
commit 68171d3302
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10853 changed files with 691087 additions and 483887 deletions

11
.gitignore vendored
View file

@ -68,6 +68,7 @@ Release
.classpath .classpath
.settings/ .settings/
.prefs .prefs
.pydevproject
# Ignore XTEXT generated dirs/files # Ignore XTEXT generated dirs/files
*/*/*/*/xtend-gen */*/*/*/xtend-gen
@ -81,12 +82,12 @@ Release
*.iml *.iml
.idea .idea
# Ignore gradle wrapper files
gradle/wrapper
gradlew
gradlew.*
# Ignore logs and core dumps # Ignore logs and core dumps
*.log *.log
core.* core.*
!core.png !core.png
!core.py
# python files
*.egg-info
__pycache__

View file

@ -32,40 +32,51 @@ authors' names directly in the source code, so it is discouraged.
Download non-Maven Central dependencies. This creates a `dependencies` directory in the repository Download non-Maven Central dependencies. This creates a `dependencies` directory in the repository
root. root.
``` ```
$ gradle -I gradle/support/fetchDependencies.gradle init gradle -I gradle/support/fetchDependencies.gradle
``` ```
Download Maven Central dependencies and setup the repository for development. By default, these Download Maven Central dependencies and setup the repository for development. By default, these
will be stored at `$HOME/.gradle/`. will be stored at `$HOME/.gradle/`.
``` ```
$ gradle prepdev gradle prepdev
``` ```
Generate nested Eclipse project files which can then be imported into Eclipse as "existing Generate nested Eclipse project files which can then be imported into Eclipse as "existing
projects". projects".
``` ```
$ gradle cleanEclipse eclipse gradle cleanEclipse eclipse
``` ```
Build native components for your current platform. Requires native tool chains to be present. Build native components for your current platform. Requires native tool chains to be present.
``` ```
$ gradle buildNatives gradle buildNatives
``` ```
Manually compile sleigh files. Ghidra will also do this at runtime when necessary. Manually compile sleigh files. Ghidra will also do this at runtime when necessary.
``` ```
$ gradle sleighCompile gradle sleighCompile
``` ```
Build Javadoc: Build Javadoc:
``` ```
$ gradle createJavadocs gradle createJavadocs
``` ```
Build Ghidra to `build/dist`. This will be a distribution intended only to run on the platform on Build Python3 packages for the Debugger:
which it was built.
``` ```
$ gradle buildGhidra gradle buildPyPackage
```
Build Ghidra to `build/dist` in an uncompressed form. This will be a distribution intended only to
run on the platform on which it was built.
```
gradle assembleAll
```
Build Ghidra to `build/dist` in a compressed form. This will be a distribution intended only to run
on the platform on which it was built.
```
gradle buildGhidra
``` ```
**Tip:** You may want to skip certain Gradle tasks to speed up your build, or to deal with **Tip:** You may want to skip certain Gradle tasks to speed up your build, or to deal with
@ -73,7 +84,7 @@ a problem later. For example, perhaps you added some new source files and the b
because of unresolved IP header issues. You can use the Gradle `-x <task>` command line argument to because of unresolved IP header issues. You can use the Gradle `-x <task>` command line argument to
prevent specific tasks from running: prevent specific tasks from running:
``` ```
$ gradle buildGhidra -x ip gradle buildGhidra -x ip
``` ```
## Known Issues ## Known Issues
@ -86,7 +97,7 @@ Sometimes you may want to move the Ghidra repository to an offline network and d
These are the recommended steps to ensure that you not only move the source repository, but all These are the recommended steps to ensure that you not only move the source repository, but all
downloaded dependencies as well: downloaded dependencies as well:
1. `gradle -I gradle/support/fetchDependencies.gradle init` 1. `gradle -I gradle/support/fetchDependencies.gradle`
2. `gradle -g dependencies/gradle prepdev` 2. `gradle -g dependencies/gradle prepdev`
3. Move ghidra directory to different system 3. Move ghidra directory to different system
4. `gradle -g dependencies/gradle buildGhidra` (on offline system) 4. `gradle -g dependencies/gradle buildGhidra` (on offline system)
@ -103,7 +114,7 @@ It is also included in the _Eclipse IDE for RCP and RAP Developers_. To generate
Eclipse projects, execute: Eclipse projects, execute:
``` ```
$ gradle eclipse -PeclipsePDE gradle eclipse -PeclipsePDE
``` ```
Import the newly generated GhidraDev projects into an Eclipse that supports this type of project. Import the newly generated GhidraDev projects into an Eclipse that supports this type of project.
@ -111,31 +122,31 @@ Import the newly generated GhidraDev projects into an Eclipse that supports this
__Note:__ If you are getting compilation errors related to PyDev and CDT, go into Eclipse's __Note:__ If you are getting compilation errors related to PyDev and CDT, go into Eclipse's
preferences, and under _Target Platform_, activate _/Eclipse GhidraDevPlugin/GhidraDev.target_. preferences, and under _Target Platform_, activate _/Eclipse GhidraDevPlugin/GhidraDev.target_.
See [GhidraDevPlugin/build_README.txt](GhidraBuild/EclipsePlugins/GhidraDev/GhidraDevPlugin/build_README.txt) See [Building GhidraDev](GhidraBuild/EclipsePlugins/GhidraDev/GhidraDevPlugin/README.md#building)
for instructions on how to build the GhidraDev plugin. for instructions on how to build the GhidraDev plugin.
## Running tests ## Running tests
To run unit tests, do: To run unit tests, do:
``` ```
$ gradle unitTestReport gradle unitTestReport
``` ```
For more complex integration tests, do: For more complex integration tests, do:
``` ```
$ gradle integrationTest gradle integrationTest
``` ```
For running both unit and integration tests and to generate a report do: For running both unit and integration tests and to generate a report do:
``` ```
$ gradle combinedTestReport gradle combinedTestReport
``` ```
## Setup build in CI ## Setup build in CI
For running tests in headless mode on Linux, in a CI environment, or in Docker, first do: For running tests in headless mode on Linux, in a CI environment, or in Docker, first do:
``` ```
$ Xvfb :99 -nolisten tcp & Xvfb :99 -nolisten tcp &
$ export DISPLAY=:99 export DISPLAY=:99
``` ```
This is required to make AWT happy. This is required to make AWT happy.
@ -176,13 +187,18 @@ If you'd like some details of our fine tuning, take a look at [building_fid.txt]
## Debugger Development ## Debugger Development
We have recently changed the Debugger's back-end architecture.
We no longer user JNA to access native Debugger APIs.
We only use it for pseudo-terminal access.
Instead, we use Python3 and a protobuf-based TCP connection for back-end integration.
### Additional Dependencies ### Additional Dependencies
In addition to Ghidra's normal dependencies, you may want the following: In addition to Ghidra's normal dependencies, you may want the following:
* WinDbg for Windows x64 * WinDbg for Windows x64
* GDB 8.0 or later for Linux amd64/x86_64 * GDB 13 or later for Linux
* LLDB 13.0 for macOS * LLDB 10 or later for macOS
The others (e.g., JNA) are handled by Gradle via Maven Central. The others (e.g., JNA) are handled by Gradle via Maven Central.
@ -193,121 +209,137 @@ These all currently reside in the `Ghidra/Debug` directory, but will likely be r
`Framework` and `Feature` directories later. Each project is listed "bottom up" with a brief `Framework` and `Feature` directories later. Each project is listed "bottom up" with a brief
description and status. description and status.
* ProposedUtils - a collection of utilities proposed to be moved to other respective projects * ProposedUtils - a collection of utilities proposed to be moved to other respective projects.
* AnnotationValidator - an experimental annotation processor for database access objects * AnnotationValidator - an experimental annotation processor for database access objects.
* Framework-TraceModeling - a database schema and set of interfaces for storing machine state over * Framework-TraceModeling - a database schema and set of interfaces for storing machine state over
time time.
* Framework-AsyncComm - a collection of utilities for asynchronous communication (packet formats * Framework-AsyncComm - a collection of utilities for asynchronous communication (packet formats
and completable-future conveniences). and completable-future conveniences).
* Framework-Debugging - specifies interfaces for debugger models and provides implementation * Framework-Debugging - specifies interfaces for debugger models and provides implementation
conveniences. conveniences. This is mostly deprecated.
* Debugger - the collection of Ghidra plugins and services comprising the Debugger UI. * Debugger - the collection of Ghidra plugins and services comprising the Debugger UI.
* Debugger-rmi-trace - the wire protocol, client, services, and UI components for Trace RMI, the new back-end architecture.
* Debugger-agent-dbgeng - the connector for WinDbg (via dbgeng.dll) on Windows x64. * Debugger-agent-dbgeng - the connector for WinDbg (via dbgeng.dll) on Windows x64.
* Debugger-agent-dbgmodel - an experimental connector for WinDbg Preview (with TTD, via * Debugger-agent-dbgmodel - an experimental connector for WinDbg Preview (with TTD, via
dbgmodel.dll) on Windows x64. dbgmodel.dll) on Windows x64. This is deprecated, as most of these features are implemented in Debugger-agent-dbgeng for the new architecture.
* Debugger-agent-dbgmodel-traceloader - an experimental "importer" for WinDbg trace files. * Debugger-agent-dbgmodel-traceloader - an experimental "importer" for WinDbg trace files. This is deprecated.
* Debugger-agent-gdb - the connector for GDB (8.0 or later recommended) on UNIX. * Debugger-agent-gdb - the connector for GDB (13 or later recommended) on UNIX.
* Debugger-swig-lldb - the Java language bindings for LLDB's SBDebugger, also proposed upstream. * Debugger-swig-lldb - the Java language bindings for LLDB's SBDebugger, also proposed upstream. This is deprecated. We now use the Python3 language bindings for LLDB.
* Debugger-agent-lldb - the connector for LLDB (13.0 required) on macOS, UNIX, and Windows. * Debugger-agent-lldb - the connector for LLDB (10 or later recommended) on macOS, UNIX, and Windows.
* Debugger-gadp - the connector for our custom wire protocol the Ghidra Asynchronous Debugging * Debugger-gadp - the connector for our custom wire protocol the Ghidra Asynchronous Debugging
Protocol. Protocol. This is deprecated. It's replaced by Debugger-rmi-trace.
* Debugger-jpda - an in-development connector for Java and Dalvik debugging via JDI (i.e., JDWP). * Debugger-jpda - an in-development connector for Java and Dalvik debugging via JDI (i.e., JDWP). This is deprecated and not yet replaced.
The Trace Modeling schema records machine state and markup over time. The Trace Modeling schema records machine state and markup over time.
It rests on the same database framework as Programs, allowing trace recordings to be stored in a It rests on the same database framework as Programs, allowing trace recordings to be stored in a Ghidra project and shared via a server, if desired.
Ghidra project and shared via a server, if desired. Trace "recording" is a de facto requirement for Trace "recording" is a de facto requirement for displaying information in Ghidra's UI.
displaying information in Ghidra's UI. However, only the machine state actually observed by the user The back-end connector has full discretion over what is recorded by using Trace RMI.
(or perhaps a script) is recorded. For most use cases, the Trace is small and ephemeral, serving Typically, only the machine state actually observed by the user (or perhaps a script) is recorded.
only to mediate between the UI components and the target's model. It supports many of the same For most use cases, the Trace is small and ephemeral, serving only to mediate between the UI components and the target's model.
markup (e.g., disassembly, data types) as Programs, in addition to tracking active threads, loaded It supports many of the same markup (e.g., disassembly, data types) as Programs, in addition to tracking active threads, loaded modues, breakpoints, etc.
modues, breakpoints, etc.
Every model (or "adapter" or "connector" or "agent") implements the API specified in Every back end (or "adapter" or "connector" or "agent") employs the Trace RMI client to populate a trace database.
Framework-Debugging. As a general rule in Ghidra, no component is allowed to access a native API and As a general rule in Ghidra, no component is allowed to access a native API and reside in the same JVM as the Ghidra UI.
reside in the same JVM as the Ghidra UI. This allows us to contain crashes, preventing data loss. To This allows us to contain crashes, preventing data loss.
accommodate this requirement -- given that debugging native applications is almost certainly going To accommodate this requirement &mdash; given that debugging native applications is almost certainly going to require access to native APIs &mdash; we've developed the Trace RMI protocol.
to require access to native APIs -- we've developed the Ghidra Asynchronous Debugging Protocol. This This also allows us to better bridge the language gap between Java and Python, which is supported by most native debuggers.
protocol is tightly coupled to Framework-Debugging, essentially exposing its methods via RMI. The This protocol is loosely coupled to Framework-TraceModeling, essentially exposing its methods via RMI, as well as some methods for controlling the UI.
protocol is built using Google's Protobuf library, providing a potential path for agent The protocol is built using Google's Protobuf library, providing a potential path for back-end implementations in alternative languages.
implementations in alternative languages. GADP provides both a server and a client implementation. We provide the Trace RMI server as a Ghidra component implemented in Java and the Trace RMI client as a Python3 package.
The server can accept any model which adheres to the specification and expose it via TCP; the client A back-end implementation may be a stand-alone executable or script that accesses the native debugger's API, or a script or plugin for the native debugger.
does the converse. When a model is instantiated in this way, it is called an "agent," because it is It then connects to Ghidra via Trace RMI to populate the trace database with information gleaned from that API.
executing in its own JVM. The other connectors, which do not use native APIs, may reside in Ghidra's It should provide a set of diagnostic commands to control and monitor that connection.
JVM and typically implement alternative wire protocols, e.g., JDWP. In both cases, the It should also use the native API to detect session and target changes so that Ghidra's UI consistently reflects the debugging session.
implementations inherit from the same interfaces.
The Debugger services maintain a collection of active connections and inspect each model for The old system relied on a "recorder" to discover targets and map them to traces in the proper Ghidra language.
potential targets. When a target is found, the service inspects the target environment and attempts That responsibility is now delegated to the back end.
to find a suitable opinion. Such an opinion, if found, instructs Ghidra how to map the objects, Typically, it examines the target's architecture and immediately creates a trace upon connection.
addresses, registers, etc. from the target namespace into Ghidra's. The target is then handed to a
Trace Recorder which begins collecting information needed to populate the UI, e.g., the program
counter, stack pointer, and the bytes of memory they refer to.
### Developing a new connector ### Developing a new connector
So Ghidra does not yet support your favorite debugger? So Ghidra does not yet support your favorite debugger?
It is tempting, exciting, but also daunting to develop your own connector. We believe the new system is much less daunting than the previous.
Please finish reading this guide, and look carefully at the ones we have so far, and perhaps ask to Still, please finish reading this guide, and look carefully at the ones we have so far, and perhaps ask to see if we are already developing one.
see if we are already developing one. Of course, in time you might also search the internet to see Of course, in time you might also search the internet to see if others are developing one.
if others are developing one. There are quite a few caveats and gotchas, the most notable being that There are quite a few caveats and gotchas, the most notable being that this interface is still in some flux.
this interface is still in quite a bit of flux. When things go wrong, it could be because of, When things go wrong, it could be because of, without limitation:
without limitation: 1) a bug on your part, 2) a bug on our part, 3) a design flaw in the interfaces,
or 4) a bug in the debugger/API you're adapting. We are still in the process of writing up this
documentation. In the meantime, we recommend using the GDB and dbgeng.dll agents as examples.
You'll also need to provide launcher(s) so that Ghidra knows how to configure and start your 1. A bug on your part
connector. Please provide launchers for your model in both configurations: as a connector in 2. A bug on our part
Ghidra's JVM, and as a GADP agent. If your model requires native API access, you should only permit 3. A design flaw in the interfaces
launching it as a GADP agent, unless you give ample warning in the launcher's description. Look at 4. A bug in the debugger/API you're adapting
the existing launchers for examples. There are many model implementation requirements that cannot be
expressed in Java interfaces. Failing to adhere to those requirements may cause different behaviors We are still (yes, still) in the process of writing up this documentation.
with and without GADP. Testing with GADP tends to reveal those implementation errors, but also In the meantime, we recommend using the GDB and dbgeng agents as examples.
obscures the source of client method calls behind network messages. We've also codified (or Be sure to look at the Python code `src/main/py`!
attempted to codify) these requirements in a suite of abstract test cases. See the `ghidra.dbg.test` The deprecated Java code `src/main/java` is still included as we transition.
package of Framework-Debugging, and again, look at existing implementations.
You'll also need to provide launcher(s) so that Ghidra knows how to configure and start your connector.
These are just shell scripts.
We use bash scripts on Linux and macOS, and we use batch files on Windows.
Try to include as many common use cases as makes sense for the debugger.
This provides the most flexibility to users and examples to power users who might create derivative launchers.
Look at the existing launchers for examples.
For testing, please follow the examples for GDB.
We no longer provide abstract classes that prescribe requirements.
Instead, we just provide GDB as an example.
Usually, we split our tests into three categories:
* Commands
* Methods
* Hooks
The Commands tests check that the user CLI commands, conventionally implemented in `commands.py`, work correctly.
In general, do the minimum connection setup, execute the command, and check that it produces the expected output and causes the expected effects.
The Methods tests check that the remote methods, conventionally implemented in `methods.py`, work correctly.
Many methods are just wrappers around CLI commands, some provided by the native debugger and some provided by `commands.py`.
These work similarly to the commands test, except that they invoke methods instead of executing commands.
Again, check the return value (rarely applicable) and that it causes the expected effects.
The Hooks tests check that the back end is able to listen for session and target changes, e.g., knowing when the target stops.
*The test should not "cheat" by executing commands or invoking methods that should instead be triggered by the listener.*
It should execute the minimal commands to setup the test, then trigger an event.
It should then check that the event in turn triggered the expected effects, e.g., updating PC upon the target stopping.
Whenever you make a change to the Python code, you'll need to re-assemble the package's source.
```
gradle assemblePyPackage
```
This is required in case your package includes generated source, as is the case for Debugger-rmi-trace.
If you want to create a new Ghidra module for your connector (recommended) use an existing one's `build.gradle` as a template.
A key part is applying the `hasPythonPackage.gradle` script.
### Adding a new platform ### Adding a new platform
If an existing connector exists for a suitable debugger on the desired platform, then adding it may If a connector already exists for a suitable debugger on the desired platform, then adding it may be very simple.
be very simple. For example, both the x86 and ARM platforms are supported by GDB, so even though For example, many platforms are supported by GDB, so even though we're currently focused on x86-64 (and to some extent arm64) support, we've provided the mappings for many.
we're currently focused on x86 support, we've provided the opinions needed for Ghidra to debug ARM These mappings are conventionally kept in each connector's `arch.py` file.
platforms (and several others) via GDB. These opinions are kept in the "Debugger" project, not their
respective "agent" projects. We imagine there are a number of platforms that could be supported
almost out of the box, except that we haven't written the necessary opinions, yet. Take a look at
the existing ones for examples.
In general, to write a new opinion, you need to know: 1) What the platform is called (including In general, to update `arch.py`, you need to know:
variant names) by the debugger, 2) What the processor language is called by Ghidra, 3) If
applicable, the mapping of target address spaces into Ghidra's address spaces, 4) If applicable, the 1. What the platform is called (including variant names) by the debugger
mapping of target register names to those in Ghidra's processor language. In most cases (3) and (4) 2. What the processor language is called by Ghidra
are already implemented by default mappers, so you can use those same mappers in your opinion. Once 3. If applicable, the mapping of target address spaces into Ghidra's address spaces
you have the opinion written, you can try debugging and recording a target. If Ghidra finds your 4. If applicable, the mapping of target register names to those in Ghidra's processor language
opinion applicable to that target, it will attempt to record, and then you can work out the kinds
from there. Again, we have a bit of documentation to do regarding common pitfalls. In most cases (3) and (4) are already implemented by the included mappers.
Naturally, you'll want to test the special cases, preferably in automated tests.
### Emulation ### Emulation
The most obvious integration path for 3rd-party emulators is to write a "connector." However, p-code The most obvious integration path for 3rd-party emulators is to write a "connector."
emulation is now an integral feature of the Ghidra UI, and it has a fairly accessible API. Namely, However, p-code emulation is an integral feature of the Ghidra UI, and it has a fairly accessible API.
for interpolation between machines states recorded in a trace, and extrapolation into future machine Namely, for interpolation between machines states recorded in a trace, and extrapolation into future machine states.
states. Integration of such emulators may still be useful to you, but we recommend trying the p-code Integration of such emulators may still be useful to you, but we recommend trying the p-code emulator to see if it suits your needs for emulation in Ghidra before pursuing integration of another emulator.
emulator to see if it suits your needs for emulation in Ghidra before pursuing integration of We also provide out-of-the-box QEMU integration via GDB.
another emulator.
### Contributing ### Contributing
Whether submitting help tickets and pull requests, please tag those related to the debugger with When submitting help tickets and pull requests, please tag those related to the debugger with "Debugger" so that we can triage them more quickly.
"Debugger" so that we can triage them more quickly.
To set up your environment, in addition to the usual Gradle tasks, process the Protobuf
specification for GADP:
```bash
$ gradle generateProto
```
If you already have an environment set up in Eclipse, please re-run `gradle prepDev eclipse` and
import the new projects.
[java]: https://dev.java [java]: https://dev.java

1
GPL/DMG/README.md Normal file
View file

@ -0,0 +1 @@
# DMG

View file

@ -3,6 +3,7 @@
##MODULE IP: LGPL 2.1 ##MODULE IP: LGPL 2.1
##MODULE IP: Public Domain ##MODULE IP: Public Domain
Module.manifest||Public Domain||||END| Module.manifest||Public Domain||||END|
README.md||GHIDRA||||END|
data/lib/csframework.jar||LGPL 2.1||||END| data/lib/csframework.jar||LGPL 2.1||||END|
data/lib/hfsexplorer-0_21-src.zip||GPL 3||||END| data/lib/hfsexplorer-0_21-src.zip||GPL 3||||END|
data/lib/hfsx.jar||GPL 3||||END| data/lib/hfsx.jar||GPL 3||||END|

View file

@ -0,0 +1 @@
# DemanglerGnu

View file

@ -17,9 +17,9 @@ apply plugin: 'eclipse'
eclipse.project.name = 'GPL DemanglerGnu' eclipse.project.name = 'GPL DemanglerGnu'
def v33_1 = "demangler_gnu_v2_33_1" def v41 = "demangler_gnu_v2_41"
def v24 = "demangler_gnu_v2_24" def v24 = "demangler_gnu_v2_24"
def srcVersion33_1 = "src/demangler_gnu_v2_33_1" def srcVersion41 = "src/demangler_gnu_v2_41"
def srcVersion24 = "src/demangler_gnu_v2_24" def srcVersion24 = "src/demangler_gnu_v2_24"
/** /**
@ -41,19 +41,18 @@ task zipBuildableSource(type:Zip) {
archiveExtension = 'zip' archiveExtension = 'zip'
// //
// Version 2.33.1 // Version 2.41
// //
from (project.projectDir.toString() + "/" + srcVersion33_1 + "c") { from (project.projectDir.toString() + "/" + srcVersion41 + "c") {
into "/" + srcVersion33_1 into "/" + srcVersion41
} }
from (project.projectDir.toString() + "/" + srcVersion33_1 + "/headers") { from (project.projectDir.toString() + "/" + srcVersion41 + "/headers") {
into "/" + srcVersion33_1 into "/" + srcVersion41
} }
from (project.projectDir.toString() + "/" + srcVersion33_1 + "/build") { from (project.projectDir.toString() + "/" + srcVersion41 + "/build") {
into "/" + srcVersion33_1 into "/" + srcVersion41
} }
from (project.projectDir.toString() + "/" + srcVersion33_1 + "/README.txt") from (project.projectDir.toString() + "/" + srcVersion41 + "/README.txt")
// //
// Version 2.24 // Version 2.24
@ -72,23 +71,25 @@ task zipBuildableSource(type:Zip) {
model { model {
//
// Version 2.33.1
//
components { components {
demangler_gnu_v2_33_1(NativeExecutableSpec) { //
// Version 2.41
//
demangler_gnu_v2_41(NativeExecutableSpec) {
targetPlatform "win_x86_64" targetPlatform "win_x86_64"
targetPlatform "linux_x86_64" targetPlatform "linux_x86_64"
targetPlatform "linux_arm_64" targetPlatform "linux_arm_64"
targetPlatform "mac_x86_64" targetPlatform "mac_x86_64"
targetPlatform "mac_arm_64" targetPlatform "mac_arm_64"
targetPlatform "freebsd_x86_64"
targetPlatform "freebsd_arm_64"
sources { sources {
c { c {
source { source {
srcDir srcVersion33_1 + "/c" srcDir srcVersion41 + "/c"
} }
exportedHeaders { exportedHeaders {
srcDir srcVersion33_1 + "/headers" srcDir srcVersion41 + "/headers"
} }
} }
} }
@ -103,6 +104,8 @@ model {
targetPlatform "linux_arm_64" targetPlatform "linux_arm_64"
targetPlatform "mac_x86_64" targetPlatform "mac_x86_64"
targetPlatform "mac_arm_64" targetPlatform "mac_arm_64"
targetPlatform "freebsd_x86_64"
targetPlatform "freebsd_arm_64"
sources { sources {
c { c {
source { source {
@ -127,7 +130,7 @@ model {
def version = b.getApplication().getName() def version = b.getApplication().getName()
if (version.equals(v33_1)) { if (version.equals(v41)) {
if (toolChain in Gcc) { if (toolChain in Gcc) {
//cCompiler.args "-DCP_DEMANGLE_DEBUG" //cCompiler.args "-DCP_DEMANGLE_DEBUG"
cCompiler.args "-DHAVE_STDLIB_H" cCompiler.args "-DHAVE_STDLIB_H"

View file

@ -5,5 +5,5 @@
##MODULE IP: LGPL 3.0 ##MODULE IP: LGPL 3.0
##MODULE IP: Public Domain ##MODULE IP: Public Domain
Module.manifest||Public Domain||||END| Module.manifest||Public Domain||||END|
README.md||GHIDRA||||END|
src/demangler_gnu_v2_24/README.txt||Public Domain||||END| src/demangler_gnu_v2_24/README.txt||Public Domain||||END|
src/demangler_gnu_v2_33_1/README.txt||Public Domain||||END|

View file

@ -903,7 +903,7 @@ ada_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
goto unknown; goto unknown;
/* Most of the demangling will trivially remove chars. Operator names /* Most of the demangling will trivially remove chars. Operator names
may add one char but because they are always preceeded by '__' which is may add one char but because they are always preceded by '__' which is
replaced by '.', they eventually never expand the size. replaced by '.', they eventually never expand the size.
A few special names such as '___elabs' add a few chars (at most 7), but A few special names such as '___elabs' add a few chars (at most 7), but
they occur only once. */ they occur only once. */

View file

@ -1,81 +0,0 @@
PURPOSE
This is a readme file to note the changes made to the binutils-2.33.1 source
code in to build its GNU demangler. The files in this directory are used to create a demangling
utility during the full build process.
COPIED SOURCE CODE / BUILDING RESTRICTIONS
Most of the files used to build the Ghidra GNU demangler are copied from binutils and have
not been changed. Further, the files in this directory are a small subset of the files used to
build the binutils suite. By copying specific files we are able to use Make and Visual Studio
to build a stand alone demangler without having to perform the more complicated build needed
to build binutils. Specifically, we do not have to run the configure utility that is
provided by binutils. This is critical, as we are using Visual Studio to build on Windows,
which does not have the configure utility support. If we ever wished to build the entire
binutils suite on Windows, then we would most likely need to use a GNU environment made for
Windows, such as MinGW.
CHANGES TO BINUTILS SOURCE
cp-demangle.c
This file contains a small, one-line change to flush to the standard output stream. Without
this change, the program, when called repeatedly from Java would hang as it attempts to read
characters that are buffered on the native side.
UPDATING
If we ever wish to update to a newer version of binutils, then we will need to re-copy the files
in this directory. That is, unless at least one of the following changes happens:
1) building a stand alone c++filt is simple enough that we can do it on each platform, or
2) we decide to build the entire binutils suite and use the full c++filt binary.
SOURCE FILES
binutils/libiberty/alloca.c
binutils/libiberty/argv.c
binutils/libiberty/cp-demangle.c
binutils/libiberty/cplus-dem.c
binutils/libiberty/d-demangle.c
binutils/libiberty/dyn-string.c
binutils/libiberty/getopt.c
binutils/libiberty/getopt1.c
binutils/libiberty/rust-demangle.c
binutils/libiberty/safe-ctype.c
binutils/libiberty/xexit.c
binutils/libiberty/xstrdup.c
binutils/include/ansidecl.h
binutils/libiberty/cp-demangle.h
binutils/include/demangle.h
binutils/include/dyn-string.h
binutils/include/getopt.h
binutils/include/libiberty.h
binutils/libiberty/rust-demangle.h
binutils/include/safe-ctype.h
This file is created to add minor missing dependencies.
missing.c
LICENSE
The files listed above are licensed by using the file header or the COPYING or COPYING.LIB file
listed in the original source directory of binutils.

File diff suppressed because it is too large Load diff

View file

@ -1,353 +0,0 @@
/* ###
* IP: LGPL 2.1
* NOTE: See binutils/libiberty/COPYING.LIB
*/
/* Demangler for the Rust programming language
Copyright (C) 2016-2019 Free Software Foundation, Inc.
Written by David Tolnay (dtolnay@gmail.com).
This file is part of the libiberty library.
Libiberty is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
In addition to the permissions in the GNU Library General Public
License, the Free Software Foundation gives you unlimited permission
to link the compiled version of this file into combinations with other
programs, and to distribute those combinations without any restriction
coming from the use of this file. (The Library Public License
restrictions do apply in other respects; for example, they cover
modification of the file, and distribution when not linked into a
combined executable.)
Libiberty is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with libiberty; see the file COPYING.LIB.
If not, see <http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "safe-ctype.h"
#include <sys/types.h>
#include <string.h>
#include <stdio.h>
#ifdef HAVE_STRING_H
#include <string.h>
#else
extern size_t strlen(const char *s);
extern int strncmp(const char *s1, const char *s2, size_t n);
extern void *memset(void *s, int c, size_t n);
#endif
#include <demangle.h>
#include "libiberty.h"
#include "rust-demangle.h"
/* Mangled Rust symbols look like this:
_$LT$std..sys..fd..FileDesc$u20$as$u20$core..ops..Drop$GT$::drop::hc68340e1baa4987a
The original symbol is:
<std::sys::fd::FileDesc as core::ops::Drop>::drop
The last component of the path is a 64-bit hash in lowercase hex,
prefixed with "h". Rust does not have a global namespace between
crates, an illusion which Rust maintains by using the hash to
distinguish things that would otherwise have the same symbol.
Any path component not starting with a XID_Start character is
prefixed with "_".
The following escape sequences are used:
"," => $C$
"@" => $SP$
"*" => $BP$
"&" => $RF$
"<" => $LT$
">" => $GT$
"(" => $LP$
")" => $RP$
" " => $u20$
"\"" => $u22$
"'" => $u27$
"+" => $u2b$
";" => $u3b$
"[" => $u5b$
"]" => $u5d$
"{" => $u7b$
"}" => $u7d$
"~" => $u7e$
A double ".." means "::" and a single "." means "-".
The only characters allowed in the mangled symbol are a-zA-Z0-9 and _.:$ */
static const char *hash_prefix = "::h";
static const size_t hash_prefix_len = 3;
static const size_t hash_len = 16;
static int is_prefixed_hash (const char *start);
static int looks_like_rust (const char *sym, size_t len);
static int unescape (const char **in, char **out, const char *seq, char value);
/* INPUT: sym: symbol that has been through C++ (gnu v3) demangling
This function looks for the following indicators:
1. The hash must consist of "h" followed by 16 lowercase hex digits.
2. As a sanity check, the hash must use between 5 and 15 of the 16
possible hex digits. This is true of 99.9998% of hashes so once
in your life you may see a false negative. The point is to
notice path components that could be Rust hashes but are
probably not, like "haaaaaaaaaaaaaaaa". In this case a false
positive (non-Rust symbol has an important path component
removed because it looks like a Rust hash) is worse than a false
negative (the rare Rust symbol is not demangled) so this sets
the balance in favor of false negatives.
3. There must be no characters other than a-zA-Z0-9 and _.:$
4. There must be no unrecognized $-sign sequences.
5. There must be no sequence of three or more dots in a row ("..."). */
int
rust_is_mangled (const char *sym)
{
size_t len, len_without_hash;
if (!sym)
return 0;
len = strlen (sym);
if (len <= hash_prefix_len + hash_len)
/* Not long enough to contain "::h" + hash + something else */
return 0;
len_without_hash = len - (hash_prefix_len + hash_len);
if (!is_prefixed_hash (sym + len_without_hash))
return 0;
return looks_like_rust (sym, len_without_hash);
}
/* A hash is the prefix "::h" followed by 16 lowercase hex digits. The
hex digits must comprise between 5 and 15 (inclusive) distinct
digits. */
static int
is_prefixed_hash (const char *str)
{
const char *end;
char seen[16];
size_t i;
int count;
if (strncmp (str, hash_prefix, hash_prefix_len))
return 0;
str += hash_prefix_len;
memset (seen, 0, sizeof(seen));
for (end = str + hash_len; str < end; str++)
if (*str >= '0' && *str <= '9')
seen[*str - '0'] = 1;
else if (*str >= 'a' && *str <= 'f')
seen[*str - 'a' + 10] = 1;
else
return 0;
/* Count how many distinct digits seen */
count = 0;
for (i = 0; i < 16; i++)
if (seen[i])
count++;
return count >= 5 && count <= 15;
}
static int
looks_like_rust (const char *str, size_t len)
{
const char *end = str + len;
while (str < end)
switch (*str)
{
case '$':
if (!strncmp (str, "$C$", 3))
str += 3;
else if (!strncmp (str, "$SP$", 4)
|| !strncmp (str, "$BP$", 4)
|| !strncmp (str, "$RF$", 4)
|| !strncmp (str, "$LT$", 4)
|| !strncmp (str, "$GT$", 4)
|| !strncmp (str, "$LP$", 4)
|| !strncmp (str, "$RP$", 4))
str += 4;
else if (!strncmp (str, "$u20$", 5)
|| !strncmp (str, "$u22$", 5)
|| !strncmp (str, "$u27$", 5)
|| !strncmp (str, "$u2b$", 5)
|| !strncmp (str, "$u3b$", 5)
|| !strncmp (str, "$u5b$", 5)
|| !strncmp (str, "$u5d$", 5)
|| !strncmp (str, "$u7b$", 5)
|| !strncmp (str, "$u7d$", 5)
|| !strncmp (str, "$u7e$", 5))
str += 5;
else
return 0;
break;
case '.':
/* Do not allow three or more consecutive dots */
if (!strncmp (str, "...", 3))
return 0;
/* Fall through */
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
case 's': case 't': case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z':
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
case 'Y': case 'Z':
case '0': case '1': case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9':
case '_':
case ':':
str++;
break;
default:
return 0;
}
return 1;
}
/*
INPUT: sym: symbol for which rust_is_mangled(sym) returned 1.
The input is demangled in-place because the mangled name is always
longer than the demangled one. */
void
rust_demangle_sym (char *sym)
{
const char *in;
char *out;
const char *end;
if (!sym)
return;
in = sym;
out = sym;
end = sym + strlen (sym) - (hash_prefix_len + hash_len);
while (in < end)
switch (*in)
{
case '$':
if (!(unescape (&in, &out, "$C$", ',')
|| unescape (&in, &out, "$SP$", '@')
|| unescape (&in, &out, "$BP$", '*')
|| unescape (&in, &out, "$RF$", '&')
|| unescape (&in, &out, "$LT$", '<')
|| unescape (&in, &out, "$GT$", '>')
|| unescape (&in, &out, "$LP$", '(')
|| unescape (&in, &out, "$RP$", ')')
|| unescape (&in, &out, "$u20$", ' ')
|| unescape (&in, &out, "$u22$", '\"')
|| unescape (&in, &out, "$u27$", '\'')
|| unescape (&in, &out, "$u2b$", '+')
|| unescape (&in, &out, "$u3b$", ';')
|| unescape (&in, &out, "$u5b$", '[')
|| unescape (&in, &out, "$u5d$", ']')
|| unescape (&in, &out, "$u7b$", '{')
|| unescape (&in, &out, "$u7d$", '}')
|| unescape (&in, &out, "$u7e$", '~'))) {
/* unexpected escape sequence, not looks_like_rust. */
goto fail;
}
break;
case '_':
/* If this is the start of a path component and the next
character is an escape sequence, ignore the underscore. The
mangler inserts an underscore to make sure the path
component begins with a XID_Start character. */
if ((in == sym || in[-1] == ':') && in[1] == '$')
in++;
else
*out++ = *in++;
break;
case '.':
if (in[1] == '.')
{
/* ".." becomes "::" */
*out++ = ':';
*out++ = ':';
in += 2;
}
else
{
/* "." becomes "-" */
*out++ = '-';
in++;
}
break;
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
case 's': case 't': case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z':
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
case 'Y': case 'Z':
case '0': case '1': case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9':
case ':':
*out++ = *in++;
break;
default:
/* unexpected character in symbol, not looks_like_rust. */
goto fail;
}
goto done;
fail:
*out++ = '?'; /* This is pretty lame, but it's hard to do better. */
done:
*out = '\0';
}
static int
unescape (const char **in, char **out, const char *seq, char value)
{
size_t len = strlen (seq);
if (strncmp (*in, seq, len))
return 0;
**out = value;
*in += len;
*out += 1;
return 1;
}

View file

@ -1,49 +0,0 @@
/* ###
* IP: LGPL 2.1
* NOTE: See binutils/libiberty/COPYING.LIB
*/
/* Internal demangler interface for the Rust programming language.
Copyright (C) 2016-2019 Free Software Foundation, Inc.
Written by David Tolnay (dtolnay@gmail.com).
This file is part of the libiberty library.
Libiberty is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
In addition to the permissions in the GNU Library General Public
License, the Free Software Foundation gives you unlimited permission
to link the compiled version of this file into combinations with other
programs, and to distribute those combinations without any restriction
coming from the use of this file. (The Library Public License
restrictions do apply in other respects; for example, they cover
modification of the file, and distribution when not linked into a
combined executable.)
Libiberty is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with libiberty; see the file COPYING.LIB.
If not, see <http://www.gnu.org/licenses/>. */
/* This file provides some definitions shared by cplus-dem.c and
rust-demangle.c. It should not be included by any other files. */
/* Returns non-zero iff MANGLED is a rust mangled symbol. MANGLED must
already have been demangled through cplus_demangle_v3. If this function
returns non-zero then MANGLED can be demangled (in-place) using
RUST_DEMANGLE_SYM. */
extern int
rust_is_mangled (const char *mangled);
/* Demangles SYM (in-place) if RUST_IS_MANGLED returned non-zero for SYM.
If RUST_IS_MANGLED returned zero for SYM then RUST_DEMANGLE_SYM might
replace characters that cannot be demangled with '?' and might truncate
SYM. After calling RUST_DEMANGLE_SYM SYM might be shorter, but never
larger. */
extern void
rust_demangle_sym (char *sym);

View file

@ -1,6 +1,6 @@
/* ### /* ###
* IP: LGPL 2.1 * IP: LGPL 2.1
* NOTE: license is not in file, but in the directory from whence it came: binutils-2.24/libiberty/COPYING.LIB * NOTE: See binutils/libiberty/COPYING.LIB
*/ */
/* alloca.c -- allocate automatically reclaimed memory /* alloca.c -- allocate automatically reclaimed memory
(Mostly) portable public-domain implementation -- D A Gwyn (Mostly) portable public-domain implementation -- D A Gwyn
@ -162,7 +162,7 @@ static header *last_alloca_header = NULL; /* -> last alloca header. */
/* @undocumented C_alloca */ /* @undocumented C_alloca */
PTR void *
C_alloca (size_t size) C_alloca (size_t size)
{ {
auto char probe; /* Probes stack depth: */ auto char probe; /* Probes stack depth: */
@ -185,7 +185,7 @@ C_alloca (size_t size)
{ {
register header *np = hp->h.next; register header *np = hp->h.next;
free ((PTR) hp); /* Collect garbage. */ free ((void *) hp); /* Collect garbage. */
hp = np; /* -> next header. */ hp = np; /* -> next header. */
} }
@ -214,7 +214,7 @@ C_alloca (size_t size)
/* User storage begins just after header. */ /* User storage begins just after header. */
return (PTR) ((char *) new_storage + sizeof (header)); return (void *) ((char *) new_storage + sizeof (header));
} }
} }

View file

@ -3,7 +3,7 @@
* NOTE: See binutils/libiberty/COPYING.LIB * NOTE: See binutils/libiberty/COPYING.LIB
*/ */
/* Create and destroy argument vectors (argv's) /* Create and destroy argument vectors (argv's)
Copyright (C) 1992-2019 Free Software Foundation, Inc. Copyright (C) 1992-2023 Free Software Foundation, Inc.
Written by Fred Fish @ Cygnus Support Written by Fred Fish @ Cygnus Support
This file is part of the libiberty library. This file is part of the libiberty library.
@ -293,8 +293,8 @@ char **buildargv (const char *input)
@deftypefn Extension int writeargv (char * const *@var{argv}, FILE *@var{file}) @deftypefn Extension int writeargv (char * const *@var{argv}, FILE *@var{file})
Write each member of ARGV, handling all necessary quoting, to the file Write each member of ARGV, handling all necessary quoting, to the file
named by FILE, separated by whitespace. Return 0 on success, non-zero associated with FILE, separated by whitespace. Return 0 on success,
if an error occurred while writing to FILE. non-zero if an error occurred while writing to FILE.
@end deftypefn @end deftypefn
@ -303,8 +303,6 @@ if an error occurred while writing to FILE.
int int
writeargv (char * const *argv, FILE *f) writeargv (char * const *argv, FILE *f)
{ {
int status = 0;
if (f == NULL) if (f == NULL)
return 1; return 1;
@ -318,29 +316,26 @@ writeargv (char * const *argv, FILE *f)
if (ISSPACE(c) || c == '\\' || c == '\'' || c == '"') if (ISSPACE(c) || c == '\\' || c == '\'' || c == '"')
if (EOF == fputc ('\\', f)) if (EOF == fputc ('\\', f))
{ return 1;
status = 1;
goto done;
}
if (EOF == fputc (c, f)) if (EOF == fputc (c, f))
{ return 1;
status = 1;
goto done;
}
arg++; arg++;
} }
/* Write out a pair of quotes for an empty argument. */
if (arg == *argv)
if (EOF == fputs ("\"\"", f))
return 1;
if (EOF == fputc ('\n', f)) if (EOF == fputc ('\n', f))
{ return 1;
status = 1;
goto done;
}
argv++; argv++;
} }
done: return 0;
return status;
} }
/* /*
@ -438,7 +433,10 @@ expandargv (int *argcp, char ***argvp)
due to CR/LF->CR translation when reading text files. due to CR/LF->CR translation when reading text files.
That does not in-and-of itself indicate failure. */ That does not in-and-of itself indicate failure. */
&& ferror (f)) && ferror (f))
goto error; {
free (buffer);
goto error;
}
/* Add a NUL terminator. */ /* Add a NUL terminator. */
buffer[len] = '\0'; buffer[len] = '\0';
/* If the file is empty or contains only whitespace, buildargv would /* If the file is empty or contains only whitespace, buildargv would

View file

@ -3,7 +3,7 @@
* NOTE: See binutils/libiberty/COPYING.LIB * NOTE: See binutils/libiberty/COPYING.LIB
*/ */
/* Demangler for GNU C++ /* Demangler for GNU C++
Copyright (C) 1989-2019 Free Software Foundation, Inc. Copyright (C) 1989-2023 Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.uucp) Written by James Clark (jjc@jclark.uucp)
Rewritten by Fred Fish (fnf@cygnus.com) for ARM and Lucid demangling Rewritten by Fred Fish (fnf@cygnus.com) for ARM and Lucid demangling
Modified by Satish Pai (pai@apollo.hp.com) for HP demangling Modified by Satish Pai (pai@apollo.hp.com) for HP demangling
@ -56,7 +56,6 @@ void * realloc ();
#define CURRENT_DEMANGLING_STYLE options #define CURRENT_DEMANGLING_STYLE options
#include "libiberty.h" #include "libiberty.h"
#include "rust-demangle.h"
enum demangling_styles current_demangling_style = auto_demangling; enum demangling_styles current_demangling_style = auto_demangling;
@ -164,27 +163,20 @@ cplus_demangle (const char *mangled, int options)
if ((options & DMGL_STYLE_MASK) == 0) if ((options & DMGL_STYLE_MASK) == 0)
options |= (int) current_demangling_style & DMGL_STYLE_MASK; options |= (int) current_demangling_style & DMGL_STYLE_MASK;
/* The Rust demangling is implemented elsewhere.
Legacy Rust symbols overlap with GNU_V3, so try Rust first. */
if (RUST_DEMANGLING || AUTO_DEMANGLING)
{
ret = rust_demangle (mangled, options);
if (ret || RUST_DEMANGLING)
return ret;
}
/* The V3 ABI demangling is implemented elsewhere. */ /* The V3 ABI demangling is implemented elsewhere. */
if (GNU_V3_DEMANGLING || RUST_DEMANGLING || AUTO_DEMANGLING) if (GNU_V3_DEMANGLING || AUTO_DEMANGLING)
{ {
ret = cplus_demangle_v3 (mangled, options); ret = cplus_demangle_v3 (mangled, options);
if (GNU_V3_DEMANGLING) if (ret || GNU_V3_DEMANGLING)
return ret;
if (ret)
{
/* Rust symbols are GNU_V3 mangled plus some extra subtitutions.
The subtitutions are always smaller, so do in place changes. */
if (rust_is_mangled (ret))
rust_demangle_sym (ret);
else if (RUST_DEMANGLING)
{
free (ret);
ret = NULL;
}
}
if (ret || RUST_DEMANGLING)
return ret; return ret;
} }
@ -208,27 +200,6 @@ cplus_demangle (const char *mangled, int options)
return (ret); return (ret);
} }
char *
rust_demangle (const char *mangled, int options)
{
/* Rust symbols are GNU_V3 mangled plus some extra subtitutions. */
char *ret = cplus_demangle_v3 (mangled, options);
/* The Rust subtitutions are always smaller, so do in place changes. */
if (ret != NULL)
{
if (rust_is_mangled (ret))
rust_demangle_sym (ret);
else
{
free (ret);
ret = NULL;
}
}
return ret;
}
/* Demangle ada names. The encoding is documented in gcc/ada/exp_dbug.ads. */ /* Demangle ada names. The encoding is documented in gcc/ada/exp_dbug.ads. */
char * char *
@ -248,7 +219,7 @@ ada_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
goto unknown; goto unknown;
/* Most of the demangling will trivially remove chars. Operator names /* Most of the demangling will trivially remove chars. Operator names
may add one char but because they are always preceeded by '__' which is may add one char but because they are always preceded by '__' which is
replaced by '.', they eventually never expand the size. replaced by '.', they eventually never expand the size.
A few special names such as '___elabs' add a few chars (at most 7), but A few special names such as '___elabs' add a few chars (at most 7), but
they occur only once. */ they occur only once. */

View file

@ -2,7 +2,7 @@
* IP: GPL 3 * IP: GPL 3
*/ */
/* Demangler for GNU C++ - main program /* Demangler for GNU C++ - main program
Copyright (C) 1989-2019 Free Software Foundation, Inc. Copyright (C) 1989-2023 Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.uucp) Written by James Clark (jjc@jclark.uucp)
Rewritten by Fred Fish (fnf@cygnus.com) for ARM and Lucid demangling Rewritten by Fred Fish (fnf@cygnus.com) for ARM and Lucid demangling
Modified by Satish Pai (pai@apollo.hp.com) for HP demangling Modified by Satish Pai (pai@apollo.hp.com) for HP demangling
@ -24,22 +24,33 @@
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. 02110-1301, USA.
CHANGE NOTICE:
This file was changed on July 22nd, 2020.
*/ CHANGE NOTICE:
This file was changed on October 31st, 2023.
#include <stdlib.h> */
#include <string.h>
// #include "sysdep.h" // Changed 10/31/23
// error reporting front end
// #include "bfd.h" // Changed 10/31/23
#include <stdlib.h> // Changed 10/31/23
#include <string.h> // Changed 10/31/23
#include "libiberty.h" #include "libiberty.h"
#include "demangle.h" #include "demangle.h"
#include "getopt.h" #include "getopt.h"
#include "safe-ctype.h" #include "safe-ctype.h"
// bfd code
// #include "bucomm.h" // Changed 10/31/23
static int flags = DMGL_PARAMS | DMGL_ANSI | DMGL_VERBOSE; static int flags = DMGL_PARAMS | DMGL_ANSI | DMGL_VERBOSE;
static int strip_underscore = 0; // TARGET_PREPENDS_UNDERSCORE; // Changed Jan 22, 2020 static int strip_underscore = 0; // TARGET_PREPENDS_UNDERSCORE; // Changed 10/31/23
static const char *program_name; // Changed Jan 22, 2020
// declared in bucomm.c
static const char *program_name; // Changed 10/31/23
static const struct option long_options[] = static const struct option long_options[] =
{ {
@ -108,10 +119,12 @@ Usage: %s [options] [mangled names]\n", program_name);
fprintf (stream, "\ fprintf (stream, "\
Options are:\n\ Options are:\n\
[-_|--strip-underscore] Ignore first leading underscore%s\n", [-_|--strip-underscore] Ignore first leading underscore%s\n",
strip_underscore ? " (default)" : ""); // Changed Jan 22, 2020 // TARGET_PREPENDS_UNDERSCORE ? " (default)" : ""); // Changed 10/31/23
strip_underscore ? " (default)" : ""); // Changed 10/31/23
fprintf (stream, "\ fprintf (stream, "\
[-n|--no-strip-underscore] Do not ignore a leading underscore%s\n", [-n|--no-strip-underscore] Do not ignore a leading underscore%s\n",
strip_underscore ? "" : " (default)"); // Changed Jan 22, 2020 // TARGET_PREPENDS_UNDERSCORE ? "" : " (default)"); // Changed 10/31/23
strip_underscore ? "" : " (default)"); // Changed 10/31/23
fprintf (stream, "\ fprintf (stream, "\
[-p|--no-params] Do not display function arguments\n\ [-p|--no-params] Do not display function arguments\n\
[-i|--no-verbose] Do not show implementation details (if any)\n\ [-i|--no-verbose] Do not show implementation details (if any)\n\
@ -130,11 +143,11 @@ Demangled names are displayed to stdout.\n\
If a name cannot be demangled it is just echoed to stdout.\n\ If a name cannot be demangled it is just echoed to stdout.\n\
If no names are provided on the command line, stdin is read.\n"); If no names are provided on the command line, stdin is read.\n");
/* Changed Jan 22, 2020 /* Changed 10/31/23
// defined in version.h
if (REPORT_BUGS_TO[0] && status == 0) if (REPORT_BUGS_TO[0] && status == 0)
fprintf (stream, _("Report bugs to %s.\n"), REPORT_BUGS_TO); fprintf (stream, _("Report bugs to %s.\n"), REPORT_BUGS_TO);
*/ */
exit (status); exit (status);
} }
@ -158,8 +171,8 @@ main (int argc, char **argv)
enum demangling_styles style = auto_demangling; enum demangling_styles style = auto_demangling;
program_name = argv[0]; program_name = argv[0];
// xmalloc_set_program_name (program_name); // Changed Jan 22, 2020 // xmalloc_set_program_name (program_name); // Changed 10/31/23
// bfd_set_error_program_name (program_name); // Changed Jan 22, 2020 // bfd_set_error_program_name (program_name); // Changed 10/31/23
expandargv (&argc, &argv); expandargv (&argc, &argv);
@ -191,7 +204,8 @@ main (int argc, char **argv)
flags &= ~ DMGL_VERBOSE; flags &= ~ DMGL_VERBOSE;
break; break;
case 'v': case 'v':
printf ("(GNU Binutils) c++filt 2.33.1\n"); // Changed Jan 22, 2020 // print_version ("c++filt"); // Changed 10/31/23
printf ("c++filt 2.41\n"); // Changed 10/31/23
return 0; return 0;
case '_': case '_':
strip_underscore = 1; strip_underscore = 1;
@ -230,13 +244,14 @@ main (int argc, char **argv)
case rust_demangling: case rust_demangling:
valid_symbols = standard_symbol_characters (); valid_symbols = standard_symbol_characters ();
break; break;
default: { default:
/* Folks should explicitly indicate the appropriate alphabet for /* Folks should explicitly indicate the appropriate alphabet for
each demangling. Providing a default would allow the each demangling. Providing a default would allow the
question to go unconsidered. */ question to go unconsidered. */
fprintf (stderr, "Internal error: no symbol alphabet for current style\n"); // Changed Jan 22, 2020 // fatal ("Internal error: no symbol alphabet for current style"); // Changed 10/31/23
exit (1); // Changed Jan 22, 2020 fprintf (stderr, "Internal error: no symbol alphabet for current style\n"); // Changed 10/31/23
} exit (1); // Changed 10/31/23
} }
for (;;) for (;;)

File diff suppressed because it is too large Load diff

View file

@ -3,7 +3,7 @@
* NOTE: See binutils/include/COPYING3 * NOTE: See binutils/include/COPYING3
*/ */
/* An abstract string datatype. /* An abstract string datatype.
Copyright (C) 1998-2019 Free Software Foundation, Inc. Copyright (C) 1998-2023 Free Software Foundation, Inc.
Contributed by Mark Mitchell (mark@markmitchell.com). Contributed by Mark Mitchell (mark@markmitchell.com).
This file is part of GNU CC. This file is part of GNU CC.
@ -281,7 +281,7 @@ dyn_string_insert_cstr (dyn_string_t dest, int pos, const char *src)
for (i = dest->length; i >= pos; --i) for (i = dest->length; i >= pos; --i)
dest->s[i + length] = dest->s[i]; dest->s[i + length] = dest->s[i];
/* Splice in the new stuff. */ /* Splice in the new stuff. */
strncpy (dest->s + pos, src, length); memcpy (dest->s + pos, src, length);
/* Compute the new length. */ /* Compute the new length. */
dest->length += length; dest->length += length;
return 1; return 1;

View file

@ -1,5 +1,5 @@
/* ### /* ###
* IP: GPL 3 * IP: GPL 3 Linking Permitted
* NOTE: See binutils/include/COPYING3 * NOTE: See binutils/include/COPYING3
*/ */
/* Getopt for GNU. /* Getopt for GNU.
@ -7,7 +7,7 @@
"Keep this file name-space clean" means, talk to drepper@gnu.org "Keep this file name-space clean" means, talk to drepper@gnu.org
before changing it! before changing it!
Copyright (C) 1987-2019 Free Software Foundation, Inc. Copyright (C) 1987-2023 Free Software Foundation, Inc.
NOTE: This source is derived from an old version taken from the GNU C NOTE: This source is derived from an old version taken from the GNU C
Library (glibc). Library (glibc).

View file

@ -1,9 +1,9 @@
/* ### /* ###
* IP: GPL 3 * IP: GPL 3 Linking Permitted
* NOTE: See binutils/include/COPYING3 * NOTE: See binutils/include/COPYING3
*/ */
/* getopt_long and getopt_long_only entry points for GNU getopt. /* getopt_long and getopt_long_only entry points for GNU getopt.
Copyright (C) 1987-2019 Free Software Foundation, Inc. Copyright (C) 1987-2023 Free Software Foundation, Inc.
NOTE: This source is derived from an old version taken from the GNU C NOTE: This source is derived from an old version taken from the GNU C
Library (glibc). Library (glibc).

View file

@ -28,7 +28,7 @@
CHANGE NOTICE: CHANGE NOTICE:
This file was created on January 22nd, 2020: This file was created on October 31st, 2023:
-This code was copied and modified from a previous version of libiberty -This code was copied and modified from a previous version of libiberty
*/ */

File diff suppressed because it is too large Load diff

View file

@ -1,10 +1,10 @@
/* ### /* ###
* IP: LGPL 2.1 * IP: LGPL 2.1
* NOTE: See binutils/include/COPYING * NOTE: See binutils/libiberty/COPYING.LIB
*/ */
/* <ctype.h> replacement macros. /* <ctype.h> replacement macros.
Copyright (C) 2000-2019 Free Software Foundation, Inc. Copyright (C) 2000-2023 Free Software Foundation, Inc.
Contributed by Zack Weinberg <zackw@stanford.edu>. Contributed by Zack Weinberg <zackw@stanford.edu>.
This file is part of the libiberty library. This file is part of the libiberty library.

View file

@ -3,7 +3,7 @@
* NOTE: See binutils/libiberty/COPYING.LIB * NOTE: See binutils/libiberty/COPYING.LIB
*/ */
/* xexit.c -- Run any exit handlers, then exit. /* xexit.c -- Run any exit handlers, then exit.
Copyright (C) 1994-2019 Free Software Foundation, Inc. Copyright (C) 1994-2023 Free Software Foundation, Inc.
This file is part of the libiberty library. This file is part of the libiberty library.
Libiberty is free software; you can redistribute it and/or Libiberty is free software; you can redistribute it and/or

View file

@ -2,8 +2,8 @@
* IP: LGPL 2.1 * IP: LGPL 2.1
* NOTE: See binutils/include/COPYING * NOTE: See binutils/include/COPYING
*/ */
/* ANSI and traditional C compatability macros /* Compiler compatibility macros
Copyright (C) 1991-2019 Free Software Foundation, Inc. Copyright (C) 1991-2023 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
@ -20,18 +20,7 @@ You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
/* ANSI and traditional C compatibility macros /* For ease of writing code which uses GCC extensions but needs to be
ANSI C is assumed if __STDC__ is #defined.
Macro ANSI C definition Traditional C definition
----- ---- - ---------- ----------- - ----------
PTR `void *' `char *'
const not defined `'
volatile not defined `'
signed not defined `'
For ease of writing code which uses GCC extensions but needs to be
portable to other compilers, we provide the GCC_VERSION macro that portable to other compilers, we provide the GCC_VERSION macro that
simplifies testing __GNUC__ and __GNUC_MINOR__ together, and various simplifies testing __GNUC__ and __GNUC_MINOR__ together, and various
wrappers around __attribute__. Also, __extension__ will be #defined wrappers around __attribute__. Also, __extension__ will be #defined
@ -66,24 +55,10 @@ So instead we use the macro below and test it against specific values. */
#define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__) #define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)
#endif /* GCC_VERSION */ #endif /* GCC_VERSION */
#if defined (__STDC__) || defined(__cplusplus) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4)) || defined(_WIN32)
/* All known AIX compilers implement these things (but don't always
define __STDC__). The RISC/OS MIPS compiler defines these things
in SVR4 mode, but does not define __STDC__. */
/* eraxxon@alumni.rice.edu: The Compaq C++ compiler, unlike many other
C++ compilers, does not define __STDC__, though it acts as if this
was so. (Verified versions: 5.7, 6.2, 6.3, 6.5) */
#define PTR void *
#undef const
#undef volatile
#undef signed
/* inline requires special treatment; it's in C99, and GCC >=2.7 supports /* inline requires special treatment; it's in C99, and GCC >=2.7 supports
it too, but it's not in C89. */ it too, but it's not in C89. */
#undef inline #undef inline
#if __STDC_VERSION__ >= 199901L || defined(__cplusplus) || (defined(__SUNPRO_C) && defined(__C99FEATURES__)) #if (!defined(__cplusplus) && __STDC_VERSION__ >= 199901L) || defined(__cplusplus) || (defined(__SUNPRO_C) && defined(__C99FEATURES__))
/* it's a keyword */ /* it's a keyword */
#else #else
# if GCC_VERSION >= 2007 # if GCC_VERSION >= 2007
@ -93,22 +68,6 @@ So instead we use the macro below and test it against specific values. */
# endif # endif
#endif #endif
#else /* Not ANSI C. */
#define PTR char *
/* some systems define these in header files for non-ansi mode */
#undef const
#undef volatile
#undef signed
#undef inline
#define const
#define volatile
#define signed
#define inline
#endif /* ANSI C. */
/* Define macros for some gcc attributes. This permits us to use the /* Define macros for some gcc attributes. This permits us to use the
macros freely, and know that they will come into play for the macros freely, and know that they will come into play for the
version of gcc in which they are supported. */ version of gcc in which they are supported. */
@ -296,6 +255,40 @@ So instead we use the macro below and test it against specific values. */
# endif # endif
#endif #endif
/* Attribute `alloc_size' was valid as of gcc 4.3. */
#ifndef ATTRIBUTE_RESULT_SIZE_1
# if (GCC_VERSION >= 4003)
# define ATTRIBUTE_RESULT_SIZE_1 __attribute__ ((alloc_size (1)))
# else
# define ATTRIBUTE_RESULT_SIZE_1
#endif
#endif
#ifndef ATTRIBUTE_RESULT_SIZE_2
# if (GCC_VERSION >= 4003)
# define ATTRIBUTE_RESULT_SIZE_2 __attribute__ ((alloc_size (2)))
# else
# define ATTRIBUTE_RESULT_SIZE_2
#endif
#endif
#ifndef ATTRIBUTE_RESULT_SIZE_1_2
# if (GCC_VERSION >= 4003)
# define ATTRIBUTE_RESULT_SIZE_1_2 __attribute__ ((alloc_size (1, 2)))
# else
# define ATTRIBUTE_RESULT_SIZE_1_2
#endif
#endif
/* Attribute `warn_unused_result' was valid as of gcc 3.3. */
#ifndef ATTRIBUTE_WARN_UNUSED_RESULT
# if GCC_VERSION >= 3003
# define ATTRIBUTE_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result))
# else
# define ATTRIBUTE_WARN_UNUSED_RESULT
# endif
#endif
/* We use __extension__ in some places to suppress -pedantic warnings /* We use __extension__ in some places to suppress -pedantic warnings
about GCC extensions. This feature didn't work properly before about GCC extensions. This feature didn't work properly before
gcc 2.8. */ gcc 2.8. */
@ -326,53 +319,12 @@ So instead we use the macro below and test it against specific values. */
#define ENUM_BITFIELD(TYPE) unsigned int #define ENUM_BITFIELD(TYPE) unsigned int
#endif #endif
#if __cpp_constexpr >= 200704 #if defined(__cplusplus) && __cpp_constexpr >= 200704
#define CONSTEXPR constexpr #define CONSTEXPR constexpr
#else #else
#define CONSTEXPR #define CONSTEXPR
#endif #endif
/* C++11 adds the ability to add "override" after an implementation of a
virtual function in a subclass, to:
(A) document that this is an override of a virtual function
(B) allow the compiler to issue a warning if it isn't (e.g. a mismatch
of the type signature).
Similarly, it allows us to add a "final" to indicate that no subclass
may subsequently override the vfunc.
Provide OVERRIDE and FINAL as macros, allowing us to get these benefits
when compiling with C++11 support, but without requiring C++11.
For gcc, use "-std=c++11" to enable C++11 support; gcc 6 onwards enables
this by default (actually GNU++14). */
#if defined __cplusplus
# if __cplusplus >= 201103
/* C++11 claims to be available: use it. Final/override were only
implemented in 4.7, though. */
# if GCC_VERSION < 4007
# define OVERRIDE
# define FINAL
# else
# define OVERRIDE override
# define FINAL final
# endif
# elif GCC_VERSION >= 4007
/* G++ 4.7 supports __final in C++98. */
# define OVERRIDE
# define FINAL __final
# else
/* No C++11 support; leave the macros empty. */
# define OVERRIDE
# define FINAL
# endif
#else
/* No C++11 support; leave the macros empty. */
# define OVERRIDE
# define FINAL
#endif
/* A macro to disable the copy constructor and assignment operator. /* A macro to disable the copy constructor and assignment operator.
When building with C++11 and above, the methods are explicitly When building with C++11 and above, the methods are explicitly
deleted, causing a compile-time error if something tries to copy. deleted, causing a compile-time error if something tries to copy.
@ -389,7 +341,7 @@ So instead we use the macro below and test it against specific values. */
so that most attempts at copy are caught at compile-time. */ so that most attempts at copy are caught at compile-time. */
#if __cplusplus >= 201103 #if defined(__cplusplus) && __cplusplus >= 201103
#define DISABLE_COPY_AND_ASSIGN(TYPE) \ #define DISABLE_COPY_AND_ASSIGN(TYPE) \
TYPE (const TYPE&) = delete; \ TYPE (const TYPE&) = delete; \
void operator= (const TYPE &) = delete void operator= (const TYPE &) = delete

View file

@ -1,9 +1,9 @@
/* ### /* ###
* IP: GPL 3 Linking Permitted * IP: LGPL 2.1
* NOTE: See binutils/libiberty/COPYING.LIB; Used GPL 3 from this file's header * NOTE: See binutils/include/COPYING
*/ */
/* Internal demangler interface for g++ V3 ABI. /* Internal demangler interface for g++ V3 ABI.
Copyright (C) 2003-2019 Free Software Foundation, Inc. Copyright (C) 2003-2023 Free Software Foundation, Inc.
Written by Ian Lance Taylor <ian@wasabisystems.com>. Written by Ian Lance Taylor <ian@wasabisystems.com>.
This file is part of the libiberty library, which is part of GCC. This file is part of the libiberty library, which is part of GCC.
@ -126,6 +126,10 @@ struct d_info
/* Non-zero if we are parsing the type operand of a conversion /* Non-zero if we are parsing the type operand of a conversion
operator, but not when in an expression. */ operator, but not when in an expression. */
int is_conversion; int is_conversion;
/* 1: using new unresolved-name grammar.
-1: using new unresolved-name grammar and saw an unresolved-name.
0: using old unresolved-name grammar. */
int unresolved_name_state;
/* If DMGL_NO_RECURSE_LIMIT is not active then this is set to /* If DMGL_NO_RECURSE_LIMIT is not active then this is set to
the current recursion level. */ the current recursion level. */
unsigned int recursion_level; unsigned int recursion_level;
@ -180,7 +184,7 @@ d_advance (struct d_info *di, int i)
extern const struct demangle_operator_info cplus_demangle_operators[]; extern const struct demangle_operator_info cplus_demangle_operators[];
#endif #endif
#define D_BUILTIN_TYPE_COUNT (34) #define D_BUILTIN_TYPE_COUNT (36)
CP_STATIC_IF_GLIBCPP_V3 CP_STATIC_IF_GLIBCPP_V3
const struct demangle_builtin_type_info const struct demangle_builtin_type_info

View file

@ -3,7 +3,7 @@
* NOTE: See binutils/include/COPYING * NOTE: See binutils/include/COPYING
*/ */
/* Defs for interface to demanglers. /* Defs for interface to demanglers.
Copyright (C) 1992-2019 Free Software Foundation, Inc. Copyright (C) 1992-2023 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License modify it under the terms of the GNU Library General Public License
@ -163,24 +163,11 @@ ada_demangle (const char *mangled, int options);
extern char * extern char *
dlang_demangle (const char *mangled, int options); dlang_demangle (const char *mangled, int options);
/* Returns non-zero iff MANGLED is a rust mangled symbol. MANGLED must
already have been demangled through cplus_demangle_v3. If this function
returns non-zero then MANGLED can be demangled (in-place) using
RUST_DEMANGLE_SYM. */
extern int extern int
rust_is_mangled (const char *mangled); rust_demangle_callback (const char *mangled, int options,
demangle_callbackref callback, void *opaque);
/* Demangles SYM (in-place) if RUST_IS_MANGLED returned non-zero for SYM.
If RUST_IS_MANGLED returned zero for SYM then RUST_DEMANGLE_SYM might
replace characters that cannot be demangled with '?' and might truncate
SYM. After calling RUST_DEMANGLE_SYM SYM might be shorter, but never
larger. */
extern void
rust_demangle_sym (char *sym);
/* Demangles MANGLED if it was GNU_V3 and then RUST mangled, otherwise
returns NULL. Uses CPLUS_DEMANGLE_V3, RUST_IS_MANGLED and
RUST_DEMANGLE_SYM. Returns a new string that is owned by the caller. */
extern char * extern char *
rust_demangle (const char *mangled, int options); rust_demangle (const char *mangled, int options);
@ -425,6 +412,9 @@ enum demangle_component_type
number which involves neither modifying the mangled string nor number which involves neither modifying the mangled string nor
allocating a new copy of the literal in memory. */ allocating a new copy of the literal in memory. */
DEMANGLE_COMPONENT_LITERAL_NEG, DEMANGLE_COMPONENT_LITERAL_NEG,
/* A vendor's builtin expression. The left subtree holds the
expression's name, and the right subtree is a argument list. */
DEMANGLE_COMPONENT_VENDOR_EXPR,
/* A libgcj compiled resource. The left subtree is the name of the /* A libgcj compiled resource. The left subtree is the name of the
resource. */ resource. */
DEMANGLE_COMPONENT_JAVA_RESOURCE, DEMANGLE_COMPONENT_JAVA_RESOURCE,
@ -463,7 +453,25 @@ enum demangle_component_type
/* A cloned function. */ /* A cloned function. */
DEMANGLE_COMPONENT_CLONE, DEMANGLE_COMPONENT_CLONE,
DEMANGLE_COMPONENT_NOEXCEPT, DEMANGLE_COMPONENT_NOEXCEPT,
DEMANGLE_COMPONENT_THROW_SPEC DEMANGLE_COMPONENT_THROW_SPEC,
DEMANGLE_COMPONENT_STRUCTURED_BINDING,
DEMANGLE_COMPONENT_MODULE_NAME,
DEMANGLE_COMPONENT_MODULE_PARTITION,
DEMANGLE_COMPONENT_MODULE_ENTITY,
DEMANGLE_COMPONENT_MODULE_INIT,
DEMANGLE_COMPONENT_TEMPLATE_HEAD,
DEMANGLE_COMPONENT_TEMPLATE_TYPE_PARM,
DEMANGLE_COMPONENT_TEMPLATE_NON_TYPE_PARM,
DEMANGLE_COMPONENT_TEMPLATE_TEMPLATE_PARM,
DEMANGLE_COMPONENT_TEMPLATE_PACK_PARM,
/* A builtin type with argument. This holds the builtin type
information. */
DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE
}; };
/* Types which are only used internally. */ /* Types which are only used internally. */
@ -485,6 +493,7 @@ struct demangle_component
Initialize to zero. Private to d_print_comp. Initialize to zero. Private to d_print_comp.
All other fields are final after initialization. */ All other fields are final after initialization. */
int d_printing; int d_printing;
int d_counting;
union union
{ {
@ -549,6 +558,15 @@ struct demangle_component
const struct demangle_builtin_type_info *type; const struct demangle_builtin_type_info *type;
} s_builtin; } s_builtin;
/* For DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE. */
struct
{
/* Builtin type. */
const struct demangle_builtin_type_info *type;
short arg;
char suffix;
} s_extended_builtin;
/* For DEMANGLE_COMPONENT_SUB_STD. */ /* For DEMANGLE_COMPONENT_SUB_STD. */
struct struct
{ {

View file

@ -3,7 +3,7 @@
* NOTE: See binutils/include/COPYING3 * NOTE: See binutils/include/COPYING3
*/ */
/* An abstract string datatype. /* An abstract string datatype.
Copyright (C) 1998-2019 Free Software Foundation, Inc. Copyright (C) 1998-2023 Free Software Foundation, Inc.
Contributed by Mark Mitchell (mark@markmitchell.com). Contributed by Mark Mitchell (mark@markmitchell.com).
This file is part of GCC. This file is part of GCC.

View file

@ -3,7 +3,7 @@
* NOTE: See binutils/include/COPYING3 * NOTE: See binutils/include/COPYING3
*/ */
/* Declarations for getopt. /* Declarations for getopt.
Copyright (C) 1989-2019 Free Software Foundation, Inc. Copyright (C) 1989-2023 Free Software Foundation, Inc.
NOTE: The canonical source of this file is maintained with the GNU C Library. NOTE: The canonical source of this file is maintained with the GNU C Library.
Bugs can be reported to bug-glibc@gnu.org. Bugs can be reported to bug-glibc@gnu.org.

View file

@ -4,7 +4,7 @@
*/ */
/* Function declarations for libiberty. /* Function declarations for libiberty.
Copyright (C) 1997-2019 Free Software Foundation, Inc. Copyright (C) 1997-2023 Free Software Foundation, Inc.
Note - certain prototypes declared in this header file are for Note - certain prototypes declared in this header file are for
functions whoes implementation copyright does not belong to the functions whoes implementation copyright does not belong to the
@ -141,6 +141,10 @@ extern const char *unix_lbasename (const char *) ATTRIBUTE_RETURNS_NONNULL ATTRI
extern char *lrealpath (const char *); extern char *lrealpath (const char *);
/* Return true when FD file descriptor exists. */
extern int is_valid_fd (int fd);
/* Concatenate an arbitrary number of strings. You must pass NULL as /* Concatenate an arbitrary number of strings. You must pass NULL as
the last argument of this function, to terminate the list of the last argument of this function, to terminate the list of
strings. Allocates memory using xmalloc. */ strings. Allocates memory using xmalloc. */
@ -314,30 +318,30 @@ extern void xmalloc_failed (size_t) ATTRIBUTE_NORETURN;
message to stderr (using the name set by xmalloc_set_program_name, message to stderr (using the name set by xmalloc_set_program_name,
if any) and then call xexit. */ if any) and then call xexit. */
extern void *xmalloc (size_t) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL; extern void *xmalloc (size_t) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_RESULT_SIZE_1 ATTRIBUTE_WARN_UNUSED_RESULT;
/* Reallocate memory without fail. This works like xmalloc. Note, /* Reallocate memory without fail. This works like xmalloc. Note,
realloc type functions are not suitable for attribute malloc since realloc type functions are not suitable for attribute malloc since
they may return the same address across multiple calls. */ they may return the same address across multiple calls. */
extern void *xrealloc (void *, size_t) ATTRIBUTE_RETURNS_NONNULL; extern void *xrealloc (void *, size_t) ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_RESULT_SIZE_2 ATTRIBUTE_WARN_UNUSED_RESULT;
/* Allocate memory without fail and set it to zero. This works like /* Allocate memory without fail and set it to zero. This works like
xmalloc. */ xmalloc. */
extern void *xcalloc (size_t, size_t) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL; extern void *xcalloc (size_t, size_t) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_RESULT_SIZE_1_2 ATTRIBUTE_WARN_UNUSED_RESULT;
/* Copy a string into a memory buffer without fail. */ /* Copy a string into a memory buffer without fail. */
extern char *xstrdup (const char *) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL; extern char *xstrdup (const char *) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_WARN_UNUSED_RESULT;
/* Copy at most N characters from string into a buffer without fail. */ /* Copy at most N characters from string into a buffer without fail. */
extern char *xstrndup (const char *, size_t) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL; extern char *xstrndup (const char *, size_t) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_WARN_UNUSED_RESULT;
/* Copy an existing memory buffer to a new memory buffer without fail. */ /* Copy an existing memory buffer to a new memory buffer without fail. */
extern void *xmemdup (const void *, size_t, size_t) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL; extern void *xmemdup (const void *, size_t, size_t) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_WARN_UNUSED_RESULT;
/* Physical memory routines. Return values are in BYTES. */ /* Physical memory routines. Return values are in BYTES. */
extern double physmem_total (void); extern double physmem_total (void);
@ -641,6 +645,13 @@ extern int pexecute (const char *, char * const *, const char *,
extern int pwait (int, int *, int); extern int pwait (int, int *, int);
/* Like bsearch, but takes and passes on an argument like qsort_r. */
extern void *bsearch_r (const void *, const void *,
size_t, size_t,
int (*)(const void *, const void *, void *),
void *);
#if defined(HAVE_DECL_ASPRINTF) && !HAVE_DECL_ASPRINTF #if defined(HAVE_DECL_ASPRINTF) && !HAVE_DECL_ASPRINTF
/* Like sprintf but provides a pointer to malloc'd storage, which must /* Like sprintf but provides a pointer to malloc'd storage, which must
be freed by the caller. */ be freed by the caller. */
@ -653,7 +664,7 @@ extern int asprintf (char **, const char *, ...) ATTRIBUTE_PRINTF_2;
extern char *xasprintf (const char *, ...) ATTRIBUTE_MALLOC ATTRIBUTE_PRINTF_1; extern char *xasprintf (const char *, ...) ATTRIBUTE_MALLOC ATTRIBUTE_PRINTF_1;
#if !HAVE_DECL_VASPRINTF #if defined(HAVE_DECL_VASPRINTF) && !HAVE_DECL_VASPRINTF
/* Like vsprintf but provides a pointer to malloc'd storage, which /* Like vsprintf but provides a pointer to malloc'd storage, which
must be freed by the caller. */ must be freed by the caller. */
@ -706,11 +717,6 @@ extern unsigned long long int strtoull (const char *nptr,
char **endptr, int base); char **endptr, int base);
#endif #endif
#if defined(HAVE_DECL_STRVERSCMP) && !HAVE_DECL_STRVERSCMP
/* Compare version strings. */
extern int strverscmp (const char *, const char *);
#endif
/* Set the title of a process */ /* Set the title of a process */
extern void setproctitle (const char *name, ...); extern void setproctitle (const char *name, ...);

View file

@ -4,7 +4,7 @@
*/ */
/* <ctype.h> replacement macros. /* <ctype.h> replacement macros.
Copyright (C) 2000-2019 Free Software Foundation, Inc. Copyright (C) 2000-2023 Free Software Foundation, Inc.
Contributed by Zack Weinberg <zackw@stanford.edu>. Contributed by Zack Weinberg <zackw@stanford.edu>.
This file is part of the libiberty library. This file is part of the libiberty library.

View file

@ -0,0 +1,27 @@
# GnuDisassembler
The GnuDisassembler extension module must be built using gradle prior to its use within Ghidra.
This module provides the ability to leverage the binutils disassembler capabilities
for various processors as a means of verifying Sleigh disassembler output syntax.
To build this extension for Linux or macOS:
1. If building for an installation of Ghidra, copy the appropriate source distribution of binutils
into this module's root directory. If building within a git clone of the full Ghidra source, copy
binutils source distribution file into the `ghidra.bin/GPL/GnuDisassembler` directory.
The supported version and archive format is identified within the build.gradle file. If a
different binutils distribution is used the build.gradle and/or buildGdis.gradle may require
modification.
The build requires the following packages to be installed:
* flex
* bison
* texinfo
* zlib1g-dev
2. Run gradle from the module's root directory (see top of `build.gradle` file for specific
instructions).
This resulting gdis executable will be located in `build/os/<platform>`.

View file

@ -1,26 +0,0 @@
The GnuDisassembler extension module must be built using gradle prior to its' use within Ghidra.
This module provides the ability to leverage the binutils disassembler capabilities
for various processors as a means of verifying Sleigh disassembler output syntax.
To build this extension for Linux or Mac OS X:
1. If building for an installation of Ghidra, copy the appropriate source distribution of
binutils into this module's root directory. If building within a git clone of the full
Ghidra source, copy binutils source distribution file into the ghidra.bin/GPL/GnuDisassembler
directory.
The supported version and archive format is identified within the build.gradle file.
If a different binutils distribution is used the build.gradle and/or buildGdis.gradle
may require modification.
The build requires the following packages to be installed:
* flex
* bison
* texinfo
* zlib1g-dev
2. Run gradle from the module's root directory (see top of build.gradle file for
specific instructions).
This resulting gdis executable will be located in build/os/<platform>.

View file

@ -28,20 +28,23 @@
// directory once the extension has been installed/unpacked by Ghidra. The binutils referenced // directory once the extension has been installed/unpacked by Ghidra. The binutils referenced
// by the script below may be downloaded from the following URL: // by the script below may be downloaded from the following URL:
// //
// https://ftp.gnu.org/pub/gnu/binutils/binutils-2.36.tar.bz2 // https://ftp.gnu.org/pub/gnu/binutils/binutils-2.41.tar.bz2
// //
ext.binutils = "binutils-2.36" ext.binutils = "binutils-2.41"
ext.binutilsDistro = "${binutils}.tar.bz2" ext.binutilsDistro = "${binutils}.tar.bz2"
// Find the GPL dir // Find the GPL dir
def gplDir = null; def gplDir = null;
if (file("../utils.gradle").exists()) { if (file("../utils.gradle").exists()) {
gplDir = file("..").getCanonicalPath() gplDir = file("..").getCanonicalPath()
ext.ghidraInstallDir = file("../..").getCanonicalPath()
ext.binutilsLocation = file("${ghidraInstallDir}/../ghidra.bin/GPL/${name}").getCanonicalPath()
} }
else { else {
// Module lives disconnected from the GPL directory, which it will need to build. // Module lives disconnected from the GPL directory, which it will need to build.
// Find a Ghidra installation directory and use its GPL directory. // Find a Ghidra installation directory and use its GPL directory.
ext.binutilsLocation = projectDir
if (file("../../Extensions").exists() && file("../../../GPL/utils.gradle").exists()) { if (file("../../Extensions").exists() && file("../../../GPL/utils.gradle").exists()) {
// Module is installed within a Ghidra installation (i.e, ghidra/Ghidra/Extensions) // Module is installed within a Ghidra installation (i.e, ghidra/Ghidra/Extensions)
gplDir = file("../../../GPL").getCanonicalPath() gplDir = file("../../../GPL").getCanonicalPath()

View file

@ -6,7 +6,7 @@ defaultTasks 'assemble'
ext.supportedPlatforms = ['mac_x86_64', 'mac_arm_64', 'linux_x86_64', 'linux_arm_64'] ext.supportedPlatforms = ['mac_x86_64', 'mac_arm_64', 'linux_x86_64', 'linux_arm_64']
ext.binutilsResource = new File("${projectDir}/${binutils}.tar.bz2") ext.binutilsResource = new File("${binutilsLocation}/${binutils}.tar.bz2")
def binutilsUnpackDir = file("${project.buildDir}/${binutils}/") def binutilsUnpackDir = file("${project.buildDir}/${binutils}/")
@ -37,8 +37,8 @@ model {
all { all {
def binutilsArtifactsDir = file("build/binutils/${targetPlatform.name}") def binutilsArtifactsDir = file("build/binutils/${targetPlatform.name}")
if ((toolChain in Gcc) || (toolChain in Clang)) { if ((toolChain in Gcc) || (toolChain in Clang)) {
cCompiler.args "-I${binutilsArtifactsDir}/include", "-I${binutilsArtifactsDir}/bfd" cCompiler.args "-I${binutilsArtifactsDir}/include", "-I${binutilsArtifactsDir}/bfd", "-I${binutilsArtifactsDir}/libsframe"
linker.args "-L${binutilsArtifactsDir}/lib", "-lopcodes", "-lbfd", "-liberty", "-lz", "-ldl" linker.args "-L${binutilsArtifactsDir}/lib", "-lopcodes", "-lbfd", "-lsframe", "-liberty", "-lz", "-ldl"
} }
} }
} }
@ -151,9 +151,10 @@ supportedPlatforms.each { platform ->
include "**/*.h" include "**/*.h"
} }
into("/lib") { into("/lib") {
from "${configDir}/bfd/libbfd.a" from "${configDir}/bfd/.libs/libbfd.a"
from "${configDir}/libiberty/libiberty.a" from "${configDir}/libiberty/libiberty.a"
from "${configDir}/opcodes/libopcodes.a" from "${configDir}/opcodes/libopcodes.a"
from "${configDir}/libsframe/.libs/libsframe.a"
} }
} }

View file

@ -3,7 +3,7 @@
##MODULE IP: Public Domain ##MODULE IP: Public Domain
.gitignore||Public Domain||||END| .gitignore||Public Domain||||END|
Module.manifest||Public Domain||||END| Module.manifest||Public Domain||||END|
README.txt||Public Domain||||END| README.md||GHIDRA||||END|
data/arm_test1.s||Public Domain||||END| data/arm_test1.s||Public Domain||||END|
data/big.elf||Public Domain||||END| data/big.elf||Public Domain||||END|
data/little.elf||Public Domain||||END| data/little.elf||Public Domain||||END|

View file

@ -45,8 +45,7 @@ void listSupportedArchMachTargets(void)
int objdump_sprintf (SFILE *f, const char *format, ...) int objdump_sprintf (SFILE *f, const char *format, ...)
{ {
int i; int n;
size_t n;
va_list args; va_list args;
va_start (args, format); va_start (args, format);
@ -57,6 +56,18 @@ int objdump_sprintf (SFILE *f, const char *format, ...)
return n; return n;
} }
/* Compatibility fix for binutils v 2.39 change to INIT_DISASSEMLE_INFO signature */
int objdump_sprintf_styled(SFILE *f, enum disassembler_style style, const char *format, ...) {
int n;
va_list args;
va_start (args, format);
n = vsnprintf (f->buffer + f->pos, BUFF_SIZE, format, args);
strncat(disassembled_buffer, f->buffer, n);
va_end (args);
return n;
}
void configureDisassembleInfo(bfd* abfd, void configureDisassembleInfo(bfd* abfd,
disassemble_info* info, disassemble_info* info,
@ -67,7 +78,7 @@ void configureDisassembleInfo(bfd* abfd,
memset(sfile.buffer, 0x00, BUFF_SIZE); memset(sfile.buffer, 0x00, BUFF_SIZE);
INIT_DISASSEMBLE_INFO(*info, stdout, objdump_sprintf); INIT_DISASSEMBLE_INFO(*info, stdout, objdump_sprintf, objdump_sprintf_styled);
info->arch = (enum bfd_architecture) arch; info->arch = (enum bfd_architecture) arch;
info->mach = mach; info->mach = mach;
info->flavour = bfd_get_flavour(abfd); info->flavour = bfd_get_flavour(abfd);

View file

@ -52,6 +52,16 @@ model {
} }
} }
} }
if (isCurrentFreeBSD()) {
gcc(Gcc) {
if (isCurrentArm_64()) {
target("freebsd_arm_64")
}
else {
target("freebsd_x86_64")
}
}
}
if (isCurrentWindows() && VISUAL_STUDIO_INSTALL_DIR) { if (isCurrentWindows() && VISUAL_STUDIO_INSTALL_DIR) {
// specify installDir because Gradle doesn't find VS Build Tools. // specify installDir because Gradle doesn't find VS Build Tools.
// See https://github.com/gradle/gradle-native/issues/617#issuecomment-575735288 // See https://github.com/gradle/gradle-native/issues/617#issuecomment-575735288

View file

@ -24,7 +24,9 @@ project.ext.PLATFORMS = [
[name: "linux_x86_64", os: "linux", arch: "x86_64"], [name: "linux_x86_64", os: "linux", arch: "x86_64"],
[name: "linux_arm_64", os: "linux", arch: "arm64"], [name: "linux_arm_64", os: "linux", arch: "arm64"],
[name: "mac_x86_64", os: "osx", arch: "x86_64"], [name: "mac_x86_64", os: "osx", arch: "x86_64"],
[name: "mac_arm_64", os: "osx", arch: "arm64"] [name: "mac_arm_64", os: "osx", arch: "arm64"],
[name: "freebsd_x86_64", os: "freebsd", arch: "x86_64"],
[name: "freebsd_arm_64", os: "freebsd", arch: "arm64"]
] ]
/********************************************************************************* /*********************************************************************************
@ -51,6 +53,9 @@ ext.getCurrentPlatformName = {
case ~/Mac OS X.*/: case ~/Mac OS X.*/:
os = "mac" os = "mac"
break break
case ~/FreeBSD.*/:
os = "freebsd"
break
default: default:
throw new GradleException("Unrecognized platform operating system: $os") throw new GradleException("Unrecognized platform operating system: $os")
} }
@ -112,6 +117,20 @@ ext.isCurrentMac = {
return isMac(getCurrentPlatformName()) return isMac(getCurrentPlatformName())
} }
/*********************************************************************************
* Returns true if the given platform is FreeBSD.
*********************************************************************************/
ext.isFreeBSD = { platform_name ->
return platform_name.startsWith("freebsd")
}
/*********************************************************************************
* Returns true if the current platform is FreeBSD.
*********************************************************************************/
ext.isCurrentFreeBSD = {
return isFreeBSD(getCurrentPlatformName())
}
/********************************************************************************* /*********************************************************************************
* Returns true if the given platform is Windows. * Returns true if the given platform is Windows.
*********************************************************************************/ *********************************************************************************/

View file

@ -27,12 +27,14 @@ def configureVisualStudio() {
// Use vswhere.exe to search for latest Visual Studio installation // Use vswhere.exe to search for latest Visual Studio installation
println "Searching for latest Visual Studio and required components..." println "Searching for latest Visual Studio and required components..."
def vswherePath = "C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\vswhere.exe" def programFiles = System.getenv()["ProgramFiles(x86)"] ?: "C:\\Program Files (x86)"
def vswherePath = findProperty("vswherePath") ?: "${programFiles}\\Microsoft Visual Studio\\Installer\\vswhere.exe"
if (!file(vswherePath).exists()) { if (!file(vswherePath).exists()) {
println " -> Visual Studio vswhere.exe not found!" println " -> Visual Studio vswhere.exe not found at \"${vswherePath}\""
println " -> To manually specify the location of vswhere.exe, add \"-PvswherePath=<vswhere path>\" to the Gradle command line arguments"
return return
} }
def vswhereProcess = "${vswherePath} -products * -latest -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -format json -utf8".execute() def vswhereProcess = "\"${vswherePath}\" -products * -latest -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -format json -utf8".execute()
def vswhereOutput = vswhereProcess.text.trim() def vswhereOutput = vswhereProcess.text.trim()
def vswhereExit = vswhereProcess.exitValue() def vswhereExit = vswhereProcess.exitValue()
if (vswhereExit != 0) { if (vswhereExit != 0) {
@ -58,8 +60,6 @@ def configureVisualStudio() {
def vcvarsPath = "${vsInstallDir}\\VC\\Auxiliary\\Build\\vcvarsall.bat" def vcvarsPath = "${vsInstallDir}\\VC\\Auxiliary\\Build\\vcvarsall.bat"
def vcvarsCmd = "\"${vcvarsPath}\" x86_amd64" def vcvarsCmd = "\"${vcvarsPath}\" x86_amd64"
def vcvarsEnvCmd = "cmd /v:ON /c ${vcvarsCmd} > nul && cmd /c echo" def vcvarsEnvCmd = "cmd /v:ON /c ${vcvarsCmd} > nul && cmd /c echo"
def toolsVersion = "${vcvarsEnvCmd} !VCToolsVersion!".execute().text.trim()
println " -> VCTools Version (default): ${toolsVersion}"
def sdkDir = "${vcvarsEnvCmd} !WindowsSdkDir!".execute().text.trim() def sdkDir = "${vcvarsEnvCmd} !WindowsSdkDir!".execute().text.trim()
println " -> SDK Directory (default): ${sdkDir}" println " -> SDK Directory (default): ${sdkDir}"
def sdkVersion = "${vcvarsEnvCmd} !WindowsSDKVersion!".execute().text.trim().replace('\\', '') def sdkVersion = "${vcvarsEnvCmd} !WindowsSDKVersion!".execute().text.trim().replace('\\', '')
@ -71,7 +71,6 @@ def configureVisualStudio() {
// Save Visual Studio information so other projects can access it // Save Visual Studio information so other projects can access it
rootProject.ext.VISUAL_STUDIO_INSTALL_DIR = vsInstallDir rootProject.ext.VISUAL_STUDIO_INSTALL_DIR = vsInstallDir
rootProject.ext.VISUAL_STUDIO_TOOLS_VERSION_DEFAULT = toolsVersion
rootProject.ext.VISUAL_STUDIO_SDK_DIR_DEFAULT = sdkDir rootProject.ext.VISUAL_STUDIO_SDK_DIR_DEFAULT = sdkDir
rootProject.ext.VISUAL_STUDIO_SDK_VERSION_DEFAULT = sdkVersion rootProject.ext.VISUAL_STUDIO_SDK_VERSION_DEFAULT = sdkVersion
rootProject.ext.VISUAL_STUDIO_SDK_VERSION_OVERRIDE = windowsTargetPlatformVersion rootProject.ext.VISUAL_STUDIO_SDK_VERSION_OVERRIDE = windowsTargetPlatformVersion

View file

@ -0,0 +1 @@
# Public_Release

View file

@ -17,5 +17,12 @@ apply from: "$rootProject.projectDir/gradle/distributableGhidraModule.gradle"
apply from: "$rootProject.projectDir/gradle/javaProject.gradle" apply from: "$rootProject.projectDir/gradle/javaProject.gradle"
apply from: "$rootProject.projectDir/gradle/jacocoProject.gradle" apply from: "$rootProject.projectDir/gradle/jacocoProject.gradle"
apply from: "$rootProject.projectDir/gradle/javaTestProject.gradle" apply from: "$rootProject.projectDir/gradle/javaTestProject.gradle"
apply from: "$rootProject.projectDir/gradle/helpProject.gradle"
apply plugin: 'eclipse' apply plugin: 'eclipse'
eclipse.project.name = 'Z Public Release' eclipse.project.name = 'Z Public Release'
rootProject.assembleDistribution {
from ("${this.projectDir}/src/main/resources/UserAgreement.html") {
into "docs"
}
}

View file

@ -1,9 +1,10 @@
##VERSION: 2.0 ##VERSION: 2.0
Module.manifest||GHIDRA||||END| Module.manifest||GHIDRA||||END|
README.md||GHIDRA||||END|
data/PDB_SYMBOL_SERVER_URLS.pdburl||GHIDRA||||END| data/PDB_SYMBOL_SERVER_URLS.pdburl||GHIDRA||||END|
src/global/docs/ChangeHistory.html||GHIDRA||||END| src/global/docs/ChangeHistory.md||GHIDRA||||END|
src/global/docs/UserAgreement.html||GHIDRA||||END| src/global/docs/UserAgreement.html||GHIDRA||||END|
src/global/docs/WhatsNew.html||GHIDRA||||END| src/global/docs/WhatsNew.md||GHIDRA||||END|
src/main/resources/UserAgreement.html||GHIDRA||||END| src/main/resources/UserAgreement.html||GHIDRA||||END|
src/main/resources/defaultTools/CodeBrowser.tool||GHIDRA||||END| src/main/resources/defaultTools/CodeBrowser.tool||GHIDRA||||END|
src/main/resources/splash.txt||GHIDRA||||END| src/main/resources/splash.txt||GHIDRA||||END|

View file

@ -1,6 +1,3 @@
Internet|https://msdl.microsoft.com/download/symbols/|WARNING: Check your organization's security policy before downloading files from the internet. Internet|https://msdl.microsoft.com/download/symbols/|WARNING: Check your organization's security policy before downloading files from the internet.
Internet|https://chromium-browser-symsrv.commondatastorage.googleapis.com|WARNING: Check your organization's security policy before downloading files from the internet. Internet|https://chromium-browser-symsrv.commondatastorage.googleapis.com|WARNING: Check your organization's security policy before downloading files from the internet.
Internet|https://symbols.mozilla.org/|WARNING: Check your organization's security policy before downloading files from the internet. Internet|https://symbols.mozilla.org/|WARNING: Check your organization's security policy before downloading files from the internet.
Internet|https://software.intel.com/sites/downloads/symbols/|WARNING: Check your organization's security policy before downloading files from the internet.
Internet|https://driver-symbols.nvidia.com/|WARNING: Check your organization's security policy before downloading files from the internet.
Internet|https://download.amd.com/dir/bin|WARNING: Check your organization's security policy before downloading files from the internet.

File diff suppressed because it is too large Load diff

View file

@ -1,20 +0,0 @@
<HTML>
<FONT SIZE="5">
Licensed under the Apache License, Version 2.0 (the "License"); Unless required by applicable law or
agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.
<BR>
<BR>
<B>As a software reverse engineering (SRE) framework, Ghidra is designed solely to facilitate
lawful SRE activities. You should always ensure that any SRE activities in which you engage are
permissible as computer software may be protected under governing law (e.g., copyright) or under an
applicable licensing agreement. In making Ghidra available for public use, the National Security
Agency does not condone or encourage any improper usage of Ghidra. Consistent with the Apache 2.0
license under which Ghidra has been made available, you are solely responsible for determining the
appropriateness of using or redistributing Ghidra.</B>
</FONT>
</HTML>

View file

@ -1,244 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD>
<TITLE> Ghidra What's New</TITLE>
<STYLE type="text/css" name="text/css">
li { font-family:times new roman; font-size:14pt; font-family:times new roman; font-size:14pt; margin-bottom: 8px; }
h1 { color:#000080; font-family:times new roman; font-size:28pt; font-style:italic; font-weight:bold; text-align:center; color:#000080; font-family:times new roman; }
h2 { padding-top:10px; color:#984c4c; font-family:times new roman; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
h3 { margin-left:40px; padding-top:10px; font-family:times new roman; font-family:times new roman; font-size:14pt; font-weight:bold; }
h4 { margin-left:40px; padding-top:10px; font-family:times new roman; font-family:times new roman; font-size:14pt; font-weight:bold; }
p { margin-left:40px; font-family:times new roman; font-size:14pt; }
table, th, td { border: 1px solid black; border-collapse: collapse; font-size:10pt; }
td { font-family:times new roman; font-size:14pt; padding-left:10px; padding-right:10px; text-align:left; vertical-align:top; }
th { font-family:times new roman; font-size:14pt; font-weight:bold; padding-left:10px; padding-right:10px; text-align:left; }
code { color:black; font-family:courier new; font-size: 12pt; }
span.code { font-family:courier new font-size: 14pt; color:#000000; }
</STYLE>
</HEAD>
<BODY>
<H1>Ghidra: NSA Reverse Engineering Software</H2>
<P>
Ghidra is a software reverse engineering (SRE) framework developed by NSA's Research Directorate.
This framework includes a suite of full-featured, high-end software analysis tools that enable
users to analyze compiled code on a variety of platforms including Windows, MacOS, and Linux.
Capabilities include disassembly, assembly, decompilation, debugging, emulation, graphing, and scripting, along with
hundreds of other features. Ghidra supports a wide variety of processor instruction sets and
executable formats and can be run in both user-interactive and automated modes. Users may also
develop their own Ghidra plug-in components and/or scripts using the exposed API. In addition there are
numerous ways to extend Ghidra such as new processors, loaders/exporters, automated analyzers,
and new visualizations.
</P>
<P>
In support of NSA's Cybersecurity mission, Ghidra was built to solve scaling and teaming problems
on complex SRE efforts and to provide a customizable and extensible SRE research platform. NSA
has applied Ghidra SRE capabilities to a variety of problems that involve analyzing malicious
code and generating deep insights for NSA analysts who seek a better understanding of potential
vulnerabilities in networks and systems.
</P>
<hr>
<H1>What's New in Ghidra 10.2</H1>
<H2>The not-so-fine print: Please Read!</H2>
<P>Ghidra 10.2 is fully backward compatible with project data from previous releases. However, programs and data type archives
which are created or modified in 10.2 will not be useable by an earlier Ghidra version.</P>
<P>This release includes many new features and capabilities, performance improvements, quite a few bug fixes, and many pull-request
contributions. Thanks to all those who have contributed their time, thoughts, and code. The Ghidra user community
thanks you too!</P>
<P>IMPORTANT: Ghidra requires Java 17 JDK to run. A newer version of Java may be acceptable, but has not been tested. Please see the
<a href="InstallationGuide.html">Ghidra Installation Guide</a> for additional information.</P>
<P>NOTE: Please note that any programs imported with a Ghidra beta versions or code built directly from source outside of a release tag may not be compatible
and may have flaws that have been corrected. Any programs analyzed from a beta or other local master source build should be considered experimental and
re-imported and analyzed with a release version. As an example, Ghidra 10.1 beta had an import flaw affecting symbol demangling that was not correctable.
Programs imported with previous release versions should upgrade correctly through various automatic upgrade mechanisms. Any program
you will continue to reverse engineer should be imported fresh with a release version or a build you trust with the latest code fixes.</P>
<P>NOTE: Ghidra Server: The Ghidra 10.2 server is compatible with Ghidra 9.2 and later Ghidra clients. Ghidra 10.2
clients are compatible with all 10.x and 9.x servers.</P>
<P>NOTE: Platform-specific native executables can be built directly from a release distribution.
The distribution currently provides Linux 64-bit, Windows 64-bit, and MacOS x86 binaries. If you have another platform,
for example a MacOS M1 based system or a Linux variant, the support/buildNatives script can build the Decompiler,
demangler, and legacy PDB executables for your plaform. Please see "Building Ghidra Native Components" section in the
the <a href="InstallationGuide.html#Build">Ghidra Installation Guide</a> for additional information.</P>
<H2>Distribution</H2>
<P> A Software Bill of Materials (SBOM) is now included in the Ghidra release. The SBOM follows the CycloneDX standard,
and can be used with tools such as Dependency-Track to help identify risk in the software supply-chain.</P>
<H2>Debugger</H2>
<P>The Debugger improvement highlights include:</P>
<blockquote>
<ul>
<li>FlatDebuggerAPI is introduced, providing a scripting API for Java-based GhidraScripts. An example <I>DemoDebuggerScript.java</I>
is included to get started.</li>
<li>P-code Emulation is improved, including numerous fixes, a new framework for system calls in emulation scripts, and a
prototype taint analyzer.</li>
<li>Compatibility is improved, including support for GDB versions 8.0.1 through 12.1, and LLDB version 14.0.</li>
<li>Support for memory/register editing is improved in Registers, Dynamic Listing, Memory, and Watches panels.</li>
<li>A new Frida connector is introduced, including support for debugging using Frida on USB/remote devices.</li>
</ul>
</blockquote>
<H2>Decompiler</H2>
<P>The Decompiler has a myriad of improvements in the latest-release. Many have been long-requested features or improvements.
Highlights of the changes include:</P>
<blockquote>
<ul>
<li>Support for union data-types. The Decompiler scores and displays the most likely field based on how code accesses the union. Alternately, a field access can be set manually.</li>
<li>Support for pointers with an offset relative to the start of a data type, usually a structure. Examples include windows LIST_ENTRY/CONTAINING_RECORD linked lists,
CString allocation data, and memory allocation records.</li>
<li>Support for pointers with a specified address space. Useful for targeting a specific address space such as SPI memory or
in Harvard architectures with multiple address spaces.</li>
<li>Improved reconciliation of overlapping views of data-types; for example, passing of sub members of a structure to a function.</li>
<li>Marker Margins, similar to the listing marker margins, have been added to display things like Debugger breakpoints.</li>
<li>A colored highlighting service has been added, allowing clients to create highlights in the form of background colors for syntax tokens in
the Decompiler UI through API calls.</li>
<li>Read-from and write-to access to a volatile variable now display as simple assignments, with a special token color, instead of as read- or write-volatile function calls.</li>
</ul>
</blockquote>
<H2>Data Types</H2>
<P>With this release of Ghidra, support for Pointer Typedefs has been expanded to facilitate the use of specialized
data type settings. Improvements have also been made to ensure that such settings are preserved within data type
archives and merge situations. These settings are not supported at the instance-level and are intended to be an
attribute of the associated pointer. The Typedef provides the ability to tailor a pointer for a specific use. It
is highly recommended that all required Pointer Typedef settings be applied prior to using the data type
(e.g., for defined data, data type components, and variables) since there is currently no change propagation for such modifications.
<P>The following Pointer Typedef settings have been introduced with this release:</p>
<blockquote>
<ul>
<li> <B>Address Space</B> - allows the destination address space to be specified for a pointer. While this does not affect pointer dereferencing operations
dictated by instruction semantics, it can aid analysis and the generation of associated memory references.</li>
<li><B>Component Offset</B> - provides the ability to specify an offset relative to the associated pointer's referenced data type such that:
<blockquote>
<code>&lt;referenced-data-type-storage-address&gt; = &lt;pointer-offset&gt; - &lt;component-offset-setting&gt;</code>
</blockquote>
</li>
<li><B>Offset Mask</B> - bit-mask to be applied prior to any bit-shift (if specified) during the computation of an actual address offset</li>
<li><B>Offset Shift</B> - bit-shift to be applied after any bit-mask (if specified) during the computation of an actual address
offset (positive: left-shift, negative: right-shift)</li>
<li><B>Pointer Type</B> - facilitates special interpretation of pointers</li>
<blockquote>
<ul>
<li> <I>default</I> - normal pointer</li>
<li> <I>image-base-relative</I> - pointers whose offset should be treated as relative to the program's image base (e.g., relative virtual address (RVA))</li>
<li> <I>relative</I> - pointers whose offset is relative to the pointer's storage address</li>
<li> <I>file-offset</I> - pointers whose offset corresponds to an offset within the loaded binary file (limited to single load file)</li>
</ul>
</blockquote>
</UL>
</blockquote>
<P> NOTE: The use and consumption of Pointer Typedef settings is in its early stages and may not be utilized by various analyzers.
In addition, some settings are not relevant to some analyzers where instruction semantics will dictate pointer dereferencing.</P>
<P> At the API level, the PointerTypedef and PointerTypedefBuilder classes have been added to simplify the creation of a Pointer Typedef.
While an explicit Typedef name may be used, Pointer Typedefs also support an auto-naming mechanism (constructed with a null/empty name)
which will simply use the pointer name followed by the settings as an attribute list; example:</P>
<blockquote><blockquote>
<code>int * __((space(ram)))</code>
</blockquote></blockquote>
<P> Within the GUI, using the <B>New-&gt;Typedef on <I>&lt;pointer&gt;</I></B> action on a selected pointer within the Data Type Tree is the quickest way to create one.
Once this is done, use the <B>Settings...</B> action on the selected Pointer Typedef. The Settings dialog will be displayed allowing the various settings
to be applied to the Typedef. Settings should be made to Typedef prior to applying it since settings change propogation is very limited.</P>
<H3>C Header File Parsing</H3>
<P>C-Parser support has been added for missing C specification syntax from C11 and C23, such as tags, macros with varargs, and _NoReturn.
Numerous parsing errors have also been fixed, including for arrays of function pointers, array definitions, and placement of compiler directives.
In addition, parsing time of extremely large header files has been drastically reduced.</P>
<P>Error handling and reporting from the Pre-Processor and C-Parser have been improved.</P>
<P>Several scripts to parse header files outside of the GUI have been included, including one that specially parses AVR8 data types and memory-mapped register
definitions from header files for each AVR8 processor variant. The scripts are <I>CreateAVR8GDTArchiveScript.java</I>, <I>CreateExampleGDTArchiveScript.java</I>, <I>CreateJNIArchivesScript.java</I>,
and <I>CreateDefaultGDTArchives.java</I>.</P>
<P> Finally, data types in open archives can be used during parsing for undefined data types in a header file. At the start of parsing, use of open
archives can be chosen or ignored without closing open archives. The header files must still parse without error,
however a missing data type or unfound header file may not cause the parsing to fail if an open archive contains a missing, but needed data type definition.</P>
<H2>Mach-O Binary Import</H2>
<P>Mach-O binary analysis continues to improve. Support has been added for new file formats introduced in iOS 16 and macOS 13.
Improvements have also been made to function identification, symbol detection, and Objective-C support.</P>
<H2>Android</H2>
<P>Import and analysis of the entire existing set of Android binaries up to version 13.x is now supported, including new support for the Multi-DEX format.
The type of binaries supported include: Android Run-Time (ART), Ahead-of-Time (OAT)/ELF, Dalvik Executables (DEX), Multi-DEX, Compact DEX (CDEX),
Verified DEX (VEX), Boot Image, and Boot Loader formats. Also included are Sleigh modules for DEX files covering each major release of Android;
the optimized instructions vary across versions.</P>
<P>A new Android APK loader will load all DEX files at one time and link the <code><B>method_lookup</B></code>
sections using <B>external references</B>. The new APK loader uses the manifest file to determine the Android version.</P>
<H2>Analysis</H2>
<P>The option <B>Assume Contiguous Functions Only</B>, for the <B>Shared Return Analyzer</B>, has been turned on by default.
The <B>Shared Return Analyzer</B> turns jump instructions into a call if the jump
target is, or should be, considered a function. When turned on, the option treats a jump
over a known function entry point to be a call, even if there is only one jump to that location. The option improves thunk function
recovery as well as decompilation results by using a call to the function instead of including the called functions code within the calling function.</P>
<P>The option has been turned on by default for all processor types except ARM. ARM Thumb binaries can sometimes use <B>BL</B> instructions,
normally used as calls, as an internal jump within a large function. If this option were on by default for such a binary it would cause
additional erroneous functions to be created. The option can be used on ARM binaries, however they should be all ARM code; otherwise any Thumb code
using <B>BL</B> for far jumps must be fixed using the Fix_ARM_Call_JumpsScript and Override_ARM_Call_JumpsScript.</P>
<H2>Machine Learning</H2>
<P>An optional MachineLearning extension has been added containing the <B>Random Forest Function Finder Plugin</B>.
The plugin finds undiscovered functions within a binary using classifiers to identify potential function starts.
The plugin trains classifiers using data sets created from known functions within a binary.
These classifiers can then be used by the plugin on the original binary or other binaries to find additional functions
missed by initial analysis.</P>
<P>The extension can be installed from the <B>Ghidra Project Window</B> via <B>File->Install Extensions...</B> </P>
<H2>Processors</H2>
<P>Updated ARM32 and AARCH64 to version v9.3 to include vfp4 instructions.</P>
<P>Improvements and bug fixes have been made to many processors to include: <B>AARCH64, ARM, AVR8, AVR32, Coldfire, JVM, MIPS, MSP430, PA-Risc, PowerPC,
RISC-V, SuperH, Tricore, V850, X86, 6502, and 68K</B>.</P>
<P> Sleigh now supports <code><B>inst_next2</B></code> as well as <code><B>inst_next</B></code> to support branching around the next instruction when its length is unknown.
Many processors have conditional skip instructions which can be used on any instruction, including another skip instruction.
Some sleigh processor developers have tried to use the delayslot() directive to accomplish instruction skipping. Unfortunately, the use of the delayslot() directive
can cause nested delay slots or the potential for branches into the delay slotted instruction, both of which are not supported.</P>
<H2>User Interface Improvements</H2>
<P>The <B>Go To...</B> dialog now provides navigation to file offsets. In addition, a new File Offset field is available in the Listing. The
field must be added to the Listing using Edit Listing Fields.
These new features can greatly simplify correlating bytes in program memory with their original location within the file from which they were imported.
Example: to go to the memory location which corresponds to the first byte in the original file, enter <B><code>file(0)</code></B> in the <B>Go To...</B> dialog.</P>
<H2>Import Formats</H2>
<P>Support has been added for loading WinDbg and APPORT dump files.</P>
<P>Redesigned the Importer's library loading options to provide finer-grained control over where libraries are searched
for on disk and in the project, as well as where newly loaded libraries are saved to.</P>
<H2>Additional Bug Fixes and Enhancements</H2>
<P> Numerous other bug fixes and improvements are fully listed in the <a href="ChangeHistory.html">ChangeHistory</a> file.</P>
<BR>
<P align="center">
<B><a href="https://www.nsa.gov/ghidra"> https://www.nsa.gov/ghidra</a></B>
</P>
</BODY>
</HTML>

View file

@ -0,0 +1,118 @@
# What's New in Ghidra 11.2
This release includes new features, enhancements, performance improvements, quite a few bug fixes,
and many pull-request contributions. Thanks to all those who have contributed their time, thoughts,
and code. The Ghidra user community thanks you too!
### The not-so-fine print: Please Read!
Ghidra 11.2 is fully backward compatible with project data from previous releases. However, programs
and data type archives which are created or modified in 11.2 will not be usable by an earlier Ghidra
version.
__IMPORTANT:__ Ghidra 11.2 requires at minimum JDK 21 to run.
__IMPORTANT:__ To use the Debugger or do a full source distribution build, you will need Python3
(3.9 to 3.12 supported) installed on your system.
__NOTE:__ There have been reports of certain features causing the XWindows server to crash. A fix
for `CVE-2024-31083` in X.org software in April 2024 introduced a regression, which has been fixed
in xwayland 23.2.6 and xorg-server 21.1.13. If you experience any crashing of Ghidra, most likely
causing a full logout, check if your xorg-server has been updated to at least the noted version.
__NOTE:__ Each build distribution will include native components (e.g., decompiler) for at least one
platform (e.g., Windows x86-64). If you have another platform that is not included in the build
distribution, you can build native components for your platform directly from the distribution.
See the `Installation Guide` for additional information. Users running with older shared libraries
and operating systems (e.g., CentOS 7.x) may also run into compatibility errors when launching
native executables such as the Decompiler and GNU Demangler which may necessitate a rebuild of
native components.
__NOTE:__ Ghidra Server: The Ghidra 11.x server is compatible with Ghidra 9.2 and later Ghidra
clients. Ghidra 11.x clients are compatible with all 10.x and 9.x servers. Although, due to
potential Java version differences, it is recommended that Ghidra Server installations older than
10.2 be upgraded. Those using 10.2 and newer should not need a server upgrade.
__NOTE:__ Any programs imported with a Ghidra beta version or code built directly from source code
outside of a release tag may not be compatible, and may have flaws that won't be corrected by using
this new release. Any programs analyzed from a beta or other local master source build should be
considered experimental and re-imported and analyzed with a release version.
Programs imported with previous release versions should upgrade correctly through various automatic
upgrade mechanisms. However, there may be improvements or bug fixes in the import and analysis
process that will provide better results than prior Ghidra versions. You might consider comparing a
fresh import of any program you will continue to reverse engineer to see if the latest Ghidra
provides better results.
## Memory Search
The __Search Memory__ feature in Ghidra has been updated substantially to provide two new features:
* The ability to perform set operations on successive searches
* The ability to (re)scan memory for changes in value
Set operations, accessible from the pull-down menu under `Search`, allow you to augment results by
performing boolean operations on an existing search. For example, you might search for the hex
pattern `DE AD` using `Search`, add `BE EF` to the pattern field, and then select `A-B` to retrieve
a list of byte sequences that begin with `DE AD` but do not include `DE AD BE EF`. Scanning for
changes is most useful in a dynamic environment, such as the Debugger. Given an existing search,
you can look for values that have changed, increased, decreased, or remained the same. Simple
examples might include looking for counters while a process is running, checking for areas of
decompressed memory, or identifying active areas of the heap.
## PDB
The `PDB Symbol Server Search Config` dialog has been changed, allowing the user to mark symbol
servers as trusted or untrusted. This is an improvement over the previous mechanism that based trust
on the symbol server's connection type.
## Debugger
__ATTENTION:__ Please either delete and re-import the default `Emulator` tool, or manually remove
the `TraceRmiPlugin` from your EmulatorTool!
There are new launchers/features for the traceRMI version of dbgeng, including extended launch
options, kernel debugging, and remote process server connections.
## Decompiler
* The Decompiler can now automatically recover strings built on the stack and initial support for
optimized heap strings has been added. Stack strings are typically found in optimized code and
obfuscated malware.
* A new Search All action has been added which displays a table containing the results found within
the current function.
## Programming Languages
Golang support for versions `1.15` and `1.16` have been added. This brings the supported Golang
versions to `1.15` through `1.22`.
## Processors
* There have been quite a few improvements to the `Sparc` processor specification, including
additional instructions, 64-bit relocation support, and better handling of call/return detection
through tracking of the `o7` link register. In addition, the calling convention for both
sparc 32 and 64 bit binaries have had an overhaul to support hidden structure return and much
improved parameter allocation of floating point and general data types.
* The `Intel M16C/60/80` sleigh processor specifications have been added. In addition, there have
been numerous fixes to the `ARM`, `RX`, `M68000`, `PIC16`, `PPC`, and `x86` processor
specifications.
## Other Improvements
* Actions have been added to compare functions directly from the Listing, Decompiler, or Functions
Table via popup menu items. If there is already a Function Comparison window showing, there are
two actions: one to add the selected function(s) to the existing comparison, and one to create a
new Function Comparison Window. This allows a workflow where users can build up a set of functions
to compare as they browse around instead of having to select them all at once.
* For Ghidra script and plugin developers who would prefer to use Visual Studio Code, a new script
`VSCodeProjectScript.java` will create a new Visual Studio Code project that is setup to do Ghidra
scripting and module development. The capabilities are similar to the Eclipse GhidraDev plugin.
* There have been major speed improvements when creating or modifying large structures within the
structure editor. In general large structure manipulation should perform fluidly no matter the
size of the structure. If the structure contains a large number of defined data, there could
still be some degradation in speed. Some fixed performance issues include: resizing a structure
smaller or larger, clicking on an item to select a row, and defining a data type either with
keyboard actions or dragging and dropping from the data type manager. In addition, the behavior
of automatically growing the size of a structure has been made consistent. Defining data on the
last element of a structure is allowed to automatically grow the structure to fit the data type.
Defining data anywhere other than the last element isn't allowed if the data type does not fit
because of defined data that would need to be cleared, or there are not enough undefined bytes.
## Additional Bug Fixes and Enhancements
Numerous other new features, improvements, and bug fixes are fully listed in the
[Change History](ChangeHistory.html) file.

View file

@ -1,4 +1,7 @@
<HTML> <HTML>
<HEAD>
<TITLE>Ghidra User Agreement</TITLE>
</HEAD>
<FONT SIZE="5"> <FONT SIZE="5">

View file

@ -0,0 +1 @@
# AnnotationValidator

View file

@ -1,3 +1,4 @@
##VERSION: 2.0 ##VERSION: 2.0
Module.manifest||GHIDRA||||END| Module.manifest||GHIDRA||||END|
README.md||GHIDRA||||END|
src/main/resources/META-INF/services/javax.annotation.processing.Processor||GHIDRA||||END| src/main/resources/META-INF/services/javax.annotation.processing.Processor||GHIDRA||||END|

View file

@ -20,13 +20,33 @@ import java.lang.annotation.Annotation;
import javax.lang.model.element.*; import javax.lang.model.element.*;
import javax.tools.Diagnostic.Kind; import javax.tools.Diagnostic.Kind;
import ghidra.util.database.DBAnnotatedObject;
/**
* An abstract class for validating annotations on {@link DBAnnotatedObject}.
*
* <p>
* Performs validation checks on annotated fields and their enclosing types.
*/
public class AbstractDBAnnotationValidator { public class AbstractDBAnnotationValidator {
protected final ValidationContext ctx; protected final ValidationContext ctx;
/**
* Construct a new {@code AbstractDBAnnotationValidator} with the specified validation context.
*
* @param ctx the validation context
*/
public AbstractDBAnnotationValidator(ValidationContext ctx) { public AbstractDBAnnotationValidator(ValidationContext ctx) {
this.ctx = ctx; this.ctx = ctx;
} }
/**
* Check the enclosing type of the annotated field.
*
* @param annotType the type of the annotation being validated
* @param field the field being validated
* @param type the enclosing type of the field
*/
protected void checkEnclosingType(Class<? extends Annotation> annotType, VariableElement field, protected void checkEnclosingType(Class<? extends Annotation> annotType, VariableElement field,
TypeElement type) { TypeElement type) {
if (type.getKind() != ElementKind.CLASS) { if (type.getKind() != ElementKind.CLASS) {

View file

@ -19,6 +19,10 @@ import java.util.Set;
import javax.lang.model.element.Modifier; import javax.lang.model.element.Modifier;
/**
* An enum to represent different levels of access specifiers (private, package-private, protected,
* public) with corresponding access levels
*/
public enum AccessSpec { public enum AccessSpec {
PRIVATE(0), PACKAGE(1), PROTECTED(2), PUBLIC(3); PRIVATE(0), PACKAGE(1), PROTECTED(2), PUBLIC(3);
@ -29,7 +33,7 @@ public enum AccessSpec {
} }
/** /**
* Checks if the second permits the same or more access than the first * Check if the second permits the same or more access than the first
* *
* @param first the first * @param first the first
* @param second the second * @param second the second

View file

@ -22,14 +22,43 @@ import javax.tools.Diagnostic.Kind;
import ghidra.util.database.annot.DBAnnotatedColumn; import ghidra.util.database.annot.DBAnnotatedColumn;
/**
* A class for validating fields annotated with {@link DBAnnotatedColumn}.
*
* <p>
* To ensure fields annotated with {@link DBAnnotatedColumn} comply with the expected criteria for
* database columns in Ghidra.
* </p>
*/
public class DBAnnotatedColumnValidator extends AbstractDBAnnotationValidator { public class DBAnnotatedColumnValidator extends AbstractDBAnnotationValidator {
final VariableElement column; final VariableElement column;
/**
* Construct a new {@code DBAnnotatedColumnValidator} with the specified validation context and
* the column element.
*
* @param ctx the validation context
* @param column the field representing the column
*/
public DBAnnotatedColumnValidator(ValidationContext ctx, VariableElement column) { public DBAnnotatedColumnValidator(ValidationContext ctx, VariableElement column) {
super(ctx); super(ctx);
this.column = column; this.column = column;
} }
/**
* Validate the annotated column field.
*
* <p>
* It performs the following checks to ensure it meets the requirements for database columns:
* <ul>
* <li>The field must be of the type specified by {@code ctx.DB_OBJECT_COLUMN_ELEM}.</li>
* <li>The field must not be declared as {@code final}.</li>
* <li>The field must be declared as {@code static}.</li>
* <li>The enclosing type of the field must meet the criteria defined in
* {@code checkEnclosingType}.</li>
* </ul>
*/
public void validate() { public void validate() {
if (!ctx.hasType(column, ctx.DB_OBJECT_COLUMN_ELEM)) { if (!ctx.hasType(column, ctx.DB_OBJECT_COLUMN_ELEM)) {
ctx.messager.printMessage(Kind.ERROR, ctx.messager.printMessage(Kind.ERROR,

View file

@ -23,6 +23,14 @@ import javax.tools.Diagnostic.Kind;
import ghidra.util.database.annot.DBAnnotatedField; import ghidra.util.database.annot.DBAnnotatedField;
/**
* A class for validating fields annotated with {@link DBAnnotatedField}
*
* <p>
* To ensure fields annotated with {@link DBAnnotatedField} meet the criteria required for database
* fields in Ghidra. It extends the {@code AbstractDBAnnotationValidator} to provide additional
* validation logic specific to database field annotations.
*/
public class DBAnnotatedFieldValidator extends AbstractDBAnnotationValidator { public class DBAnnotatedFieldValidator extends AbstractDBAnnotationValidator {
final VariableElement field; final VariableElement field;
final Map<TypeMirror, TypeElement> javaToDBTypeMap; final Map<TypeMirror, TypeElement> javaToDBTypeMap;
@ -39,6 +47,13 @@ public class DBAnnotatedFieldValidator extends AbstractDBAnnotationValidator {
final TypeElement ENUM_CODEC_ELEM; final TypeElement ENUM_CODEC_ELEM;
/**
* Construct a new {@code DBAnnotatedFieldValidator} with the specified validation context and
* field element.
*
* @param ctx the validation context
* @param field the field to validate
*/
public DBAnnotatedFieldValidator(ValidationContext ctx, VariableElement field) { public DBAnnotatedFieldValidator(ValidationContext ctx, VariableElement field) {
super(ctx); super(ctx);
this.field = field; this.field = field;
@ -59,6 +74,13 @@ public class DBAnnotatedFieldValidator extends AbstractDBAnnotationValidator {
ENUM_CODEC_ELEM = ctx.elementUtils.getTypeElement(ENUM_CODEC_NAME); ENUM_CODEC_ELEM = ctx.elementUtils.getTypeElement(ENUM_CODEC_NAME);
} }
/**
* Associate a primitive type and its boxed type with the specified codec type in the map.
*
* @param map the map linking java types to their corresponding codec types
* @param kind the primitive type kind
* @param codecName the fully qualified name of the codec type
*/
protected void putPrimitiveTypeCodec(Map<TypeMirror, TypeElement> map, TypeKind kind, protected void putPrimitiveTypeCodec(Map<TypeMirror, TypeElement> map, TypeKind kind,
String codecName) { String codecName) {
PrimitiveType primitive = ctx.typeUtils.getPrimitiveType(kind); PrimitiveType primitive = ctx.typeUtils.getPrimitiveType(kind);
@ -68,12 +90,26 @@ public class DBAnnotatedFieldValidator extends AbstractDBAnnotationValidator {
map.put(boxed, codec); map.put(boxed, codec);
} }
/**
* Associate a specified class type with the specified codec type in the map.
*
* @param map the map linking Java types to their corresponding codec types
* @param cls the class type
* @param codecName the fully qualified name of the codec type
*/
protected void putTypeCodec(Map<TypeMirror, TypeElement> map, Class<?> cls, String codecName) { protected void putTypeCodec(Map<TypeMirror, TypeElement> map, Class<?> cls, String codecName) {
TypeMirror type = ctx.elementUtils.getTypeElement(cls.getCanonicalName()).asType(); TypeMirror type = ctx.elementUtils.getTypeElement(cls.getCanonicalName()).asType();
TypeElement codec = ctx.elementUtils.getTypeElement(codecName); TypeElement codec = ctx.elementUtils.getTypeElement(codecName);
map.put(type, codec); map.put(type, codec);
} }
/**
* Associate a primitive array type with the specified codec type inthe map.
*
* @param map the map linking Java types to their corresponding codec types
* @param kind the primitive type kind
* @param codecName the fully qualified name of the codec type
*/
protected void putPrimitiveArrayTypeCodec(Map<TypeMirror, TypeElement> map, TypeKind kind, protected void putPrimitiveArrayTypeCodec(Map<TypeMirror, TypeElement> map, TypeKind kind,
String codecName) { String codecName) {
PrimitiveType primitive = ctx.typeUtils.getPrimitiveType(kind); PrimitiveType primitive = ctx.typeUtils.getPrimitiveType(kind);
@ -82,6 +118,19 @@ public class DBAnnotatedFieldValidator extends AbstractDBAnnotationValidator {
map.put(array, codec); map.put(array, codec);
} }
/**
* Validate the annotated field to ensure it meets the requirements for database fields.
*
* <p>
* It performs the following checks:
* <ul>
* <li>The field must not be declared as {@code final}.</li>
* <li>The field must not be declared as {@code static}.</li>
* <li>The enclosing type of the field must meet the criteria defined in
* {@code checkEnclosingType}.</li>
* <li>The codec types for the field must be appropriate.</li>
* </ul>
*/
public void validate() { public void validate() {
Set<Modifier> mods = field.getModifiers(); Set<Modifier> mods = field.getModifiers();
if (mods.contains(Modifier.FINAL)) { if (mods.contains(Modifier.FINAL)) {
@ -101,6 +150,12 @@ public class DBAnnotatedFieldValidator extends AbstractDBAnnotationValidator {
checkCodecTypes(type); checkCodecTypes(type);
} }
/**
* Return the default codec type element for the specified Java type.
*
* @param javaType the Java type for which the default codec is needed
* @return the default codec type element, or {@code null} if no default codec is found
*/
protected TypeElement getDefaultCodecType(TypeMirror javaType) { protected TypeElement getDefaultCodecType(TypeMirror javaType) {
if (ctx.isEnumType(javaType)) { if (ctx.isEnumType(javaType)) {
return ENUM_CODEC_ELEM; return ENUM_CODEC_ELEM;
@ -108,6 +163,12 @@ public class DBAnnotatedFieldValidator extends AbstractDBAnnotationValidator {
return javaToDBTypeMap.get(javaType); return javaToDBTypeMap.get(javaType);
} }
/**
* Return the codec type element specified in the {@link DBAnnotatedField} annotation for the
* field, or the default codec type if none is specified.
*
* @return the codec type element for the field
*/
protected TypeElement getCodecTypeElement() { protected TypeElement getCodecTypeElement() {
DBAnnotatedField annotation = field.getAnnotation(DBAnnotatedField.class); DBAnnotatedField annotation = field.getAnnotation(DBAnnotatedField.class);
TypeElement codecElem; TypeElement codecElem;
@ -123,6 +184,12 @@ public class DBAnnotatedFieldValidator extends AbstractDBAnnotationValidator {
return codecElem; return codecElem;
} }
/**
* Check the codec types associated with the field to ensure they meet the necessary
* requirements.
*
* @param objectType the type of the enclosing object
*/
protected void checkCodecTypes(TypeElement objectType) { protected void checkCodecTypes(TypeElement objectType) {
TypeElement codecType = getCodecTypeElement(); TypeElement codecType = getCodecTypeElement();

View file

@ -29,8 +29,10 @@ import ghidra.util.database.annot.*;
/** /**
* A compile-time annotation processor for {@link DBAnnotatedObject}-related annotations. * A compile-time annotation processor for {@link DBAnnotatedObject}-related annotations.
* *
* Currently just performs compile-time checks. It does not generate any code, but perhaps one day, * <p>
* it will. * This processor performs compile-time validation checks on annotations related to
* {@link DBAnnotatedObject}. Currently just performs compile-time checks. It does not generate any
* code, but perhaps one day, it will.
*/ */
//@AutoService(Processor.class) // TODO: Evaluate Google's auto-service as a dependency //@AutoService(Processor.class) // TODO: Evaluate Google's auto-service as a dependency
public class DBAnnotatedObjectProcessor extends AbstractProcessor { public class DBAnnotatedObjectProcessor extends AbstractProcessor {
@ -39,6 +41,11 @@ public class DBAnnotatedObjectProcessor extends AbstractProcessor {
private ValidationContext ctx; private ValidationContext ctx;
/**
* Initialize the processor with the given preprocessing environment.
*
* @param env the processing environment
*/
@Override @Override
public synchronized void init(ProcessingEnvironment env) { public synchronized void init(ProcessingEnvironment env) {
//System.err.println("HERE4"); //System.err.println("HERE4");
@ -46,6 +53,14 @@ public class DBAnnotatedObjectProcessor extends AbstractProcessor {
ctx = new ValidationContext(env); ctx = new ValidationContext(env);
} }
/**
* Process the specified annotations for the current round of processing..
*
* @param annotations the set of annotations to process
* @param roundEnv the environment for information about the current and prior round
* @return {@code true} if the annotations are claimed by this processor, {@code false}
* otherwise
*/
@Override @Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
Map<TypeElement, DBAnnotatedObjectValidator> types = new LinkedHashMap<>(); Map<TypeElement, DBAnnotatedObjectValidator> types = new LinkedHashMap<>();
@ -76,21 +91,40 @@ public class DBAnnotatedObjectProcessor extends AbstractProcessor {
return true; return true;
} }
/**
* Provide completion suggestion for the specified element, annotation, and member.
*
* @param element the element being annotated
* @param annotation the annotation being processed
* @param member the annotation member being completed
* @param userText the text entered by the user
* @return an iterable of completions.
*/
@Override @Override
public Iterable<? extends Completion> getCompletions(Element element, public Iterable<? extends Completion> getCompletions(Element element,
AnnotationMirror annotation, ExecutableElement member, String userText) { AnnotationMirror annotation, ExecutableElement member, String userText) {
// TODO Auto-generated method stub
return super.getCompletions(element, annotation, member, userText); return super.getCompletions(element, annotation, member, userText);
} }
/**
* Return the latest supported source version.
*
* @return the latest supported source version
*/
@Override @Override
public SourceVersion getSupportedSourceVersion() { public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported(); return SourceVersion.latestSupported();
} }
/**
* Return the set of supported annotation types.
*
* @return the set of supported annotation types
*/
@Override @Override
public Set<String> getSupportedAnnotationTypes() { public Set<String> getSupportedAnnotationTypes() {
return SUPPORTED_ANNOTATIONS.stream().map(Class::getCanonicalName).collect( return SUPPORTED_ANNOTATIONS.stream()
Collectors.toSet()); .map(Class::getCanonicalName)
.collect(Collectors.toSet());
} }
} }

View file

@ -20,31 +20,62 @@ import java.util.*;
import javax.lang.model.element.*; import javax.lang.model.element.*;
import javax.tools.Diagnostic.Kind; import javax.tools.Diagnostic.Kind;
import ghidra.util.database.DBAnnotatedObject;
import ghidra.util.database.annot.*; import ghidra.util.database.annot.*;
/**
* Validate {@link DBAnnotatedObject}-related annotations on a given type element.
*
* <p>
* This class ensures that annotations such as {@link DBAnnotatedField}, {@link DBAnnotatedColumn},
* and {@link DBAnnotatedObjectInfo} are applied correctly and consistently on the fields and
* columns of a class.
*/
public class DBAnnotatedObjectValidator { public class DBAnnotatedObjectValidator {
private final ValidationContext ctx; private final ValidationContext ctx;
private final TypeElement type; private final TypeElement type;
private final Map<String, DBAnnotatedFieldValidator> fieldsByName = new LinkedHashMap<>(); private final Map<String, DBAnnotatedFieldValidator> fieldsByName = new LinkedHashMap<>();
private final Map<String, DBAnnotatedColumnValidator> columnsByName = new LinkedHashMap<>(); private final Map<String, DBAnnotatedColumnValidator> columnsByName = new LinkedHashMap<>();
/**
* Construct a new validator for the given type element within the specified validation context
*
* @param ctx the validation context
* @param type the type element to be validated
*/
public DBAnnotatedObjectValidator(ValidationContext ctx, TypeElement type) { public DBAnnotatedObjectValidator(ValidationContext ctx, TypeElement type) {
this.ctx = ctx; this.ctx = ctx;
this.type = type; this.type = type;
} }
/**
* Add a field annotated with {@link DBAnnotatedField} to be validator.
*
* @param field the field element annotated with {@link DBAnnotatedField}
*/
public void addAnnotatedField(VariableElement field) { public void addAnnotatedField(VariableElement field) {
DBAnnotatedField annotation = field.getAnnotation(DBAnnotatedField.class); DBAnnotatedField annotation = field.getAnnotation(DBAnnotatedField.class);
assert annotation != null; assert annotation != null;
fieldsByName.put(annotation.column(), new DBAnnotatedFieldValidator(ctx, field)); fieldsByName.put(annotation.column(), new DBAnnotatedFieldValidator(ctx, field));
} }
/**
* Add a column annotated with {@link DBAnnotatedColumn} to the validator.
*
* @param column the field element annotated with {@link DBAnnotatedColumn}
*/
public void addAnnotatedColumn(VariableElement column) { public void addAnnotatedColumn(VariableElement column) {
DBAnnotatedColumn annotation = column.getAnnotation(DBAnnotatedColumn.class); DBAnnotatedColumn annotation = column.getAnnotation(DBAnnotatedColumn.class);
assert annotation != null; assert annotation != null;
columnsByName.put(annotation.value(), new DBAnnotatedColumnValidator(ctx, column)); columnsByName.put(annotation.value(), new DBAnnotatedColumnValidator(ctx, column));
} }
/**
* Validate the annotated fields, columns, and the type element itself.
*
* <p>
* Checks for various annotation constraints and consistency rules.
*/
public void validate() { public void validate() {
DBAnnotatedObjectInfo annotation = type.getAnnotation(DBAnnotatedObjectInfo.class); DBAnnotatedObjectInfo annotation = type.getAnnotation(DBAnnotatedObjectInfo.class);
if (annotation != null && type.getKind() != ElementKind.CLASS) { if (annotation != null && type.getKind() != ElementKind.CLASS) {
@ -81,18 +112,27 @@ public class DBAnnotatedObjectValidator {
checkMissing(); checkMissing();
} }
/**
* Validate all fields annotated with {@link DBAnnotatedField}.
*/
protected void validateFields() { protected void validateFields() {
for (DBAnnotatedFieldValidator fv : fieldsByName.values()) { for (DBAnnotatedFieldValidator fv : fieldsByName.values()) {
fv.validate(); fv.validate();
} }
} }
/**
* Validate all columns annotated with {@link DBAnnotatedColumn}.
*/
protected void validateColumns() { protected void validateColumns() {
for (DBAnnotatedColumnValidator cv : columnsByName.values()) { for (DBAnnotatedColumnValidator cv : columnsByName.values()) {
cv.validate(); cv.validate();
} }
} }
/**
* Check for missing corresponding annotations between fields and columns.
*/
protected void checkMissing() { protected void checkMissing() {
Set<String> names = new LinkedHashSet<>(); Set<String> names = new LinkedHashSet<>();
names.addAll(fieldsByName.keySet()); names.addAll(fieldsByName.keySet());
@ -121,6 +161,13 @@ public class DBAnnotatedObjectValidator {
} }
/**
* Check that the access specifiers of the field and column are compatible.
*
* @param field the field element
* @param column the column element
* @param name the name of the column
*/
protected void checkAccess(VariableElement field, VariableElement column, String name) { protected void checkAccess(VariableElement field, VariableElement column, String name) {
AccessSpec fieldSpec = AccessSpec.get(field.getModifiers()); AccessSpec fieldSpec = AccessSpec.get(field.getModifiers());
AccessSpec columnSpec = AccessSpec.get(column.getModifiers()); AccessSpec columnSpec = AccessSpec.get(column.getModifiers());

View file

@ -38,6 +38,11 @@ public class ValidationContext {
final TypeElement DEFAULT_CODEC_ELEM; final TypeElement DEFAULT_CODEC_ELEM;
final TypeElement ENUM_ELEM; final TypeElement ENUM_ELEM;
/**
* Construct a Validation Context with the specified processing environment/
*
* @param env the processing environment
*/
public ValidationContext(ProcessingEnvironment env) { public ValidationContext(ProcessingEnvironment env) {
typeUtils = env.getTypeUtils(); typeUtils = env.getTypeUtils();
elementUtils = env.getElementUtils(); elementUtils = env.getElementUtils();
@ -54,14 +59,35 @@ public class ValidationContext {
ENUM_ELEM = elementUtils.getTypeElement(Enum.class.getCanonicalName()); ENUM_ELEM = elementUtils.getTypeElement(Enum.class.getCanonicalName());
} }
/**
* Check if t1 is a subclass of t2.
*
* @param t1 the potential subclass
* @param t2 the potential superclass
* @return true if t1 is a subclass of t2, false otherwise
*/
public boolean isSubclass(TypeElement t1, TypeElement t2) { public boolean isSubclass(TypeElement t1, TypeElement t2) {
return typeUtils.isSubtype(typeUtils.erasure(t1.asType()), typeUtils.erasure(t2.asType())); return typeUtils.isSubtype(typeUtils.erasure(t1.asType()), typeUtils.erasure(t2.asType()));
} }
/**
* Check if the field has the specified type.
*
* @param field the field element
* @param type the type element
* @return true if the field has the specified type, false otherwise
*/
public boolean hasType(VariableElement field, TypeElement type) { public boolean hasType(VariableElement field, TypeElement type) {
return hasType(field, type.asType()); return hasType(field, type.asType());
} }
/**
* Check if the field has the specified type.
*
* @param field the field element
* @param type the type mirror
* @return true if the field has the specified type, false otherwise
*/
public boolean hasType(VariableElement field, TypeMirror type) { public boolean hasType(VariableElement field, TypeMirror type) {
TypeMirror fieldType = field.asType(); TypeMirror fieldType = field.asType();
try { try {
@ -86,9 +112,16 @@ public class ValidationContext {
} }
return typeUtils.isAssignable(fieldType, type); return typeUtils.isAssignable(fieldType, type);
// return typeUtils.isSameType(fieldType, type); // return typeUtils.isSameType(fieldType, type);
} }
/**
* Check if t1 is capturable by t2.
*
* @param t1 is the type to check
* @param t2 the capture target type
* @return true if t1 is capturable by t2, false otherwise
*/
public boolean isCapturable(TypeMirror t1, TypeMirror t2) { public boolean isCapturable(TypeMirror t1, TypeMirror t2) {
// TODO: This only works for typevar at top level... // TODO: This only works for typevar at top level...
// TODO: Need to figure out how to check for capture and check // TODO: Need to figure out how to check for capture and check
@ -105,6 +138,12 @@ public class ValidationContext {
return typeUtils.isSubtype(t1, t2); return typeUtils.isSubtype(t1, t2);
} }
/**
* Check if the type is an enum type.
*
* @param t the type mirror to check
* @return true if the type is an enum type, false otherwise
*/
public boolean isEnumType(TypeMirror t) { public boolean isEnumType(TypeMirror t) {
if (t.getKind() != TypeKind.DECLARED) { if (t.getKind() != TypeKind.DECLARED) {
return false; return false;
@ -113,6 +152,13 @@ public class ValidationContext {
return typeUtils.isSubtype(t, enumType); return typeUtils.isSubtype(t, enumType);
} }
/**
* Find the supertype of a set of declared types that matches the specified super type.
*
* @param types the set of declared types
* @param superType the super type element to match
* @return the matching declared type, or null if no match is found
*/
protected DeclaredType findSupertype(Set<DeclaredType> types, TypeElement superType) { protected DeclaredType findSupertype(Set<DeclaredType> types, TypeElement superType) {
Set<DeclaredType> next; Set<DeclaredType> next;
while (!types.isEmpty()) { while (!types.isEmpty()) {
@ -132,14 +178,35 @@ public class ValidationContext {
return null; return null;
} }
/**
* Find the supertype of a declared type that matches the specified super type element.
*
* @param type the declared type
* @param superElem the super type element to match
* @return the matching declared type, or null if no match is found
*/
public DeclaredType findSupertype(DeclaredType type, TypeElement superElem) { public DeclaredType findSupertype(DeclaredType type, TypeElement superElem) {
return findSupertype(Set.of(type), superElem); return findSupertype(Set.of(type), superElem);
} }
/**
* Find the supertype of a type element that matches the specified super type element.
*
* @param elem the type element
* @param superElem the super type element to match
* @return the matching declared type, or null if no match is found
*/
public DeclaredType findSupertype(TypeElement elem, TypeElement superElem) { public DeclaredType findSupertype(TypeElement elem, TypeElement superElem) {
return findSupertype((DeclaredType) elem.asType(), superElem); return findSupertype((DeclaredType) elem.asType(), superElem);
} }
/**
* Convert the type arguments of the super type element to a map.
*
* @param superElem the super type element
* @param superType the declared super type
* @return a map of type argument names to their corresponding type mirrors
*/
protected Map<String, TypeMirror> toArgsMap(TypeElement superElem, DeclaredType superType) { protected Map<String, TypeMirror> toArgsMap(TypeElement superElem, DeclaredType superType) {
List<? extends TypeParameterElement> typeParameters = superElem.getTypeParameters(); List<? extends TypeParameterElement> typeParameters = superElem.getTypeParameters();
List<? extends TypeMirror> typeArguments = superType.getTypeArguments(); List<? extends TypeMirror> typeArguments = superType.getTypeArguments();
@ -151,14 +218,34 @@ public class ValidationContext {
return result; return result;
} }
/**
* Get the type arguments of a declared type as a map.
*
* @param type the declared type
* @param superElem the super type element
* @return a map of type argument names to their corresponding type mirrors
*/
public Map<String, TypeMirror> getArguments(DeclaredType type, TypeElement superElem) { public Map<String, TypeMirror> getArguments(DeclaredType type, TypeElement superElem) {
return toArgsMap(superElem, findSupertype(type, superElem)); return toArgsMap(superElem, findSupertype(type, superElem));
} }
/**
* Get the type arguments of a type element as a map.
*
* @param elem the type element
* @param superElem the super type element
* @return a map of type argument names to their corresponding type mirrors
*/
public Map<String, TypeMirror> getArguments(TypeElement elem, TypeElement superElem) { public Map<String, TypeMirror> getArguments(TypeElement elem, TypeElement superElem) {
return toArgsMap(superElem, findSupertype(elem, superElem)); return toArgsMap(superElem, findSupertype(elem, superElem));
} }
/**
* Format the given type mirror as a string.
*
* @param type the type mirror to format
* @return the formatted type mirror as a string
*/
public String format(TypeMirror type) { public String format(TypeMirror type) {
FormatVisitor vis = new FormatVisitor(); FormatVisitor vis = new FormatVisitor();
type.accept(vis, null); type.accept(vis, null);
@ -166,9 +253,20 @@ public class ValidationContext {
} }
} }
/**
* Class for formatting {@link TypeMirror} instances into a readable string
*/
class FormatVisitor implements TypeVisitor<Void, Void> { class FormatVisitor implements TypeVisitor<Void, Void> {
StringBuffer buf = new StringBuffer(); StringBuffer buf = new StringBuffer();
/**
* Visit method for {@link TypeMirror}. Delegates to specific visit methods based on the type
* kind.
*
* @param t the type mirror to visit
* @param p unused parameter (can be {@code null})
* @return {@code null}
*/
@Override @Override
public Void visit(TypeMirror t, Void p) { public Void visit(TypeMirror t, Void p) {
switch (t.getKind()) { switch (t.getKind()) {
@ -207,18 +305,39 @@ class FormatVisitor implements TypeVisitor<Void, Void> {
} }
} }
/**
* Visit method for {@link PrimitiveType}.
*
* @param t the primitive type to visit
* @param p unused parameter (can be {@code null})
* @return {@code null}
*/
@Override @Override
public Void visitPrimitive(PrimitiveType t, Void p) { public Void visitPrimitive(PrimitiveType t, Void p) {
buf.append(t.toString()); buf.append(t.toString());
return null; return null;
} }
/**
* Visit method for {@link NullType}.
*
* @param t the null type to visit
* @param p unused parameter (can be {@code null})
* @return {@code null}
*/
@Override @Override
public Void visitNull(NullType t, Void p) { public Void visitNull(NullType t, Void p) {
buf.append(t.toString()); buf.append(t.toString());
return null; return null;
} }
/**
* Visit method for {@link ArrayType}.
*
* @param t the array type to visit
* @param p unused parameter (can be {@code null})
* @return {@code null}
*/
@Override @Override
public Void visitArray(ArrayType t, Void p) { public Void visitArray(ArrayType t, Void p) {
visit(t.getComponentType()); visit(t.getComponentType());
@ -226,6 +345,13 @@ class FormatVisitor implements TypeVisitor<Void, Void> {
return null; return null;
} }
/**
* Visit method for {@link DeclaredType}.
*
* @param t the declared type to visit
* @param p unused parameter (can be {@code null})
* @return {@code null}
*/
@Override @Override
public Void visitDeclared(DeclaredType t, Void p) { public Void visitDeclared(DeclaredType t, Void p) {
buf.append(t.asElement().toString()); buf.append(t.asElement().toString());
@ -242,12 +368,26 @@ class FormatVisitor implements TypeVisitor<Void, Void> {
return null; return null;
} }
/**
* Visit method for {@link ErrorType}.
*
* @param t the error type to visit
* @param p unused parameter (can be {@code null})
* @return {@code null}
*/
@Override @Override
public Void visitError(ErrorType t, Void p) { public Void visitError(ErrorType t, Void p) {
buf.append(t.toString()); buf.append(t.toString());
return null; return null;
} }
/**
* Visit method for {@link TypeVariable}.
*
* @param t the type variable to visit
* @param p unused parameter (can be {@code null})
* @return {@code null}
*/
@Override @Override
public Void visitTypeVariable(TypeVariable t, Void p) { public Void visitTypeVariable(TypeVariable t, Void p) {
buf.append(t.toString()); buf.append(t.toString());
@ -264,6 +404,13 @@ class FormatVisitor implements TypeVisitor<Void, Void> {
return null; return null;
} }
/**
* Visit method for {@link WildcardType}.
*
* @param t the wildcard type to visit
* @param p unused parameter (can be {@code null})
* @return {@code null}
*/
@Override @Override
public Void visitWildcard(WildcardType t, Void p) { public Void visitWildcard(WildcardType t, Void p) {
buf.append("?"); buf.append("?");
@ -280,24 +427,52 @@ class FormatVisitor implements TypeVisitor<Void, Void> {
return null; return null;
} }
/**
* Visit method for {@link ExecutableType}.
*
* @param t the executable type to visit
* @param p unused parameter (can be {@code null})
* @return {@code null}
*/
@Override @Override
public Void visitExecutable(ExecutableType t, Void p) { public Void visitExecutable(ExecutableType t, Void p) {
buf.append(t.toString()); buf.append(t.toString());
return null; return null;
} }
/**
* Visit method for {@link NoType}.
*
* @param t the no-type to visit
* @param p unused parameter (can be {@code null})
* @return {@code null}
*/
@Override @Override
public Void visitNoType(NoType t, Void p) { public Void visitNoType(NoType t, Void p) {
buf.append(t.toString()); buf.append(t.toString());
return null; return null;
} }
/**
* Visit method for unknown {@link TypeMirror} instances.
*
* @param t the unknown type to visit
* @param p unused parameter (can be {@code null})
* @return {@code null}
*/
@Override @Override
public Void visitUnknown(TypeMirror t, Void p) { public Void visitUnknown(TypeMirror t, Void p) {
buf.append(t.toString()); buf.append(t.toString());
return null; return null;
} }
/**
* Visit method for {@link UnionType}.
*
* @param t the union type to visit
* @param p unused parameter (can be {@code null})
* @return {@code null}
*/
@Override @Override
public Void visitUnion(UnionType t, Void p) { public Void visitUnion(UnionType t, Void p) {
Iterator<? extends TypeMirror> it = t.getAlternatives().iterator(); Iterator<? extends TypeMirror> it = t.getAlternatives().iterator();
@ -311,6 +486,13 @@ class FormatVisitor implements TypeVisitor<Void, Void> {
return null; return null;
} }
/**
* Visit method for {@link IntersectionType}.
*
* @param t the intersection type to visit
* @param p unused parameter (can be {@code null})
* @return {@code null}
*/
@Override @Override
public Void visitIntersection(IntersectionType t, Void p) { public Void visitIntersection(IntersectionType t, Void p) {
Iterator<? extends TypeMirror> it = t.getBounds().iterator(); Iterator<? extends TypeMirror> it = t.getBounds().iterator();

View file

@ -0,0 +1,5 @@
MODULE FILE LICENSE: pypkg/dist/capstone-5.0.1-py3-none-win_amd64.whl BSD-3-CAPSTONE
MODULE FILE LICENSE: pypkg/dist/comtypes-1.4.1-py3-none-any.whl MIT
MODULE FILE LICENSE: pypkg/dist/Pybag-2.2.12-py3-none-any.whl MIT
MODULE FILE LICENSE: pypkg/dist/pywin32-306-cp312-cp312-win_amd64.whl Python Software Foundation License

View file

@ -0,0 +1 @@
# Debugger-agent-dbgeng

View file

@ -18,32 +18,72 @@ apply from: "$rootProject.projectDir/gradle/jacocoProject.gradle"
apply from: "$rootProject.projectDir/gradle/javaTestProject.gradle" apply from: "$rootProject.projectDir/gradle/javaTestProject.gradle"
apply from: "$rootProject.projectDir/gradle/nativeProject.gradle" apply from: "$rootProject.projectDir/gradle/nativeProject.gradle"
apply from: "$rootProject.projectDir/gradle/distributableGhidraModule.gradle" apply from: "$rootProject.projectDir/gradle/distributableGhidraModule.gradle"
apply from: "$rootProject.projectDir/gradle/hasPythonPackage.gradle"
apply from: "$rootProject.projectDir/gradle/debugger/hasNodepJar.gradle" apply from: "$rootProject.projectDir/gradle/debugger/hasNodepJar.gradle"
apply plugin: 'eclipse' apply plugin: 'eclipse'
eclipse.project.name = 'Debug Debugger-agent-dbgeng' eclipse.project.name = 'Debug Debugger-agent-dbgeng'
dependencies { ext.tlb = file("build/os/win_x86_64/dbgmodel.tlb")
api project(":Framework-AsyncComm")
api project(":Framework-Debugging")
api project(":Debugger-gadp")
//testImplementation project(":Base") if ("win_x86_64".equals(getCurrentPlatformName())) {
testImplementation project(path: ':Framework-AsyncComm', configuration: 'testArtifacts')
testImplementation project(path: ':Framework-Debugging', configuration: 'testArtifacts') String makeName = "win_x86_64DbgmodelTlbMake"
testImplementation project(path: ":Debugger-gadp", configuration: 'testArtifacts') task(type: Exec, makeName) {
ext.tmpBatch = file("build/buildTlb.bat")
ext.idl = file("src/main/py/src/ghidradbg/dbgmodel/DbgModel.idl")
inputs.file(idl)
outputs.file(tlb)
doFirst {
file(tlb).parentFile.mkdirs()
def midlCmd = "midl /tlb ${tlb} ${idl}"
println "Executing: " + midlCmd
tmpBatch.withWriter { out ->
out.println "call " + VISUAL_STUDIO_VCVARS_CMD
out.println midlCmd
}
}
doLast {
assert file(tlb).exists() : "Failed to build dbgmodel.tlb"
}
commandLine "cmd", "/c", tmpBatch
}
tasks.assemblePyPackage {
from(tasks."$makeName") {
into("src/ghidradbg/dbgmodel/tlb")
}
}
} }
else if (file(tlb).exists()) {
tasks.nodepJar { // required for multi-platform build
manifest { tasks.assemblePyPackage {
attributes['Main-Class'] = 'agent.dbgeng.gadp.DbgEngGadpServer' from(tlb) {
println "Copying existing tlb build artifact: " + tlb
into("src/ghidradbg/dbgmodel/tlb")
}
}
}
else {
def prebuiltTlb = new File(rootProject.BIN_REPO + '/' + getGhidraRelativePath(project) + "/os/win_x86_64/dbgmodel.tlb")
if (prebuiltTlb.exists()) {
println "Copying prebuilt dbgmodel.tlb"
tasks.assemblePyPackage {
from(rootProject.BIN_REPO + '/' + getGhidraRelativePath(project) + "/os/win_x86_64/dbgmodel.tlb") {
into("src/ghidradbg/dbgmodel/tlb")
}
}
}
else {
println "WARNING: dbgmodel.tlb omitted from ghidradbg python package"
} }
} }
test { distributePyDep("Pybag-2.2.12-py3-none-any.whl")
jvmArgs('-Xrs') // TODO: Is this needed, or left over from trial-and-error distributePyDep("capstone-5.0.1-py3-none-win_amd64.whl")
if ("win_x86_64".equals(getCurrentPlatformName())) { distributePyDep("comtypes-1.4.1-py3-none-any.whl")
dependsOn(":Framework-Debugging:testSpecimenWin_x86_64") distributePyDep("pywin32-306-cp312-cp312-win_amd64.whl")
}
}

View file

@ -1,5 +1,18 @@
##VERSION: 2.0 ##VERSION: 2.0
##MODULE IP: Apache License 2.0 ##MODULE IP: Apache License 2.0
##MODULE IP: MIT
Module.manifest||GHIDRA||||END| Module.manifest||GHIDRA||||END|
src/javaprovider/def/javaprovider.def||GHIDRA||||END| README.md||GHIDRA||||END|
src/javaprovider/rc/javaprovider.rc||GHIDRA||||END| data/debugger-launchers/kernel-dbgeng.bat||GHIDRA||||END|
data/debugger-launchers/local-dbgeng-attach.bat||GHIDRA||||END|
data/debugger-launchers/local-dbgeng-ext.bat||GHIDRA||||END|
data/debugger-launchers/local-dbgeng.bat||GHIDRA||||END|
data/debugger-launchers/local-ttd.bat||GHIDRA||||END|
data/debugger-launchers/remote-dbgeng.bat||GHIDRA||||END|
src/main/py/LICENSE||GHIDRA||||END|
src/main/py/MANIFEST.in||GHIDRA||||END|
src/main/py/README.md||GHIDRA||||END|
src/main/py/pyproject.toml||GHIDRA||||END|
src/main/py/src/ghidradbg/dbgmodel/DbgModel.idl||GHIDRA||||END|
src/main/py/src/ghidradbg/schema.xml||GHIDRA||||END|
src/main/py/src/ghidrattd/schema.xml||GHIDRA||||END|

View file

@ -0,0 +1,20 @@
::@title dbgeng-kernel
::@desc <html><body width="300px">
::@desc <h3>Kernel debugging using <tt>dbgeng</tt> (in a Python interpreter)</h3>
::@desc <p>
::@desc This will connect the kernel debugger to a remote machine using <tt>dbgeng.dll</tt>.
::@desc For setup instructions, press <b>F1</b>.
::@desc </p>
::@desc </body></html>
::@menu-group local
::@icon icon.debugger
::@help TraceRmiLauncherServicePlugin#dbgeng_kernel
::@env OPT_PYTHON_EXE:file!="python" "Python command" "The path to the Python 3 interpreter. Omit the full path to resolve using the system PATH."
:: Use env instead of args, because "all args except first" is terrible to implement in batch
::@env OPT_TARGET_ARGS:str="" "Arguments" "Connection-string arguments (a la .server)"
::@env OPT_USE_DBGMODEL:bool=true "Use dbgmodel" "Load and use dbgmodel.dll if it is available."
::@env WINDBG_DIR:dir="" "Path to dbgeng.dll directory" "Path containing dbgeng and associated DLLS (if not Windows Kits)."
@echo off
"%OPT_PYTHON_EXE%" -i ..\support\kernel-dbgeng.py

View file

@ -0,0 +1,20 @@
::@title dbgeng-attach
::@desc <html><body width="300px">
::@desc <h3>Attach with <tt>dbgeng</tt> (in a Python interpreter)</h3>
::@desc <p>
::@desc This will attach to a running target on the local machine using <tt>dbgeng.dll</tt>.
::@desc For setup instructions, press <b>F1</b>.
::@desc </p>
::@desc </body></html>
::@menu-group local
::@icon icon.debugger
::@help TraceRmiLauncherServicePlugin#dbgeng_attach
::@env OPT_PYTHON_EXE:file!="python" "Python command" "The path to the Python 3 interpreter. Omit the full path to resolve using the system PATH."
::@env OPT_TARGET_PID:int=0 "Process id" "The target process id"
::@env OPT_ATTACH_FLAGS:int=0 "Attach flags" "Attach flags"
::@env OPT_USE_DBGMODEL:bool=true "Use dbgmodel" "Load and use dbgmodel.dll if it is available."
::@env WINDBG_DIR:dir="" "Path to dbgeng.dll directory" "Path containing dbgeng and associated DLLS (if not Windows Kits)."
@echo off
"%OPT_PYTHON_EXE%" -i ..\support\local-dbgeng-attach.py

View file

@ -0,0 +1,27 @@
::@title dbgeng-ext
::@image-opt env:OPT_TARGET_IMG
::@desc <html><body width="300px">
::@desc <h3>Launch with <tt>dbgeng</tt> (in a Python interpreter)</h3>
::@desc <p>
::@desc This will launch the target on the local machine using <tt>dbgeng.dll</tt>.
::@desc For setup instructions, press <b>F1</b>.
::@desc </p>
::@desc </body></html>
::@menu-group local
::@icon icon.debugger
::@help TraceRmiLauncherServicePlugin#dbgeng_ext
::@env OPT_PYTHON_EXE:file!="python" "Python command" "The path to the Python 3 interpreter. Omit the full path to resolve using the system PATH."
:: Use env instead of args, because "all args except first" is terrible to implement in batch
::@env OPT_TARGET_IMG:file!="" "Image" "The target binary executable image"
::@env OPT_TARGET_ARGS:str="" "Arguments" "Command-line arguments to pass to the target"
::@env OPT_USE_DBGMODEL:bool=true "Use dbgmodel" "Load and use dbgmodel.dll if it is available."
::@env WINDBG_DIR:dir="" "Path to dbgeng.dll directory" "Path containing dbgeng and associated DLLS (if not Windows Kits)."
::@env OPT_TARGET_DIR:str="" "Dir" "Initial directory"
::@env OPT_TARGET_ENV:str="" "Env" "Environment variables (sep=/0)"
::@env OPT_CREATE_FLAGS:int="1" "Create flags" "Creation flags"
::@env OPT_CREATE_ENGFLAGS:int="0" "Create flags (Engine)" "Engine-specific creation flags"
::@env OPT_VERIFIER_FLAGS:int="0" "Verifier flags" "Verifier flags"
@echo off
"%OPT_PYTHON_EXE%" -i ..\support\local-dbgeng-ext.py

View file

@ -0,0 +1,22 @@
::@title dbgeng
::@image-opt env:OPT_TARGET_IMG
::@desc <html><body width="300px">
::@desc <h3>Launch with <tt>dbgeng</tt> (in a Python interpreter)</h3>
::@desc <p>
::@desc This will launch the target on the local machine using <tt>dbgeng.dll</tt>.
::@desc For setup instructions, press <b>F1</b>.
::@desc </p>
::@desc </body></html>
::@menu-group local
::@icon icon.debugger
::@help TraceRmiLauncherServicePlugin#dbgeng
::@env OPT_PYTHON_EXE:file!="python" "Python command" "The path to the Python 3 interpreter. Omit the full path to resolve using the system PATH."
:: Use env instead of args, because "all args except first" is terrible to implement in batch
::@env OPT_TARGET_IMG:file!="" "Image" "The target binary executable image"
::@env OPT_TARGET_ARGS:str="" "Arguments" "Command-line arguments to pass to the target"
::@env OPT_USE_DBGMODEL:bool=true "Use dbgmodel" "Load and use dbgmodel.dll if it is available."
::@env WINDBG_DIR:dir="" "Path to dbgeng.dll directory" "Path containing dbgeng and associated DLLS (if not Windows Kits)."
@echo off
"%OPT_PYTHON_EXE%" -i ..\support\local-dbgeng.py

View file

@ -0,0 +1,21 @@
::@title ttd
::@desc <html><body width="300px">
::@desc <h3>Launch with <tt>ttd</tt> (in a Python interpreter)</h3>
::@desc <p>
::@desc This will launch the target on the local machine for time-travel debugging.
::@desc For setup instructions, press <b>F1</b>.
::@desc </p>
::@desc </body></html>
::@menu-group local
::@icon icon.debugger
::@help TraceRmiLauncherServicePlugin#dbgeng_ttd
::@env OPT_PYTHON_EXE:file!="python" "Python command" "The path to the Python 3 interpreter. Omit the full path to resolve using the system PATH."
:: Use env instead of args, because "all args except first" is terrible to implement in batch
::@env OPT_TARGET_IMG:file!="" "Trace (.run)" "A trace associated with the target binary executable"
::@env OPT_TARGET_ARGS:str="" "Arguments" "Command-line arguments to pass to the target"
::@env OPT_USE_DBGMODEL:bool=true "Use dbgmodel" "Load and use dbgmodel.dll if it is available."
::@env OPT_DBGMODEL_PATH:dir="" "Path to dbgeng.dll & \\ttd" "Path containing dbgeng and associated DLLS (if not Windows Kits)."
@echo off
"%OPT_PYTHON_EXE%" -i ..\support\local-ttd.py

View file

@ -0,0 +1,23 @@
::@title dbgeng-remote
::@image-opt env:OPT_TARGET_IMG
::@desc <html><body width="300px">
::@desc <h3>Launch with <tt>dbgeng</tt> remotely (in a Python interpreter)</h3>
::@desc <p>
::@desc This will launch the target on a remote machine using <tt>dbgeng.dll</tt>.
::@desc For setup instructions, press <b>F1</b>.
::@desc </p>
::@desc </body></html>
::@menu-group local
::@icon icon.debugger
::@help TraceRmiLauncherServicePlugin#dbgeng_remote
::@env OPT_PYTHON_EXE:file!="python" "Python command" "The path to the Python 3 interpreter. Omit the full path to resolve using the system PATH."
:: Use env instead of args, because "all args except first" is terrible to implement in batch
::@env OPT_TARGET_IMG:str!="" "Image" "The target binary executable image"
::@env OPT_TARGET_ARGS:str="" "Arguments" "Command-line arguments to pass to the target"
::@env OPT_CONNECT_STRING:str="" "Connection" "Connection-string arguments (a la dbgsrv args)"
::@env OPT_USE_DBGMODEL:bool=true "Use dbgmodel" "Load and use dbgmodel.dll if it is available."
::@env WINDBG_DIR:dir="" "Path to dbgeng.dll directory" "Path containing dbgeng and associated DLLS (if not Windows Kits)."
@echo off
"%OPT_PYTHON_EXE%" -i ..\support\remote-dbgeng.py

View file

@ -0,0 +1,67 @@
## ###
# IP: GHIDRA
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
##
import os
import sys
home = os.getenv('GHIDRA_HOME')
if os.path.isdir(f'{home}\\ghidra\\.git'):
sys.path.append(
f'{home}\\ghidra\\Ghidra\\Debug\\Debugger-agent-dbgeng\\build\\pypkg\\src')
sys.path.append(
f'{home}\\ghidra\\Ghidra\\Debug\\Debugger-rmi-trace\\build\\pypkg\\src')
elif os.path.isdir(f'{home}\\.git'):
sys.path.append(
f'{home}\\Ghidra\\Debug\\Debugger-agent-dbgeng\\build\\pypkg\\src')
sys.path.append(
f'{home}\\Ghidra\\Debug\\Debugger-rmi-trace\\build\\pypkg\\src')
else:
sys.path.append(
f'{home}\\Ghidra\\Debug\\Debugger-agent-dbgeng\\pypkg\\src')
sys.path.append(f'{home}\\Ghidra\\Debug\\Debugger-rmi-trace\\pypkg\\src')
def main():
# Delay these imports until sys.path is patched
from ghidradbg import commands as cmd
from pybag.dbgeng import core as DbgEng
from ghidradbg.hooks import on_state_changed
from ghidradbg.util import dbg
# So that the user can re-enter by typing repl()
global repl
repl = cmd.repl
cmd.ghidra_trace_connect(os.getenv('GHIDRA_TRACE_RMI_ADDR'))
args = os.getenv('OPT_TARGET_ARGS')
cmd.ghidra_trace_attach_kernel(args, start_trace=False)
# TODO: HACK
try:
dbg.wait()
except KeyboardInterrupt as ki:
dbg.interrupt()
cmd.ghidra_trace_start(os.getenv('OPT_TARGET_IMG'))
cmd.ghidra_trace_sync_enable()
on_state_changed(DbgEng.DEBUG_CES_EXECUTION_STATUS, DbgEng.DEBUG_STATUS_BREAK)
cmd.repl()
if __name__ == '__main__':
main()

View file

@ -0,0 +1,69 @@
## ###
# IP: GHIDRA
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
##
import os
import sys
home = os.getenv('GHIDRA_HOME')
if os.path.isdir(f'{home}\\ghidra\\.git'):
sys.path.append(
f'{home}\\ghidra\\Ghidra\\Debug\\Debugger-agent-dbgeng\\build\\pypkg\\src')
sys.path.append(
f'{home}\\ghidra\\Ghidra\\Debug\\Debugger-rmi-trace\\build\\pypkg\\src')
elif os.path.isdir(f'{home}\\.git'):
sys.path.append(
f'{home}\\Ghidra\\Debug\\Debugger-agent-dbgeng\\build\\pypkg\\src')
sys.path.append(
f'{home}\\Ghidra\\Debug\\Debugger-rmi-trace\\build\\pypkg\\src')
else:
sys.path.append(
f'{home}\\Ghidra\\Debug\\Debugger-agent-dbgeng\\pypkg\\src')
sys.path.append(f'{home}\\Ghidra\\Debug\\Debugger-rmi-trace\\pypkg\\src')
def main():
# Delay these imports until sys.path is patched
from ghidradbg import commands as cmd
from pybag.dbgeng import core as DbgEng
from ghidradbg.hooks import on_state_changed
from ghidradbg.util import dbg
# So that the user can re-enter by typing repl()
global repl
repl = cmd.repl
cmd.ghidra_trace_connect(os.getenv('GHIDRA_TRACE_RMI_ADDR'))
flags = os.getenv('OPT_ATTACH_FLAGS')
cmd.ghidra_trace_attach(
os.getenv('OPT_TARGET_PID'), flags, start_trace=False)
# TODO: HACK
try:
dbg.wait()
except KeyboardInterrupt as ki:
dbg.interrupt()
cmd.ghidra_trace_start(os.getenv('OPT_TARGET_IMG'))
cmd.ghidra_trace_sync_enable()
on_state_changed(DbgEng.DEBUG_CES_EXECUTION_STATUS, DbgEng.DEBUG_STATUS_BREAK)
cmd.repl()
if __name__ == '__main__':
main()

View file

@ -0,0 +1,77 @@
## ###
# IP: GHIDRA
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
##
import os
import sys
home = os.getenv('GHIDRA_HOME')
if os.path.isdir(f'{home}\\ghidra\\.git'):
sys.path.append(
f'{home}\\ghidra\\Ghidra\\Debug\\Debugger-agent-dbgeng\\build\\pypkg\\src')
sys.path.append(
f'{home}\\ghidra\\Ghidra\\Debug\\Debugger-rmi-trace\\build\\pypkg\\src')
elif os.path.isdir(f'{home}\\.git'):
sys.path.append(
f'{home}\\Ghidra\\Debug\\Debugger-agent-dbgeng\\build\\pypkg\\src')
sys.path.append(
f'{home}\\Ghidra\\Debug\\Debugger-rmi-trace\\build\\pypkg\\src')
else:
sys.path.append(
f'{home}\\Ghidra\\Debug\\Debugger-agent-dbgeng\\pypkg\\src')
sys.path.append(f'{home}\\Ghidra\\Debug\\Debugger-rmi-trace\\pypkg\\src')
def main():
# Delay these imports until sys.path is patched
from ghidradbg import commands as cmd
from pybag.dbgeng import core as DbgEng
from ghidradbg.hooks import on_state_changed
from ghidradbg.util import dbg
# So that the user can re-enter by typing repl()
global repl
repl = cmd.repl
cmd.ghidra_trace_connect(os.getenv('GHIDRA_TRACE_RMI_ADDR'))
args = os.getenv('OPT_TARGET_ARGS')
if args:
args = ' ' + args
cmd.ghidra_trace_create_ext(
os.getenv('OPT_TARGET_IMG') + args,
os.getenv('OPT_TARGET_DIR'),
os.getenv('OPT_TARGET_ENV'),
os.getenv('OPT_CREATE_FLAGS'),
os.getenv('OPT_CREATE_ENGFLAGS'),
os.getenv('OPT_VERIFIER_FLAGS'),
start_trace=False)
# TODO: HACK
try:
dbg.wait()
except KeyboardInterrupt as ki:
dbg.interrupt()
cmd.ghidra_trace_start(os.getenv('OPT_TARGET_IMG'))
cmd.ghidra_trace_sync_enable()
on_state_changed(DbgEng.DEBUG_CES_EXECUTION_STATUS, DbgEng.DEBUG_STATUS_BREAK)
cmd.repl()
if __name__ == '__main__':
main()

View file

@ -0,0 +1,71 @@
## ###
# IP: GHIDRA
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
##
import os
import sys
home = os.getenv('GHIDRA_HOME')
if os.path.isdir(f'{home}\\ghidra\\.git'):
sys.path.append(
f'{home}\\ghidra\\Ghidra\\Debug\\Debugger-agent-dbgeng\\build\\pypkg\\src')
sys.path.append(
f'{home}\\ghidra\\Ghidra\\Debug\\Debugger-rmi-trace\\build\\pypkg\\src')
elif os.path.isdir(f'{home}\\.git'):
sys.path.append(
f'{home}\\Ghidra\\Debug\\Debugger-agent-dbgeng\\build\\pypkg\\src')
sys.path.append(
f'{home}\\Ghidra\\Debug\\Debugger-rmi-trace\\build\\pypkg\\src')
else:
sys.path.append(
f'{home}\\Ghidra\\Debug\\Debugger-agent-dbgeng\\pypkg\\src')
sys.path.append(f'{home}\\Ghidra\\Debug\\Debugger-rmi-trace\\pypkg\\src')
def main():
# Delay these imports until sys.path is patched
from ghidradbg import commands as cmd
from pybag.dbgeng import core as DbgEng
from ghidradbg.hooks import on_state_changed
from ghidradbg.util import dbg
# So that the user can re-enter by typing repl()
global repl
repl = cmd.repl
cmd.ghidra_trace_connect(os.getenv('GHIDRA_TRACE_RMI_ADDR'))
args = os.getenv('OPT_TARGET_ARGS')
if args:
args = ' ' + args
cmd.ghidra_trace_create(
os.getenv('OPT_TARGET_IMG') + args, start_trace=False)
# TODO: HACK
try:
dbg.wait()
except KeyboardInterrupt as ki:
dbg.interrupt()
cmd.ghidra_trace_start(os.getenv('OPT_TARGET_IMG'))
cmd.ghidra_trace_sync_enable()
on_state_changed(DbgEng.DEBUG_CES_EXECUTION_STATUS, DbgEng.DEBUG_STATUS_BREAK)
cmd.repl()
if __name__ == '__main__':
main()

View file

@ -0,0 +1,58 @@
## ###
# IP: GHIDRA
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
##
import os
import sys
home = os.getenv('GHIDRA_HOME')
if os.path.isdir(f'{home}\\ghidra\\.git'):
sys.path.append(
f'{home}\\ghidra\\Ghidra\\Debug\\Debugger-agent-dbgeng\\build\\pypkg\\src')
sys.path.append(
f'{home}\\ghidra\\Ghidra\\Debug\\Debugger-rmi-trace\\build\\pypkg\\src')
elif os.path.isdir(f'{home}\\.git'):
sys.path.append(
f'{home}\\Ghidra\\Debug\\Debugger-agent-dbgeng\\build\\pypkg\\src')
sys.path.append(
f'{home}\\Ghidra\\Debug\\Debugger-rmi-trace\\build\\pypkg\\src')
else:
sys.path.append(
f'{home}\\Ghidra\\Debug\\Debugger-agent-dbgeng\\pypkg\\src')
sys.path.append(f'{home}\\Ghidra\\Debug\\Debugger-rmi-trace\\pypkg\\src')
def main():
# Delay these imports until sys.path is patched
from ghidrattd import commands as cmd
from ghidrattd import hooks
###from ghidrattd.util import dbg
cmd.ghidra_trace_connect(os.getenv('GHIDRA_TRACE_RMI_ADDR'))
args = os.getenv('OPT_TARGET_ARGS')
if args:
args = ' ' + args
cmd.ghidra_trace_create(
os.getenv('OPT_TARGET_IMG') + args, start_trace=True)
cmd.ghidra_trace_sync_enable()
hooks.on_stop()
cmd.repl()
if __name__ == '__main__':
main()

View file

@ -0,0 +1,73 @@
## ###
# IP: GHIDRA
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
##
import os
import sys
home = os.getenv('GHIDRA_HOME')
if os.path.isdir(f'{home}\\ghidra\\.git'):
sys.path.append(
f'{home}\\ghidra\\Ghidra\\Debug\\Debugger-agent-dbgeng\\build\\pypkg\\src')
sys.path.append(
f'{home}\\ghidra\\Ghidra\\Debug\\Debugger-rmi-trace\\build\\pypkg\\src')
elif os.path.isdir(f'{home}\\.git'):
sys.path.append(
f'{home}\\Ghidra\\Debug\\Debugger-agent-dbgeng\\build\\pypkg\\src')
sys.path.append(
f'{home}\\Ghidra\\Debug\\Debugger-rmi-trace\\build\\pypkg\\src')
else:
sys.path.append(
f'{home}\\Ghidra\\Debug\\Debugger-agent-dbgeng\\pypkg\\src')
sys.path.append(f'{home}\\Ghidra\\Debug\\Debugger-rmi-trace\\pypkg\\src')
def main():
# Delay these imports until sys.path is patched
from ghidradbg import commands as cmd
from pybag.dbgeng import core as DbgEng
from ghidradbg.hooks import on_state_changed
from ghidradbg.util import dbg
# So that the user can re-enter by typing repl()
global repl
repl = cmd.repl
cmd.ghidra_trace_connect(os.getenv('GHIDRA_TRACE_RMI_ADDR'))
args = os.getenv('OPT_TARGET_ARGS')
if args:
args = ' ' + args
cmd.ghidra_trace_connect_server(os.getenv('OPT_CONNECT_STRING'))
img = os.getenv('OPT_TARGET_IMG')
if img is not None and img != "":
cmd.ghidra_trace_create(img + args, start_trace=False)
# TODO: HACK
try:
dbg.wait()
except KeyboardInterrupt as ki:
dbg.interrupt()
cmd.ghidra_trace_start(os.getenv('OPT_TARGET_IMG'))
cmd.ghidra_trace_sync_enable()
on_state_changed(DbgEng.DEBUG_CES_EXECUTION_STATUS, DbgEng.DEBUG_STATUS_BREAK)
cmd.repl()
if __name__ == '__main__':
main()

View file

@ -1,224 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define INITGUID
#include <engextcpp.hpp>
#include <jni.h>
#include "resource.h"
#define CHECK_RESULT(x, y) do { \
HRESULT hr = (x); \
if (hr != S_OK) { \
fprintf(stderr, "HRESULT of %s = %x\n", ##x, hr); \
return y; \
} \
} while (0)
class EXT_CLASS : public ExtExtension {
public:
virtual HRESULT Initialize();
virtual void Uninitialize();
//virtual void OnSessionAccessible(ULONG64 Argument);
EXT_COMMAND_METHOD(java_add_cp);
EXT_COMMAND_METHOD(java_set);
EXT_COMMAND_METHOD(java_get);
EXT_COMMAND_METHOD(java_run);
void run_command(PCSTR name);
};
EXT_DECLARE_GLOBALS();
JavaVM* jvm = NULL;
JNIEnv* env = NULL;
jclass clsCommands = NULL;
char JDK_JVM_DLL_PATH[] = "\\jre\\bin\\server\\jvm.dll";
char JRE_JVM_DLL_PATH[] = "\\bin\\server\\jvm.dll";
typedef jint (_cdecl *CreateJavaVMFunc)(JavaVM**, void**, void*);
HRESULT EXT_CLASS::Initialize() {
HRESULT result = ExtExtension::Initialize();
if (result != S_OK) {
return result;
}
char* env_java_home = getenv("JAVA_HOME");
if (env_java_home == NULL) {
fprintf(stderr, "JAVA_HOME is not set\n");
fflush(stderr);
return E_FAIL;
}
char* java_home = strdup(env_java_home);
size_t home_len = strlen(java_home);
if (java_home[home_len - 1] == '\\') {
java_home[home_len - 1] = '\0';
}
size_t full_len = home_len + sizeof(JDK_JVM_DLL_PATH);
char* full_path = new char[full_len];
HMODULE jvmDll = NULL;
// Try the JRE path first;
strcpy_s(full_path, full_len, java_home);
strcat_s(full_path, full_len, JRE_JVM_DLL_PATH);
fprintf(stderr, "Trying to find jvm.dll at %s\n", full_path);
fflush(stderr);
jvmDll = LoadLibraryA(full_path);
if (jvmDll == NULL) {
// OK, then try the JDK path
strcpy_s(full_path, full_len, java_home);
strcat_s(full_path, full_len, JDK_JVM_DLL_PATH);
fprintf(stderr, "Trying to find jvm.dll at %s\n", full_path);
fflush(stderr);
jvmDll = LoadLibraryA(full_path);
}
free(full_path);
free(java_home);
if (jvmDll == NULL) {
fprintf(stderr, "Could not find the jvm.dll\n");
fflush(stderr);
return E_FAIL;
}
fprintf(stderr, "Found it!\n");
fflush(stderr);
JavaVMOption options[2];
JavaVMInitArgs vm_args = { 0 };
vm_args.version = JNI_VERSION_1_8;
vm_args.nOptions = sizeof(options)/sizeof(options[0]);
vm_args.options = options;
options[0].optionString = "-Xrs";
options[1].optionString = "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005";
vm_args.ignoreUnrecognized = false;
CreateJavaVMFunc create_jvm = NULL;
//create_jvm = JNI_CreateJavaVM;
create_jvm = (CreateJavaVMFunc) GetProcAddress(jvmDll, "JNI_CreateJavaVM");
jint jni_result = create_jvm(&jvm, (void**)&env, &vm_args);
if (jni_result != JNI_OK) {
jvm = NULL;
fprintf(stderr, "Could not initialize JVM: %d: ", jni_result);
switch (jni_result) {
case JNI_ERR:
fprintf(stderr, "unknown error");
break;
case JNI_EDETACHED:
fprintf(stderr, "thread detached from the VM");
break;
case JNI_EVERSION:
fprintf(stderr, "JNI version error");
break;
case JNI_ENOMEM:
fprintf(stderr, "not enough memory");
break;
case JNI_EEXIST:
fprintf(stderr, "VM already created");
break;
case JNI_EINVAL:
fprintf(stderr, "invalid arguments");
break;
}
fprintf(stderr, "\n");
fflush(stderr);
return E_FAIL;
}
HMODULE hJavaProviderModule = GetModuleHandle(TEXT("javaprovider"));
HRSRC resCommandsClassfile = FindResource(hJavaProviderModule, MAKEINTRESOURCE(IDR_CLASSFILE1), TEXT("Classfile"));
HGLOBAL gblCommandsClassfile = LoadResource(hJavaProviderModule, resCommandsClassfile);
LPVOID lpCommandsClassfile = LockResource(gblCommandsClassfile);
DWORD szCommandsClassfile = SizeofResource(hJavaProviderModule, resCommandsClassfile);
clsCommands = env->DefineClass(
"javaprovider/Commands", NULL, (jbyte*) lpCommandsClassfile, szCommandsClassfile
);
if (clsCommands == NULL) {
fprintf(stderr, "Could not define Commands class\n");
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
return E_FAIL;
}
}
return S_OK;
}
void EXT_CLASS::Uninitialize() {
if (jvm != NULL) {
jvm->DestroyJavaVM();
}
ExtExtension::Uninitialize();
}
void EXT_CLASS::run_command(PCSTR name) {
// TODO: Throw an exception during load, then!
if (jvm == NULL) {
Out("javaprovider extension did not load properly.\n");
return;
}
if (clsCommands == NULL) {
Out("javaprovider extension did not load properly.\n");
return;
}
PCSTR args = GetRawArgStr();
jmethodID mthCommand = env->GetStaticMethodID(clsCommands, name, "(Ljava/lang/String;)V");
if (mthCommand == NULL) {
Out("INTERNAL ERROR: No such command: %s\n", name);
return;
}
jstring argsStr = env->NewStringUTF(args);
if (argsStr == NULL) {
Out("Could not create Java string for arguments.\n");
return;
}
env->CallStaticVoidMethod(clsCommands, mthCommand, argsStr);
env->DeleteLocalRef(argsStr);
if (env->ExceptionCheck()) {
Out("Exception during javaprovider command:\n");
env->ExceptionDescribe(); // TODO: Send this to output callbacks, not console.
env->ExceptionClear();
}
}
EXT_COMMAND(java_add_cp, "Add an element to the class path", "{{custom}}") {
run_command("java_add_cp");
}
EXT_COMMAND(java_set, "Set a Java system property", "{{custom}}") {
run_command("java_set");
}
EXT_COMMAND(java_get, "Get a Java system property", "{{custom}}") {
run_command("java_get");
}
EXT_COMMAND(java_run, "Execute the named java class", "{{custom}}") {
run_command("java_run");
}
#define JNA extern "C" __declspec(dllexport)
JNA HRESULT createClient(PDEBUG_CLIENT* client) {
return g_ExtInstance.m_Client->CreateClient(client);
}

View file

@ -1,13 +0,0 @@
EXPORTS
; For ExtCpp
DebugExtensionInitialize
DebugExtensionUninitialize
DebugExtensionNotify
help
; My Commands
java_add_cp
java_set
java_get
java_run

View file

@ -1,16 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <Windows.h>

View file

@ -1,31 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by javaprovider.rc
//
#define IDR_CLASSFILE1 101
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View file

@ -1,95 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package agent.dbgeng;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import agent.dbgeng.model.impl.DbgModelImpl;
import ghidra.dbg.DebuggerModelFactory;
import ghidra.dbg.DebuggerObjectModel;
import ghidra.dbg.util.ConfigurableFactory.FactoryDescription;
import ghidra.program.model.listing.Program;
@FactoryDescription(
brief = "MS dbgeng.dll (WinDbg)",
htmlDetails = """
Connect to the Microsoft Debug Engine.
This is the same engine that powers WinDbg.
This is best for most Windows userspace and kernel targets.
Kernel debugging is still experimental.
This will access the native API, which may put Ghidra's JVM at risk.""")
public class DbgEngInJvmDebuggerModelFactory implements DebuggerModelFactory {
protected String remote = "none"; // Require user to start server
@FactoryOption("DebugConnect options (.server)")
public final Property<String> agentRemoteOption =
Property.fromAccessors(String.class, this::getAgentRemote, this::setAgentRemote);
protected String transport = "none"; // Require user to start server
@FactoryOption("Remote process server options (untested)")
public final Property<String> agentTransportOption =
Property.fromAccessors(String.class, this::getAgentTransport, this::setAgentTransport);
@Override
public CompletableFuture<? extends DebuggerObjectModel> build() {
DbgModelImpl model = new DbgModelImpl();
List<String> cmds = new ArrayList<>();
completeCommandLine(cmds);
return model.startDbgEng(cmds.toArray(new String[cmds.size()])).thenApply(__ -> model);
}
@Override
public int getPriority(Program program) {
// TODO: Might instead look for the DLL
if (!System.getProperty("os.name").toLowerCase().contains("windows")) {
return -1;
}
if (program != null) {
String exe = program.getExecutablePath();
if (exe == null || exe.isBlank()) {
return -1;
}
}
return 80;
}
public String getAgentTransport() {
return transport;
}
public void setAgentTransport(String transport) {
this.transport = transport;
}
public String getAgentRemote() {
return remote;
}
public void setAgentRemote(String remote) {
this.remote = remote;
}
protected void completeCommandLine(List<String> cmd) {
if (!remote.equals("none") && !remote.equals("")) {
cmd.addAll(List.of(remote));
}
if (!transport.equals("none") && !transport.equals("")) {
cmd.addAll(List.of(transport));
}
}
}

View file

@ -1,72 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package agent.dbgeng.dbgeng;
import com.sun.jna.platform.win32.WinNT.HRESULT;
import com.sun.jna.platform.win32.COM.COMException;
import com.sun.jna.platform.win32.COM.COMUtils;
/**
* Utilities for interacting with Microsoft COM objects beyond those provided by {@link COMUtils}.
*
* See the MSDN for details on the meanings of the return codes for the function or method of
* interest.
*/
public interface COMUtilsExtra {
public static HRESULT E_UNEXPECTED = new HRESULT(0x8000FFFF);
public static HRESULT E_BOUNDS = new HRESULT(0x8000000B);
public static HRESULT E_NOTIMPLEMENTED = new HRESULT(0x80004001);
public static HRESULT E_NOINTERFACE = new HRESULT(0x80004002);
public static HRESULT E_COM_EXC = new HRESULT(0x80004003);
public static HRESULT E_FAIL = new HRESULT(0x80004005);
public static HRESULT E_CANTCALLOUT_INASYNCCALL = new HRESULT(0x80010004);
public static HRESULT E_INTERNALEXCEPTION = new HRESULT(0x80040205);
public static HRESULT E_ACCESS_DENIED = new HRESULT(0x80070005);
public static HRESULT E_CANNOT_READ = new HRESULT(0x8007001E);
public static HRESULT E_INVALID_PARAM = new HRESULT(0x80070057);
public static HRESULT E_SCOPE_NOT_FOUND = new HRESULT(0x8007013E);
/**
* Check if the given exception represents an {@code E_NOINTERFACE} result
*
* @param e the exception
* @return true if {@code E_NOINTERFACE}
*/
static boolean isE_NOINTERFACE(COMException e) {
return E_NOINTERFACE.equals(e.getHresult());
}
/**
* Check if the given exception represents an {@code E_UNEXPECTED} result
*
* @param e the exception
* @return true if {@code E_UNEXPECTED}
*/
static boolean isE_UNEXPECTED(COMException e) {
return E_UNEXPECTED.equals(e.getHresult());
}
/**
* Check if the given exception represents an {@code E_INTERNALEXCEPTION} result
*
* @param e the exception
* @return true if {@code E_INTERNALEXCEPTION}
*/
static boolean isE_INTERNALEXCEPTION(COMException e) {
return E_INTERNALEXCEPTION.equals(e.getHresult());
}
}

View file

@ -1,163 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package agent.dbgeng.dbgeng;
import java.lang.ref.Cleaner;
import com.sun.jna.WString;
import com.sun.jna.platform.win32.Kernel32Util;
import com.sun.jna.platform.win32.WinDef.DWORD;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.platform.win32.COM.IUnknown;
import agent.dbgeng.impl.dbgeng.client.DebugClientInternal;
import agent.dbgeng.jna.dbgeng.DbgEngNative;
import ghidra.comm.util.BitmaskSet;
import ghidra.util.Msg;
/**
* A wrapper for Microsoft's {@code dbgeng.dll} that presents a Java-friendly interface.
*
* This is the "root interface" from which all other interfaces to {@code dbgeng.dll} are generated.
* Not every method listed in the documentation, nor every method present in the header, is
* implemented. Only those that were necessary to implement the SCTL adapter. However, the class and
* interface hierarchy was designed so that adding the remaining methods should be fairly
* straightforward. This wrapper attempts to obtain the most capable COM interfaces for the debug
* client that it knows. Again, newer interfaces should be fairly straightforward to add.
*
* Methods that are "obviously" wrappers for a COM method are left undocumented, unless there is
* some nuance to how it has been wrapped. In many cases, a parameter which is an integer in the COM
* method may be presented as an {@code enum} or {@link BitmaskSet} by the wrapper. Consult the MSDN
* for the meaning of the various values and bit flags.
*
* Each wrapper interface is implemented by several COM interface wrappers: one for each known COM
* interface version. The wrapper is optimistic, in that it declares wrapper methods even for COM
* methods that are only available in later versions. The implementations limited to earlier COM
* interfaces should either emulate the operation, or throw an
* {@link UnsupportedOperationException}. Where a newer method is provided by a newer interface, a
* wrapper implementation should prefer the latest. For example, one series of interfaces introduces
* {@code *Wide} variants of existing methods. Since Java also uses a UTF-16-like string encoding
* internally, JNA permits wide strings to be passed by reference. Thus, the wide variant is always
* preferred.
*
* Pay careful attention to the threading requirements imposed by {@code dbgeng.dll} these can be
* found in the MSDN. As a general rule of thumb, if the method is reentrant (i.e., it can be called
* from any thread), it is declared in the {@code *Reentrant} variant of the wrapper interface.
* There are few of these. Unless the documentation explicitly lists the method as reentrant, do not
* declare it there. Many methods appear to execute successfully from the wrong thread, but cause
* latent issues. A practice to prevent accidental use of non-reentrant methods outside of the
* client's owning thread is to ensure that only the owning thread can see the full interface. All
* other threads should only have access to the reentrant interface.
*
* If you implement methods that introduce a new callback class, use the existing callback type
* hierarchies as a model. There are many classes to implement. Furthermore, be sure to keep a
* reference to any active callback instances within the wrapper that uses them. The JNA has no way
* of knowing whether or not the instance is still being used by the external C/C++ library. If you
* do not store a reference, the JVM will think it's garbage and free it, even though COM is still
* using it. Drop the reference only when you are certain nothing external has a reference to it.
*/
public class DbgEng {
private static final Cleaner CLEANER = Cleaner.create();
private static class ReleaseCOMObject implements Runnable {
private final IUnknown obj;
ReleaseCOMObject(IUnknown obj) {
this.obj = obj;
}
@Override
public void run() {
Msg.debug(this, "Releasing COM object: " + obj);
obj.Release();
}
}
private static class ReleaseHANDLE implements Runnable {
private final HANDLE handle;
public ReleaseHANDLE(HANDLE handle) {
this.handle = handle;
}
@Override
public void run() {
Kernel32Util.closeHandle(handle);
}
}
public static class OpaqueCleanable {
@SuppressWarnings("unused") // A reference to control GC
private final Object state;
@SuppressWarnings("unused") // A reference to control GC
private final Cleaner.Cleanable cleanable;
public OpaqueCleanable(Object state, Cleaner.Cleanable cleanable) {
this.state = state;
this.cleanable = cleanable;
}
}
public static OpaqueCleanable releaseWhenPhantom(Object owner, IUnknown obj) {
ReleaseCOMObject state = new ReleaseCOMObject(obj);
return new OpaqueCleanable(state, CLEANER.register(owner, state));
}
public static OpaqueCleanable releaseWhenPhantom(Object owner, HANDLE handle) {
ReleaseHANDLE state = new ReleaseHANDLE(handle);
return new OpaqueCleanable(state, CLEANER.register(owner, state));
}
/**
* Connect to a debug session.
*
* See {@code DebugConnect} or {@code DebugConnectWide} on the MSDN.
*
* @param remoteOptions the options, like those given to {@code -remote}
* @return a new client connected as specified
*/
public static DebugClient debugConnect(String remoteOptions) {
WString options = new WString(remoteOptions);
return DebugClientInternal.tryPreferredInterfaces((refiid,
ppClient) -> DbgEngNative.INSTANCE.DebugConnectWide(options, refiid, ppClient));
}
/**
* Create a debug client.
*
* Typically, this client is connected to the "local server". See {@code DebugCreate} on the
* MSDN.
*
* @return a new client
*/
public static DebugClient debugCreate() {
return DebugClientInternal.tryPreferredInterfaces(DbgEngNative.INSTANCE::DebugCreate);
}
/**
* Create a debug client with the given options.
*
* See {@code DebugCreateEx} on the MSDN.
*
* @param options the options
* @return a new client
*/
public static DebugClient debugCreate(int options) {
DWORD dwOpts = new DWORD(options);
return DebugClientInternal.tryPreferredInterfaces(
(refiid, ppClient) -> DbgEngNative.INSTANCE.DebugCreateEx(refiid, dwOpts, ppClient));
}
}

View file

@ -1,83 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package agent.dbgeng.dbgeng;
/**
* A wrapper for {@code IDebugAdvanced} and its newer variants.
*/
public interface DebugAdvanced {
public static class DebugThreadBasicInformation {
public final Integer exitStatus;
public final Integer priorityClass;
public final Integer priority;
public final Long createTime;
public final Long exitTime;
public final Long kernelTime;
public final Long userTime;
public final Long startOffset;
public final Long affinity;
public DebugThreadBasicInformation(Integer exitStatus, Integer priorityClass,
Integer priority, Long createTime, Long exitTime, Long kernelTime, Long userTime,
Long startOffset, Long affinity) {
this.exitStatus = exitStatus;
this.priorityClass = priorityClass;
this.priority = priority;
this.createTime = createTime;
this.exitTime = exitTime;
this.kernelTime = kernelTime;
this.userTime = userTime;
this.startOffset = startOffset;
this.affinity = affinity;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("<DebugThreadBasicInformation:\n");
if (exitStatus != null) {
sb.append(" exitStatus: " + exitStatus + "\n");
}
if (priorityClass != null) {
sb.append(" priorityClass: " + priorityClass + "\n");
}
if (priority != null) {
sb.append(" priority: " + priority + "\n");
}
if (createTime != null) {
sb.append(" createTime: " + createTime + "\n");
}
if (exitTime != null) {
sb.append(" exitTime: " + exitTime + "\n");
}
if (kernelTime != null) {
sb.append(" kernelTime: " + kernelTime + "\n");
}
if (userTime != null) {
sb.append(" userTime: " + userTime + "\n");
}
if (startOffset != null) {
sb.append(" startOffset: " + startOffset + "\n");
}
if (affinity != null) {
sb.append(" affinity: " + affinity + "\n");
}
sb.append(">");
return sb.toString();
}
}
DebugThreadBasicInformation getThreadBasicInformation(DebugThreadId tid);
}

View file

@ -1,137 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package agent.dbgeng.dbgeng;
import agent.dbgeng.jna.dbgeng.WinNTExtra.Machine;
import ghidra.comm.util.BitmaskSet;
import ghidra.comm.util.BitmaskUniverse;
/**
* A wrapper for {@code IDebugBreakpoint} and its newer variants.
*/
public interface DebugBreakpoint {
public static enum BreakType {
CODE, DATA, TIME, INLINE;
}
public static class BreakFullType {
public final BreakType breakType;
public final Machine procType; // TODO: Guessing the values are from WinNT
public BreakFullType(BreakType breakType, Machine procType) {
this.breakType = breakType;
this.procType = procType;
}
}
public static enum BreakFlags implements BitmaskUniverse {
GO_ONLY(1 << 0), //
DEFERRED(1 << 1), //
ENABLED(1 << 2), //
ADDER_ONLY(1 << 3), //
ONE_SHOT(1 << 4), //
;
private BreakFlags(int mask) {
this.mask = mask;
}
private final int mask;
@Override
public long getMask() {
return mask;
}
}
public static enum BreakAccess implements BitmaskUniverse {
READ(1 << 0), //
WRITE(1 << 1), //
EXECUTE(1 << 2), //
IO(1 << 3), //
;
private BreakAccess(int mask) {
this.mask = mask;
}
private final int mask;
@Override
public long getMask() {
return mask;
}
}
public static class BreakDataParameters {
public int size;
public BitmaskSet<BreakAccess> access;
public BreakDataParameters(int size, BitmaskSet<BreakAccess> access) {
this.size = size;
this.access = access;
}
}
void remove();
int getId();
BreakFullType getType();
DebugClient getAdder();
BitmaskSet<BreakFlags> getFlags();
void addFlags(BitmaskSet<BreakFlags> flags);
void addFlags(BreakFlags... flags);
void removeFlags(BitmaskSet<BreakFlags> flags);
void removeFlags(BreakFlags... flags);
void setFlags(BitmaskSet<BreakFlags> flags);
void setFlags(BreakFlags... flags);
/**
* Get the location on target that triggers the breakpoint
*
* <p>
* If the breakpoint is deferred, this will return {@code null}. In that case, use
* {@link #getOffsetExpression()}.
*
* @return the offset, or {@code null}
*/
Long getOffset();
void setOffset(long offset);
String getOffsetExpression();
void setOffsetExpression(String expression);
BreakDataParameters getDataParameters();
void setDataParameters(BreakDataParameters params);
void setDataParameters(int size, BitmaskSet<BreakAccess> access);
void setDataParameters(int size, BreakAccess... access);
void dispose();
}

View file

@ -1,434 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package agent.dbgeng.dbgeng;
import java.util.List;
import com.sun.jna.platform.win32.WinBase;
import agent.dbgeng.dbgeng.DebugRunningProcess.Description;
import agent.dbgeng.dbgeng.DebugRunningProcess.Description.ProcessDescriptionFlags;
import ghidra.comm.util.BitmaskSet;
import ghidra.comm.util.BitmaskUniverse;
/**
* A wrapper for {@code IDebugClient} and its newer variants.
*/
public interface DebugClient extends DebugClientReentrant {
public static enum ExecutionState {
RUNNING, STOPPED;
}
public static enum DebugStatus {
NO_CHANGE(false, null, 13), //
GO(true, ExecutionState.RUNNING, 10), //
GO_HANDLED(true, ExecutionState.RUNNING, 9), //
GO_NOT_HANDLED(true, ExecutionState.RUNNING, 8), //
STEP_OVER(true, ExecutionState.RUNNING, 7), //
STEP_INTO(true, ExecutionState.RUNNING, 5), //
BREAK(false, ExecutionState.STOPPED, 0), //
NO_DEBUGGEE(true, null, 1), // shouldWait is true to handle process creation
STEP_BRANCH(true, ExecutionState.RUNNING, 6), //
IGNORE_EVENT(false, null, 11), //
RESTART_REQUESTED(true, null, 12), //
REVERSE_GO(true, null, 0xff), //
REVERSE_STEP_BRANCH(true, null, 0xff), //
REVERSE_STEP_OVER(true, null, 0xff), //
REVERSE_STEP_INTO(true, null, 0xff), //
OUT_OF_SYNC(false, null, 2), //
WAIT_INPUT(false, null, 3), //
TIMEOUT(false, null, 4), //
;
public static final long MASK = 0xaf;
public static final long INSIDE_WAIT = 0x100000000L;
public static final long WAIT_TIMEOUT = 0x200000000L;
DebugStatus(boolean shouldWait, ExecutionState threadState, int precedence) {
this.shouldWait = shouldWait;
this.threadState = threadState;
this.precedence = precedence;
}
public final boolean shouldWait;
public final ExecutionState threadState;
public final int precedence; // 0 is highest
public static DebugStatus fromArgument(long argument) {
return values()[(int) (argument & MASK)];
}
public static boolean isInsideWait(long argument) {
return (argument & INSIDE_WAIT) != 0;
}
public static boolean isWaitTimeout(long argument) {
return (argument & WAIT_TIMEOUT) != 0;
}
}
public static enum SessionStatus {
ACTIVE, //
END_SESSION_ACTIVE_TERMINATE,//
END_SESSION_ACTIVE_DETACH, //
END_SESSION_PASSIVE, //
END, //
REBOOT, //
HIBERNATE, //
FAILURE, //
;
}
public static enum ChangeDebuggeeState implements BitmaskUniverse {
ALL(0xffffffff), //
REGISTERS(1 << 0), //
DATA(1 << 1), //
REFRESH(1 << 2), //
;
private ChangeDebuggeeState(int mask) {
this.mask = mask;
}
private final int mask;
@Override
public long getMask() {
return mask;
}
}
public static enum ChangeEngineState implements BitmaskUniverse {
ALL(0xffffffff), //
CURRENT_THREAD(1 << 0), //
EFFECTIVE_PROCESSOR(1 << 1), //
BREAKPOINTS(1 << 2), //
CODE_LEVEL(1 << 3), //
EXECUTION_STATUS(1 << 4), //
ENGINE_OPTIONS(1 << 5), //
LOG_FILE(1 << 6), //
RADIX(1 << 7), //
EVENT_FILTERS(1 << 8), //
PROCESS_OPTIONS(1 << 9), //
EXTENSIONS(1 << 10), //
SYSTEMS(1 << 11), //
ASSEMBLY_OPTIONS(1 << 12), //
EXPRESSION_SYNTAX(1 << 13), //
TEXT_REPLACEMENTS(1 << 14), //
;
private ChangeEngineState(int mask) {
this.mask = mask;
}
private final int mask;
@Override
public long getMask() {
return mask;
}
}
public static enum ChangeSymbolState implements BitmaskUniverse {
ALL(0xffffffff), //
LOADS(1 << 0), //
UNLOADS(1 << 1), //
SCOPE(1 << 2), //
PATHS(1 << 3), //
SYMBOL_OPTIONS(1 << 4), //
TYPE_OPTIONS(1 << 5), //
;
private ChangeSymbolState(int mask) {
this.mask = mask;
}
private final int mask;
@Override
public long getMask() {
return mask;
}
}
public static enum DebugAttachFlags implements BitmaskUniverse {
DEFAULT(0), //
NONINVASIVE(1 << 0), //
EXISTING(1 << 1), //
NONINVASIVE_NO_SUSPEND(1 << 2), //
INVASIVE_NO_INITIAL_BREAK(1 << 3), //
INVASIVE_RESUME_PROCESS(1 << 4), //
NONINVASIVE_ALLOW_PARTIAL(1 << 5), //
;
DebugAttachFlags(int mask) {
this.mask = mask;
}
private final int mask;
@Override
public long getMask() {
return mask;
}
}
public static enum DebugCreateFlags implements BitmaskUniverse {
DEBUG_PROCESS(WinBase.DEBUG_PROCESS), //
DEBUG_ONLY_THIS_PROCESS(WinBase.DEBUG_ONLY_THIS_PROCESS), //
CREATE_SUSPENDED(WinBase.CREATE_SUSPENDED), //
DETACHED_PROCESS(WinBase.DETACHED_PROCESS), //
CREATE_NEW_CONSOLE(WinBase.CREATE_NEW_CONSOLE), //
//NORMAL_PRIORITY_CLASS(WinBase.NORMAL_PRIORITY_CLASS), //
//IDLE_PRIORITY_CLASS(WinBase.IDLE_PRIORITY_CLASS), //
//HIGH_PRIORITY_CLASS(WinBase.HIGH_PRIORITY_CLASS), //
//REALTIME_PRIORITY_CLASS(WinBase.REALTIME_PRIORITY_CLASS), //
CREATE_NEW_PROCESS_GROUP(WinBase.CREATE_NEW_PROCESS_GROUP), //
CREATE_UNICODE_ENVIRONMENT(WinBase.CREATE_UNICODE_ENVIRONMENT), //
CREATE_SEPARATE_WOW_VDM(WinBase.CREATE_SEPARATE_WOW_VDM), //
CREATE_SHARED_WOW_VDM(WinBase.CREATE_SHARED_WOW_VDM), //
CREATE_FORCEDOS(WinBase.CREATE_FORCEDOS), //
//BELOW_NORMAL_PRIORITY_CLASS(WinBase.BELOW_NORMAL_PRIORITY_CLASS), //
//ABOVE_NORMAL_PRIORITY_CLASS(WinBase.ABOVE_NORMAL_PRIORITY_CLASS), //
INHERIT_PARENT_AFFINITY(WinBase.INHERIT_PARENT_AFFINITY), //
//INHERIT_CALLER_PRIORITY(WinBase.INHERIT_CALLER_PRIORITY), //
CREATE_PROTECTED_PROCESS(WinBase.CREATE_PROTECTED_PROCESS), //
EXTENDED_STARTUPINFO_PRESENT(WinBase.EXTENDED_STARTUPINFO_PRESENT), //
//PROCESS_MODE_BACKGROUND_BEGIN(WinBase.PROCESS_MODE_BACKGROUND_BEGIN), //
//PROCESS_MODE_BACKGROUND_END(WinBase.PROCESS_MODE_BACKGROUND_END), //
CREATE_BREAKAWAY_FROM_JOB(WinBase.CREATE_BREAKAWAY_FROM_JOB), //
CREATE_PRESERVE_CODE_AUTHZ_LEVEL(WinBase.CREATE_PRESERVE_CODE_AUTHZ_LEVEL), //
CREATE_DEFAULT_ERROR_MODE(WinBase.CREATE_DEFAULT_ERROR_MODE), //
CREATE_NO_WINDOW(WinBase.CREATE_NO_WINDOW), //
//PROFILE_USER(WinBase.PROFILE_USER), //
//PROFILE_KERNEL(WinBase.PROFILE_KERNEL), //
//PROFILE_SERVER(WinBase.PROFILE_SERVER), //
//CREATE_IGNORE_SYSTEM_DEFAULT(WinBase.CREATE_IGNORE_SYSTEM_DEFAULT), //
DEBUG_CREATE_NO_DEBUG_HEAP(0x00000400), //
DEBUG_CREATE_THROUGH_RTL(0x00010000), //
;
DebugCreateFlags(int mask) {
this.mask = mask;
}
private final int mask;
@Override
public long getMask() {
return mask;
}
}
public enum DebugEngCreateFlags implements BitmaskUniverse {
DEBUG_ECREATE_PROCESS_DEFAULT(0x00000000),
DEBUG_ECREATE_INHERIT_HANDLES(0x00000001),
DEBUG_ECREATE_USE_VERIFIER_FLAGS(0x00000002),
DEBUG_ECREATE_USE_IMPLICIT_COMMAND_LINE(0x00000004);
DebugEngCreateFlags(int mask) {
this.mask = mask;
}
private final int mask;
@Override
public long getMask() {
return mask;
}
}
public enum DebugVerifierFlags implements BitmaskUniverse {
DEBUG_VERIFIER_DEFAULT(0x00000000);
DebugVerifierFlags(int mask) {
this.mask = mask;
}
private final int mask;
@Override
public long getMask() {
return mask;
}
}
public enum DebugEndSessionFlags {
DEBUG_END_PASSIVE(0x00000000),
DEBUG_END_ACTIVE_TERMINATE(0x00000001),
DEBUG_END_ACTIVE_DETACH(0x00000002),
DEBUG_END_REENTRANT(0x00000003),
DEBUG_END_DISCONNECT(0x00000004);
DebugEndSessionFlags(int value) {
this.value = value;
}
private final int value;
public long getValue() {
return value;
}
}
public enum DebugOutputFlags {
DEBUG_OUTPUT_NORMAL(0x1), //
DEBUG_OUTPUT_ERROR(0x2), //
DEBUG_OUTPUT_WARNING(0x4), //
DEBUG_OUTPUT_VERBOSE(0x8), //
DEBUG_OUTPUT_PROMPT(0x10), //
DEBUG_OUTPUT_PROMPT_REGISTERS(0x20), //
DEBUG_OUTPUT_EXTENSION_WARNING(0x40), //
DEBUG_OUTPUT_DEBUGGEE(0x80), //
DEBUG_OUTPUT_DEBUGGEE_PROMPT(0x100), //
DEBUG_OUTPUT_SYMBOLS(0x200);
DebugOutputFlags(int value) {
this.value = value;
}
private final int value;
public long getValue() {
return value;
}
}
/**
* Obtain the advanced interface to this client.
*
* @return the advanced interface
*/
DebugAdvanced getAdvanced();
/**
* Obtain the control interface to this client
*
* @return the control interface
*/
@Override
DebugControl getControl();
/**
* Obtain the data spaces interface to this client
*
* @return the data spaces interface
*/
DebugDataSpaces getDataSpaces();
/**
* Obtain the registers interface to this client
*
* @return the registers interface
*/
DebugRegisters getRegisters();
/**
* Obtain the symbols interface to this client
*
* @return the symbols interface
*/
DebugSymbols getSymbols();
/**
* Obtain the system objects interface to this client
*
* @return the system objects interface
*/
DebugSystemObjects getSystemObjects();
/**
* The the ID for the local server
*
* @return the ID
*/
DebugServerId getLocalServer();
void attachKernel(long flags, String options);
void startProcessServer(String options);
DebugServerId connectProcessServer(String options);
boolean dispatchCallbacks(int timeout);
void flushCallbacks();
default void dispatchCallbacks() {
this.dispatchCallbacks(-1);
}
void exitDispatch(DebugClient client);
default void exitDispatch() {
exitDispatch(this);
}
void setInputCallbacks(DebugInputCallbacks cb);
void setOutputCallbacks(DebugOutputCallbacks cb);
void setEventCallbacks(DebugEventCallbacks cb);
List<DebugRunningProcess> getRunningProcesses(DebugServerId server);
Description getProcessDescription(DebugServerId si, int systemId,
BitmaskSet<ProcessDescriptionFlags> flags);
void attachProcess(DebugServerId si, long processId, BitmaskSet<DebugAttachFlags> attachFlags);
void createProcess(DebugServerId si, String commandLine,
String initialDirectory, String environment,
BitmaskSet<DebugCreateFlags> createFlags,
BitmaskSet<DebugEngCreateFlags> engCreateFlags,
BitmaskSet<DebugVerifierFlags> verifierFlags);
void createProcessAndAttach(DebugServerId si, String commandLine,
BitmaskSet<DebugCreateFlags> createFlags, int processId,
BitmaskSet<DebugAttachFlags> attachFlags);
void startServer(String options);
// Only in IDebugClient2
void waitForProcessServerEnd(int timeout);
default void waitForProcessServerEnd() {
waitForProcessServerEnd(-1);
}
void terminateCurrentProcess();
void detachCurrentProcess();
void abandonCurrentProcess();
void connectSession(int flags);
void endSession(DebugEndSessionFlags flags);
// Only in IDebugClient4+
void openDumpFileWide(String fileName);
}

View file

@ -1,46 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package agent.dbgeng.dbgeng;
/**
* An interface containing the subset of {@link DebugClient} methods which are reentrant.
*
* All other methods should be called only by the thread which created the client.
*/
public interface DebugClientReentrant {
/**
* Create a new client for the calling thread, connected to the same session as this client.
*
* @return the new client
*/
DebugClient createClient();
/**
* Get the reentrant control interface to the client
*
* @return the control interface
*/
DebugControlReentrant getControl();
/**
* End a session without acquiring locks
*
* Note. This method calls {@code IDebugClient::EndSession(DEBUG_END_REENTRANT)}. Per the MSDN,
* this may leave the engine in an indeterminate state. The engine should no longer be used by
* this process. It's really only appropriate to use this method when terminating the debugger.
*/
void endSessionReentrant();
}

View file

@ -1,447 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package agent.dbgeng.dbgeng;
import java.util.ArrayList;
import java.util.List;
import com.sun.jna.platform.win32.WinBase;
import com.sun.jna.platform.win32.COM.COMException;
import agent.dbgeng.dbgeng.DebugBreakpoint.BreakType;
import agent.dbgeng.dbgeng.DebugClient.DebugStatus;
import ghidra.comm.util.BitmaskSet;
import ghidra.comm.util.BitmaskUniverse;
import ghidra.util.Msg;
/**
* A wrapper for {@code IDebugControl} and its newer variants.
*/
public interface DebugControl extends DebugControlReentrant {
public static final BitmaskSet<DebugOutputControl> SET_ALL_CLIENTS =
BitmaskSet.of(DebugOutputControl.ALL_CLIENTS);
public static final BitmaskSet<DebugExecute> SET_DEFAULT = BitmaskSet.of(DebugExecute.DEFAULT);
public static enum DebugOutputLevel implements BitmaskUniverse {
NORMAL(1 << 0), //
ERROR(1 << 1), //
WARNING(1 << 2), //
VERBOSE(1 << 3), //
PROMPT(1 << 4), //
PROMPT_REGISTERS(1 << 5), //
EXTENSION_WARNING(1 << 6), //
OUTPUT_DEBUGEE(1 << 7), //
OUTPUT_DEBUGEE_PROMPT(1 << 8), //
OUTPUT_SYMBOLS(1 << 9), //
OUTPUT_STATUS(1 << 10), //
;
private final int mask;
DebugOutputLevel(int mask) {
this.mask = mask;
}
@Override
public long getMask() {
return mask;
}
}
public static enum DebugOutputControl implements BitmaskUniverse {
THIS_CLIENT(0), //
ALL_CLIENTS(1), //
ALL_OTHER_CLIENTS(2), //
IGNORE(3), //
LOG_ONLY(4), //
SEND_MASK(7), //
NOT_LOGGED(1 << 3), //
OVERRIDE_MASK(1 << 4), //
DML(1 << 5), //
AMBIENT_DML(0xfffffffe), //
AMBIENT_TEXT(0xffffffff), //
AMBIENT(0xffffffff), //
;
private final int mask;
DebugOutputControl(int mask) {
this.mask = mask;
}
@Override
public long getMask() {
return mask;
}
}
public static enum DebugExecute implements BitmaskUniverse {
DEFAULT(0), //
ECHO(1 << 0), //
NOT_LOGGED(1 << 1), //
NO_REPEAT(1 << 2), //
;
private final int mask;
DebugExecute(int mask) {
this.mask = mask;
}
@Override
public long getMask() {
return mask;
}
}
public static enum DebugInterrupt {
ACTIVE, //
PASSIVE, //
EXIT, //
;
}
public static enum DebugFilterOrdinals {
DEBUG_FILTER_CREATE_THREAD, //
DEBUG_FILTER_EXIT_THREAD, //
DEBUG_FILTER_CREATE_PROCESS, //
DEBUG_FILTER_EXIT_PROCESS, //
DEBUG_FILTER_LOAD_MODULE, //
DEBUG_FILTER_UNLOAD_MODULE, //
DEBUG_FILTER_SYSTEM_ERROR, //
DEBUG_FILTER_INITIAL_BREAKPOINT, //
DEBUG_FILTER_INITIAL_MODULE_LOAD, //
DEBUG_FILTER_DEBUGGEE_OUTPUT, //
;
}
public static enum DebugFilterExecutionOption {
DEBUG_FILTER_BREAK(0, "Break"), //
DEBUG_FILTER_SECOND_CHANCE_BREAK(1, "Second-chance Break"), //
DEBUG_FILTER_OUTPUT(2, "Output-only"), //
DEBUG_FILTER_IGNORE(3, "Ignore"), //
DEBUG_FILTER_REMOVE(4, "Remove"), //
;
public static DebugFilterExecutionOption getByNumber(int val) {
for (DebugFilterExecutionOption m : DebugFilterExecutionOption.values()) {
if (m.val == val) {
return m;
}
}
return null;
}
DebugFilterExecutionOption(int val, String description) {
this.val = val;
this.description = description;
}
public final int val;
public final String description;
}
public static enum DebugFilterContinuationOption {
DEBUG_FILTER_GO_HANDLED(0, "Handled"), //
DEBUG_FILTER_GO_NOT_HANDLED(1, "Not Handled"), //
;
public static DebugFilterContinuationOption getByNumber(int val) {
for (DebugFilterContinuationOption m : DebugFilterContinuationOption.values()) {
if (m.val == val) {
return m;
}
}
return null;
}
DebugFilterContinuationOption(int val, String description) {
this.val = val;
this.description = description;
}
public final int val;
public final String description;
}
boolean getInterrupt();
int getInterruptTimeout();
void setInterruptTimeout(int seconds);
void print(BitmaskSet<DebugOutputLevel> levels, String message);
/**
* A shortcut for {@link #print(BitmaskSet, String)} that includes a newline.
*
* @param levels the log levels for the message
* @param message the message
*/
void println(BitmaskSet<DebugOutputLevel> levels, String message);
/**
* A shortcut for {@link #print(BitmaskSet, String)} that applies to a single level.
*
* @param level the log level for the message
* @param message the message
*/
default void print(DebugOutputLevel level, String message) {
print(BitmaskSet.of(level), message);
}
/**
* A shortcut for {@link #print(BitmaskSet, String)} that includes a newline and applies to a
* single level.
*
* @param level the log level for the message
* @param message the message
*/
default void println(DebugOutputLevel level, String message) {
println(BitmaskSet.of(level), message);
}
/**
* A shortcut for {@link #print(BitmaskSet, String)} at normal level.
*
* @param message the message
*/
default void out(String message) {
print(DebugOutputLevel.NORMAL, message);
}
/**
* A shortcut for {@link #println(BitmaskSet, String)} at normal level.
*
* @param message the message
*/
default void outln(String message) {
println(DebugOutputLevel.NORMAL, message);
}
/**
* A shortcut for {@link #print(BitmaskSet, String)} at warning level.
*
* @param message the message
*/
default void warn(String message) {
print(DebugOutputLevel.WARNING, message);
}
/**
* A shortcut for {@link #println(BitmaskSet, String)} at warning level.
*
* @param message the message
*/
default void warnln(String message) {
println(DebugOutputLevel.WARNING, message);
}
/**
* A shortcut for {@link #print(BitmaskSet, String)} at error level.
*
* @param message the message
*/
default void err(String message) {
print(DebugOutputLevel.ERROR, message);
}
/**
* A shortcut for {@link #println(BitmaskSet, String)} at error level.
*
* @param message the message
*/
default void errln(String message) {
println(DebugOutputLevel.ERROR, message);
}
/**
* A shortcut for {@link #print(BitmaskSet, String)} at verbose level.
*
* @param message the message
*/
default void verb(String message) {
print(DebugOutputLevel.VERBOSE, message);
}
/**
* A shortcut for {@link #println(BitmaskSet, String)} at verbose level.
*
* @param message the message
*/
default void verbln(String message) {
println(DebugOutputLevel.VERBOSE, message);
}
<T extends DebugValue> T evaluate(Class<T> desiredType, String expression);
void execute(BitmaskSet<DebugOutputControl> ctl, String str, BitmaskSet<DebugExecute> flags);
/**
* A shortcut for {@link #execute(BitmaskSet, String, BitmaskSet)} outputting to all clients
* with the default execution flag.
*
* @param str the command string
*/
default void execute(String str) {
execute(SET_ALL_CLIENTS, str, SET_DEFAULT);
}
void prompt(BitmaskSet<DebugOutputControl> ctl, String message);
String getPromptText();
void returnInput(String input);
DebugStatus getExecutionStatus();
void setExecutionStatus(DebugStatus status);
int getNumberBreakpoints();
DebugBreakpoint getBreakpointByIndex(int index);
/**
* Shortcut to retrieve all breakpoints for the current process.
*
* <p>
* Uses {@link #getNumberBreakpoints()} and {@link #getBreakpointByIndex(int)} to enumerate all
* breakpoints for the current process.
*
* @return the list of retrieved breakpoints.
*/
default List<DebugBreakpoint> getBreakpoints() {
int count = getNumberBreakpoints();
List<DebugBreakpoint> result = new ArrayList<>(count);
for (int i = 0; i < count; i++) {
try {
result.add(getBreakpointByIndex(i));
}
catch (COMException e) {
if (!COMUtilsExtra.isE_NOINTERFACE(e)) {
throw e;
}
Msg.trace(this, "Discarding private breakpoint at index " + i);
}
}
return result;
}
/**
* Get a breakpoint by ID
*
* According to the MSDN, though the IDs may be global, this method should only succeed for
* breakpoints belonging to the current process.
*
* @param id
* @return
*/
DebugBreakpoint getBreakpointById(int id);
/**
* Add a (resolved) breakpoint with the given type and desired id
*
* <p>
* This is equivalent, in part, to the {@code bp} command.
*
* @param type the type
* @param desiredId the desired id
* @return the breakpoint, disabled at offset 0
*/
DebugBreakpoint addBreakpoint(BreakType type, int desiredId);
/**
* Add a (resolved) breakpoint with the given type and any id
*
* <p>
* This is equivalent, in part, to the {@code bp} command.
*
* @param type the type
* @return the breakpoint, disable at offset 0
*/
DebugBreakpoint addBreakpoint(BreakType type);
/**
* Add an unresolved breakpoint with the given type and desired id
*
* <p>
* This is equivalent, in part, to the {@code bu} command. See the MSDN for a comparison of
* {@code bu} and {@code bp}.
*
* @param type the type
* @param desiredId the desired id
* @return the breakpoint, disabled at offset 0
*/
DebugBreakpoint addBreakpoint2(BreakType type, int desiredId);
/**
* Add an unresolved breakpoint with the given type and any id
*
* <p>
* This is equivalent, in part, to the {@code bu} command. See the MSDN for a comparison of
* {@code bu} and {@code bp}.
*
* @param desiredId the desired id
* @return the breakpoint, disabled at offset 0
*/
DebugBreakpoint addBreakpoint2(BreakType type);
void waitForEvent(int timeout);
DebugEventInformation getLastEventInformation();
DebugStackInformation getStackTrace(long frameOffset, long stackOffset, long instructionOffset);
/**
* Shortcut for {@link #waitForEvent(int)} with infinite timeout.
*/
default void waitForEvent() {
waitForEvent(WinBase.INFINITE);
}
int getActualProcessorType();
int getEffectiveProcessorType();
int getExecutingProcessorType();
int getDebuggeeType();
DebugFilterInformation getNumberEventFilters();
String getEventFilterText(int index, int size);
String getEventFilterCommand(int index, int size);
void setEventFilterCommand(int index, String text);
DebugSpecificFilterInformation getSpecificFilterParameters(int start, int count);
void setSpecificFilterParameters(int start, int count, DebugSpecificFilterInformation info);
String getSpecificFilterArgument(int index, int size);
void setSpecificFilterArgument(int index, String arg);
DebugExceptionFilterInformation getExceptionFilterParameters(int start, int[] codes, int count);
void setExceptionFilterParameters(int count, DebugExceptionFilterInformation info);
String getExceptionFilterSecondCommand(int index, int size);
void setExceptionFilterSecondCommand(int index, String cmd);
}

View file

@ -1,27 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package agent.dbgeng.dbgeng;
import agent.dbgeng.dbgeng.DebugControl.DebugInterrupt;
/**
* An interface containing the subset of {@link DebugControl} methods which are reentrant.
*
* All other methods should be called only by the thread which created the client.
*/
public interface DebugControlReentrant {
void setInterrupt(DebugInterrupt interrupt);
}

View file

@ -1,290 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package agent.dbgeng.dbgeng;
import java.nio.ByteBuffer;
import java.util.*;
import com.sun.jna.platform.win32.COM.COMException;
import ghidra.comm.util.BitmaskSet;
import ghidra.comm.util.BitmaskUniverse;
import ghidra.util.Msg;
/**
* A wrapper for {@code IDebugDataSpaces} and its newer variants.
*/
public interface DebugDataSpaces {
public enum PageState {
COMMIT(0x1000), FREE(0x10000), RESERVE(0x2000);
private final int val;
private PageState(int val) {
this.val = val;
}
public static PageState byValue(int val) {
for (PageState state : values()) {
if (state.val == val) {
return state;
}
}
Msg.warn(PageState.class, "No such value: 0x" + Integer.toHexString(val));
return null;
}
}
public enum PageProtection implements BitmaskUniverse {
NOACCESS(1 << 0, false, false, false), //
READONLY(1 << 1, true, false, false), //
READWRITE(1 << 2, true, true, false), //
WRITE_COPY(1 << 3, true, true, false), // Becomes READWRITE after copy
EXECUTE(1 << 4, false, false, true), //
EXECUTE_READ(1 << 5, true, false, true), //
EXECUTE_READWRITE(1 << 6, true, true, true), //
EXECUTE_WRITECOPY(1 << 7, true, true, true), //
//
GUARD(1 << 8, false, false, false), //
NOCACHE(1 << 9, false, false, false), //
WRITECOMBINE(1 << 10, false, false, false), //
;
private PageProtection(int mask, boolean isRead, boolean isWrite, boolean isExecute) {
this.mask = mask;
this.isRead = isRead;
this.isWrite = isWrite;
this.isExecute = isExecute;
}
final int mask;
final boolean isRead;
final boolean isWrite;
final boolean isExecute;
@Override
public long getMask() {
return mask;
}
public boolean isRead() {
return isRead;
}
public boolean isWrite() {
return isWrite;
}
public boolean isExecute() {
return isExecute;
}
}
public enum PageType {
NONE(0), //
IMAGE(0x1000000), //
MAPPED(0x40000), //
PRIVATE(0x20000), //
;
private final int val;
private PageType(int val) {
this.val = val;
}
public static PageType byValue(int val) {
for (PageType type : values()) {
if (type.val == val) {
return type;
}
}
Msg.warn(PageType.class, "No such value: 0x" + Integer.toHexString(val));
return null;
}
}
public static class DebugMemoryBasicInformation {
public final long baseAddress;
public final long allocationBase;
public final Set<PageProtection> allocationProtect;
public final long regionSize;
public final PageState state;
public final Set<PageProtection> protect;
public final PageType type;
public DebugMemoryBasicInformation(long baseAddress, long allocationBase,
BitmaskSet<PageProtection> allocationProtect, long regionSize, PageState state,
BitmaskSet<PageProtection> protect, PageType type) {
this.baseAddress = baseAddress;
this.allocationBase = allocationBase;
this.allocationProtect = Collections.unmodifiableSet(allocationProtect);
this.regionSize = regionSize;
this.state = state;
this.protect = Collections.unmodifiableSet(protect);
this.type = type;
}
@Override
public String toString() {
return "<DebugMemoryBasicInformation:\n" + //
" baseAddress=" + Long.toHexString(baseAddress) + "h,\n" + //
" allocationBase=" + Long.toHexString(allocationBase) + "h,\n" + //
" allocationProtect=" + allocationProtect + ",\n" + //
" regionSize=" + Long.toHexString(regionSize) + "h,\n" + //
" state=" + state + ",\n" + //
" protect=" + protect + ",\n" + //
" type=" + type + "\n" + //
">";
}
@Override
public int hashCode() {
return Objects.hash(baseAddress, allocationBase, allocationProtect, regionSize, state,
protect, type);
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof DebugMemoryBasicInformation)) {
return false;
}
DebugMemoryBasicInformation that = (DebugMemoryBasicInformation) obj;
if (this.baseAddress != that.baseAddress) {
return false;
}
if (this.allocationBase != that.allocationBase) {
return false;
}
if (!this.allocationProtect.equals(that.allocationProtect)) {
return false;
}
if (this.regionSize != that.regionSize) {
return false;
}
if (this.state != that.state) {
return false;
}
if (!this.protect.equals(that.protect)) {
return false;
}
if (this.type != that.type) {
return false;
}
return true;
}
}
int readVirtual(long offset, ByteBuffer into, int len);
int writeVirtual(long offset, ByteBuffer from, int len);
int readVirtualUncached(long offset, ByteBuffer into, int len);
int writeVirtualUncached(long offset, ByteBuffer from, int len);
int readPhysical(long offset, ByteBuffer into, int len);
int writePhysical(long offset, ByteBuffer from, int len);
int readControl(int processor, long offset, ByteBuffer into, int len);
int writeControl(int processor, long offset, ByteBuffer from, int len);
int readBusData(int busDataType, int busNumber, int slotNumber, long offset, ByteBuffer into,
int len);
int writeBusData(int busDataType, int busNumber, int slotNumber, long offset, ByteBuffer from,
int len);
int readIo(int interfaceType, int busNumber, int addressSpace, long offset, ByteBuffer into,
int len);
int writeIo(int interfaceType, int busNumber, int addressSpace, long offset, ByteBuffer from,
int len);
long readMsr(int msr);
void writeMsr(int msr, long value);
int readDebuggerData(int offset, ByteBuffer into, int len);
DebugMemoryBasicInformation queryVirtual(long offset);
long virtualToPhysical(long offset);
/**
* A shortcut for iterating over virtual memory regions.
*
* This operates by calling {@link #queryVirtual(long)} to get each next entry, starting at an
* offset of -start-, adding the size of the returned region to determine the offset for the
* next call.
*
* @param start the starting offset
* @return an iterator over virtual memory regions after the given start
*/
default Iterable<DebugMemoryBasicInformation> iterateVirtual(long start) {
return new Iterable<DebugMemoryBasicInformation>() {
@Override
public Iterator<DebugMemoryBasicInformation> iterator() {
return new Iterator<DebugMemoryBasicInformation>() {
private long last = start;
private long offset = start;
private DebugMemoryBasicInformation next = doGetNext();
private DebugMemoryBasicInformation getNext() {
if (Long.compareUnsigned(last, offset) < 0) {
return doGetNext();
}
return null;
}
private DebugMemoryBasicInformation doGetNext() {
try {
DebugMemoryBasicInformation info = queryVirtual(offset);
last = offset;
if (info != null) {
offset += info.regionSize;
}
return info;
}
catch (COMException e) {
if (!COMUtilsExtra.isE_NOINTERFACE(e)) {
throw e;
}
return null;
}
}
@Override
public boolean hasNext() {
return next != null;
}
@Override
public DebugMemoryBasicInformation next() {
DebugMemoryBasicInformation ret = next;
next = getNext();
if (ret.equals(next)) {
next = null;
}
return ret;
}
};
}
};
}
}

View file

@ -1,116 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package agent.dbgeng.dbgeng;
import java.lang.annotation.*;
import agent.dbgeng.dbgeng.DebugClient.*;
import ghidra.comm.util.BitmaskSet;
import ghidra.comm.util.BitmaskUniverse;
/**
* The interface for receiving event callbacks via {@code IDebugEventCallbacks} or a newer variant.
*
* Note: The wrapper implementation will select the appropriate native interface version.
*
* Note: Even though {@link #changeDebuggeeState(BitmaskSet, long)},
* {@link #changeEngineState(BitmaskSet, long)} and {@link #changeSymbolState(BitmaskSet, long)}
* purport to return a {@link DebugStatus}, the returned value is ignored by {@code dbgeng.dll}.
*/
public interface DebugEventCallbacks {
public static enum DebugEvent implements BitmaskUniverse {
BREAKPOINT(1 << 0), //
EXCEPTION(1 << 1), //
CREATE_THREAD(1 << 2), //
EXIT_THREAD(1 << 3), //
CREATE_PROCESS(1 << 4), //
EXIT_PROCESS(1 << 5), //
LOAD_MODULE(1 << 6), //
UNLOAD_MODULE(1 << 7), //
SYSTEM_ERROR(1 << 8), //
SESSION_STATUS(1 << 9), //
CHANGE_DEBUGEE_STATE(1 << 10), //
CHANGE_ENGINE_STATE(1 << 11), //
CHANGE_SYMBOL_STATE(1 << 12), //
;
private DebugEvent(int mask) {
this.mask = mask;
}
private final int mask;
@Override
public long getMask() {
return mask;
}
}
/**
* An annotation for marking each callback with its interest flag.
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
static @interface ForInterest {
/**
* The flag corresponding to the annotated callback method
*
* @return the flag
*/
DebugEvent value();
}
BitmaskSet<DebugEvent> getInterestMask();
@ForInterest(DebugEvent.BREAKPOINT)
DebugStatus breakpoint(DebugBreakpoint bp);
@ForInterest(DebugEvent.EXCEPTION)
DebugStatus exception(DebugExceptionRecord64 exception, boolean firstChance);
@ForInterest(DebugEvent.CREATE_THREAD)
DebugStatus createThread(DebugThreadInfo debugThreadInfo);
@ForInterest(DebugEvent.EXIT_THREAD)
DebugStatus exitThread(int exitCode);
@ForInterest(DebugEvent.CREATE_PROCESS)
DebugStatus createProcess(DebugProcessInfo debugProcessInfo);
@ForInterest(DebugEvent.EXIT_PROCESS)
DebugStatus exitProcess(int exitCode);
@ForInterest(DebugEvent.LOAD_MODULE)
DebugStatus loadModule(DebugModuleInfo debugModuleInfo);
@ForInterest(DebugEvent.UNLOAD_MODULE)
DebugStatus unloadModule(String imageBaseName, long baseOffset);
@ForInterest(DebugEvent.SYSTEM_ERROR)
DebugStatus systemError(int error, int level);
@ForInterest(DebugEvent.SESSION_STATUS)
DebugStatus sessionStatus(SessionStatus status);
@ForInterest(DebugEvent.CHANGE_DEBUGEE_STATE)
DebugStatus changeDebuggeeState(BitmaskSet<ChangeDebuggeeState> flags, long argument);
@ForInterest(DebugEvent.CHANGE_ENGINE_STATE)
DebugStatus changeEngineState(BitmaskSet<ChangeEngineState> flags, long argument);
@ForInterest(DebugEvent.CHANGE_SYMBOL_STATE)
DebugStatus changeSymbolState(BitmaskSet<ChangeSymbolState> flags, long argument);
}

View file

@ -1,70 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package agent.dbgeng.dbgeng;
import agent.dbgeng.jna.dbgeng.WinNTExtra;
public class DebugEventInformation {
private int type;
private DebugProcessId pid;
private DebugThreadId tid;
private DebugSessionId sid;
private int executingProcessorType = WinNTExtra.Machine.IMAGE_FILE_MACHINE_AMD64.val;
public DebugEventInformation(int type, int pid, int tid) {
this.type = type;
this.pid = new DebugProcessRecord(pid);
this.tid = new DebugThreadRecord(tid);
}
public int getType() {
return type;
}
public DebugSessionId getSessionId() {
return sid;
}
public DebugProcessId getProcessId() {
return pid;
}
public DebugThreadId getThreadId() {
return tid;
}
public void setThread(DebugThreadId tid) {
this.tid = tid;
}
public void setProcess(DebugProcessId pid) {
this.pid = pid;
}
public void setSession(DebugSessionId sid) {
this.sid = sid;
}
public int getExecutingProcessorType() {
return executingProcessorType;
}
public void setExecutingProcessorType(int execType) {
this.executingProcessorType = execType;
}
}

View file

@ -1,42 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package agent.dbgeng.dbgeng;
import agent.dbgeng.jna.dbgeng.DbgEngNative.DEBUG_EXCEPTION_FILTER_PARAMETERS;
public class DebugExceptionFilterInformation {
private int nParams;
private DEBUG_EXCEPTION_FILTER_PARAMETERS[] parameters;
public DebugExceptionFilterInformation(int nParams,
DEBUG_EXCEPTION_FILTER_PARAMETERS[] parameters) {
this.nParams = nParams;
this.parameters = parameters;
}
public int getNumberOfParameters() {
return nParams;
}
public DEBUG_EXCEPTION_FILTER_PARAMETERS getParameter(int paramNumber) {
return parameters[paramNumber];
}
public DEBUG_EXCEPTION_FILTER_PARAMETERS[] getParameters() {
return parameters;
}
}

View file

@ -1,41 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package agent.dbgeng.dbgeng;
import java.util.Collections;
import java.util.List;
/**
* Data copied from a {@code EXCEPTION_RECORD64} as defined in {@code winnt.h}.
*
* TODO: Some enums, flags, etc., to help interpret some of the fields.
*/
public class DebugExceptionRecord64 {
public final int code; // TODO: How to interpret
public final int flags; // TODO: How to interpret
public final long record; // TODO: How to interpret
public final long address;
public final List<Long> information;
public DebugExceptionRecord64(int code, int flags, long record, long address,
List<Long> information) {
this.code = code;
this.flags = flags;
this.record = record;
this.address = address;
this.information = Collections.unmodifiableList(information);
}
}

View file

@ -1,42 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package agent.dbgeng.dbgeng;
public class DebugFilterInformation {
private int nEvents;
private int nSpecificExceptions;
private int nArbitraryExceptions;
public DebugFilterInformation(int nEvents, int nSpecificExceptions, int nArbitraryExceptions) {
this.nEvents = nEvents;
this.nSpecificExceptions = nSpecificExceptions;
this.nArbitraryExceptions = nArbitraryExceptions;
}
public int getNumberEvents() {
return nEvents;
}
public int getNumberSpecificExceptions() {
return nSpecificExceptions;
}
public int getNumberArbitraryExceptions() {
return nArbitraryExceptions;
}
}

View file

@ -1,31 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package agent.dbgeng.dbgeng;
/**
* The interface for receiving input callbacks via {@code IDebugInputCallbacks} or a newer variant.
*
* Note: The wrapper implementation will select the appropriate native interface version.
*/
@FunctionalInterface
public interface DebugInputCallbacks {
public void startInput(long bufferSize);
default void endInput() {
// Optional implementation
}
}

View file

@ -1,47 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package agent.dbgeng.dbgeng;
/**
* Handle to a module (program or library image).
*/
public interface DebugModule {
public enum DebugModuleName {
IMAGE, MODULE, LOADED_IMAGE, SYMBOL_FILE, MAPPED_IMAGE;
}
/**
* Get a name for the module.
*
* @param which identifies which name
* @return the requested name, if available
*/
String getName(DebugModuleName which);
/**
* Get the index assigned to this module.
*
* @return the index
*/
int getIndex();
/**
* Get the base address where this module is loaded, if applicable.
*
* @return the base address
*/
long getBase();
}

View file

@ -1,64 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package agent.dbgeng.dbgeng;
/**
* Information about a module (program or library image).
*
* The fields correspond to the parameters taken by {@code LoadModule} of
* {@code IDebugEventCallbacks}. They also appear as a subset of parameters taken by
* {@code CreateProcess} of {@code IDebugEventCallbacks}.
*/
public class DebugModuleInfo {
public final long imageFileHandle;
public final long baseOffset;
public final int moduleSize;
public final int checkSum;
public final int timeDateStamp;
private String moduleName;
private String imageName;
public DebugModuleInfo(long imageFileHandle, long baseOffset, int moduleSize, String moduleName,
String imageName, int checkSum, int timeDateStamp) {
this.imageFileHandle = imageFileHandle;
this.baseOffset = baseOffset;
this.moduleSize = moduleSize;
this.setModuleName(moduleName);
this.setImageName(imageName);
this.checkSum = checkSum;
this.timeDateStamp = timeDateStamp; // TODO: Convert to DateTime?
}
public String toString() {
return Long.toHexString(baseOffset);
}
public String getModuleName() {
return moduleName;
}
public void setModuleName(String moduleName) {
this.moduleName = moduleName;
}
public String getImageName() {
return imageName;
}
public void setImageName(String imageName) {
this.imageName = imageName;
}
}

View file

@ -1,32 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package agent.dbgeng.dbgeng;
import agent.dbgeng.dbgeng.DebugControl.DebugOutputLevel;
/**
* The interface for receiving output callbacks via {@code IDebugOutputCallbacks} or a newer
* variant.
*
* Note: The wrapper implementation will select the apprirate native interface version.
*
* TODO: Change {@link #output(int, String)} {@code mask} parameter to use {@link DebugOutputLevel}
* flags.
*/
@FunctionalInterface
public interface DebugOutputCallbacks {
void output(int mask, String text);
}

Some files were not shown because too many files have changed in this diff Show more