Merge "gdb: allow gdbclient.py to find local files."

This commit is contained in:
David Pursell
2015-10-21 18:41:33 +00:00
committed by Gerrit Code Review
2 changed files with 69 additions and 19 deletions

View File

@@ -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):

View 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)