1<html> 2<head> 3<title>Dalvik Debugger Support</title> 4</head> 5 6<body> 7<h1>Dalvik Debugger Support</h1> 8 9<p> 10The Dalvik virtual machine supports source-level debugging with many popular 11development environments. Any tool that allows remote debugging over JDWP 12(the 13<a href="http://java.sun.com/javase/6/docs/technotes/guides/jpda/jdwp-spec.html"> 14Java Debug Wire Protocol</a>) is expected work. Supported debuggers 15include jdb, Eclipse, IntelliJ, and JSwat. 16</p><p> 17The VM does not support tools based on JVMTI (Java Virtual 18Machine Tool Interface). This is a relatively intrusive approach that 19relies on bytecode insertion, something the Dalvik VM does not currently 20support. 21</p><p> 22Dalvik's implementation of JDWP also includes hooks for supporting 23DDM (Dalvik Debug Monitor) features, notably as implemented by DDMS 24(Dalvik Debug Monitor Server) and the Eclipse ADT plugin. The protocol 25and VM interaction is described in some detail 26<a href="debugmon.html">here</a>. 27</p><p> 28All of the debugger support in the VM lives in the <code>dalvik/vm/jdwp</code> 29directory, and is almost entirely isolated from the rest of the VM sources. 30<code>dalvik/vm/Debugger.c</code> bridges the gap. The goal in doing so 31was to make it easier to re-use the JDWP code in other projects. 32</p><p> 33 34 35<h2>Implementation</h2> 36 37<p> 38Every VM that has debugging enabled starts a "JDWP" thread. The thread 39typically sits idle until DDMS or a debugger connects. The thread is 40only responsible for handling requests from the debugger; VM-initated 41communication, such as notifying the debugger when the VM has stopped at 42a breakpoint, are sent from the affected thread. 43</p><p> 44When the VM is started from the Android app framework, debugging is enabled 45for all applications when the system property <code>ro.debuggable</code> 46is set to </code>1</code> (use <code>adb shell getprop ro.debuggable</code> 47to check it). If it's zero, debugging can be enabled via the application's 48manifest, which must include <code>android:debuggable="true"</code> in the 49<code><application></code> element. 50 51</p><p> 52The VM recognizes the difference between a connection from DDMS and a 53connection from a debugger (either directly or in concert with DDMS). 54A connection from DDMS alone doesn't result in a change in VM behavior, 55but when the VM sees debugger packets it allocates additional data 56structures and may switch to a different implementation of the interpreter. 57</p><p> 58Because Dalvik maps bytecode into memory read-only, some common 59techniques are difficult to implement without allocating additional memory. 60For example, suppose the debugger sets a breakpoint in a method. The 61quick way to handle this is to insert a breakpoint instruction directly 62into the code. When the instruction is reached, the breakpoint handler 63engages. Without this, it's necessary to perform an "is there a breakpoint 64here" scan. Even with some optimizations, the debug-enabled interpreter 65is much slower than the regular interpreter (perhaps 5x). 66</p><p> 67The JDWP protocol is stateless, so the VM handles individual debugger 68requests as they arrive, and posts events to the debugger as they happen. 69</p><p> 70 71 72<h2>Debug Data</h2> 73<p> Source code debug data, which includes mappings of source code to 74bytecode and lists describing which registers are used to hold method 75arguments and local variables, are optionally emitted by the Java compiler. 76When <code>dx</code> converts Java bytecode to Dalvik bytecode, it must 77also convert this debug data. 78</p><p> 79<code>dx</code> must also ensure that it doesn't perform operations 80that confuse the debugger. For example, re-using registers that hold 81method arguments and the "<code>this</code>" pointer is allowed in 82Dalvik bytecode if the values are never used or no longer needed. 83This can be very confusing for the debugger (and the programmer) 84since the values have method scope and aren't expected to disappear. For 85this reason, <code>dx</code> generates sub-optimal code in some situations 86when debugging support is enabled. 87</p><p> 88Some of the debug data is used for other purposes; in particular, having 89filename and line number data is necessary for generating useful exception 90stack traces. This data can be omitted by <code>dx</code> to make the DEX 91file smaller. 92</p><p> 93 94 95<h2>Usage</h2> 96 97<p> 98The Dalvik VM supports many of the same command-line flags that other popular 99desktop VMs do. To start a VM with debugging enabled, you add a command-line 100flag with some basic options. The basic incantation looks something 101like this: 102 103<pre>-Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=y</pre> 104or 105<pre>-agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=y</pre> 106 107</p><p> 108After the initial prefix, options are provided as name=value pairs. The 109options currently supported by the Dalvik VM are: 110<dl> 111 <dt>transport (no default)</dt> 112 <dd>Communication transport mechanism to use. Dalvik supports 113 TCP/IP sockets (<code>dt_socket</code>) and connection over USB 114 through ADB (<code>dt_android_adb</code>). 115 </dd> 116 117 <dt>server (default='n')</dt> 118 <dd>Determines whether the VM acts as a client or a server. When 119 acting as a server, the VM waits for a debugger to connect to it. 120 When acting as a client, the VM attempts to connect to a waiting 121 debugger. 122 </dd> 123 124 <dt>suspend (default='n')</dt> 125 <dd>If set to 'y', the VM will wait for a debugger connection 126 before executing application code. When the debugger connects (or 127 when the VM finishes connecting to the debugger), the VM tells the 128 debugger that it has suspended, and will not proceed until told 129 to resume. If set to 'n', the VM just plows ahead. 130 </dd> 131 132 <dt>address (default="")</dt> 133 <dd>This must be <code>hostname:port</code> when <code>server=n</code>, 134 but can be just <code>port</code> when <code>server=y</code>. This 135 specifies the IP address and port number to connect or listen to. 136 <br> 137 Listening on port 0 has a special meaning: try to 138 listen on port 8000; if that fails, try 8001, 8002, and so on. (This 139 behavior is non-standard and may be removed from a future release.) 140 <br>This option has no meaning for <code>transport=dt_android_adb</code>. 141 </dd> 142 143 <dt>help (no arguments)</dt> 144 <dd>If this is the only option, a brief usage message is displayed. 145 </dd> 146 147 <dt>launch, onthrow, oncaught, timeout</dt> 148 <dd>These options are accepted but ignored. 149 </dd> 150</dl> 151 152</p><p> 153To debug a program on an Android device using DDMS over USB, you could 154use a command like this: 155<pre>% dalvikvm -agentlib:jdwp=transport=dt_android_adb,suspend=y,server=y -cp /data/foo.jar Foo</pre> 156 157This tells the Dalvik VM to run the program with debugging enabled, listening 158for a connection from DDMS, and waiting for a debugger. The program will show 159up with an app name of "?" in the process list, because it wasn't started 160from the Android application framework. From here you would connect your 161debugger to the appropriate DDMS listen port (e.g. 162<code>jdb -attach localhost:8700</code> after selecting it in the app list). 163 164</p><p> 165To debug a program on an Android device using TCP/IP bridged across ADB, 166you would first need to set up forwarding: 167<pre>% adb forward tcp:8000 tcp:8000 168% adb shell dalvikvm -agentlib:jdwp=transport=dt_socket,address=8000,suspend=y,server=y -cp /data/foo.jar Foo</pre> 169and then <code>jdb -attach localhost:8000</code>. 170</p><p> 171(In the above examples, the VM will be suspended when you attach. In jdb, 172type <code>cont</code> to continue.) 173</p><p> 174The DDMS integration makes the <code>dt_android_adb</code> transport much 175more convenient when debugging on an Android device, but when working with 176Dalvik on the desktop it makes sense to use the TCP/IP transport. 177</p><p> 178 179 180<h2>Known Issues and Limitations</h2> 181 182</p><p> 183Most of the optional features JDWP allows are not implemented. These 184include field access watchpoints and better tracking of monitors. 185</p><p> 186Not all JDWP requests are implemented. In particular, anything that 187never gets emitted by the debuggers we've used is not supported and will 188result in error messages being logged. Support will be added when a 189use case is uncovered. 190</p><p> 191 192</p><p> 193The debugger and garbage collector are somewhat loosely 194integrated at present. The VM currently guarantees that any object the 195debugger is aware of will not be garbage collected until after the 196debugger disconnects. This can result in a build-up over time while the 197debugger is connected. For example, if the debugger sees a running 198thread, the associated Thread object will not be collected, even after 199the thread terminates. 200</p><p> 201The situation is exacerbated by a flaw in the exception processing code, 202which results in nearly all exceptions being added to the "do not discard" 203list, even if the debugger never sees them. Having a debugger attached 204to a program that throws lots of exceptions can result in out-of-memory 205errors. This will be fixed in a future release. 206</p><p> 207The only way to "unlock" the references is to detach and reattach the 208debugger. 209</p><p> 210 211</p><p> 212The translation from Java bytecode to Dalvik bytecode may result in 213identical sequences of instructions being combined. This can make it 214look like the wrong bit of code is being executed. For example: 215<pre> int test(int i) { 216 if (i == 1) { 217 return 0; 218 } 219 return 1; 220 }</pre> 221The Dalvik bytecode uses a common <code>return</code> instruction for both 222<code>return</code> statements, so when <code>i</code> is 1 the debugger 223will single-step through <code>return 0</code> and then <code>return 1</code>. 224</p><p> 225 226</p><p> 227Dalvik handles synchronized methods differently from other VMs. 228Instead of marking a method as <code>synchronized</code> and expecting 229the VM to handle the locks, <code>dx</code> inserts a "lock" 230instruction at the top of the method and an "unlock" instruction in a 231synthetic <code>finally</code> block. As a result, when single-stepping 232a <code>return</code> statement, the "current line" cursor may jump to 233the last line in the method. 234</p><p> 235This can also affect the way the debugger processes exceptions. The 236debugger may decide to break on an 237exception based on whether that exception is "caught" or "uncaught". To 238be considered uncaught, there must be no matching <code>catch</code> block 239or <code>finally</code> clause between the current point of execution and 240the top of the thread. An exception thrown within or below a synchronized 241method will always be considered "caught", so the debugger won't stop 242until the exception is re-thrown from the synthetic <code>finally</code> block. 243</p><p> 244 245 246<address>Copyright © 2009 The Android Open Source Project</address> 247</p> 248 249</body> 250</html> 251