@@ -6,6 +6,7 @@ import com.sun.tools.attach.*
66import kotlin.system.exitProcess
77import java.lang.management.ManagementFactory
88import java.io.File
9+ import java.lang.IllegalArgumentException
910
1011// This file is the only one that uses com.sun.tools.attach.VirtualMachine. That's important because that
1112// 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
2425
2526// If run directly, can either list potential targets (list-targets) or attach to a target (pid, ...config)
2627fun 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" )
3734 }
3835
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()
3942 vms.forEach { vmd ->
4043 if (vmd.id() != pid) {
4144 println (" ${vmd.id()} :${vmd.displayName()} " )
4245 }
4346 }
4447
4548 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 {
4754 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" )
4856 exitProcess(2 )
4957 }
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+ }
5064
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+ }
5275
76+ fun attachAgent (
77+ pid : String ,
78+ agentArg : String
79+ ) {
5380 val jarPath = File (
5481 ConstantProxySelector ::class .java // Any arbitrary class defined inside this JAR
5582 .protectionDomain.codeSource.location.path
5683 ).absolutePath
5784
58- // Inject the agent with our config arguments into the target VM
85+ // Inject the agent into the target VM
5986 try {
6087 val vm: VirtualMachine = VirtualMachine .attach(pid)
61- vm.loadAgent(jarPath, formatConfigArg(proxyHost, proxyPort, certPath) )
88+ vm.loadAgent(jarPath, agentArg )
6289 vm.detach()
6390 } catch (e: AgentLoadException ) {
6491 if (e.message == " 0" ) {
0 commit comments