Java process to connect to its own debugger interface
Asked Answered
G

0

6

Within a Java process, I want to access the JDI (Java Debugging Interface) of that same process.

I make the following assumptions:

  • The process is being executed within the debugger (in Intelli/J)
  • I use the Oracle JVM 8
  • I run Linux (no portability is needed)

That is, I want to do something like:

import com.sun.jdi.*
import com.sun.jdi.connect.*

VirtualMachine vm = new SelfConnector().attach()

(Except, of course, that there is no such object.)

How can I connect to my own VM?

Why do I want that?

I wish to write a function findObj that finds an object via its unique ID. For example, if in the Intelli/J debugger I see a variable "x = {Something@1234}", then I want to be able to add a watch expression "findObj(1234)" that finds and return the object. That way, I will be able to see the object #1234 even after the variable x has been changed or I have left the current stack frame.

I believe that I can implement this function once I have access to the JDI for the current process.

[EDIT: It does not answer the question, but it solves my use case: In Intellij/J you can "mark" objects, and use these markers in watch expressions.]

What have I tried?

I have tried to connect to the process itself via a SocketAttach AttachingConnector using the hostname and port that Intelli/J supplies in the -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:39469,suspend=y,server=n argument when starting the Java process in a debug session. (Following roughly the method described here.) I get:

Exception in thread "main" java.net.ConnectException: Connection refused

Probably because Intelli/J is already connected and one cannot connect twice to that port? [EDIT: Intellij/J starts the jwdp agent with parameter server=n which means the process will do the connecting. Hence the connection refused. But further experiments show that even if one uses server=y, at most one connection is accepted.]

Another approach was to use a ProcessAttach AttachingConnector. In that case, I got:

Exception in thread "main" java.io.IOException: Not a debuggee, or not listening for debugger to attach
Graehl answered 7/8, 2016 at 20:22 Comment(8)
The problem is the uniqueID as you put it is not actually unique. The hashCode is NOT unique and the numeric number after the @ symbol is actually the Hex of the HashCode. docs.oracle.com/javase/7/docs/api/java/lang/Object.html grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/…Nolde
@JohnnyV I did not mean the hash code. The debugger (at least in Intelli/J) shows in the variable view: x = {Type@123} Type@abcdef. Here 123 is the unique ID that I mean, and abcdef is the hashCode you refer to. {Type@123} is generated by the debugger, and Type@abcdef is just the output of toString().Graehl
I think the first thing to do is figure out how Intelli/J is coming up with {klass@1234} because I'm not aware of any unique ID in the instance memory. #26357686Nolde
A unique ID is available via the JDI, see the method uniqueID here: docs.oracle.com/javase/8/docs/jdk/api/jpda/jdi/index.html?com/…. I assume that this is the ID that Intelli/J uses, although I can't be sure.Graehl
If you look at VirtualMachineImpl.java line #1069 in HotSpot you see that the uniqueID is most likely the memory address of the object. That said, objects can move memory address at any given point in time.Nolde
The comment in VirtualMachineImpl.java might be incorrect. The source of ObjectReferenceImpl.uniqueID() indicates that the uniqueID is a sequential number (see github.com/JetBrains/jdk8u_hotspot/blob/b37ae60/agent/src/share/…)Graehl
The confusing part is the JDK version of ObjectReferenceImpl takes a long as an constructor parameter: github.com/JetBrains/jdk8u_jdk/blob/… Back tracking that code leads to the conversion of Oop to a long somehow.Nolde
Let us continue this discussion in chat.Graehl

© 2022 - 2024 — McMap. All rights reserved.