• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>&lt;application&gt;</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>
58Pre-Froyo implementations of the Dalvik VM used read-only memory mappings
59for all bytecode, which made it necessary to scan for breakpoints by
60comparing the program counter to a set of addresses.  In Froyo this was
61changed to allow insertion of breakpoint opcodes.  This allows the VM
62to execute code more quickly, and does away with the hardcoded limit
63of 20 breakpoints.  Even with this change, however, the debug-enabled
64interpreter is much slower than the regular interpreter (perhaps 5x).
65</p><p>
66The JDWP protocol is stateless, so the VM handles individual debugger
67requests as they arrive, and posts events to the debugger as they happen.
68</p><p>
69
70
71<h2>Debug Data</h2>
72<p> Source code debug data, which includes mappings of source code to
73bytecode and lists describing which registers are used to hold method
74arguments and local variables, are optionally emitted by the Java compiler.
75When <code>dx</code> converts Java bytecode to Dalvik bytecode, it must
76also convert this debug data.
77</p><p>
78<code>dx</code> must also ensure that it doesn't perform operations
79that confuse the debugger.  For example, re-using registers that hold
80method arguments and the "<code>this</code>" pointer is allowed in
81Dalvik bytecode if the values are never used or no longer needed.
82This can be very confusing for the debugger (and the programmer)
83since the values have method scope and aren't expected to disappear.  For
84this reason, <code>dx</code> generates sub-optimal code in some situations
85when debugging support is enabled.
86</p><p>
87Some of the debug data is used for other purposes; in particular, having
88filename and line number data is necessary for generating useful exception
89stack traces.  This data can be omitted by <code>dx</code> to make the DEX
90file smaller.
91</p><p>
92
93
94<h2>Usage</h2>
95
96<p>
97The Dalvik VM supports many of the same command-line flags that other popular
98desktop VMs do.  To start a VM with debugging enabled, you add a command-line
99flag with some basic options.  The basic incantation looks something
100like this:
101
102<pre>-Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=y</pre>
103or
104<pre>-agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=y</pre>
105
106</p><p>
107After the initial prefix, options are provided as name=value pairs.  The
108options currently supported by the Dalvik VM are:
109<dl>
110    <dt>transport (no default)</dt>
111    <dd>Communication transport mechanism to use.  Dalvik supports
112    TCP/IP sockets (<code>dt_socket</code>) and connection over USB
113    through ADB (<code>dt_android_adb</code>).
114    </dd>
115
116    <dt>server (default='n')</dt>
117    <dd>Determines whether the VM acts as a client or a server.  When
118    acting as a server, the VM waits for a debugger to connect to it.
119    When acting as a client, the VM attempts to connect to a waiting
120    debugger.
121    </dd>
122
123    <dt>suspend (default='n')</dt>
124    <dd>If set to 'y', the VM will wait for a debugger connection
125    before executing application code.  When the debugger connects (or
126    when the VM finishes connecting to the debugger), the VM tells the
127    debugger that it has suspended, and will not proceed until told
128    to resume.  If set to 'n', the VM just plows ahead.
129    </dd>
130
131    <dt>address (default="")</dt>
132    <dd>This must be <code>hostname:port</code> when <code>server=n</code>,
133    but can be just <code>port</code> when <code>server=y</code>.  This
134    specifies the IP address and port number to connect or listen to.
135    <br>
136    Listening on port 0 has a special meaning: try to
137    listen on port 8000; if that fails, try 8001, 8002, and so on.  (This
138    behavior is non-standard and may be removed from a future release.)
139    <br>This option has no meaning for <code>transport=dt_android_adb</code>.
140    </dd>
141
142    <dt>help (no arguments)</dt>
143    <dd>If this is the only option, a brief usage message is displayed.
144    </dd>
145
146    <dt>launch, onthrow, oncaught, timeout</dt>
147    <dd>These options are accepted but ignored.
148    </dd>
149</dl>
150
151</p><p>
152To debug a program on an Android device using DDMS over USB, you could
153use a command like this:
154<pre>% dalvikvm -agentlib:jdwp=transport=dt_android_adb,suspend=y,server=y -cp /data/foo.jar Foo</pre>
155
156This tells the Dalvik VM to run the program with debugging enabled, listening
157for a connection from DDMS, and waiting for a debugger.  The program will show
158up with an app name of "?" in the process list, because it wasn't started
159from the Android application framework.  From here you would connect your
160debugger to the appropriate DDMS listen port (e.g.
161<code>jdb -attach localhost:8700</code> after selecting it in the app list).
162
163</p><p>
164To debug a program on an Android device using TCP/IP bridged across ADB,
165you would first need to set up forwarding:
166<pre>% adb forward tcp:8000 tcp:8000
167% adb shell dalvikvm -agentlib:jdwp=transport=dt_socket,address=8000,suspend=y,server=y -cp /data/foo.jar Foo</pre>
168and then <code>jdb -attach localhost:8000</code>.
169</p><p>
170(In the above examples, the VM will be suspended when you attach.  In jdb,
171type <code>cont</code> to continue.)
172</p><p>
173The DDMS integration makes the <code>dt_android_adb</code> transport much
174more convenient when debugging on an Android device, but when working with
175Dalvik on the desktop it makes sense to use the TCP/IP transport.
176</p><p>
177
178
179<h2>Known Issues and Limitations</h2>
180
181</p><p>
182Most of the optional features JDWP allows are not implemented.  These
183include field access watchpoints and better tracking of monitors.
184</p><p>
185Not all JDWP requests are implemented.  In particular, anything that
186never gets emitted by the debuggers we've used is not supported and will
187result in error messages being logged.  Support will be added when a
188use case is uncovered.
189</p><p>
190&nbsp;
191</p><p>
192The debugger and garbage collector are somewhat loosely
193integrated at present.  The VM currently guarantees that any object the
194debugger is aware of will not be garbage collected until after the
195debugger disconnects.  This can result in a build-up over time while the
196debugger is connected.  For example, if the debugger sees a running
197thread, the associated Thread object will not be collected, even after
198the thread terminates.
199</p><p>
200The only way to "unlock" the references is to detach and reattach the
201debugger.
202</p><p>
203&nbsp;
204</p><p>
205The translation from Java bytecode to Dalvik bytecode may result in
206identical sequences of instructions being combined.  This can make it
207look like the wrong bit of code is being executed.  For example:
208<pre>    int test(int i) {
209        if (i == 1) {
210            return 0;
211        }
212        return 1;
213    }</pre>
214The Dalvik bytecode uses a common <code>return</code> instruction for both
215<code>return</code> statements, so when <code>i</code> is 1 the debugger
216will single-step through <code>return 0</code> and then <code>return 1</code>.
217</p><p>
218&nbsp;
219</p><p>
220Dalvik handles synchronized methods differently from other VMs.
221Instead of marking a method as <code>synchronized</code> and expecting
222the VM to handle the locks, <code>dx</code> inserts a "lock"
223instruction at the top of the method and an "unlock" instruction in a
224synthetic <code>finally</code> block.  As a result, when single-stepping
225a <code>return</code> statement, the "current line" cursor may jump to
226the last line in the method.
227</p><p>
228This can also affect the way the debugger processes exceptions.  The
229debugger may decide to break on an
230exception based on whether that exception is "caught" or "uncaught".  To
231be considered uncaught, there must be no matching <code>catch</code> block
232or <code>finally</code> clause between the current point of execution and
233the top of the thread.  An exception thrown within or below a synchronized
234method will always be considered "caught", so the debugger won't stop
235until the exception is re-thrown from the synthetic <code>finally</code> block.
236</p><p>
237
238
239<address>Copyright &copy; 2009 The Android Open Source Project</address>
240</p>
241
242</body>
243</html>
244