1*90c8c64dSAndroid Build Coastguard Worker#!/usr/bin/env python3 2*90c8c64dSAndroid Build Coastguard Worker# 3*90c8c64dSAndroid Build Coastguard Worker# Copyright (C) 2015 The Android Open Source Project 4*90c8c64dSAndroid Build Coastguard Worker# 5*90c8c64dSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 6*90c8c64dSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 7*90c8c64dSAndroid Build Coastguard Worker# You may obtain a copy of the License at 8*90c8c64dSAndroid Build Coastguard Worker# 9*90c8c64dSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 10*90c8c64dSAndroid Build Coastguard Worker# 11*90c8c64dSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 12*90c8c64dSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 13*90c8c64dSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*90c8c64dSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 15*90c8c64dSAndroid Build Coastguard Worker# limitations under the License. 16*90c8c64dSAndroid Build Coastguard Worker# 17*90c8c64dSAndroid Build Coastguard Worker 18*90c8c64dSAndroid Build Coastguard Workerimport argparse 19*90c8c64dSAndroid Build Coastguard Workerimport json 20*90c8c64dSAndroid Build Coastguard Workerimport logging 21*90c8c64dSAndroid Build Coastguard Workerimport os 22*90c8c64dSAndroid Build Coastguard Workerimport pathlib 23*90c8c64dSAndroid Build Coastguard Workerimport posixpath 24*90c8c64dSAndroid Build Coastguard Workerimport re 25*90c8c64dSAndroid Build Coastguard Workerimport shutil 26*90c8c64dSAndroid Build Coastguard Workerimport subprocess 27*90c8c64dSAndroid Build Coastguard Workerimport sys 28*90c8c64dSAndroid Build Coastguard Workerimport tempfile 29*90c8c64dSAndroid Build Coastguard Workerimport textwrap 30*90c8c64dSAndroid Build Coastguard Workerfrom typing import Any, BinaryIO 31*90c8c64dSAndroid Build Coastguard Worker 32*90c8c64dSAndroid Build Coastguard Workerimport adb 33*90c8c64dSAndroid Build Coastguard Worker# Shared functions across gdbclient.py and ndk-gdb.py. 34*90c8c64dSAndroid Build Coastguard Workerimport gdbrunner 35*90c8c64dSAndroid Build Coastguard Worker 36*90c8c64dSAndroid Build Coastguard Workerg_temp_dirs = [] 37*90c8c64dSAndroid Build Coastguard Worker 38*90c8c64dSAndroid Build Coastguard Workerg_vscode_config_marker_begin = '// #lldbclient-generated-begin' 39*90c8c64dSAndroid Build Coastguard Workerg_vscode_config_marker_end = '// #lldbclient-generated-end' 40*90c8c64dSAndroid Build Coastguard Worker 41*90c8c64dSAndroid Build Coastguard Worker 42*90c8c64dSAndroid Build Coastguard Workerdef read_toolchain_config(root: str) -> str: 43*90c8c64dSAndroid Build Coastguard Worker """Finds out current toolchain version.""" 44*90c8c64dSAndroid Build Coastguard Worker version_output = subprocess.check_output( 45*90c8c64dSAndroid Build Coastguard Worker f'{root}/build/soong/scripts/get_clang_version.py', 46*90c8c64dSAndroid Build Coastguard Worker text=True) 47*90c8c64dSAndroid Build Coastguard Worker return version_output.strip() 48*90c8c64dSAndroid Build Coastguard Worker 49*90c8c64dSAndroid Build Coastguard Worker 50*90c8c64dSAndroid Build Coastguard Workerdef get_lldb_path(toolchain_path: str) -> str | None: 51*90c8c64dSAndroid Build Coastguard Worker for lldb_name in ['lldb.sh', 'lldb.cmd', 'lldb', 'lldb.exe']: 52*90c8c64dSAndroid Build Coastguard Worker debugger_path = os.path.join(toolchain_path, "bin", lldb_name) 53*90c8c64dSAndroid Build Coastguard Worker if os.path.isfile(debugger_path): 54*90c8c64dSAndroid Build Coastguard Worker return debugger_path 55*90c8c64dSAndroid Build Coastguard Worker return None 56*90c8c64dSAndroid Build Coastguard Worker 57*90c8c64dSAndroid Build Coastguard Worker 58*90c8c64dSAndroid Build Coastguard Workerdef get_lldb_server_path(root: str, clang_base: str, clang_version: str, arch: str) -> str: 59*90c8c64dSAndroid Build Coastguard Worker arch = { 60*90c8c64dSAndroid Build Coastguard Worker 'arm': 'arm', 61*90c8c64dSAndroid Build Coastguard Worker 'arm64': 'aarch64', 62*90c8c64dSAndroid Build Coastguard Worker 'riscv64': 'riscv64', 63*90c8c64dSAndroid Build Coastguard Worker 'x86': 'i386', 64*90c8c64dSAndroid Build Coastguard Worker 'x86_64': 'x86_64', 65*90c8c64dSAndroid Build Coastguard Worker }[arch] 66*90c8c64dSAndroid Build Coastguard Worker return os.path.join(root, clang_base, "linux-x86", 67*90c8c64dSAndroid Build Coastguard Worker clang_version, "runtimes_ndk_cxx", arch, "lldb-server") 68*90c8c64dSAndroid Build Coastguard Worker 69*90c8c64dSAndroid Build Coastguard Worker 70*90c8c64dSAndroid Build Coastguard Workerdef get_tracer_pid(device: adb.AndroidDevice, pid: int | str | None) -> int: 71*90c8c64dSAndroid Build Coastguard Worker if pid is None: 72*90c8c64dSAndroid Build Coastguard Worker return 0 73*90c8c64dSAndroid Build Coastguard Worker 74*90c8c64dSAndroid Build Coastguard Worker line, _ = device.shell(["grep", "-e", "^TracerPid:", "/proc/{}/status".format(pid)]) 75*90c8c64dSAndroid Build Coastguard Worker tracer_pid = re.sub('TracerPid:\t(.*)\n', r'\1', line) 76*90c8c64dSAndroid Build Coastguard Worker return int(tracer_pid) 77*90c8c64dSAndroid Build Coastguard Worker 78*90c8c64dSAndroid Build Coastguard Worker 79*90c8c64dSAndroid Build Coastguard Workerdef parse_args() -> argparse.Namespace: 80*90c8c64dSAndroid Build Coastguard Worker parser = gdbrunner.ArgumentParser() 81*90c8c64dSAndroid Build Coastguard Worker 82*90c8c64dSAndroid Build Coastguard Worker group = parser.add_argument_group(title="attach target") 83*90c8c64dSAndroid Build Coastguard Worker group = group.add_mutually_exclusive_group(required=True) 84*90c8c64dSAndroid Build Coastguard Worker group.add_argument( 85*90c8c64dSAndroid Build Coastguard Worker "-p", dest="target_pid", metavar="PID", type=int, 86*90c8c64dSAndroid Build Coastguard Worker help="attach to a process with specified PID") 87*90c8c64dSAndroid Build Coastguard Worker group.add_argument( 88*90c8c64dSAndroid Build Coastguard Worker "-n", dest="target_name", metavar="NAME", 89*90c8c64dSAndroid Build Coastguard Worker help="attach to a process with specified name") 90*90c8c64dSAndroid Build Coastguard Worker group.add_argument( 91*90c8c64dSAndroid Build Coastguard Worker "-r", dest="run_cmd", metavar="CMD", nargs=argparse.REMAINDER, 92*90c8c64dSAndroid Build Coastguard Worker help="run a binary on the device, with args") 93*90c8c64dSAndroid Build Coastguard Worker 94*90c8c64dSAndroid Build Coastguard Worker parser.add_argument( 95*90c8c64dSAndroid Build Coastguard Worker "--port", nargs="?", default="5039", 96*90c8c64dSAndroid Build Coastguard Worker help="Unused **host** port to forward the debug_socket to.[default: 5039]") 97*90c8c64dSAndroid Build Coastguard Worker parser.add_argument( 98*90c8c64dSAndroid Build Coastguard Worker "--user", nargs="?", default="root", 99*90c8c64dSAndroid Build Coastguard Worker help="user to run commands as on the device [default: root]") 100*90c8c64dSAndroid Build Coastguard Worker parser.add_argument( 101*90c8c64dSAndroid Build Coastguard Worker "--setup-forwarding", default=None, 102*90c8c64dSAndroid Build Coastguard Worker choices=["lldb", "vscode-lldb"], 103*90c8c64dSAndroid Build Coastguard Worker help=("Set up lldb-server and port forwarding. Prints commands or " + 104*90c8c64dSAndroid Build Coastguard Worker ".vscode/launch.json configuration needed to connect the debugging " + 105*90c8c64dSAndroid Build Coastguard Worker "client to the server. 'vscode' with lldb and 'vscode-lldb' both " + 106*90c8c64dSAndroid Build Coastguard Worker "require the 'vadimcn.vscode-lldb' extension.")) 107*90c8c64dSAndroid Build Coastguard Worker parser.add_argument( 108*90c8c64dSAndroid Build Coastguard Worker "--vscode-launch-props", default=None, 109*90c8c64dSAndroid Build Coastguard Worker dest="vscode_launch_props", 110*90c8c64dSAndroid Build Coastguard Worker help=("JSON with extra properties to add to launch parameters when using " + 111*90c8c64dSAndroid Build Coastguard Worker "vscode-lldb forwarding.")) 112*90c8c64dSAndroid Build Coastguard Worker parser.add_argument( 113*90c8c64dSAndroid Build Coastguard Worker "--vscode-launch-file", default=None, 114*90c8c64dSAndroid Build Coastguard Worker dest="vscode_launch_file", 115*90c8c64dSAndroid Build Coastguard Worker help=textwrap.dedent(f"""Path to .vscode/launch.json file for the generated launch 116*90c8c64dSAndroid Build Coastguard Worker config when using vscode-lldb forwarding. The file needs to 117*90c8c64dSAndroid Build Coastguard Worker contain two marker lines: '{g_vscode_config_marker_begin}' 118*90c8c64dSAndroid Build Coastguard Worker and '{g_vscode_config_marker_end}'. The config will be written inline 119*90c8c64dSAndroid Build Coastguard Worker between these lines, replacing any text that is already there.""")) 120*90c8c64dSAndroid Build Coastguard Worker 121*90c8c64dSAndroid Build Coastguard Worker parser.add_argument( 122*90c8c64dSAndroid Build Coastguard Worker "--env", nargs=1, action="append", metavar="VAR=VALUE", 123*90c8c64dSAndroid Build Coastguard Worker help="set environment variable when running a binary") 124*90c8c64dSAndroid Build Coastguard Worker parser.add_argument( 125*90c8c64dSAndroid Build Coastguard Worker "--chroot", nargs='?', default="", metavar="PATH", 126*90c8c64dSAndroid Build Coastguard Worker help="run command in a chroot in the given directory. Cannot be used with --cwd.") 127*90c8c64dSAndroid Build Coastguard Worker parser.add_argument( 128*90c8c64dSAndroid Build Coastguard Worker "--cwd", nargs='?', default="", metavar="PATH", 129*90c8c64dSAndroid Build Coastguard Worker help="working directory for the command. Cannot be used with --chroot.") 130*90c8c64dSAndroid Build Coastguard Worker 131*90c8c64dSAndroid Build Coastguard Worker return parser.parse_args() 132*90c8c64dSAndroid Build Coastguard Worker 133*90c8c64dSAndroid Build Coastguard Worker 134*90c8c64dSAndroid Build Coastguard Workerdef verify_device(device: adb.AndroidDevice) -> None: 135*90c8c64dSAndroid Build Coastguard Worker names = set([device.get_prop("ro.build.product"), device.get_prop("ro.product.name")]) 136*90c8c64dSAndroid Build Coastguard Worker target_device = os.environ["TARGET_PRODUCT"] 137*90c8c64dSAndroid Build Coastguard Worker if target_device not in names: 138*90c8c64dSAndroid Build Coastguard Worker msg = "You used the wrong lunch: TARGET_PRODUCT ({}) does not match attached device ({})" 139*90c8c64dSAndroid Build Coastguard Worker sys.exit(msg.format(target_device, ", ".join(n if n else "None" for n in names))) 140*90c8c64dSAndroid Build Coastguard Worker 141*90c8c64dSAndroid Build Coastguard Worker 142*90c8c64dSAndroid Build Coastguard Workerdef get_device_dir_exists(device: adb.AndroidDevice, dir: str) -> bool: 143*90c8c64dSAndroid Build Coastguard Worker exit_code, _, _ = device.shell_nocheck(['[', '-d', dir, ']']) 144*90c8c64dSAndroid Build Coastguard Worker return exit_code == 0 145*90c8c64dSAndroid Build Coastguard Worker 146*90c8c64dSAndroid Build Coastguard Worker 147*90c8c64dSAndroid Build Coastguard Workerdef get_remote_pid(device: adb.AndroidDevice, process_name: str) -> int: 148*90c8c64dSAndroid Build Coastguard Worker processes = gdbrunner.get_processes(device) 149*90c8c64dSAndroid Build Coastguard Worker if process_name not in processes: 150*90c8c64dSAndroid Build Coastguard Worker msg = "failed to find running process {}".format(process_name) 151*90c8c64dSAndroid Build Coastguard Worker sys.exit(msg) 152*90c8c64dSAndroid Build Coastguard Worker pids = processes[process_name] 153*90c8c64dSAndroid Build Coastguard Worker if len(pids) > 1: 154*90c8c64dSAndroid Build Coastguard Worker msg = "multiple processes match '{}': {}".format(process_name, pids) 155*90c8c64dSAndroid Build Coastguard Worker sys.exit(msg) 156*90c8c64dSAndroid Build Coastguard Worker 157*90c8c64dSAndroid Build Coastguard Worker # Fetch the binary using the PID later. 158*90c8c64dSAndroid Build Coastguard Worker return pids[0] 159*90c8c64dSAndroid Build Coastguard Worker 160*90c8c64dSAndroid Build Coastguard Worker 161*90c8c64dSAndroid Build Coastguard Workerdef make_temp_dir(prefix: str) -> str: 162*90c8c64dSAndroid Build Coastguard Worker global g_temp_dirs 163*90c8c64dSAndroid Build Coastguard Worker result = tempfile.mkdtemp(prefix='lldbclient-linker-') 164*90c8c64dSAndroid Build Coastguard Worker g_temp_dirs.append(result) 165*90c8c64dSAndroid Build Coastguard Worker return result 166*90c8c64dSAndroid Build Coastguard Worker 167*90c8c64dSAndroid Build Coastguard Worker 168*90c8c64dSAndroid Build Coastguard Workerdef ensure_linker(device: adb.AndroidDevice, sysroot: str, interp: str | None) -> str | None: 169*90c8c64dSAndroid Build Coastguard Worker """Ensure that the device's linker exists on the host. 170*90c8c64dSAndroid Build Coastguard Worker 171*90c8c64dSAndroid Build Coastguard Worker PT_INTERP is usually /system/bin/linker[64], but on the device, that file is 172*90c8c64dSAndroid Build Coastguard Worker a symlink to /apex/com.android.runtime/bin/linker[64]. The symbolized linker 173*90c8c64dSAndroid Build Coastguard Worker binary on the host is located in ${sysroot}/apex, not in ${sysroot}/system, 174*90c8c64dSAndroid Build Coastguard Worker so add the ${sysroot}/apex path to the solib search path. 175*90c8c64dSAndroid Build Coastguard Worker 176*90c8c64dSAndroid Build Coastguard Worker PT_INTERP will be /system/bin/bootstrap/linker[64] for executables using the 177*90c8c64dSAndroid Build Coastguard Worker non-APEX/bootstrap linker. No search path modification is needed. 178*90c8c64dSAndroid Build Coastguard Worker 179*90c8c64dSAndroid Build Coastguard Worker For a tapas build, only an unbundled app is built, and there is no linker in 180*90c8c64dSAndroid Build Coastguard Worker ${sysroot} at all, so copy the linker from the device. 181*90c8c64dSAndroid Build Coastguard Worker 182*90c8c64dSAndroid Build Coastguard Worker Returns: 183*90c8c64dSAndroid Build Coastguard Worker A directory to add to the soinfo search path or None if no directory 184*90c8c64dSAndroid Build Coastguard Worker needs to be added. 185*90c8c64dSAndroid Build Coastguard Worker """ 186*90c8c64dSAndroid Build Coastguard Worker 187*90c8c64dSAndroid Build Coastguard Worker # Static executables have no interpreter. 188*90c8c64dSAndroid Build Coastguard Worker if interp is None: 189*90c8c64dSAndroid Build Coastguard Worker return None 190*90c8c64dSAndroid Build Coastguard Worker 191*90c8c64dSAndroid Build Coastguard Worker # lldb will search for the linker using the PT_INTERP path. First try to find 192*90c8c64dSAndroid Build Coastguard Worker # it in the sysroot. 193*90c8c64dSAndroid Build Coastguard Worker local_path = os.path.join(sysroot, interp.lstrip("/")) 194*90c8c64dSAndroid Build Coastguard Worker if os.path.exists(local_path): 195*90c8c64dSAndroid Build Coastguard Worker return None 196*90c8c64dSAndroid Build Coastguard Worker 197*90c8c64dSAndroid Build Coastguard Worker # If the linker on the device is a symlink, search for the symlink's target 198*90c8c64dSAndroid Build Coastguard Worker # in the sysroot directory. 199*90c8c64dSAndroid Build Coastguard Worker interp_real, _ = device.shell(["realpath", interp]) 200*90c8c64dSAndroid Build Coastguard Worker interp_real = interp_real.strip() 201*90c8c64dSAndroid Build Coastguard Worker local_path = os.path.join(sysroot, interp_real.lstrip("/")) 202*90c8c64dSAndroid Build Coastguard Worker if os.path.exists(local_path): 203*90c8c64dSAndroid Build Coastguard Worker if posixpath.basename(interp) == posixpath.basename(interp_real): 204*90c8c64dSAndroid Build Coastguard Worker # Add the interpreter's directory to the search path. 205*90c8c64dSAndroid Build Coastguard Worker return os.path.dirname(local_path) 206*90c8c64dSAndroid Build Coastguard Worker else: 207*90c8c64dSAndroid Build Coastguard Worker # If PT_INTERP is linker_asan[64], but the sysroot file is 208*90c8c64dSAndroid Build Coastguard Worker # linker[64], then copy the local file to the name lldb expects. 209*90c8c64dSAndroid Build Coastguard Worker result = make_temp_dir('lldbclient-linker-') 210*90c8c64dSAndroid Build Coastguard Worker shutil.copy(local_path, os.path.join(result, posixpath.basename(interp))) 211*90c8c64dSAndroid Build Coastguard Worker return result 212*90c8c64dSAndroid Build Coastguard Worker 213*90c8c64dSAndroid Build Coastguard Worker # Pull the system linker. 214*90c8c64dSAndroid Build Coastguard Worker result = make_temp_dir('lldbclient-linker-') 215*90c8c64dSAndroid Build Coastguard Worker device.pull(interp, os.path.join(result, posixpath.basename(interp))) 216*90c8c64dSAndroid Build Coastguard Worker return result 217*90c8c64dSAndroid Build Coastguard Worker 218*90c8c64dSAndroid Build Coastguard Worker 219*90c8c64dSAndroid Build Coastguard Workerdef handle_switches(args, sysroot: str) -> tuple[BinaryIO, int | None, str | None]: 220*90c8c64dSAndroid Build Coastguard Worker """Fetch the targeted binary and determine how to attach lldb. 221*90c8c64dSAndroid Build Coastguard Worker 222*90c8c64dSAndroid Build Coastguard Worker Args: 223*90c8c64dSAndroid Build Coastguard Worker args: Parsed arguments. 224*90c8c64dSAndroid Build Coastguard Worker sysroot: Local sysroot path. 225*90c8c64dSAndroid Build Coastguard Worker 226*90c8c64dSAndroid Build Coastguard Worker Returns: 227*90c8c64dSAndroid Build Coastguard Worker (binary_file, attach_pid, run_cmd). 228*90c8c64dSAndroid Build Coastguard Worker Precisely one of attach_pid or run_cmd will be None. 229*90c8c64dSAndroid Build Coastguard Worker """ 230*90c8c64dSAndroid Build Coastguard Worker 231*90c8c64dSAndroid Build Coastguard Worker device = args.device 232*90c8c64dSAndroid Build Coastguard Worker binary_file = None 233*90c8c64dSAndroid Build Coastguard Worker pid = None 234*90c8c64dSAndroid Build Coastguard Worker run_cmd = None 235*90c8c64dSAndroid Build Coastguard Worker 236*90c8c64dSAndroid Build Coastguard Worker args.su_cmd = ["su", args.user] if args.user else [] 237*90c8c64dSAndroid Build Coastguard Worker 238*90c8c64dSAndroid Build Coastguard Worker if args.target_pid: 239*90c8c64dSAndroid Build Coastguard Worker # Fetch the binary using the PID later. 240*90c8c64dSAndroid Build Coastguard Worker pid = args.target_pid 241*90c8c64dSAndroid Build Coastguard Worker elif args.target_name: 242*90c8c64dSAndroid Build Coastguard Worker # Fetch the binary using the PID later. 243*90c8c64dSAndroid Build Coastguard Worker pid = get_remote_pid(device, args.target_name) 244*90c8c64dSAndroid Build Coastguard Worker elif args.run_cmd: 245*90c8c64dSAndroid Build Coastguard Worker if not args.run_cmd[0]: 246*90c8c64dSAndroid Build Coastguard Worker sys.exit("empty command passed to -r") 247*90c8c64dSAndroid Build Coastguard Worker run_cmd = args.run_cmd 248*90c8c64dSAndroid Build Coastguard Worker if not run_cmd[0].startswith("/"): 249*90c8c64dSAndroid Build Coastguard Worker try: 250*90c8c64dSAndroid Build Coastguard Worker run_cmd[0] = gdbrunner.find_executable_path(device, args.run_cmd[0], 251*90c8c64dSAndroid Build Coastguard Worker run_as_cmd=args.su_cmd) 252*90c8c64dSAndroid Build Coastguard Worker except RuntimeError: 253*90c8c64dSAndroid Build Coastguard Worker sys.exit("Could not find executable '{}' passed to -r, " 254*90c8c64dSAndroid Build Coastguard Worker "please provide an absolute path.".format(args.run_cmd[0])) 255*90c8c64dSAndroid Build Coastguard Worker 256*90c8c64dSAndroid Build Coastguard Worker binary_file, local = gdbrunner.find_file(device, run_cmd[0], sysroot, 257*90c8c64dSAndroid Build Coastguard Worker run_as_cmd=args.su_cmd) 258*90c8c64dSAndroid Build Coastguard Worker if binary_file is None: 259*90c8c64dSAndroid Build Coastguard Worker assert pid is not None 260*90c8c64dSAndroid Build Coastguard Worker try: 261*90c8c64dSAndroid Build Coastguard Worker binary_file, local = gdbrunner.find_binary(device, pid, sysroot, 262*90c8c64dSAndroid Build Coastguard Worker run_as_cmd=args.su_cmd) 263*90c8c64dSAndroid Build Coastguard Worker except adb.ShellError: 264*90c8c64dSAndroid Build Coastguard Worker sys.exit("failed to pull binary for PID {}".format(pid)) 265*90c8c64dSAndroid Build Coastguard Worker 266*90c8c64dSAndroid Build Coastguard Worker if not local: 267*90c8c64dSAndroid Build Coastguard Worker logging.warning("Couldn't find local unstripped executable in {}," 268*90c8c64dSAndroid Build Coastguard Worker " symbols may not be available.".format(sysroot)) 269*90c8c64dSAndroid Build Coastguard Worker 270*90c8c64dSAndroid Build Coastguard Worker return (binary_file, pid, run_cmd) 271*90c8c64dSAndroid Build Coastguard Worker 272*90c8c64dSAndroid Build Coastguard Workerdef merge_launch_dict(base: dict[str, Any], to_add: dict[str, Any] | None) -> None: 273*90c8c64dSAndroid Build Coastguard Worker """Merges two dicts describing VSCode launch.json properties: base and 274*90c8c64dSAndroid Build Coastguard Worker to_add. Base is modified in-place with items from to_add. 275*90c8c64dSAndroid Build Coastguard Worker Items from to_add that are not present in base are inserted. Items that are 276*90c8c64dSAndroid Build Coastguard Worker present are merged following these rules: 277*90c8c64dSAndroid Build Coastguard Worker - Lists are merged with to_add elements appended to the end of base 278*90c8c64dSAndroid Build Coastguard Worker list. Only a list can be merged with a list. 279*90c8c64dSAndroid Build Coastguard Worker - dicts are merged recursively. Only a dict can be merged with a dict. 280*90c8c64dSAndroid Build Coastguard Worker - Other present values in base get overwritten with values from to_add. 281*90c8c64dSAndroid Build Coastguard Worker 282*90c8c64dSAndroid Build Coastguard Worker The reason for these rules is that merging in new values should prefer to 283*90c8c64dSAndroid Build Coastguard Worker expand the existing set instead of overwriting where possible. 284*90c8c64dSAndroid Build Coastguard Worker """ 285*90c8c64dSAndroid Build Coastguard Worker if to_add is None: 286*90c8c64dSAndroid Build Coastguard Worker return 287*90c8c64dSAndroid Build Coastguard Worker 288*90c8c64dSAndroid Build Coastguard Worker for key, val in to_add.items(): 289*90c8c64dSAndroid Build Coastguard Worker if key not in base: 290*90c8c64dSAndroid Build Coastguard Worker base[key] = val 291*90c8c64dSAndroid Build Coastguard Worker else: 292*90c8c64dSAndroid Build Coastguard Worker if isinstance(base[key], list) and not isinstance(val, list): 293*90c8c64dSAndroid Build Coastguard Worker raise ValueError(f'Cannot merge non-list into list at key={key}. ' + 294*90c8c64dSAndroid Build Coastguard Worker 'You probably need to wrap your value into a list.') 295*90c8c64dSAndroid Build Coastguard Worker if not isinstance(base[key], list) and isinstance(val, list): 296*90c8c64dSAndroid Build Coastguard Worker raise ValueError(f'Cannot merge list into non-list at key={key}.') 297*90c8c64dSAndroid Build Coastguard Worker if isinstance(base[key], dict) != isinstance(val, dict): 298*90c8c64dSAndroid Build Coastguard Worker raise ValueError(f'Cannot merge dict and non-dict at key={key}') 299*90c8c64dSAndroid Build Coastguard Worker 300*90c8c64dSAndroid Build Coastguard Worker # We don't allow the user to overwrite or interleave lists and don't allow 301*90c8c64dSAndroid Build Coastguard Worker # to delete dict entries. 302*90c8c64dSAndroid Build Coastguard Worker # It can be done but would make the implementation a bit more complicated 303*90c8c64dSAndroid Build Coastguard Worker # and provides less value than adding elements. 304*90c8c64dSAndroid Build Coastguard Worker # We expect that the config generated by gdbclient doesn't contain anything 305*90c8c64dSAndroid Build Coastguard Worker # the user would want to remove. 306*90c8c64dSAndroid Build Coastguard Worker if isinstance(base[key], list): 307*90c8c64dSAndroid Build Coastguard Worker base[key] += val 308*90c8c64dSAndroid Build Coastguard Worker elif isinstance(base[key], dict): 309*90c8c64dSAndroid Build Coastguard Worker merge_launch_dict(base[key], val) 310*90c8c64dSAndroid Build Coastguard Worker else: 311*90c8c64dSAndroid Build Coastguard Worker base[key] = val 312*90c8c64dSAndroid Build Coastguard Worker 313*90c8c64dSAndroid Build Coastguard Worker 314*90c8c64dSAndroid Build Coastguard Workerdef generate_vscode_lldb_script(root: str, sysroot: str, binary_name: str, port: str | int, solib_search_path: list[str], extra_props: dict[str, Any] | None) -> str: 315*90c8c64dSAndroid Build Coastguard Worker # TODO It would be nice if we didn't need to copy this or run the 316*90c8c64dSAndroid Build Coastguard Worker # lldbclient.py program manually. Doing this would probably require 317*90c8c64dSAndroid Build Coastguard Worker # writing a vscode extension or modifying an existing one. 318*90c8c64dSAndroid Build Coastguard Worker # TODO: https://code.visualstudio.com/api/references/vscode-api#debug and 319*90c8c64dSAndroid Build Coastguard Worker # https://code.visualstudio.com/api/extension-guides/debugger-extension and 320*90c8c64dSAndroid Build Coastguard Worker # https://github.com/vadimcn/vscode-lldb/blob/6b775c439992b6615e92f4938ee4e211f1b060cf/extension/pickProcess.ts#L6 321*90c8c64dSAndroid Build Coastguard Worker res = { 322*90c8c64dSAndroid Build Coastguard Worker "name": "(lldbclient.py) Attach {} (port: {})".format(binary_name.split("/")[-1], port), 323*90c8c64dSAndroid Build Coastguard Worker "type": "lldb", 324*90c8c64dSAndroid Build Coastguard Worker "request": "custom", 325*90c8c64dSAndroid Build Coastguard Worker "relativePathBase": root, 326*90c8c64dSAndroid Build Coastguard Worker "sourceMap": { "/b/f/w" : root, '': root, '.': root }, 327*90c8c64dSAndroid Build Coastguard Worker "initCommands": ['settings append target.exec-search-paths {}'.format(' '.join(solib_search_path))], 328*90c8c64dSAndroid Build Coastguard Worker "targetCreateCommands": ["target create {}".format(binary_name), 329*90c8c64dSAndroid Build Coastguard Worker "target modules search-paths add / {}/".format(sysroot)], 330*90c8c64dSAndroid Build Coastguard Worker "processCreateCommands": ["gdb-remote {}".format(str(port))] 331*90c8c64dSAndroid Build Coastguard Worker } 332*90c8c64dSAndroid Build Coastguard Worker merge_launch_dict(res, extra_props) 333*90c8c64dSAndroid Build Coastguard Worker return json.dumps(res, indent=4) 334*90c8c64dSAndroid Build Coastguard Worker 335*90c8c64dSAndroid Build Coastguard Workerdef generate_lldb_script(root: str, sysroot: str, binary_name: str, port: str | int, solib_search_path: list[str]) -> str: 336*90c8c64dSAndroid Build Coastguard Worker commands = [] 337*90c8c64dSAndroid Build Coastguard Worker commands.append( 338*90c8c64dSAndroid Build Coastguard Worker 'settings append target.exec-search-paths {}'.format(' '.join(solib_search_path))) 339*90c8c64dSAndroid Build Coastguard Worker 340*90c8c64dSAndroid Build Coastguard Worker commands.append('target create {}'.format(binary_name)) 341*90c8c64dSAndroid Build Coastguard Worker # For RBE support. 342*90c8c64dSAndroid Build Coastguard Worker commands.append("settings append target.source-map '/b/f/w' '{}'".format(root)) 343*90c8c64dSAndroid Build Coastguard Worker commands.append("settings append target.source-map '' '{}'".format(root)) 344*90c8c64dSAndroid Build Coastguard Worker commands.append('target modules search-paths add / {}/'.format(sysroot)) 345*90c8c64dSAndroid Build Coastguard Worker commands.append('# If the below `gdb-remote` fails, run the command manually, ' 346*90c8c64dSAndroid Build Coastguard Worker + 'as it may have raced with lldbserver startup.') 347*90c8c64dSAndroid Build Coastguard Worker commands.append('gdb-remote {}'.format(str(port))) 348*90c8c64dSAndroid Build Coastguard Worker return '\n'.join(commands) 349*90c8c64dSAndroid Build Coastguard Worker 350*90c8c64dSAndroid Build Coastguard Worker 351*90c8c64dSAndroid Build Coastguard Workerdef generate_setup_script(sysroot: str, linker_search_dir: str | None, binary_name: str, is64bit: bool, port: str | int, debugger: str, vscode_launch_props: dict[str, Any] | None) -> str: 352*90c8c64dSAndroid Build Coastguard Worker # Generate a setup script. 353*90c8c64dSAndroid Build Coastguard Worker root = os.environ["ANDROID_BUILD_TOP"] 354*90c8c64dSAndroid Build Coastguard Worker symbols_dir = os.path.join(sysroot, "system", "lib64" if is64bit else "lib") 355*90c8c64dSAndroid Build Coastguard Worker vendor_dir = os.path.join(sysroot, "vendor", "lib64" if is64bit else "lib") 356*90c8c64dSAndroid Build Coastguard Worker 357*90c8c64dSAndroid Build Coastguard Worker solib_search_path = [] 358*90c8c64dSAndroid Build Coastguard Worker symbols_paths = ["", "hw", "ssl/engines", "drm", "egl", "soundfx"] 359*90c8c64dSAndroid Build Coastguard Worker vendor_paths = ["", "hw", "egl"] 360*90c8c64dSAndroid Build Coastguard Worker solib_search_path += [os.path.join(symbols_dir, x) for x in symbols_paths] 361*90c8c64dSAndroid Build Coastguard Worker solib_search_path += [os.path.join(vendor_dir, x) for x in vendor_paths] 362*90c8c64dSAndroid Build Coastguard Worker if linker_search_dir is not None: 363*90c8c64dSAndroid Build Coastguard Worker solib_search_path += [linker_search_dir] 364*90c8c64dSAndroid Build Coastguard Worker 365*90c8c64dSAndroid Build Coastguard Worker if debugger == "vscode-lldb": 366*90c8c64dSAndroid Build Coastguard Worker return generate_vscode_lldb_script( 367*90c8c64dSAndroid Build Coastguard Worker root, sysroot, binary_name, port, solib_search_path, vscode_launch_props) 368*90c8c64dSAndroid Build Coastguard Worker elif debugger == 'lldb': 369*90c8c64dSAndroid Build Coastguard Worker return generate_lldb_script( 370*90c8c64dSAndroid Build Coastguard Worker root, sysroot, binary_name, port, solib_search_path) 371*90c8c64dSAndroid Build Coastguard Worker else: 372*90c8c64dSAndroid Build Coastguard Worker raise Exception("Unknown debugger type " + debugger) 373*90c8c64dSAndroid Build Coastguard Worker 374*90c8c64dSAndroid Build Coastguard Worker 375*90c8c64dSAndroid Build Coastguard Workerdef insert_commands_into_vscode_config(dst_launch_config: str, setup_commands: str) -> str: 376*90c8c64dSAndroid Build Coastguard Worker """Inserts setup commands into launch config between two marker lines. 377*90c8c64dSAndroid Build Coastguard Worker Marker lines are set in global variables g_vscode_config_marker_end and g_vscode_config_marker_end. 378*90c8c64dSAndroid Build Coastguard Worker The commands are inserted with the same indentation as the first marker line. 379*90c8c64dSAndroid Build Coastguard Worker 380*90c8c64dSAndroid Build Coastguard Worker Args: 381*90c8c64dSAndroid Build Coastguard Worker dst_launch_config: Config to insert commands into. 382*90c8c64dSAndroid Build Coastguard Worker setup_commands: Commands to insert. 383*90c8c64dSAndroid Build Coastguard Worker Returns: 384*90c8c64dSAndroid Build Coastguard Worker Config with inserted commands. 385*90c8c64dSAndroid Build Coastguard Worker Raises: 386*90c8c64dSAndroid Build Coastguard Worker ValueError if the begin marker is not found or not terminated with an end marker. 387*90c8c64dSAndroid Build Coastguard Worker """ 388*90c8c64dSAndroid Build Coastguard Worker 389*90c8c64dSAndroid Build Coastguard Worker # We expect the files to be small (~10s KB), so we use simple string concatenation 390*90c8c64dSAndroid Build Coastguard Worker # for simplicity and readability even if it is slower. 391*90c8c64dSAndroid Build Coastguard Worker output = "" 392*90c8c64dSAndroid Build Coastguard Worker found_at_least_one_begin = False 393*90c8c64dSAndroid Build Coastguard Worker unterminated_begin_line = None 394*90c8c64dSAndroid Build Coastguard Worker 395*90c8c64dSAndroid Build Coastguard Worker # It might be tempting to rewrite this using find() or even regexes, 396*90c8c64dSAndroid Build Coastguard Worker # but keeping track of line numbers, preserving whitespace, and detecting indent 397*90c8c64dSAndroid Build Coastguard Worker # becomes tricky enough that this simple loop is more clear. 398*90c8c64dSAndroid Build Coastguard Worker for linenum, line in enumerate(dst_launch_config.splitlines(keepends=True), start=1): 399*90c8c64dSAndroid Build Coastguard Worker if unterminated_begin_line != None: 400*90c8c64dSAndroid Build Coastguard Worker if line.strip() == g_vscode_config_marker_end: 401*90c8c64dSAndroid Build Coastguard Worker unterminated_begin_line = None 402*90c8c64dSAndroid Build Coastguard Worker else: 403*90c8c64dSAndroid Build Coastguard Worker continue 404*90c8c64dSAndroid Build Coastguard Worker output += line 405*90c8c64dSAndroid Build Coastguard Worker if line.strip() == g_vscode_config_marker_begin: 406*90c8c64dSAndroid Build Coastguard Worker found_at_least_one_begin = True 407*90c8c64dSAndroid Build Coastguard Worker unterminated_begin_line = linenum 408*90c8c64dSAndroid Build Coastguard Worker marker_indent = line[:line.find(g_vscode_config_marker_begin)] 409*90c8c64dSAndroid Build Coastguard Worker output += textwrap.indent(setup_commands, marker_indent) + '\n' 410*90c8c64dSAndroid Build Coastguard Worker 411*90c8c64dSAndroid Build Coastguard Worker if not found_at_least_one_begin: 412*90c8c64dSAndroid Build Coastguard Worker raise ValueError(f"Did not find begin marker line '{g_vscode_config_marker_begin}' " + 413*90c8c64dSAndroid Build Coastguard Worker "in the VSCode launch file") 414*90c8c64dSAndroid Build Coastguard Worker 415*90c8c64dSAndroid Build Coastguard Worker if unterminated_begin_line is not None: 416*90c8c64dSAndroid Build Coastguard Worker raise ValueError(f"Unterminated begin marker at line {unterminated_begin_line} " + 417*90c8c64dSAndroid Build Coastguard Worker f"in the VSCode launch file. Add end marker line to file: '{g_vscode_config_marker_end}'") 418*90c8c64dSAndroid Build Coastguard Worker 419*90c8c64dSAndroid Build Coastguard Worker return output 420*90c8c64dSAndroid Build Coastguard Worker 421*90c8c64dSAndroid Build Coastguard Worker 422*90c8c64dSAndroid Build Coastguard Workerdef replace_file_contents(dst_path: os.PathLike, contents: str) -> None: 423*90c8c64dSAndroid Build Coastguard Worker """Replaces the contents of the file pointed to by dst_path. 424*90c8c64dSAndroid Build Coastguard Worker 425*90c8c64dSAndroid Build Coastguard Worker This function writes the new contents into a temporary file, then atomically swaps it with 426*90c8c64dSAndroid Build Coastguard Worker the target file. This way if a write fails, the original file is not overwritten. 427*90c8c64dSAndroid Build Coastguard Worker 428*90c8c64dSAndroid Build Coastguard Worker Args: 429*90c8c64dSAndroid Build Coastguard Worker dst_path: The path to the file to be replaced. 430*90c8c64dSAndroid Build Coastguard Worker contents: The new contents of the file. 431*90c8c64dSAndroid Build Coastguard Worker Raises: 432*90c8c64dSAndroid Build Coastguard Worker Forwards exceptions from underlying filesystem methods. 433*90c8c64dSAndroid Build Coastguard Worker """ 434*90c8c64dSAndroid Build Coastguard Worker tempf = tempfile.NamedTemporaryFile('w', delete=False) 435*90c8c64dSAndroid Build Coastguard Worker try: 436*90c8c64dSAndroid Build Coastguard Worker tempf.write(contents) 437*90c8c64dSAndroid Build Coastguard Worker os.replace(tempf.name, dst_path) 438*90c8c64dSAndroid Build Coastguard Worker except: 439*90c8c64dSAndroid Build Coastguard Worker os.remove(tempf.name) 440*90c8c64dSAndroid Build Coastguard Worker raise 441*90c8c64dSAndroid Build Coastguard Worker 442*90c8c64dSAndroid Build Coastguard Worker 443*90c8c64dSAndroid Build Coastguard Workerdef write_vscode_config(vscode_launch_file: pathlib.Path, setup_commands: str) -> None: 444*90c8c64dSAndroid Build Coastguard Worker """Writes setup_commands into the file pointed by vscode_launch_file. 445*90c8c64dSAndroid Build Coastguard Worker 446*90c8c64dSAndroid Build Coastguard Worker See insert_commands_into_vscode_config for the description of how the setup commands are written. 447*90c8c64dSAndroid Build Coastguard Worker """ 448*90c8c64dSAndroid Build Coastguard Worker contents = insert_commands_into_vscode_config(vscode_launch_file.read_text(), setup_commands) 449*90c8c64dSAndroid Build Coastguard Worker replace_file_contents(vscode_launch_file, contents) 450*90c8c64dSAndroid Build Coastguard Worker 451*90c8c64dSAndroid Build Coastguard Worker 452*90c8c64dSAndroid Build Coastguard Workerdef do_main() -> None: 453*90c8c64dSAndroid Build Coastguard Worker required_env = ["ANDROID_BUILD_TOP", 454*90c8c64dSAndroid Build Coastguard Worker "ANDROID_PRODUCT_OUT", "TARGET_PRODUCT"] 455*90c8c64dSAndroid Build Coastguard Worker for env in required_env: 456*90c8c64dSAndroid Build Coastguard Worker if env not in os.environ: 457*90c8c64dSAndroid Build Coastguard Worker sys.exit( 458*90c8c64dSAndroid Build Coastguard Worker "Environment variable '{}' not defined, have you run lunch?".format(env)) 459*90c8c64dSAndroid Build Coastguard Worker 460*90c8c64dSAndroid Build Coastguard Worker args = parse_args() 461*90c8c64dSAndroid Build Coastguard Worker device = args.device 462*90c8c64dSAndroid Build Coastguard Worker 463*90c8c64dSAndroid Build Coastguard Worker if device is None: 464*90c8c64dSAndroid Build Coastguard Worker sys.exit("ERROR: Failed to find device.") 465*90c8c64dSAndroid Build Coastguard Worker 466*90c8c64dSAndroid Build Coastguard Worker root = os.environ["ANDROID_BUILD_TOP"] 467*90c8c64dSAndroid Build Coastguard Worker sysroot = os.path.join(os.environ["ANDROID_PRODUCT_OUT"], "symbols") 468*90c8c64dSAndroid Build Coastguard Worker 469*90c8c64dSAndroid Build Coastguard Worker if args.cwd: 470*90c8c64dSAndroid Build Coastguard Worker if not get_device_dir_exists(device, args.cwd): 471*90c8c64dSAndroid Build Coastguard Worker raise ValueError('Working directory does not exist on device: {}'.format(args.cwd)) 472*90c8c64dSAndroid Build Coastguard Worker if args.chroot: 473*90c8c64dSAndroid Build Coastguard Worker # See the comment in start_gdbserver about why this is not implemented. 474*90c8c64dSAndroid Build Coastguard Worker raise ValueError('--cwd and --chroot cannot be used together') 475*90c8c64dSAndroid Build Coastguard Worker 476*90c8c64dSAndroid Build Coastguard Worker # Make sure the environment matches the attached device. 477*90c8c64dSAndroid Build Coastguard Worker # Skip when running in a chroot because the chroot lunch target may not 478*90c8c64dSAndroid Build Coastguard Worker # match the device's lunch target. 479*90c8c64dSAndroid Build Coastguard Worker if not args.chroot: 480*90c8c64dSAndroid Build Coastguard Worker verify_device(device) 481*90c8c64dSAndroid Build Coastguard Worker 482*90c8c64dSAndroid Build Coastguard Worker debug_socket = "/data/local/tmp/debug_socket" 483*90c8c64dSAndroid Build Coastguard Worker pid = None 484*90c8c64dSAndroid Build Coastguard Worker run_cmd = None 485*90c8c64dSAndroid Build Coastguard Worker 486*90c8c64dSAndroid Build Coastguard Worker # Fetch binary for -p, -n. 487*90c8c64dSAndroid Build Coastguard Worker binary_file, pid, run_cmd = handle_switches(args, sysroot) 488*90c8c64dSAndroid Build Coastguard Worker 489*90c8c64dSAndroid Build Coastguard Worker vscode_launch_props = None 490*90c8c64dSAndroid Build Coastguard Worker if args.vscode_launch_props: 491*90c8c64dSAndroid Build Coastguard Worker if args.setup_forwarding != "vscode-lldb": 492*90c8c64dSAndroid Build Coastguard Worker raise ValueError( 493*90c8c64dSAndroid Build Coastguard Worker 'vscode-launch-props requires --setup-forwarding=vscode-lldb') 494*90c8c64dSAndroid Build Coastguard Worker vscode_launch_props = json.loads(args.vscode_launch_props) 495*90c8c64dSAndroid Build Coastguard Worker 496*90c8c64dSAndroid Build Coastguard Worker vscode_launch_file = None 497*90c8c64dSAndroid Build Coastguard Worker if args.vscode_launch_file: 498*90c8c64dSAndroid Build Coastguard Worker if args.setup_forwarding != "vscode-lldb": 499*90c8c64dSAndroid Build Coastguard Worker raise ValueError( 500*90c8c64dSAndroid Build Coastguard Worker 'vscode-launch-file requires --setup-forwarding=vscode-lldb') 501*90c8c64dSAndroid Build Coastguard Worker vscode_launch_file = args.vscode_launch_file 502*90c8c64dSAndroid Build Coastguard Worker 503*90c8c64dSAndroid Build Coastguard Worker with binary_file: 504*90c8c64dSAndroid Build Coastguard Worker if sys.platform.startswith("linux"): 505*90c8c64dSAndroid Build Coastguard Worker platform_name = "linux-x86" 506*90c8c64dSAndroid Build Coastguard Worker elif sys.platform.startswith("darwin"): 507*90c8c64dSAndroid Build Coastguard Worker platform_name = "darwin-x86" 508*90c8c64dSAndroid Build Coastguard Worker else: 509*90c8c64dSAndroid Build Coastguard Worker sys.exit("Unknown platform: {}".format(sys.platform)) 510*90c8c64dSAndroid Build Coastguard Worker 511*90c8c64dSAndroid Build Coastguard Worker arch = gdbrunner.get_binary_arch(binary_file) 512*90c8c64dSAndroid Build Coastguard Worker is64bit = arch.endswith("64") 513*90c8c64dSAndroid Build Coastguard Worker 514*90c8c64dSAndroid Build Coastguard Worker # Make sure we have the linker 515*90c8c64dSAndroid Build Coastguard Worker clang_base = 'prebuilts/clang/host' 516*90c8c64dSAndroid Build Coastguard Worker clang_version = read_toolchain_config(root) 517*90c8c64dSAndroid Build Coastguard Worker toolchain_path = os.path.join(root, clang_base, platform_name, 518*90c8c64dSAndroid Build Coastguard Worker clang_version) 519*90c8c64dSAndroid Build Coastguard Worker llvm_readobj_path = os.path.join(toolchain_path, "bin", "llvm-readobj") 520*90c8c64dSAndroid Build Coastguard Worker interp = gdbrunner.get_binary_interp(binary_file.name, llvm_readobj_path) 521*90c8c64dSAndroid Build Coastguard Worker linker_search_dir = ensure_linker(device, sysroot, interp) 522*90c8c64dSAndroid Build Coastguard Worker 523*90c8c64dSAndroid Build Coastguard Worker tracer_pid = get_tracer_pid(device, pid) 524*90c8c64dSAndroid Build Coastguard Worker if tracer_pid == 0: 525*90c8c64dSAndroid Build Coastguard Worker cmd_prefix = args.su_cmd 526*90c8c64dSAndroid Build Coastguard Worker if args.env: 527*90c8c64dSAndroid Build Coastguard Worker cmd_prefix += ['env'] + [v[0] for v in args.env] 528*90c8c64dSAndroid Build Coastguard Worker 529*90c8c64dSAndroid Build Coastguard Worker # Start lldb-server. 530*90c8c64dSAndroid Build Coastguard Worker server_local_path = get_lldb_server_path(root, clang_base, clang_version, arch) 531*90c8c64dSAndroid Build Coastguard Worker server_remote_path = "/data/local/tmp/{}-lldb-server".format(arch) 532*90c8c64dSAndroid Build Coastguard Worker gdbrunner.start_gdbserver( 533*90c8c64dSAndroid Build Coastguard Worker device, server_local_path, server_remote_path, 534*90c8c64dSAndroid Build Coastguard Worker target_pid=pid, run_cmd=run_cmd, debug_socket=debug_socket, 535*90c8c64dSAndroid Build Coastguard Worker port=args.port, run_as_cmd=cmd_prefix, lldb=True, chroot=args.chroot, cwd=args.cwd) 536*90c8c64dSAndroid Build Coastguard Worker else: 537*90c8c64dSAndroid Build Coastguard Worker print( 538*90c8c64dSAndroid Build Coastguard Worker "Connecting to tracing pid {} using local port {}".format( 539*90c8c64dSAndroid Build Coastguard Worker tracer_pid, args.port)) 540*90c8c64dSAndroid Build Coastguard Worker gdbrunner.forward_gdbserver_port(device, local=args.port, 541*90c8c64dSAndroid Build Coastguard Worker remote="tcp:{}".format(args.port)) 542*90c8c64dSAndroid Build Coastguard Worker 543*90c8c64dSAndroid Build Coastguard Worker debugger_path = get_lldb_path(toolchain_path) 544*90c8c64dSAndroid Build Coastguard Worker debugger = args.setup_forwarding or 'lldb' 545*90c8c64dSAndroid Build Coastguard Worker 546*90c8c64dSAndroid Build Coastguard Worker # Generate the lldb script. 547*90c8c64dSAndroid Build Coastguard Worker setup_commands = generate_setup_script(sysroot=sysroot, 548*90c8c64dSAndroid Build Coastguard Worker linker_search_dir=linker_search_dir, 549*90c8c64dSAndroid Build Coastguard Worker binary_name=binary_file.name, 550*90c8c64dSAndroid Build Coastguard Worker is64bit=is64bit, 551*90c8c64dSAndroid Build Coastguard Worker port=args.port, 552*90c8c64dSAndroid Build Coastguard Worker debugger=debugger, 553*90c8c64dSAndroid Build Coastguard Worker vscode_launch_props=vscode_launch_props) 554*90c8c64dSAndroid Build Coastguard Worker 555*90c8c64dSAndroid Build Coastguard Worker if not args.setup_forwarding: 556*90c8c64dSAndroid Build Coastguard Worker # Print a newline to separate our messages from the GDB session. 557*90c8c64dSAndroid Build Coastguard Worker print("") 558*90c8c64dSAndroid Build Coastguard Worker 559*90c8c64dSAndroid Build Coastguard Worker # Start lldb. 560*90c8c64dSAndroid Build Coastguard Worker gdbrunner.start_gdb(debugger_path, setup_commands, lldb=True) 561*90c8c64dSAndroid Build Coastguard Worker else: 562*90c8c64dSAndroid Build Coastguard Worker if args.setup_forwarding == "vscode-lldb" and vscode_launch_file: 563*90c8c64dSAndroid Build Coastguard Worker write_vscode_config(pathlib.Path(vscode_launch_file) , setup_commands) 564*90c8c64dSAndroid Build Coastguard Worker print(f"Generated config written to '{vscode_launch_file}'") 565*90c8c64dSAndroid Build Coastguard Worker else: 566*90c8c64dSAndroid Build Coastguard Worker print("") 567*90c8c64dSAndroid Build Coastguard Worker print(setup_commands) 568*90c8c64dSAndroid Build Coastguard Worker print("") 569*90c8c64dSAndroid Build Coastguard Worker if args.setup_forwarding == "vscode-lldb": 570*90c8c64dSAndroid Build Coastguard Worker print(textwrap.dedent(""" 571*90c8c64dSAndroid Build Coastguard Worker Paste the above json into .vscode/launch.json and start the debugger as 572*90c8c64dSAndroid Build Coastguard Worker normal.""")) 573*90c8c64dSAndroid Build Coastguard Worker else: 574*90c8c64dSAndroid Build Coastguard Worker print(textwrap.dedent(""" 575*90c8c64dSAndroid Build Coastguard Worker Paste the lldb commands above into the lldb frontend to set up the 576*90c8c64dSAndroid Build Coastguard Worker lldb-server connection.""")) 577*90c8c64dSAndroid Build Coastguard Worker 578*90c8c64dSAndroid Build Coastguard Worker print(textwrap.dedent(""" 579*90c8c64dSAndroid Build Coastguard Worker Press enter in this terminal once debugging is finished to shut lldb-server 580*90c8c64dSAndroid Build Coastguard Worker down and close all the ports.""")) 581*90c8c64dSAndroid Build Coastguard Worker print("") 582*90c8c64dSAndroid Build Coastguard Worker input("Press enter to shut down lldb-server") 583*90c8c64dSAndroid Build Coastguard Worker 584*90c8c64dSAndroid Build Coastguard Worker 585*90c8c64dSAndroid Build Coastguard Workerdef main(): 586*90c8c64dSAndroid Build Coastguard Worker try: 587*90c8c64dSAndroid Build Coastguard Worker do_main() 588*90c8c64dSAndroid Build Coastguard Worker finally: 589*90c8c64dSAndroid Build Coastguard Worker global g_temp_dirs 590*90c8c64dSAndroid Build Coastguard Worker for temp_dir in g_temp_dirs: 591*90c8c64dSAndroid Build Coastguard Worker shutil.rmtree(temp_dir) 592*90c8c64dSAndroid Build Coastguard Worker 593*90c8c64dSAndroid Build Coastguard Worker 594*90c8c64dSAndroid Build Coastguard Workerif __name__ == "__main__": 595*90c8c64dSAndroid Build Coastguard Worker main() 596