GP-1007: Fix GADP agent nodepJar issues

This commit is contained in:
Dan 2023-03-03 13:54:07 -05:00
parent 865cd22cab
commit 3be53dc05e
15 changed files with 262 additions and 385 deletions

View file

@ -18,8 +18,10 @@ apply from: "$rootProject.projectDir/gradle/jacocoProject.gradle"
apply from: "$rootProject.projectDir/gradle/javaTestProject.gradle"
apply from: "$rootProject.projectDir/gradle/nativeProject.gradle"
apply from: "$rootProject.projectDir/gradle/distributableGhidraModule.gradle"
apply plugin: 'eclipse'
apply from: "$rootProject.projectDir/gradle/debugger/hasNodepJar.gradle"
apply plugin: 'eclipse'
eclipse.project.name = 'Debug Debugger-agent-dbgeng'
dependencies {
@ -33,53 +35,12 @@ dependencies {
testImplementation project(path: ":Debugger-gadp", configuration: 'testArtifacts')
}
def boolean filterJar(File jarfile) {
if (jarfile.name.contains("gradle-api")) {
return false
} else if (jarfile.name.contains("groovy-all")) {
return false
} else if (jarfile.name.contains("gradle-installation-beacon")) {
return false
}
return true
}
jar {
tasks.nodepJar {
manifest {
attributes['Main-Class'] = 'agent.dbgeng.gadp.DbgEngGadpServer'
}
}
task configureNodepJar {
dependsOn(configurations.default)
doLast {
configurations.default.files.forEach {
if (filterJar(it)) {
nodepJar.from(zipTree(it))
}
}
}
}
task nodepJar(type: Jar) {
inputs.file(file(jar.archivePath))
dependsOn(configureNodepJar)
dependsOn(jar)
archiveAppendix = 'nodep'
manifest {
attributes['Main-Class'] = 'agent.dbgeng.gadp.DbgEngGadpServer'
}
from(zipTree(jar.archivePath))
// TODO: This kind of stinks. I could probably apply some judicious excludes
// images I don't care.
// I probably must include duplicate LICENSE files, so that all are included
// IDK why the duplicate OSGi framework classes, but I probably don't care.
duplicatesStrategy = 'include'
}
test {
jvmArgs('-Xrs') // TODO: Is this needed, or left over from trial-and-error
if ("win_x86_64".equals(getCurrentPlatformName())) {

View file

@ -30,10 +30,28 @@ import ghidra.dbg.agent.AgentWindow;
import ghidra.util.Msg;
public interface DbgEngGadpServer extends AutoCloseable {
public static final String USAGE =
"""
This is the GADP server for Windows dbgeng.dll. Usage:
gadp-agent-gdbeng [-H HOST/ADDR] [-p PORT] [-i ID] [-t TRANSPORT]
[-r REMOTE]
Options:
--host/-H The address of the interface on which to listen.
--port/-p The TCP port on which to listen for GADP. Default is 12345
--transport/-t The transport specification for the Process Server. Default
is tcp:port=11200
--remote/-r The transport specification for a remote server.
Starts a dbgeng.dll-based GADP server "agent". Once the server has started, it
will print the interface IP and port.
""";
public static final String DEFAULT_DBGSRV_TRANSPORT = "tcp:port=11200";
/**
* The entry point for the SCTL-DBGENG server in stand-alone mode
* The entry point for the GADP-DBGENG server in stand-alone mode
*
* Run it to see help.
*
@ -55,7 +73,7 @@ public interface DbgEngGadpServer extends AutoCloseable {
/**
* Create a new instance of the server
*
* @param addr the address to bind the SCTL server to
* @param addr the address to bind the GADP server to
* @param busId the client ID the server should use on the bus for synthesized commands
* @param dbgSrvTransport the transport specification for the {@code dbgeng.dll} server
* @return the server instance
@ -71,7 +89,6 @@ public interface DbgEngGadpServer extends AutoCloseable {
public class DbgEngRunner {
protected InetSocketAddress bindTo;
protected List<String> dbgengArgs = new ArrayList<>();
protected byte busId = 1;
protected String dbgSrvTransport = DEFAULT_DBGSRV_TRANSPORT;
protected String remote = null;
@ -134,23 +151,6 @@ public interface DbgEngGadpServer extends AutoCloseable {
}
iface = ait.next();
}
else if ("-i".equals(a) || "--bus-id".equals(a)) {
if (!ait.hasNext()) {
System.err.println("Expected ID");
printUsage();
System.exit(-1);
}
String busIdStr = ait.next();
try {
busId = Byte.parseByte(busIdStr);
//dbgengArgs.add(busIdStr);
}
catch (NumberFormatException e) {
System.err.println("Byte required. Got " + busIdStr);
printUsage();
System.exit(-1);
}
}
else if ("-t".equals(a) || "--transport".equals(a)) {
if (!ait.hasNext()) {
System.err.println("Expected TRANSPORT");
@ -181,23 +181,7 @@ public interface DbgEngGadpServer extends AutoCloseable {
}
protected void printUsage() {
System.out.println("This is the GADP server for Windows dbgeng.dll. Usage:");
System.out.println();
System.out.println(" [-H HOST/ADDR] [-p PORT] [-i ID] [-t TRANSPORT] [-r REMOTE]");
System.out.println();
System.out.println("Options:");
System.out.println(
" --host/-H The address of the interface on which to listen.");
System.out.println(" Default is localhost");
System.out.println(
" --port/-p The TCP port on which to listen for GADP. Default is 12345");
System.out.println(
" --bus-id/-i The numeric client id for synthetic requests. Default is 1");
System.out.println(
" --transport/-t The transport specification for the Process Server.");
System.out.println(" Default is tcp:port=11200");
System.out.println(
" --remote/-r The transport specification for a remote server.");
System.out.println(USAGE);
}
}
@ -209,7 +193,7 @@ public interface DbgEngGadpServer extends AutoCloseable {
CompletableFuture<Void> startDbgEng(String[] args);
/**
* Get the local address to which the SCTL server is bound.
* Get the local address to which the GADP server is bound.
*
* @return the local socket address
*/

View file

@ -19,6 +19,8 @@ apply from: "$rootProject.projectDir/gradle/javaTestProject.gradle"
apply from: "$rootProject.projectDir/gradle/nativeProject.gradle"
apply from: "$rootProject.projectDir/gradle/distributableGhidraModule.gradle"
apply from: "$rootProject.projectDir/gradle/debugger/hasNodepJar.gradle"
apply plugin: 'eclipse'
eclipse.project.name = 'Debug Debugger-agent-dbgmodel'
@ -31,52 +33,12 @@ dependencies {
testImplementation project(path: ":Debugger-gadp", configuration: 'testArtifacts')
}
def boolean filterJar(File jarfile) {
if (jarfile.name.contains("gradle-api")) {
return false
} else if (jarfile.name.contains("groovy-all")) {
return false
} else if (jarfile.name.contains("gradle-installation-beacon")) {
return false
}
return true
}
jar {
tasks.nodepJar {
manifest {
attributes['Main-Class'] = 'agent.dbgmodel.gadp.DbgModelGadpServer'
}
}
task configureNodepJar {
dependsOn(configurations.default)
doLast {
configurations.default.files.forEach {
if (filterJar(it)) {
nodepJar.from(zipTree(it))
}
}
}
}
task nodepJar(type: Jar) {
inputs.file(file(jar.archivePath))
dependsOn(configureNodepJar)
dependsOn(jar)
archiveAppendix = 'nodep'
manifest {
attributes['Main-Class'] = 'agent.dbgmodel.gadp.DbgModelGadpServer'
}
from(zipTree(jar.archivePath))
// TODO: This kind of stinks. I could probably apply some judicious excludes
// images I don't care.
// I probably must include duplicate LICENSE files, so that all are included
// IDK why the duplicate OSGi framework classes, but I probably don't care.
duplicatesStrategy = 'include'
}
test {
jvmArgs('-Xrs') // TODO: Is this needed, or left over from trial-and-error
if ("win_x86_64".equals(getCurrentPlatformName())) {

View file

@ -28,47 +28,35 @@ import ghidra.dbg.agent.AgentWindow;
import ghidra.util.Msg;
/**
* The interface for the SCTL-{@code dbgeng.dll} server
* The interface for the GADP-{@code dbgeng.dll} server
*
* <p>
* This is just an interface to specify the truly public methods. This is also a convenient place to
* put all the command-line parsing logic.
*
* This server implements the SCTL commands necessary to have a smooth debugging experience in
* <p>
* This server implements the GADP commands necessary to have a smooth debugging experience in
* Ghidra. It implements almost every command that has use on a binary without debugging
* information. It operates as a standalone debugging server based on {@code dbgeng.dll}, which can
* accept other {@code dbgeng.dll}-based clients as well as SCTL clients.
* accept other {@code dbgeng.dll}-based clients as well as GADP clients.
*
* <p>
* Without limitation, the caveats are listed here:
*
* 1) The {@code Tnames} request in not implemented. The only namespaces available are those given
* in the {@code Rstat} response.
*
* 2) For binaries without a debugging database (pdb file), the symbol commands only search the
* exported symbols.
*
* 3) The type commands are not implemented. Ghidra can read most PDB files directly.
*
* 4) While SCTL presents thread-specific control, {@code dbgeng.dll} does not. Continue ("g" in
* {@code dbgeng.dll}) affects all debugged targets, except those with higher suspect counts and
* <ol>
* <li>For binaries without a debugging database (pdb file), the symbol commands only search the
* exported symbols.</li>
* <li>The type commands are not implemented. Ghidra can read most PDB files directly.</li>
* <li>While GADP presents thread-specific control, {@code dbgeng.dll} does not. Continue ("g" in
* {@code dbgeng.dll}) affects all debugged targets, except those with higher suspend counts and
* those that are frozen. The API makes it impossible to perfectly track which threads are actually
* executed by "g". The server thus assumes that all threads run when any thread runs, and it will
* synthesize the commands to reflect that in the connected clients.
*
* 5) The {@code Ttrace} command is not supported. The user can configure filters in the host
* debugger; however, some events will always be trapped by the SCTL server. Future versions may
* adjust this.
*
* 6) Snapshots are not supported. {@code dbgeng.dll} as no equivalent.
*
* 7) System calls are no yet reported. Windows programs do not use {@code fork} and {@code exec}.
* Instead, calls to {@code CreateProcess} cause the server to synthesize {@code Tattach} commands.
*
* 8) The {@code Tunwind1} command is not supported. Ghidra should unwind instead.
* executed by "g". The server thus assumes that all threads run when any thread runs.</li>
* </ol>
*/
public interface DbgModelGadpServer extends DbgEngGadpServer {
/**
* The entry point for the SCTL-DBGENG server in stand-alone mode
* The entry point for the GADP-DBGMODEL server in stand-alone mode
*
* Run it to see help.
*
@ -90,7 +78,7 @@ public interface DbgModelGadpServer extends DbgEngGadpServer {
/**
* Create a new instance of the server
*
* @param addr the address to bind the SCTL server to
* @param addr the address to bind the GADP server to
* @param busId the client ID the server should use on the bus for synthesized commands
* @param dbgSrvTransport the transport specification for the {@code dbgeng.dll} server
* @return the server instance

View file

@ -19,6 +19,8 @@ apply from: "$rootProject.projectDir/gradle/javaTestProject.gradle"
apply from: "$rootProject.projectDir/gradle/nativeProject.gradle"
apply from: "$rootProject.projectDir/gradle/distributableGhidraModule.gradle"
apply from: "$rootProject.projectDir/gradle/debugger/hasExecutableJar.gradle"
apply plugin: 'eclipse'
eclipse.project.name = 'Debug Debugger-agent-frida'
@ -33,68 +35,14 @@ dependencies {
testImplementation project(path: ':Debugger-gadp', configuration: 'testArtifacts')
}
def boolean filterJar(File jarfile) {
if (jarfile.name.contains("gradle-api")) {
return false
} else if (jarfile.name.contains("groovy-all")) {
return false
} else if (jarfile.name.contains("gradle-installation-beacon")) {
return false
}
return true
}
jar {
tasks.nodepJar {
manifest {
attributes['Main-Class'] = 'agent.lldb.gadp.FridaGadpServer'
}
}
task configureNodepJar {
doLast {
configurations.default.files.forEach {
if (filterJar(it)) {
nodepJar.from(zipTree(it))
}
}
}
}
task nodepJar(type: Jar) {
inputs.file(file(jar.archivePath))
dependsOn(configureNodepJar)
dependsOn(jar)
archiveAppendix = 'nodep'
manifest {
attributes['Main-Class'] = 'agent.lldb.gadp.FridaGadpServer'
}
from(zipTree(jar.archivePath))
}
task executableJar {
ext.execsh = file("src/main/sh/execjar.sh")
ext.jarfile = file(nodepJar.archivePath)
tasks.executableJar {
ext.outjar = file("${buildDir}/bin/gadp-agent-frida")
dependsOn(nodepJar)
inputs.file(execsh)
inputs.file(jarfile)
outputs.file(outjar)
doLast {
outjar.parentFile.mkdirs()
outjar.withOutputStream { output ->
execsh.withInputStream { input ->
output << input
}
jarfile.withInputStream { input ->
output << input
}
}
exec {
commandLine("chmod", "+x", outjar)
}
}
}
test {

View file

@ -28,6 +28,17 @@ import ghidra.dbg.agent.AgentWindow;
import ghidra.util.Msg;
public interface FridaGadpServer extends AutoCloseable {
public static final String USAGE =
"""
This is the GADP server for Frida. Usage:
gadp-agent-frida [-H HOST/ADDR] [-p PORT]
Options:
--host/-H The address of the interface on which to listen. Default is
localhost
--port/-p The TCP port on which to listen for GADP. Default is 12345
""";
/**
* The entry point for the Frida server in stand-alone mode
@ -133,16 +144,7 @@ public interface FridaGadpServer extends AutoCloseable {
}
protected void printUsage() {
System.out.println("This is the GADP server for Frida. Usage:");
System.out.println();
System.out.println(" [-H HOST/ADDR] [-p PORT] [-i ID] [-t TRANSPORT] [-r REMOTE]");
System.out.println();
System.out.println("Options:");
System.out.println(
" --host/-H The address of the interface on which to listen.");
System.out.println(" Default is localhost");
System.out.println(
" --port/-p The TCP port on which to listen for GADP. Default is 12345");
System.out.println(USAGE);
}
}

View file

@ -0,0 +1,22 @@
#!/usr/bin/bash
## ###
# 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.
##
# This clever bit can be prepended to a JAR to make it self-executable
set -e
java -jar "$0" ${@:1}
exit

View file

@ -19,6 +19,8 @@ apply from: "$rootProject.projectDir/gradle/javaTestProject.gradle"
apply from: "$rootProject.projectDir/gradle/nativeProject.gradle"
apply from: "$rootProject.projectDir/gradle/distributableGhidraModule.gradle"
apply from: "$rootProject.projectDir/gradle/debugger/hasExecutableJar.gradle"
apply plugin: 'eclipse'
eclipse.project.name = 'Debug Debugger-agent-gdb'
@ -33,74 +35,14 @@ dependencies {
testImplementation project(path: ':Debugger-gadp', configuration: 'testArtifacts')
}
def boolean filterJar(File jarfile) {
if (jarfile.name.contains("gradle-api")) {
return false
} else if (jarfile.name.contains("groovy-all")) {
return false
} else if (jarfile.name.contains("gradle-installation-beacon")) {
return false
}
return true
}
jar {
tasks.nodepJar {
manifest {
attributes['Main-Class'] = 'agent.gdb.gadp.GdbGadpServer'
}
}
task configureNodepJar {
dependsOn(configurations.default)
doLast {
configurations.default.files.forEach {
if (filterJar(it)) {
nodepJar.from(zipTree(it))
}
}
}
}
task nodepJar(type: Jar) {
inputs.file(file(jar.archivePath))
dependsOn(configureNodepJar)
dependsOn(jar)
archiveAppendix = 'nodep'
manifest {
attributes['Main-Class'] = 'agent.gdb.gadp.GdbGadpServer'
}
from(zipTree(jar.archivePath))
// TODO: This kind of stinks. I could probably apply some judicious excludes
// images I don't care.
// I probably must include duplicate LICENSE files, so that all are included
// IDK why the duplicate OSGi framework classes, but I probably don't care.
duplicatesStrategy = 'include'
}
task executableJar {
ext.execsh = file("src/main/sh/execjar.sh")
ext.jarfile = file(nodepJar.archivePath)
tasks.executableJar {
ext.outjar = file("${buildDir}/bin/gadp-agent-gdb")
dependsOn(nodepJar)
inputs.file(execsh)
inputs.file(jarfile)
outputs.file(outjar)
doLast {
outjar.parentFile.mkdirs()
outjar.withOutputStream { output ->
execsh.withInputStream { input ->
output << input
}
jarfile.withInputStream { input ->
output << input
}
}
exec {
commandLine("chmod", "+x", outjar)
}
}
}
test {

View file

@ -30,6 +30,38 @@ import ghidra.dbg.agent.AgentWindow;
import ghidra.util.Msg;
public interface GdbGadpServer extends AutoCloseable {
public static final String USAGE =
"""
This is the GADP wrapper for GDB. Usage:
gadp-agent-gdb [GDB options] [--agent-args [-H HOST/ADDR] [-p PORT]
[-g CMD] [-x]]
Options:
Use gdb -h for suitable [GDB options]
THE FOLLOWING OPTIONS MUST BE PRECEDED BY --agent-args
--host/-H The address of the interface on which to listen. Default is
localhost
--port/-p The TCP port on which to listen. Default is 12345. 0 for
automatic.
--gdb-cmd/-g The command to launch gdb. Default is 'gdb'
--existing/-x Do not launch gdb. Instead just open a pty
Starts a GDB-based GADP server "agent". In general, it can be invoked in the
same manner as standard gdb. Arguments to control the GADP server and GDB
invocation are given after the --gadp-args flag. Once the server has started, it
will print the interface IP and port. The -g and -x flags are mutually
exclusive. The one appearing last get preference. The -x flags causes the agent
to refrain from launching its own gdb process. Instead, it prints the file name
of a pseudo terminal (pty) where it expects a GDB/MI v2 interpreter from an
existing gdb process. Use the new-ui command (available since GDB version 7.12)
to join the agent to the existing session:
(gdb) new-ui mi2 /dev/ptyXX
""";
public static void main(String[] args) throws Exception {
try {
new Runner().run(args);
@ -73,7 +105,7 @@ public interface GdbGadpServer extends AutoCloseable {
Iterator<String> ait = Arrays.asList(args).iterator();
while (ait.hasNext()) {
String a = ait.next();
if ("--gadp-args".equals(a)) {
if ("--agent-args".equals(a)) {
break;
}
else if ("-h".equals(a) || "--help".equals(a)) {
@ -131,45 +163,7 @@ public interface GdbGadpServer extends AutoCloseable {
}
private void printUsage() {
System.out.println("This is the GADP wrapper for GDB. Usage:");
System.out.println();
System.out.println(
" gadpgdb [GDB options] [--gadp-args [-H HOST/ADDR] [-p PORT] [-g CMD] [-x]]");
System.out.println();
System.out.println("Options:");
System.out.println();
System.out.println("Use gdb -h for suitable [GDB options]");
System.out.println();
System.out.println(
" --host/-H The address of the interface on which to listen. Default is localhost");
System.out.println(
" --port/-p The TCP port on which to listen. Default is 12345. 0 for automatic.");
System.out.println(
" --gdb-cmd/-g The command to launch gdb. Default is 'gdb'");
System.out.println(
" --existing/-x Do not launch gdb. Instead just open a pty");
System.out.println();
System.out.println(
"Starts a GDB-based GADP server \"agent\". In general, it can be invoked in");
System.out.println(
"the same manner as standard gdb. Arguments to control the GADP server and");
System.out.println(
"GDB invocation are given after the --gadp-args flag. Once the server has");
System.out.println(
"started, it will print the interface IP and port. The -g and -x flags are");
System.out.println(
"mutually exclusive. The one appearing last get preference. The -x flags");
System.out.println(
"causes the agent to refrain from launching its own gdb process. Instead,");
System.out.println(
"it prints the file name of a private terminate (pty) where it expects a");
System.out.println(
"GDB/MI v2 interpreter from an existing gdb process. Use the new-ui command");
System.out.println(
"(available since GDB version 7.12) to join the agent to the existing");
System.out.println("session:");
System.out.println();
System.out.println("(gdb) new-ui mi2 /dev/ptyXX");
System.out.println(USAGE);
}
}

View file

@ -18,5 +18,5 @@
set -e
java -jar "$0"
java -jar "$0" ${@:1}
exit

View file

@ -19,6 +19,8 @@ apply from: "$rootProject.projectDir/gradle/javaTestProject.gradle"
apply from: "$rootProject.projectDir/gradle/nativeProject.gradle"
apply from: "$rootProject.projectDir/gradle/distributableGhidraModule.gradle"
apply from: "$rootProject.projectDir/gradle/debugger/hasExecutableJar.gradle"
apply plugin: 'eclipse'
eclipse.project.name = 'Debug Debugger-agent-lldb'
@ -33,68 +35,14 @@ dependencies {
testImplementation project(path: ':Debugger-gadp', configuration: 'testArtifacts')
}
def boolean filterJar(File jarfile) {
if (jarfile.name.contains("gradle-api")) {
return false
} else if (jarfile.name.contains("groovy-all")) {
return false
} else if (jarfile.name.contains("gradle-installation-beacon")) {
return false
}
return true
}
jar {
tasks.nodepJar {
manifest {
attributes['Main-Class'] = 'agent.lldb.gadp.LldbGadpServer'
}
}
task configureNodepJar {
doLast {
configurations.default.files.forEach {
if (filterJar(it)) {
nodepJar.from(zipTree(it))
}
}
}
}
task nodepJar(type: Jar) {
inputs.file(file(jar.archivePath))
dependsOn(configureNodepJar)
dependsOn(jar)
archiveAppendix = 'nodep'
manifest {
attributes['Main-Class'] = 'agent.lldb.gadp.LldbGadpServer'
}
from(zipTree(jar.archivePath))
}
task executableJar {
ext.execsh = file("src/main/sh/execjar.sh")
ext.jarfile = file(nodepJar.archivePath)
tasks.executableJar {
ext.outjar = file("${buildDir}/bin/gadp-agent-lldb")
dependsOn(nodepJar)
inputs.file(execsh)
inputs.file(jarfile)
outputs.file(outjar)
doLast {
outjar.parentFile.mkdirs()
outjar.withOutputStream { output ->
execsh.withInputStream { input ->
output << input
}
jarfile.withInputStream { input ->
output << input
}
}
exec {
commandLine("chmod", "+x", outjar)
}
}
}
test {

View file

@ -28,6 +28,17 @@ import ghidra.dbg.agent.AgentWindow;
import ghidra.util.Msg;
public interface LldbGadpServer extends AutoCloseable {
public static final String USAGE =
"""
This is the GADP server for Frida. Usage:
gadp-agent-lldb [-H HOST/ADDR] [-p PORT]
Options:
--host/-H The address of the interface on which to listen. Default is
localhost
--port/-p The TCP port on which to listen for GADP. Default is 12345
""";
/**
* The entry point for the LLDB server in stand-alone mode
@ -133,16 +144,7 @@ public interface LldbGadpServer extends AutoCloseable {
}
protected void printUsage() {
System.out.println("This is the GADP server for LLVM's lldb. Usage:");
System.out.println();
System.out.println(" [-H HOST/ADDR] [-p PORT] [-i ID] [-t TRANSPORT] [-r REMOTE]");
System.out.println();
System.out.println("Options:");
System.out.println(
" --host/-H The address of the interface on which to listen.");
System.out.println(" Default is localhost");
System.out.println(
" --port/-p The TCP port on which to listen for GADP. Default is 12345");
System.out.println(USAGE);
}
}

View file

@ -0,0 +1,22 @@
#!/usr/bin/bash
## ###
# 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.
##
# This clever bit can be prepended to a JAR to make it self-executable
set -e
java -jar "$0" ${@:1}
exit

View file

@ -0,0 +1,41 @@
/* ###
* 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.
*/
apply from: "$rootProject.projectDir/gradle/debugger/hasNodepJar.gradle"
task executableJar {
ext.execsh = file("src/main/sh/execjar.sh")
ext.jarfile = file(nodepJar.archivePath)
ext.outjar = file("${buildDir}/bin/run")
dependsOn(nodepJar)
inputs.file { execsh }
inputs.file { jarfile }
outputs.file { outjar }
doLast {
outjar.parentFile.mkdirs()
outjar.withOutputStream { output ->
execsh.withInputStream { input ->
output << input
}
jarfile.withInputStream { input ->
output << input
}
}
exec {
commandLine("chmod", "+x", outjar)
}
}
}

View file

@ -0,0 +1,61 @@
/* ###
* 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.
*/
def boolean filterJar(File jarfile) {
if (jarfile.name.contains("gradle-api")) {
return false
} else if (jarfile.name.contains("groovy-all")) {
return false
} else if (jarfile.name.contains("gradle-installation-beacon")) {
return false
}
return true
}
task configureNodepJar {
dependsOn(configurations.default)
doLast {
configurations.default.files.forEach { jar ->
if (filterJar(jar)) {
nodepJar.from(zipTree(jar)) {
// The real solution here is probably to sort out the dependency graph
// Still, I imagine some of the excludes will be necessary
exclude "help/**"
exclude "images/**"
exclude "OSGI-OPT/**"
exclude "org/osgi/**"
exclude "aQute/**"
// Duplicate. And signature breaks nodep jar
exclude "META-INF/*.SF"
exclude "META-INF/*.DSA"
exclude "META-INF/*.RSA"
// Ensure all LICENSES are included, by renaming to avoid collisions
rename("((LICENSE)|(AL2\\.0)|(LGPL2\\.1)|(NOTICE)|(NOTICE.txt)|(DEPENDENCIES))", "${jar.name}-\$1")
}
}
}
}
}
task nodepJar(type: Jar) {
inputs.file(file(jar.archivePath))
dependsOn(configureNodepJar)
dependsOn(jar)
archiveAppendix = 'nodep'
from(zipTree(jar.archivePath))
duplicatesStrategy = 'exclude'
}