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
This commit is contained in:
Haibo Huang
2020-01-06 14:40:27 -08:00
parent eaee8a5229
commit e194fcecf9

View File

@@ -33,6 +33,27 @@ import gdbrunner
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 @@ def get_gdbserver_path(root, arch):
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 @@ def parse_args():
".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 @@ end
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 @@ def generate_setup_script(gdbpath, sysroot, linker_search_dir, binary_file, is64
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 @@ def do_main():
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")