Add --lldb to gdbclient.py
Test: `gdbclient.py --lldb -r /system/bin/toybox` and try `b main` `c`
Test: `/data/local/tmp/arm64-lldb-server gdbserver :5039 /system/bin/toybox` and `gdbclient.py --lldb -p 4909`
Change-Id: If7b6895e9c778cdee3764a4058cf70238bdd6b8a
diff --git a/scripts/gdbclient.py b/scripts/gdbclient.py
index e3a0503..65f21d7 100755
--- a/scripts/gdbclient.py
+++ b/scripts/gdbclient.py
@@ -33,6 +33,27 @@
g_temp_dirs = []
+
+def read_toolchain_config(root):
+ """Finds out current toolchain path and version."""
+ def get_value(str):
+ return str[str.index('"') + 1:str.rindex('"')]
+
+ config_path = os.path.join(root, 'build', 'soong', 'cc', 'config',
+ 'global.go')
+ with open(config_path) as f:
+ contents = f.readlines()
+ clang_base = ""
+ clang_version = ""
+ for line in contents:
+ line = line.strip()
+ if line.startswith('ClangDefaultBase'):
+ clang_base = get_value(line)
+ elif line.startswith('ClangDefaultVersion'):
+ clang_version = get_value(line)
+ return (clang_base, clang_version)
+
+
def get_gdbserver_path(root, arch):
path = "{}/prebuilts/misc/gdbserver/android-{}/gdbserver{}"
if arch.endswith("64"):
@@ -41,6 +62,17 @@
return path.format(root, arch, "")
+def get_lldb_server_path(root, clang_base, clang_version, arch):
+ arch = {
+ 'arm': 'arm',
+ 'arm64': 'aarch64',
+ 'x86': 'i386',
+ 'x86_64': 'x86_64',
+ }[arch]
+ return os.path.join(root, clang_base, "linux-x86",
+ clang_version, "runtimes_ndk_cxx", arch, "lldb-server")
+
+
def get_tracer_pid(device, pid):
if pid is None:
return 0
@@ -77,6 +109,10 @@
".vscode/launch.json configuration needed to connect the debugging " +
"client to the server."))
+ lldb_group = parser.add_mutually_exclusive_group()
+ lldb_group.add_argument("--lldb", action="store_true", help="Use lldb.")
+ lldb_group.add_argument("--no-lldb", action="store_true", help="Do not use lldb.")
+
parser.add_argument(
"--env", nargs=1, action="append", metavar="VAR=VALUE",
help="set environment variable when running a binary")
@@ -300,7 +336,19 @@
return gdb_commands
-def generate_setup_script(gdbpath, sysroot, linker_search_dir, binary_file, is64bit, port, debugger, connect_timeout=5):
+
+def generate_lldb_script(sysroot, binary_name, port, solib_search_path):
+ commands = []
+ commands.append(
+ 'settings append target.exec-search-paths {}'.format(' '.join(solib_search_path)))
+
+ commands.append('target create {}'.format(binary_name))
+ commands.append('target modules search-paths add / {}/'.format(sysroot))
+ commands.append('gdb-remote {}'.format(port))
+ return '\n'.join(commands)
+
+
+def generate_setup_script(debugger_path, sysroot, linker_search_dir, binary_file, is64bit, port, debugger, connect_timeout=5):
# Generate a setup script.
# TODO: Detect the zygote and run 'art-on' automatically.
root = os.environ["ANDROID_BUILD_TOP"]
@@ -323,9 +371,12 @@
if debugger == "vscode":
return generate_vscode_script(
- gdbpath, root, sysroot, binary_file.name, port, dalvik_gdb_script, solib_search_path)
+ debugger_path, root, sysroot, binary_file.name, port, dalvik_gdb_script, solib_search_path)
elif debugger == "gdb":
return generate_gdb_script(root, sysroot, binary_file.name, port, dalvik_gdb_script, solib_search_path, connect_timeout)
+ elif debugger == 'lldb':
+ return generate_lldb_script(
+ sysroot, binary_file.name, port, solib_search_path)
else:
raise Exception("Unknown debugger type " + debugger)
@@ -369,60 +420,78 @@
is64bit = arch.endswith("64")
# Make sure we have the linker
- llvm_readobj_path = os.path.join(root, "prebuilts", "clang", "host", platform_name,
- "llvm-binutils-stable", "llvm-readobj")
+ clang_base, clang_version = read_toolchain_config(root)
+ toolchain_path = os.path.join(root, clang_base, platform_name,
+ clang_version)
+ llvm_readobj_path = os.path.join(toolchain_path, "bin", "llvm-readobj")
interp = gdbrunner.get_binary_interp(binary_file.name, llvm_readobj_path)
linker_search_dir = ensure_linker(device, sysroot, interp)
tracer_pid = get_tracer_pid(device, pid)
+ use_lldb = args.lldb
if tracer_pid == 0:
cmd_prefix = args.su_cmd
if args.env:
cmd_prefix += ['env'] + [v[0] for v in args.env]
# Start gdbserver.
- gdbserver_local_path = get_gdbserver_path(root, arch)
- gdbserver_remote_path = "/data/local/tmp/{}-gdbserver".format(arch)
+ if use_lldb:
+ server_local_path = get_lldb_server_path(
+ root, clang_base, clang_version, arch)
+ server_remote_path = "/data/local/tmp/{}-lldb-server".format(
+ arch)
+ else:
+ server_local_path = get_gdbserver_path(root, arch)
+ server_remote_path = "/data/local/tmp/{}-gdbserver".format(
+ arch)
gdbrunner.start_gdbserver(
- device, gdbserver_local_path, gdbserver_remote_path,
+ device, server_local_path, server_remote_path,
target_pid=pid, run_cmd=run_cmd, debug_socket=debug_socket,
- port=args.port, run_as_cmd=cmd_prefix)
+ port=args.port, run_as_cmd=cmd_prefix, lldb=use_lldb)
else:
- print "Connecting to tracing pid {} using local port {}".format(tracer_pid, args.port)
+ print(
+ "Connecting to tracing pid {} using local port {}".format(
+ tracer_pid, args.port))
gdbrunner.forward_gdbserver_port(device, local=args.port,
remote="tcp:{}".format(args.port))
- gdb_path = os.path.join(root, "prebuilts", "gdb", platform_name, "bin",
- "gdb")
+ if use_lldb:
+ debugger_path = os.path.join(toolchain_path, "bin", "lldb")
+ debugger = 'lldb'
+ else:
+ debugger_path = os.path.join(
+ root, "prebuilts", "gdb", platform_name, "bin", "gdb")
+ debugger = args.setup_forwarding or "gdb"
+
# Generate a gdb script.
- setup_commands = generate_setup_script(gdbpath=gdb_path,
+ setup_commands = generate_setup_script(debugger_path=debugger_path,
sysroot=sysroot,
linker_search_dir=linker_search_dir,
binary_file=binary_file,
is64bit=is64bit,
port=args.port,
- debugger=args.setup_forwarding or "gdb")
+ debugger=debugger)
- if not args.setup_forwarding:
+ if use_lldb or not args.setup_forwarding:
# Print a newline to separate our messages from the GDB session.
print("")
# Start gdb.
- gdbrunner.start_gdb(gdb_path, setup_commands)
+ gdbrunner.start_gdb(debugger_path, setup_commands, lldb=use_lldb)
else:
print("")
- print setup_commands
+ print(setup_commands)
print("")
if args.setup_forwarding == "vscode":
- print textwrap.dedent("""
+ print(textwrap.dedent("""
Paste the above json into .vscode/launch.json and start the debugger as
normal. Press enter in this terminal once debugging is finished to shutdown
- the gdbserver and close all the ports.""")
+ the gdbserver and close all the ports."""))
else:
- print textwrap.dedent("""
+ print(textwrap.dedent("""
Paste the above gdb commands into the gdb frontend to setup the gdbserver
connection. Press enter in this terminal once debugging is finished to
- shutdown the gdbserver and close all the ports.""")
+ shutdown the gdbserver and close all the ports."""))
print("")
raw_input("Press enter to shutdown gdbserver")