2015-04-08 15:54:31 +08:00
|
|
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
|
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
|
|
<head>
|
|
|
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
|
|
|
<link href="style.css" rel="stylesheet" type="text/css" />
|
|
|
|
<title>Remote debugging with LLDB</title>
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<div class="www_title">
|
|
|
|
The <strong>LLDB</strong> Debugger
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div id="container">
|
|
|
|
<div id="content">
|
|
|
|
|
|
|
|
<!--#include virtual="sidebar.incl"-->
|
|
|
|
|
|
|
|
<div id="middle">
|
|
|
|
<h1 class="postheader">Remote debugging</h1>
|
|
|
|
<div class="postcontent">
|
|
|
|
<p>
|
|
|
|
Remote debugging refers to the act of debugging a process which is running on a
|
|
|
|
different system, than the debugger itself. We shall refer to the system running
|
|
|
|
the debugger as the <em>local</em> system, while the system running the debugged
|
|
|
|
process will be the <em>remote</em> system.
|
|
|
|
</p>
|
|
|
|
|
|
|
|
<p>
|
|
|
|
To enable remote debugging, LLDB employs a client-server architecture. The client
|
|
|
|
part runs on the local system and the remote system runs the server. The client and
|
|
|
|
server communicate using the gdb-remote protocol, usually transported over TCP/IP.
|
|
|
|
More information on the protocol can be found
|
|
|
|
<a href="https://sourceware.org/gdb/current/onlinedocs/gdb/Remote-Protocol.html">here</a>
|
|
|
|
and the LLDB-specific extensions are documented in
|
|
|
|
<code>docs/lldb-gdb-remote.txt</code> file inside LLDB source repository. Besides the
|
|
|
|
gdb-remote stub, the server part of LLDB also consists of a <em>platform</em> binary,
|
|
|
|
which is responsible for performing advanced debugging operations, like copying files
|
|
|
|
from/to the remote system and can be used to execute arbitrary shell commands on the
|
|
|
|
remote system.
|
|
|
|
</p>
|
|
|
|
|
|
|
|
<p>
|
|
|
|
In order to reduce code complexity and improve remote debugging experience LLDB on
|
|
|
|
Linux and OSX uses the remote debugging stub even when debugging a process locally.
|
|
|
|
This is achieved by spawning a remote stub process locally and communicating with it
|
|
|
|
over the loopback interface. In the case of local debugging this whole process is
|
|
|
|
transparent to the user. The platform binary is not used in this case, since no file
|
|
|
|
transfers are needed.
|
|
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div class="postfooter"></div>
|
|
|
|
<div class="post">
|
|
|
|
<h1 class="postheader">Preparation for remote debugging</h1>
|
|
|
|
<div class="postcontent">
|
|
|
|
<p>
|
|
|
|
While the process of actual debugging (stepping, backtraces, evaluating
|
|
|
|
expressions) is same as in the local case, in the case of remote debugging, more
|
|
|
|
preparation is needed as the required binaries cannot started on the remote system
|
|
|
|
automatically. Also, if the remote system runs a different OS or architecture, the
|
|
|
|
server component needs to be compiled separately.
|
|
|
|
</p>
|
|
|
|
|
|
|
|
<h2>Remote system</h2>
|
|
|
|
<p>
|
|
|
|
On Linux and Android, all required remote functionality is contained in the
|
|
|
|
<code>lldb-server</code> binary. This binary combines the functionality of the
|
2015-06-18 13:27:05 +08:00
|
|
|
platform and gdb-remote stub. A single binary facilitates deployment and reduces
|
2015-04-08 15:54:31 +08:00
|
|
|
code size, since the two functions share a lot of code. The
|
|
|
|
<code>lldb-server</code> binary is also statically linked with the rest of LLDB
|
|
|
|
(unlike <code>lldb</code>, which dynamically links to <code>liblldb.so</code> by
|
|
|
|
default), so it does not have any dependencies on the rest of lldb. On Mac OSX and
|
|
|
|
iOS, the remote-gdb functionality is implemented by the <code>debugserver</code>
|
|
|
|
binary, which you will need to deploy alongside <code>lldb-server</code>.
|
|
|
|
</p>
|
|
|
|
|
|
|
|
<p>
|
|
|
|
The binaries mentioned above need to be present on the remote system to enable
|
|
|
|
remote debugging. You can either compile on the remote system directly or copy them
|
|
|
|
from the local machine. If compiling locally and the remote architecture differs
|
|
|
|
from the local one, you will need to cross-compile the correct version of the binaries.
|
|
|
|
More information on cross-compiling LLDB can be found on the
|
|
|
|
<a href="build.html#cross-compilation">build</a> page.
|
|
|
|
</p>
|
|
|
|
|
|
|
|
<p>
|
|
|
|
Once the binaries are in place, you just need to run the <code>lldb-server</code>
|
|
|
|
in platform mode and specify the port it should listen on. For example, the command
|
|
|
|
</p>
|
2017-11-29 04:04:43 +08:00
|
|
|
<code>
|
|
|
|
remote% <b>lldb-server platform --listen "*:1234" --server</b>
|
|
|
|
</code>
|
2015-04-08 15:54:31 +08:00
|
|
|
<p>
|
|
|
|
will start the LLDB platform and wait for incoming connections from any address to
|
|
|
|
port 1234. Specifying an address instead of <code>*</code> will only allow
|
|
|
|
connections originating from that address. Adding a <code>--server</code> parameter
|
|
|
|
to the command line will fork off a new process for every incoming connection,
|
|
|
|
allowing multiple parallel debug sessions.
|
|
|
|
</p>
|
|
|
|
|
|
|
|
<h2>Local system</h2>
|
|
|
|
|
|
|
|
<p>
|
|
|
|
On the local system, you need to let LLDB know that you intend to do remote
|
|
|
|
debugging. This is achieved through the <code>platform</code> command and its
|
|
|
|
sub-commands. As a first step you need to choose the correct platform plug-in for
|
|
|
|
your remote system. A list of available plug-ins can be obtained through
|
|
|
|
<code>platform list</code>.
|
|
|
|
</p>
|
2017-11-29 04:04:43 +08:00
|
|
|
<code>
|
|
|
|
local% <b>lldb</b>
|
|
|
|
<br>(lldb) <b>platform list</b>
|
|
|
|
<br>Available platforms:
|
|
|
|
<br>host: Local Mac OS X user platform plug-in.
|
|
|
|
<br>remote-freebsd: Remote FreeBSD user platform plug-in.
|
|
|
|
<br>remote-linux: Remote Linux user platform plug-in.
|
|
|
|
<br>remote-netbsd: Remote NetBSD user platform plug-in.
|
|
|
|
<br>remote-windows: Remote Windows user platform plug-in.
|
|
|
|
<br>remote-android: Remote Android user platform plug-in.
|
|
|
|
<br>remote-ios: Remote iOS platform plug-in.
|
|
|
|
<br>remote-macosx: Remote Mac OS X user platform plug-in.
|
|
|
|
<br>ios-simulator: iOS simulator platform plug-in.
|
|
|
|
<br>darwin-kernel: Darwin Kernel platform plug-in.
|
|
|
|
<br>tvos-simulator: Apple TV simulator platform plug-in.
|
|
|
|
<br>watchos-simulator: Apple Watch simulator platform plug-in.
|
|
|
|
<br>remote-tvos: Remote Apple TV platform plug-in.
|
|
|
|
<br>remote-watchos: Remote Apple Watch platform plug-in.
|
|
|
|
<br>remote-gdb-server: A platform that uses the GDB remote protocol as the communication transport.
|
|
|
|
</code>
|
2015-04-08 15:54:31 +08:00
|
|
|
<p>
|
|
|
|
The default platform is the platform <code>host</code> which is used for local
|
|
|
|
debugging. Apart from this, the list should contain a number of plug-ins, for
|
|
|
|
debugging different kinds of systems. The remote plug-ins are prefixed with
|
2017-11-29 04:04:43 +08:00
|
|
|
"<code>remote-</code>". For example, to debug a remote Linux application:
|
|
|
|
<br>
|
|
|
|
<code>
|
2018-05-29 17:10:46 +08:00
|
|
|
<br>(lldb) <b>platform select remote-linux</b>
|
2017-11-29 04:04:43 +08:00
|
|
|
</code>
|
2015-04-08 15:54:31 +08:00
|
|
|
|
|
|
|
<p>
|
|
|
|
After selecting the platform plug-in, you should receive a prompt which confirms
|
|
|
|
the selected platform, and states that you are not connected. This is because
|
|
|
|
remote plug-ins need to be connected to their remote platform counterpart to
|
|
|
|
operate. This is achieved using the <code>platform connect</code> command. This
|
|
|
|
command takes a number of arguments (as always, use the <code>help</code> command
|
|
|
|
to find out more), but normally you only need to specify the address to connect to,
|
|
|
|
e.g.:
|
2017-11-29 04:04:43 +08:00
|
|
|
<br>
|
|
|
|
<code>
|
|
|
|
<br>(lldb) <b>platform connect connect://remote:1234</b>
|
|
|
|
<br> Platform: remote-linux
|
|
|
|
<br> Triple: x86_64-gnu-linux
|
|
|
|
<br> Hostname: remote
|
|
|
|
<br> Connected: yes
|
|
|
|
<br>WorkingDir: /tmp
|
|
|
|
</code>
|
|
|
|
<p>
|
|
|
|
Note that the platform has a working directory of <code>/tmp</code>. This directory
|
|
|
|
will be used as the directory that executables will be uploaded to by default when
|
|
|
|
launching a process from <em>local</em>.
|
2015-04-08 15:54:31 +08:00
|
|
|
<p>
|
|
|
|
After this, you should be able to debug normally. You can use the
|
|
|
|
<code>process attach</code> to attach to an existing remote process or
|
|
|
|
<code>target create</code>, <code>process launch</code> to start a new one. The
|
|
|
|
platform plugin will transparently take care of uploading or downloading the
|
|
|
|
executable in order to be able to debug. If your application needs additional
|
|
|
|
files, you can transfer them using the platform commands: <code>get-file</code>,
|
|
|
|
<code>put-file</code>, <code>mkdir</code>, etc. The environment can be prepared
|
|
|
|
further using the <code>platform shell</code> command.
|
|
|
|
</p>
|
2017-11-29 04:04:43 +08:00
|
|
|
<h3>Launching a locally built process on the remote machine</h3>
|
|
|
|
<h4>Install and run in the platform working directory</h4>
|
|
|
|
<p>
|
|
|
|
To launch a locally built process on the remote system in the
|
|
|
|
platform working directory:
|
|
|
|
<br>
|
|
|
|
<code>
|
|
|
|
<br>(lldb) <b>file a.out</b>
|
|
|
|
<br>(lldb) <b>run</b>
|
|
|
|
</code>
|
|
|
|
<p>
|
|
|
|
This will cause LLDB to create a target with the "a.out"
|
|
|
|
executable that you cross built. The "run" command will cause
|
|
|
|
LLDB to upload "a.out" to the platform's current working
|
|
|
|
directory only if the file has changed.
|
|
|
|
The platform connection allows us to transfer files, but also
|
|
|
|
allows us to get the MD5 checksum of the file on the other end
|
|
|
|
and only upload the file if it has changed. LLDB will automatically
|
|
|
|
launch a lldb-server in gdbremote mode to allow you to debug this
|
|
|
|
executable, connect to it and start your debug session for you.
|
|
|
|
</p>
|
|
|
|
<h4>Changing the platform working directory</h4>
|
|
|
|
<p>
|
|
|
|
You can change the platform working directory while connected to
|
|
|
|
the platform with:
|
|
|
|
<br>
|
|
|
|
<code>
|
|
|
|
<br>(lldb) <b>platform settings -w /usr/local/bin</b>
|
|
|
|
</code>
|
|
|
|
<p>
|
|
|
|
And you can verify it worked using "platform status":
|
|
|
|
<br>
|
|
|
|
<code>
|
|
|
|
<br>(lldb) <b>platform status</b>
|
|
|
|
<br> Platform: remote-linux
|
|
|
|
<br> Triple: x86_64-gnu-linux
|
|
|
|
<br> Hostname: remote
|
|
|
|
<br> Connected: yes
|
|
|
|
<br>WorkingDir: /usr/local/bin
|
|
|
|
</code>
|
|
|
|
<p>
|
|
|
|
If we run again, the program will be installed into /usr/local/bin.
|
|
|
|
</p>
|
|
|
|
|
2015-04-08 15:54:31 +08:00
|
|
|
|
2017-11-29 04:04:43 +08:00
|
|
|
<h4>Install and run by specifying a remote install path</h4>
|
|
|
|
<p>
|
|
|
|
If you want the "a.out" executable to be installed into
|
2018-05-29 17:10:46 +08:00
|
|
|
"/bin/a.out" instead of the platform's current working directory,
|
2017-11-29 04:04:43 +08:00
|
|
|
we can set the platform file specification using python:
|
|
|
|
<br>
|
|
|
|
<code>
|
|
|
|
<br>(lldb) <b>file a.out</b>
|
|
|
|
<br>(lldb) <b>script lldb.target.module['a.out'].SetPlatformFileSpec("/bin/a.out")</b>
|
|
|
|
<br>(lldb) <b>run</b>
|
|
|
|
</code>
|
|
|
|
<p>
|
|
|
|
Now when you run your program, the program will be uploaded to
|
2018-05-29 17:10:46 +08:00
|
|
|
"/bin/a.out" instead of the platform current working directory.
|
2017-11-29 04:04:43 +08:00
|
|
|
Only the main executable is uploaded to the remote system by
|
|
|
|
default when launching the application. If you have shared
|
|
|
|
libraries that should also be uploaded, then you can add the
|
|
|
|
locally build shared library to the current target and set its
|
|
|
|
platform file specification:
|
|
|
|
</p>
|
|
|
|
<code>
|
|
|
|
<br>(lldb) <b>file a.out</b>
|
|
|
|
<br>(lldb) <b>target module add /local/build/libfoo.so</b>
|
|
|
|
<br>(lldb) <b>target module add /local/build/libbar.so</b>
|
|
|
|
<br>(lldb) <b>script lldb.target.module['libfoo.so'].SetPlatformFileSpec("/usr/lib/libfoo.so")</b>
|
|
|
|
<br>(lldb) <b>script lldb.target.module['libbar.so'].SetPlatformFileSpec("/usr/local/lib/libbar.so")</b>
|
|
|
|
<br>(lldb) <b>run</b>
|
|
|
|
</code>
|
|
|
|
<h4>Attaching to a remote process</h4>
|
|
|
|
<p>
|
|
|
|
If you want to attach to a remote process, you can first list the
|
|
|
|
processes on the remote system:
|
|
|
|
</p>
|
|
|
|
<code>
|
|
|
|
<br>(lldb) <b>platform process list</b>
|
|
|
|
<br>223 matching processes were found on "remote-linux"
|
|
|
|
<br>PID PARENT USER TRIPLE NAME
|
|
|
|
<br>====== ====== ========== ======================== ============================
|
|
|
|
<br>68639 90652 x86_64-apple-macosx lldb
|
|
|
|
<br>...
|
|
|
|
</code>
|
|
|
|
<p>
|
|
|
|
Then attaching is as simple as specifying the remote process ID:
|
|
|
|
</p>
|
|
|
|
<code>
|
|
|
|
<br>(lldb) <b>attach 68639</b>
|
|
|
|
</code>
|
2015-04-08 15:54:31 +08:00
|
|
|
</div>
|
|
|
|
<div class="postfooter"></div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</body>
|
|
|
|
</html>
|