Merge "gdb: allow gdbclient.py to find local files."
This commit is contained in:
@@ -167,24 +167,65 @@ def start_gdbserver(device, gdbserver_local_path, gdbserver_remote_path,
|
||||
stderr=gdbclient_output)
|
||||
|
||||
|
||||
def pull_file(device, path, user=None):
|
||||
"""Pull a file from a device as a user."""
|
||||
def find_file(device, executable_path, sysroot, user=None):
|
||||
"""Finds a device executable file.
|
||||
|
||||
file_name = "gdbclient-binary-{}".format(os.getppid())
|
||||
remote_temp_path = "/data/local/tmp/{}".format(file_name)
|
||||
local_temp_path = os.path.join(tempfile.gettempdir(), file_name)
|
||||
cmd = get_run_as_cmd(user, ["cat", path, ">", remote_temp_path])
|
||||
try:
|
||||
device.shell(cmd)
|
||||
except adb.ShellError:
|
||||
raise RuntimeError("Failed to copy file to temporary folder on device")
|
||||
device.pull(remote_temp_path, local_temp_path)
|
||||
return open(local_temp_path, "r")
|
||||
This function first attempts to find the local file which will
|
||||
contain debug symbols. If that fails, it will fall back to
|
||||
downloading the stripped file from the device.
|
||||
|
||||
Args:
|
||||
device: the AndroidDevice object to use.
|
||||
executable_path: absolute path to the executable or symlink.
|
||||
sysroot: absolute path to the built symbol sysroot.
|
||||
user: if necessary, the user to download the file as.
|
||||
|
||||
Returns:
|
||||
A tuple containing (<open file object>, <was found locally>).
|
||||
|
||||
Raises:
|
||||
RuntimeError: could not find the executable binary.
|
||||
ValueError: |executable_path| is not absolute.
|
||||
"""
|
||||
if not os.path.isabs(executable_path):
|
||||
raise ValueError("'{}' is not an absolute path".format(executable_path))
|
||||
|
||||
def generate_files():
|
||||
"""Yields (<file name>, <found locally>) tuples."""
|
||||
# First look locally to avoid shelling into the device if possible.
|
||||
# os.path.join() doesn't combine absolute paths, use + instead.
|
||||
yield (sysroot + executable_path, True)
|
||||
|
||||
# Next check if the path is a symlink.
|
||||
try:
|
||||
target = device.shell(['readlink', '-e', '-n', executable_path])[0]
|
||||
yield (sysroot + target, True)
|
||||
except adb.ShellError:
|
||||
pass
|
||||
|
||||
# Last, download the stripped executable from the device if necessary.
|
||||
file_name = "gdbclient-binary-{}".format(os.getppid())
|
||||
remote_temp_path = "/data/local/tmp/{}".format(file_name)
|
||||
local_path = os.path.join(tempfile.gettempdir(), file_name)
|
||||
cmd = get_run_as_cmd(user,
|
||||
["cat", executable_path, ">", remote_temp_path])
|
||||
try:
|
||||
device.shell(cmd)
|
||||
except adb.ShellError:
|
||||
raise RuntimeError("Failed to copy '{}' to temporary folder on "
|
||||
"device".format(executable_path))
|
||||
device.pull(remote_temp_path, local_path)
|
||||
yield (local_path, False)
|
||||
|
||||
for path, found_locally in generate_files():
|
||||
if os.path.isfile(path):
|
||||
return (open(path, "r"), found_locally)
|
||||
raise RuntimeError('Could not find executable {}'.format(executable_path))
|
||||
|
||||
|
||||
def pull_binary(device, pid, user=None):
|
||||
"""Pull a running process's binary from a device as a user"""
|
||||
return pull_file(device, "/proc/{}/exe".format(pid), user)
|
||||
def find_binary(device, pid, sysroot, user=None):
|
||||
"""Finds a device executable file corresponding to |pid|."""
|
||||
return find_file(device, "/proc/{}/exe".format(pid), sysroot, user)
|
||||
|
||||
|
||||
def get_binary_arch(binary_file):
|
||||
|
||||
@@ -106,7 +106,7 @@ def ensure_linker(device, sysroot, is64bit):
|
||||
device.pull(remote_path, local_path)
|
||||
|
||||
|
||||
def handle_switches(args):
|
||||
def handle_switches(args, sysroot):
|
||||
"""Fetch the targeted binary and determine how to attach gdb.
|
||||
|
||||
Args:
|
||||
@@ -135,14 +135,20 @@ def handle_switches(args):
|
||||
if not args.run_cmd[0].startswith("/"):
|
||||
sys.exit("commands passed to -r must use absolute paths")
|
||||
run_cmd = args.run_cmd
|
||||
binary_file = gdbrunner.pull_file(device, run_cmd[0], user=args.user)
|
||||
binary_file, local = gdbrunner.find_file(device, run_cmd[0], sysroot,
|
||||
user=args.user)
|
||||
if binary_file is None:
|
||||
assert pid is not None
|
||||
try:
|
||||
binary_file = gdbrunner.pull_binary(device, pid=pid, user=args.user)
|
||||
binary_file, local = gdbrunner.find_binary(device, pid, sysroot,
|
||||
user=args.user)
|
||||
except adb.ShellError:
|
||||
sys.exit("failed to pull binary for PID {}".format(pid))
|
||||
|
||||
if not local:
|
||||
logging.warning("Couldn't find local unstripped executable in {},"
|
||||
" symbols may not be available.".format(sysroot))
|
||||
|
||||
return (binary_file, pid, run_cmd)
|
||||
|
||||
def generate_gdb_script(sysroot, binary_file, is64bit, port, connect_timeout=5):
|
||||
@@ -216,7 +222,7 @@ def main():
|
||||
run_cmd = None
|
||||
|
||||
# Fetch binary for -p, -n.
|
||||
binary_file, pid, run_cmd = handle_switches(args)
|
||||
binary_file, pid, run_cmd = handle_switches(args, sysroot)
|
||||
|
||||
with binary_file:
|
||||
arch = gdbrunner.get_binary_arch(binary_file)
|
||||
@@ -249,6 +255,9 @@ def main():
|
||||
gdb_path = os.path.join(root, "prebuilts", "gdb", platform_name, "bin",
|
||||
"gdb")
|
||||
|
||||
# Print a newline to separate our messages from the GDB session.
|
||||
print("")
|
||||
|
||||
# Start gdb.
|
||||
gdbrunner.start_gdb(gdb_path, gdb_commands)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user