gdb: allow gdbclient.py to find local files.
gdbclient.py is always downloading the stripped version of executable files from the device. This CL first tries to find the unstripped local file before falling back to the stripped version. Bug: http://b/24947939 Change-Id: I7a49d0d8b28590ee99ce892d3e3476921f4ae974
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.
|
||||||
|
|
||||||
file_name = "gdbclient-binary-{}".format(os.getppid())
|
This function first attempts to find the local file which will
|
||||||
remote_temp_path = "/data/local/tmp/{}".format(file_name)
|
contain debug symbols. If that fails, it will fall back to
|
||||||
local_temp_path = os.path.join(tempfile.gettempdir(), file_name)
|
downloading the stripped file from the device.
|
||||||
cmd = get_run_as_cmd(user, ["cat", path, ">", remote_temp_path])
|
|
||||||
try:
|
Args:
|
||||||
device.shell(cmd)
|
device: the AndroidDevice object to use.
|
||||||
except adb.ShellError:
|
executable_path: absolute path to the executable or symlink.
|
||||||
raise RuntimeError("Failed to copy file to temporary folder on device")
|
sysroot: absolute path to the built symbol sysroot.
|
||||||
device.pull(remote_temp_path, local_temp_path)
|
user: if necessary, the user to download the file as.
|
||||||
return open(local_temp_path, "r")
|
|
||||||
|
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):
|
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