I'm attempting to operate JDB programmatically. Unlike any sane debugger, JDB refers to the source code using class names instead of source file names. I'm assuming it's related to having the bytecode stored in multiple .class files instead of a single file(you would expect compilation with the -g
flag to produce some reference to the source files, but making things easy is not the Java way...)
When JDB refers to classes I can usually do some string manipulations and look at the source file names to figure out which source file declares the relevant class. When I need to supply a class name for a breakpoint, I can read the file to get the package name, use the file name as the class name and generate the full class name that way. These two cases I got them working.
The problem starts with inner classes and anonymous classes. They reside in their own class files, and their names are mangled versions of the class that contains them. To set a breakpoint there I need the mangled name.
For example - this is Main.java
(+line numbers):
1: public class Main{
2: public static void main(String[] args){
3: new Object(){
4: @Override public String toString(){
5: System.out.println("hi");
6: return "";
7: }
8: }.toString();
9: }
10:}
I compile it using javac -g Main.java
and got Main.class
and Main$1.class
. I'm running jdb
:
Initializing jdb ...
> stop on Main.main
Deferring breakpoint Main.main.
It will be set after the class is loaded.
> run Main
run Main
Set uncaught java.lang.Throwable
Set deferred uncaught java.lang.Throwable
>
VM Started: Set deferred breakpoint Main.main
Breakpoint hit: "thread=main", Main.main(), line=3 bci=0
3 new Object(){
(I needed that part to load Main.class
- otherwise I would simply get "It will be set after the class is loaded." for all the breakpoint setting attempts.)
If I set a breakpoint for line 8 it works properly:
main[1] stop at Main:8
Set breakpoint Main:8
If I set a breakpoint for line 5 - which is part of the anonymous class - I get an error:
main[1] stop at Main:5
Unable to set breakpoint Main:5 : No code at line 5 in Main
Line 5 clearly contains code - the problem is that the code is not compiled into Main.class
- it's compiled into Main$1.class
, so I need to write instead:
main[1] stop at Main$1:5
Deferring breakpoint Main$1:5.
It will be set after the class is loaded.
Now, the way Java splits the bytecode into .class files is deterministic, and in this simple example it's easy to figure out what goes where - when you examine it with human eyes - but I need a way to figure the mangled class names programmatically(with VimScript) for real world source files. Trying to syntactically analyze the source file and figure out which is what is too complex a task - there ought to be a simpler way.
Maybe extract that information from the .class files, or question JDB about it, or even make JDB use source file names like any sane debugger for any sane language...