-
Liebe Threader,
ich bin jetzt seit einer Weile dabei, mich mit dem JDI zu befassen, das in Java integriert ist. Mein Ziel ist es, einen kleinen eigenen Debugger zu bauen, den ich hinterher hoffentlich je nach Projekt modifizieren kann.. Das Grundgerüst steht auch schon:
Code java:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
class StateExaminer { static boolean _connected = false; public StateExaminer (String sClassName) { EventQueue eventQueue; LaunchingConnector lconnector = Bootstrap.virtualMachineManager ().defaultConnector (); Map<String, Argument> launchingArgs = lconnector.defaultArguments (); VirtualMachine vm; Argument mainArg = launchingArgs.get ("main"); mainArg.setValue (sClassName); for (String sKey: launchingArgs.keySet ()) { System.out.println (sKey + ": " + launchingArgs.get (sKey)); } try { vm = lconnector.launch (launchingArgs); vm.setDebugTraceMode (VirtualMachine.TRACE_EVENTS); _connected = true; new RedirectedStream (vm.process ().getErrorStream ()); new RedirectedStream (vm.process ().getInputStream ()); EventRequestManager eventManager = vm.eventRequestManager (); ClassPrepareRequest classPrepare = eventManager.createClassPrepareRequest (); classPrepare.setSuspendPolicy (EventRequest.SUSPEND_EVENT_THREAD); classPrepare.enable (); MethodExitRequest methodExit = eventManager.createMethodExitRequest (); methodExit.setSuspendPolicy (EventRequest.SUSPEND_EVENT_THREAD); methodExit.enable (); ExceptionRequest exception = eventManager.createExceptionRequest (null, true, true); exception.setSuspendPolicy (EventRequest.SUSPEND_EVENT_THREAD); exception.enable (); eventQueue = vm.eventQueue (); vm.resume (); while (_connected) { EventSet eventSet = eventQueue.remove (); for (EventIterator it = eventSet.eventIterator (); it.hasNext ();) { Event event = it.next (); if (event instanceof MethodExitEvent) { // MethodExitEvent meEvt = (MethodExitEvent) event; // Noch zu erweiternder Code } else if (event instanceof ClassPrepareEvent) { ClassPrepareEvent cpEvt = (ClassPrepareEvent) event; System.out.println ("Loading " + cpEvt.referenceType ().name ()); } else if (event instanceof ExceptionEvent) { ExceptionEvent excEvt = (ExceptionEvent) event; System.out.println ("Error: " + excEvt); } else if (event instanceof VMDisconnectEvent) { System.out.println ("VM disconnected"); _connected = false; } } if (_connected) { eventSet.resume (); } } } catch (Exception exc) { System.out.println (exc); } } /** * Liefert den Status der Verbindung zwischen Debugger-JVM und Mirror-JVM * @return */ public static boolean getConnection () { return _connected; } }
Die benutzte Klasse RedirectedStream enthält Folgendes:
Code java:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; class RedirectedStream extends Thread { InputStreamReader in; OutputStreamWriter out; public RedirectedStream (InputStream in) { super (); this.in = new InputStreamReader (in); out = new OutputStreamWriter (System.out); start (); } public void run () { while (StateExaminer.getConnection ()) { char[] cBuf = new char[1024]; try { while (in.read (cBuf) > 0) { out.write (cBuf); } } catch (IOException e) { System.out.println ("Could not read from/write to stream"); } } } }
Leider gibt mir das Programm, wenn ich es ausführe und die Datei "DebugDummy" übergebe (diese liegt im gleichen Verzeichnis wie StateExaminer.class), eine NoClassDefNotFoundException zurück, wenn die erzeugte Mirror-VM versucht, diese zu laden -.- Kann mir jemand helfen, den Fehler zu beheben?
Hier noch DebugDummy.class:
Geändert von Teaxtor (08.08.11 um 18:47 Uhr) Grund: Bessere Lesbarkeit des Codes
-
08.08.11 17:54 #2SE Tutorials.de Gastzugang
Verwende für Java-Codes bitte Java-Code-Tags *siehe meine Signatur* da das Syntaxhighlightning die Lesbarkeit verbessert.
-
Ok, jetzt habe ich das ganze selbst gelöst: das Problem, woran es IMO lag, war, dass die zu debuggende Klasse nicht im Klassenpfad der initialisierenden VM lag; zudem gab es keine Möglichkeit, diesen zu ändern. Daher habe ich jetzt statt "com.sun.jdi.CommandLineLaunch" den LaunchingConnector mit dem Namen "com.sun.jdi.RawCommandLineLaunch" benutzt, der hier diese Einstellungsmöglichkeiten besitzt.
Dazu habe ich den Code wie folgt geändert:
Code java:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
import java.io.File; [..] // sind gegebenfalls angepasst worden import com.sun.jdi.request.MethodExitRequest; class StateExaminer { static boolean _connected = false; /** * Konstruktor: Initialisiert den Debugger für die übergebene Klasse (definiert durch Klassenpfad und -name) und startet ihn * @param sClassPath * @param sClassName */ public StateExaminer (String sClassPath, String sClassName) { EventQueue eventQueue; LaunchingConnector lconnector = getLaunchingConnector ("com.sun.jdi.RawCommandLineLaunch"); Map<String, Argument> launchingArgs = lconnector.defaultArguments (); PathSearchingVirtualMachine vm; Argument commandArg = launchingArgs.get ("command"); commandArg.setValue ("java " + "-Xrunjdwp:transport=dt_shmem,address=irgendeinstring,suspend=y" + " -cp " + sClassPath + " " + sClassName); Argument addressArg = launchingArgs.get ("address"); addressArg.setValue ("irgendeinstring"); for (String sKey: launchingArgs.keySet ()) { System.out.println (sKey + ": " + launchingArgs.get (sKey)); } try { [...] hat sich nichts geändert } } /** * Liefert den mit sIdentifier bezeichneten LaunchingConnector - * entweder com.sun.jdi.CommandLineLaunch oder com.sun.jdi.RawCommandLineLaunch * @param sIdentifier Bezeichner des Connectors * @return */ private LaunchingConnector getLaunchingConnector (String sIdentifier) { LaunchingConnector lcRet = null; List<LaunchingConnector> connectors = Bootstrap.virtualMachineManager ().launchingConnectors (); for (LaunchingConnector connector: connectors) { if (connector.name ().equals (sIdentifier)) { lcRet = connector; } } return lcRet; } /** * Liefert den Status der Verbindung zwischen Debugger-JVM und Target-JVM * @return */ public static boolean getConnection () { return _connected; }
Zur Erläuterung: Bei dem RawCommandLineLauncher muss das gesamte Argument, mit dem man die zu debuggende Klasse in der Konsole debuggen würde, als "command" gesetzt werden..
-> der Vorteil: über die Option -cp <Path> kann ein BaseDirectory definiert werden, von dem aus dann versucht wird, die zu ladende Klasse zu finden.
Zum Argument:
"java": bezeichnet den zu nutzenden Java-Interpreter.. es gibt glaub ich noch andere, aber mir fallen die grad nicht mehr einCode java:1
"java " + "-Xrunjdwp:transport=dt_shmem,address=irgendeinstring,suspend=y" + " -cp " + sClassPath + " " + sClassName
"-Xrunjdwp:[...]": hier wird der interpreter angewiesen, die verbindung zur VM über das Java Debugging Wire Protocol mit den darauffolgenden Optionen herzustellen; die Optionen wären
"transport=dt_shmem": Der Informationsaustausch zwischen Debugger-VM und Target-VM wird über Shared Memory (nur unter Windows) realisiert; eine andere Möglichkeit wäre "dt_socket", genaueres dazu lest ihr euch bitte in der JDI Spezifikation von Oracle durch
"adress=irgendeinstring": dies ist die Referenzadresse der Target-VM, über die später die Debugger-VM versuchen wird, eine Verbindung aufzubauen; bei der Shared Memory-Variante ist es egal, welche Bezeichnung ihr hier angebt (es sollte eine sinnvolle sein
)
"suspend=y": Definiert, ob die Target-VM nach dem Starten angehalten werden soll oder ob sie mit dem Ausführen er geladenen Klasse anfangen soll; bei "y" wird sie angehalten und muss dann mitwieder gestartet werden - siehe QuelltextCode java:1
vm.resume()
Letzlich muss noch das "address"-Argument des RawCommandLineLaunch-Connectors auf die im Argument benutzte Addresse gesetzt werden - siehe Quelltext
Ähnliche Themen
-
Java Native Interface
Von Technoblade im Forum C/C++Antworten: 8Letzter Beitrag: 20.06.11, 00:06 -
LineNos: Stacktraces mit Debugging Information anreichern via Java Agent
Von Thomas Darimont im Forum JavaAntworten: 1Letzter Beitrag: 09.06.11, 10:05 -
Java native Interface
Von Technoblade im Forum JavaAntworten: 9Letzter Beitrag: 22.04.11, 08:51 -
Java Native Interface
Von SKORP79 im Forum JavaAntworten: 10Letzter Beitrag: 31.10.05, 14:56 -
Hilfe bei Java Native Interface
Von mister_ex im Forum JavaAntworten: 2Letzter Beitrag: 15.06.04, 09:33



1Danke


Zitieren
Login





