@@ -6,6 +6,7 @@ import com.sun.tools.attach.*
6
6
import kotlin.system.exitProcess
7
7
import java.lang.management.ManagementFactory
8
8
import java.io.File
9
+ import java.lang.IllegalArgumentException
9
10
10
11
// This file is the only one that uses com.sun.tools.attach.VirtualMachine. That's important because that
11
12
// requires tools.jar to be in your classpath (i.e. it requires a JDK not a JRE). If you run this without
@@ -24,41 +25,67 @@ val x: Class<*> = try { // Var declaration required for static init for some rea
24
25
25
26
// If run directly, can either list potential targets (list-targets) or attach to a target (pid, ...config)
26
27
fun main (args : Array <String >) {
27
- if (args.size == 1 && args[0 ] == " list-targets" ) {
28
- // This isn't guaranteed to work everywhere, but it should work in most places:
29
- val (pid) = ManagementFactory .getRuntimeMXBean().name.split(" @" )
30
-
31
- val vms = VirtualMachine .list()
32
- if (vms.isEmpty()) {
33
- // VMs should never be empty, because at the very least _we_ should be in there! If it's empty then
34
- // scanning isn't working at all, and we should fail clearly.
35
- System .err.println (" Can't scan for attachable JVMs. Are we running in a JRE instead of a JDK?" )
36
- exitProcess(4 )
28
+ // Self-test ensures that the JVM we're using is capable of scanning & attachment. It *doesn't* fully
29
+ // test its ability to transform classes as we'd like.
30
+ if (args.size == 1 && args[0 ] == " self-test" ) {
31
+ val selfAttachAllowed = System .getProperty(" jdk.attach.allowAttachSelf" )
32
+ if (selfAttachAllowed != " true" ) {
33
+ throw IllegalArgumentException (" Cannot run self-test without -Djdk.attach.allowAttachSelf=true" )
37
34
}
38
35
36
+ getTargets() // Check we can scan for targets
37
+ attachAgent(getOwnPid(), " attach-test" ) // Check we can attach (against ourselves)
38
+ } else if (args.size == 1 && args[0 ] == " list-targets" ) {
39
+ // List-targets prints a list of pid:name target paids
40
+ val pid = getOwnPid()
41
+ val vms = getTargets()
39
42
vms.forEach { vmd ->
40
43
if (vmd.id() != pid) {
41
44
println (" ${vmd.id()} :${vmd.displayName()} " )
42
45
}
43
46
}
44
47
45
48
exitProcess(0 )
46
- } else if (args.size != 4 ) {
49
+ } else if (args.size == 4 ) {
50
+ // 4-args format attaches to a target pid with the given config values
51
+ val (pid, proxyHost, proxyPort, certPath) = args
52
+ attachAgent(pid, formatConfigArg(proxyHost, proxyPort, certPath))
53
+ } else {
47
54
System .err.println (" Usage: java -jar <agent.jar> <target-PID> <proxyHost> <proxyPort> <path-to-certificate>" )
55
+ System .err.println (" Or pass a single 'self-test' or 'list-target' arg to check capabilities or scan for pids" )
48
56
exitProcess(2 )
49
57
}
58
+ }
59
+
60
+ fun getOwnPid (): String {
61
+ // This should work in general, but it's implementation dependent:
62
+ return ManagementFactory .getRuntimeMXBean().name.split(" @" )[0 ]
63
+ }
50
64
51
- val (pid, proxyHost, proxyPort, certPath) = args
65
+ fun getTargets (): List <VirtualMachineDescriptor > {
66
+ val vms = VirtualMachine .list()
67
+ if (vms.isEmpty()) {
68
+ // VMs should never be empty, because at the very least _we_ should be in there! If it's empty then
69
+ // scanning isn't working at all, and we should fail clearly.
70
+ System .err.println (" Can't scan for attachable JVMs. Are we running in a JRE instead of a JDK?" )
71
+ exitProcess(4 )
72
+ }
73
+ return vms
74
+ }
52
75
76
+ fun attachAgent (
77
+ pid : String ,
78
+ agentArg : String
79
+ ) {
53
80
val jarPath = File (
54
81
ConstantProxySelector ::class .java // Any arbitrary class defined inside this JAR
55
82
.protectionDomain.codeSource.location.path
56
83
).absolutePath
57
84
58
- // Inject the agent with our config arguments into the target VM
85
+ // Inject the agent into the target VM
59
86
try {
60
87
val vm: VirtualMachine = VirtualMachine .attach(pid)
61
- vm.loadAgent(jarPath, formatConfigArg(proxyHost, proxyPort, certPath) )
88
+ vm.loadAgent(jarPath, agentArg )
62
89
vm.detach()
63
90
} catch (e: AgentLoadException ) {
64
91
if (e.message == " 0" ) {
0 commit comments