llvm/lldb/docs/use/remote.rst

Remote Debugging
================

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 local system, while the system running the debugged
process will be the remote system.

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 here and
the LLDB-specific extensions are documented in docs/lldb-gdb-remote.txt file
inside LLDB source repository. Besides the gdb-remote stub, the server part of
LLDB also consists of a platform 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.

In order to reduce code complexity and improve remote debugging experience LLDB
on Linux and macOS 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.

Preparation for Remote Debugging
---------------------------------

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.

Remote system
*************

On Linux and Android, all required remote functionality is contained in the
lldb-server binary. This binary combines the functionality of the platform and
gdb-remote stub. A single binary facilitates deployment and reduces code size,
since the two functions share a lot of code. The lldb-server binary is also
statically linked with the rest of LLDB (unlike lldb, which dynamically links
to liblldb.so by default), so it does not have any dependencies on the rest of
lldb. On macOS and iOS, the remote-gdb functionality is implemented by the
debugserver binary, which you will need to deploy alongside lldb-server.

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
build page.

Once the binaries are in place, you just need to run the lldb-server in
platform mode and specify the port it should listen on. For example, the
command

::

   remote% lldb-server platform --listen "*:1234" --server

will start the LLDB platform and wait for incoming connections from any address
to port 1234. Specifying an address instead of * will only allow connections
originating from that address. Adding a --server parameter to the command line
will fork off a new process for every incoming connection, allowing multiple
parallel debug sessions.

Local system
************

On the local system, you need to let LLDB know that you intend to do remote
debugging. This is achieved through the platform 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 platform list.

::

   local% lldb
   (lldb) platform list
   Available platforms:
   host: Local macOS user platform plug-in.
   remote-freebsd: Remote FreeBSD user platform plug-in.
   remote-linux: Remote Linux user platform plug-in.
   remote-netbsd: Remote NetBSD user platform plug-in.
   remote-windows: Remote Windows user platform plug-in.
   remote-android: Remote Android user platform plug-in.
   remote-ios: Remote iOS platform plug-in.
   remote-macosx: Remote macOS user platform plug-in.
   ios-simulator: iOS simulator platform plug-in.
   darwin-kernel: Darwin Kernel platform plug-in.
   tvos-simulator: Apple TV simulator platform plug-in.
   watchos-simulator: Apple Watch simulator platform plug-in.
   remote-tvos: Remote Apple TV platform plug-in.
   remote-watchos: Remote Apple Watch platform plug-in.
   remote-gdb-server: A platform that uses the GDB remote protocol as the communication transport.

The default platform is the platform host 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 "remote-".
For example, to debug a remote Linux application:

::

   (lldb) platform select remote-linux

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 platform connect command.
This command takes a number of arguments (as always, use the help command to
find out more), but normally you only need to specify the address to connect
to, e.g.:

::

   (lldb) platform connect connect://remote:1234
     Platform: remote-linux
       Triple: x86_64-gnu-linux
     Hostname: remote
    Connected: yes
   WorkingDir: /tmp

Note that the platform has a working directory of /tmp. This directory will be
used as the directory that executables will be uploaded to by default when
launching a process from local.

After this, you should be able to debug normally. You can use the process
attach to attach to an existing remote process or target create, process launch
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: get-file, put-file, mkdir, etc. The environment can be prepared
further using the platform shell command.

When using the "remote-android" platform, the client LLDB forwards two ports, one
for connecting to the platform, and another for connecting to the gdbserver.
The client ports are configurable through the environment variables
ANDROID_PLATFORM_LOCAL_PORT and ANDROID_PLATFORM_LOCAL_GDB_PORT, respectively.

Launching a locally built process on the remote machine
-------------------------------------------------------

Install and run in the platform working directory
*************************************************

To launch a locally built process on the remote system in the platform working
directory:

::

   (lldb) file a.out
   (lldb) run

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.

Changing the platform working directory
***************************************

You can change the platform working directory while connected to the platform
with:

::

   (lldb) platform settings -w /usr/local/bin

And you can verify it worked using "platform status":

::

   (lldb) platform status
     Platform: remote-linux
       Triple: x86_64-gnu-linux
     Hostname: remote
    Connected: yes
   WorkingDir: /usr/local/bin

If we run again, the program will be installed into ``/usr/local/bin``.

Install and run by specifying a remote install path
***************************************************

If you want the "a.out" executable to be installed into "/bin/a.out" instead of
the platform's current working directory, we can set the platform file
specification using python:

::

   (lldb) file a.out
   (lldb) script lldb.target.module['a.out'].SetPlatformFileSpec("/bin/a.out")
   (lldb) run

Now when you run your program, the program will be uploaded to "/bin/a.out"
instead of the platform current working directory. 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:

::

   (lldb) file a.out
   (lldb) target module add /local/build/libfoo.so
   (lldb) target module add /local/build/libbar.so
   (lldb) script lldb.target.module['libfoo.so'].SetPlatformFileSpec("/usr/lib/libfoo.so")
   (lldb) script lldb.target.module['libbar.so'].SetPlatformFileSpec("/usr/local/lib/libbar.so")
   (lldb) run

Attaching to a remote process
*****************************

If you want to attach to a remote process, you can first list the processes on
the remote system:

::

   (lldb) platform process list
   223 matching processes were found on "remote-linux"
   PID    PARENT USER       TRIPLE                   NAME
   ====== ====== ========== ======================== ============================
   68639  90652             x86_64-apple-macosx      lldb
   ...

Then attaching is as simple as specifying the remote process ID:

::

   (lldb) attach 68639