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)
|
stderr=gdbclient_output)
|
||||||
|
|
||||||
|
|
||||||
def pull_file(device, path, user=None):
|
def find_file(device, executable_path, sysroot, user=None):
|
||||||
"""Pull a file from a device as a user."""
|
"""Finds a device executable file.
|
||||||
|
|
||||||
|
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())
|
file_name = "gdbclient-binary-{}".format(os.getppid())
|
||||||
remote_temp_path = "/data/local/tmp/{}".format(file_name)
|
remote_temp_path = "/data/local/tmp/{}".format(file_name)
|
||||||
local_temp_path = os.path.join(tempfile.gettempdir(), file_name)
|
local_path = os.path.join(tempfile.gettempdir(), file_name)
|
||||||
cmd = get_run_as_cmd(user, ["cat", path, ">", remote_temp_path])
|
cmd = get_run_as_cmd(user,
|
||||||
|
["cat", executable_path, ">", remote_temp_path])
|
||||||
try:
|
try:
|
||||||
device.shell(cmd)
|
device.shell(cmd)
|
||||||
except adb.ShellError:
|
except adb.ShellError:
|
||||||
raise RuntimeError("Failed to copy file to temporary folder on device")
|
raise RuntimeError("Failed to copy '{}' to temporary folder on "
|
||||||
device.pull(remote_temp_path, local_temp_path)
|
"device".format(executable_path))
|
||||||
return open(local_temp_path, "r")
|
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):
|
def find_binary(device, pid, sysroot, user=None):
|
||||||
"""Pull a running process's binary from a device as a user"""
|
"""Finds a device executable file corresponding to |pid|."""
|
||||||
return pull_file(device, "/proc/{}/exe".format(pid), user)
|
return find_file(device, "/proc/{}/exe".format(pid), sysroot, user)
|
||||||
|
|
||||||
|
|
||||||
def get_binary_arch(binary_file):
|
def get_binary_arch(binary_file):
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ def ensure_linker(device, sysroot, is64bit):
|
|||||||
device.pull(remote_path, local_path)
|
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.
|
"""Fetch the targeted binary and determine how to attach gdb.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -135,14 +135,20 @@ def handle_switches(args):
|
|||||||
if not args.run_cmd[0].startswith("/"):
|
if not args.run_cmd[0].startswith("/"):
|
||||||
sys.exit("commands passed to -r must use absolute paths")
|
sys.exit("commands passed to -r must use absolute paths")
|
||||||
run_cmd = args.run_cmd
|
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:
|
if binary_file is None:
|
||||||
assert pid is not None
|
assert pid is not None
|
||||||
try:
|
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:
|
except adb.ShellError:
|
||||||
sys.exit("failed to pull binary for PID {}".format(pid))
|
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)
|
return (binary_file, pid, run_cmd)
|
||||||
|
|
||||||
def generate_gdb_script(sysroot, binary_file, is64bit, port, connect_timeout=5):
|
def generate_gdb_script(sysroot, binary_file, is64bit, port, connect_timeout=5):
|
||||||
@@ -216,7 +222,7 @@ def main():
|
|||||||
run_cmd = None
|
run_cmd = None
|
||||||
|
|
||||||
# Fetch binary for -p, -n.
|
# 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:
|
with binary_file:
|
||||||
arch = gdbrunner.get_binary_arch(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_path = os.path.join(root, "prebuilts", "gdb", platform_name, "bin",
|
||||||
"gdb")
|
"gdb")
|
||||||
|
|
||||||
|
# Print a newline to separate our messages from the GDB session.
|
||||||
|
print("")
|
||||||
|
|
||||||
# Start gdb.
|
# Start gdb.
|
||||||
gdbrunner.start_gdb(gdb_path, gdb_commands)
|
gdbrunner.start_gdb(gdb_path, gdb_commands)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user