1cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)# Copyright 2014 The Chromium Authors. All rights reserved.
2cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
3cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)# found in the LICENSE file.
4cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
5cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)import glob
6cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)import hashlib
7cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)import logging
8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)import os
9f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)import platform
10cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)import re
11cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)import shutil
12cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)import subprocess
13cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccifrom telemetry import decorators
151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccifrom telemetry.core import platform as telemetry_platform
166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)from telemetry.core import util
176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)from telemetry.core.platform.profiler import android_prebuilt_profiler_helper
186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)from telemetry.util import support_binaries
196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
20f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)try:
21f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  import sqlite3
22f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)except ImportError:
23f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  sqlite3 = None
24f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
26cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)_TEXT_SECTION = '.text'
28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
30f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)def _ElfMachineId(elf_file):
31f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  headers = subprocess.check_output(['readelf', '-h', elf_file])
32f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return re.match(r'.*Machine:\s+(\w+)', headers, re.DOTALL).group(1)
33f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
34f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
35f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)def _ElfSectionAsString(elf_file, section):
36f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return subprocess.check_output(['readelf', '-p', section, elf_file])
37f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
38f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
39cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)def _ElfSectionMd5Sum(elf_file, section):
40cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  result = subprocess.check_output(
41cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      'readelf -p%s "%s" | md5sum' % (section, elf_file), shell=True)
42cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return result.split(' ', 1)[0]
43cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
44cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
45cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)def _FindMatchingUnstrippedLibraryOnHost(device, lib):
46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  lib_base = os.path.basename(lib)
47cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
48116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  device_md5 = device.RunShellCommand('md5 "%s"' % lib, as_root=True)[0]
49cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  device_md5 = device_md5.split(' ', 1)[0]
50cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
51f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  def FindMatchingStrippedLibrary(out_path):
52f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    # First find a matching stripped library on the host. This avoids the need
53f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    # to pull the stripped library from the device, which can take tens of
54f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    # seconds.
55f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    host_lib_pattern = os.path.join(out_path, '*_apk', 'libs', '*', lib_base)
56f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    for stripped_host_lib in glob.glob(host_lib_pattern):
57f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      with open(stripped_host_lib) as f:
58f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        host_md5 = hashlib.md5(f.read()).hexdigest()
59f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        if host_md5 == device_md5:
60f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          return stripped_host_lib
61f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
62f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  for build_dir, build_type in util.GetBuildDirectories():
63f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    out_path = os.path.join(build_dir, build_type)
64f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    stripped_host_lib = FindMatchingStrippedLibrary(out_path)
65f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if stripped_host_lib:
66f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break
67cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  else:
68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return None
69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
70cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  # The corresponding unstripped library will be under out/Release/lib.
71cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  unstripped_host_lib = os.path.join(out_path, 'lib', lib_base)
72cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  # Make sure the unstripped library matches the stripped one. We do this
74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  # by comparing the hashes of text sections in both libraries. This isn't an
75cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  # exact guarantee, but should still give reasonable confidence that the
76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  # libraries are compatible.
77cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  # TODO(skyostil): Check .note.gnu.build-id instead once we're using
78cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  # --build-id=sha1.
79cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  # pylint: disable=W0631
80cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (_ElfSectionMd5Sum(unstripped_host_lib, _TEXT_SECTION) !=
81cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      _ElfSectionMd5Sum(stripped_host_lib, _TEXT_SECTION)):
82cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return None
83cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return unstripped_host_lib
84cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
85cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci@decorators.Cache
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccidef GetPerfhostName():
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return 'perfhost_' + telemetry_platform.GetHostPlatform().GetOSVersionName()
891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
91cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)# Ignored directories for libraries that aren't useful for symbolization.
92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)_IGNORED_LIB_PATHS = [
93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  '/data/dalvik-cache',
94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  '/tmp'
95cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)]
96cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
97cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
98cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)def GetRequiredLibrariesForPerfProfile(profile_file):
99cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  """Returns the set of libraries necessary to symbolize a given perf profile.
100cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
101cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  Args:
102cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    profile_file: Path to perf profile to analyse.
103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
104cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  Returns:
105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    A set of required library file names.
106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  """
107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  with open(os.devnull, 'w') as dev_null:
1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    perfhost_path = support_binaries.FindPath(GetPerfhostName(), 'linux')
1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    perf = subprocess.Popen([perfhost_path, 'script', '-i', profile_file],
110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                             stdout=dev_null, stderr=subprocess.PIPE)
111cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    _, output = perf.communicate()
112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  missing_lib_re = re.compile(
113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      r'^Failed to open (.*), continuing without symbols')
114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  libs = set()
115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  for line in output.split('\n'):
116cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    lib = missing_lib_re.match(line)
117cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if lib:
118cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      lib = lib.group(1)
119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      path = os.path.dirname(lib)
120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if any(path.startswith(ignored_path)
121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)             for ignored_path in _IGNORED_LIB_PATHS) or path == '/':
122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        continue
123cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      libs.add(lib)
124cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return libs
125cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
126cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
127f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)def GetRequiredLibrariesForVTuneProfile(profile_file):
128f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  """Returns the set of libraries necessary to symbolize a given VTune profile.
129f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
130f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  Args:
131f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    profile_file: Path to VTune profile to analyse.
132f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
133f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  Returns:
134f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    A set of required library file names.
135f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  """
136f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  db_file = os.path.join(profile_file, 'sqlite-db', 'dicer.db')
137f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  conn = sqlite3.connect(db_file)
138f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
139f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  try:
140f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    # The 'dd_module_file' table lists all libraries on the device. Only the
141f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    # ones with 'bin_located_path' are needed for the profile.
142f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    query = 'SELECT bin_path, bin_located_path FROM dd_module_file'
143f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return set(row[0] for row in conn.cursor().execute(query) if row[1])
144f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  finally:
145f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    conn.close()
146f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
147f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
148cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)def CreateSymFs(device, symfs_dir, libraries, use_symlinks=True):
149cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  """Creates a symfs directory to be used for symbolizing profiles.
150cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
151cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  Prepares a set of files ("symfs") to be used with profilers such as perf for
152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  converting binary addresses into human readable function names.
153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  Args:
155cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    device: DeviceUtils instance identifying the target device.
156cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    symfs_dir: Path where the symfs should be created.
157cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    libraries: Set of library file names that should be included in the symfs.
158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    use_symlinks: If True, link instead of copy unstripped libraries into the
159cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      symfs. This will speed up the operation, but the resulting symfs will no
160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      longer be valid if the linked files are modified, e.g., by rebuilding.
161cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  Returns:
163cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    The absolute path to the kernel symbols within the created symfs.
164cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  """
165cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  logging.info('Building symfs into %s.' % symfs_dir)
166cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
167cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  mismatching_files = {}
168cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  for lib in libraries:
169cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    device_dir = os.path.dirname(lib)
170cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    output_dir = os.path.join(symfs_dir, device_dir[1:])
171cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if not os.path.exists(output_dir):
172cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      os.makedirs(output_dir)
173cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    output_lib = os.path.join(output_dir, os.path.basename(lib))
174cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
1751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if lib.startswith('/data/app/'):
176cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      # If this is our own library instead of a system one, look for a matching
177cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      # unstripped library under the out directory.
178cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      unstripped_host_lib = _FindMatchingUnstrippedLibraryOnHost(device, lib)
179cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if not unstripped_host_lib:
180cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        logging.warning('Could not find symbols for %s.' % lib)
181cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        logging.warning('Is the correct output directory selected '
182cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                        '(CHROMIUM_OUT_DIR)? Did you install the APK after '
183cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                        'building?')
184cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        continue
185cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if use_symlinks:
186cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        if os.path.lexists(output_lib):
187cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          os.remove(output_lib)
188cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        os.symlink(os.path.abspath(unstripped_host_lib), output_lib)
189cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      # Copy the unstripped library only if it has been changed to avoid the
190cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      # delay. Add one second to the modification time to guard against file
191cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      # systems with poor timestamp resolution.
192cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      elif not os.path.exists(output_lib) or \
193cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          (os.stat(unstripped_host_lib).st_mtime >
194cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)           os.stat(output_lib).st_mtime + 1):
195cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        logging.info('Copying %s to %s' % (unstripped_host_lib, output_lib))
196cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        shutil.copy2(unstripped_host_lib, output_lib)
197cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    else:
198cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      # Otherwise save a copy of the stripped system library under the symfs so
199cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      # the profiler can at least use the public symbols of that library. To
200cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      # speed things up, only pull files that don't match copies we already
201cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      # have in the symfs.
202cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if not device_dir in mismatching_files:
203cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        changed_files = device.old_interface.GetFilesChanged(output_dir,
204cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                                             device_dir)
205cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        mismatching_files[device_dir] = [
206cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            device_path for _, device_path in changed_files]
207cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
208cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if not os.path.exists(output_lib) or lib in mismatching_files[device_dir]:
209cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        logging.info('Pulling %s to %s' % (lib, output_lib))
210116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        device.PullFile(lib, output_lib)
211cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
212cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  # Also pull a copy of the kernel symbols.
213cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  output_kallsyms = os.path.join(symfs_dir, 'kallsyms')
214cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if not os.path.exists(output_kallsyms):
215116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    device.PullFile('/proc/kallsyms', output_kallsyms)
216cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return output_kallsyms
217cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
218cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
219cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)def PrepareDeviceForPerf(device):
220cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  """Set up a device for running perf.
221cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
222cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  Args:
223cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    device: DeviceUtils instance identifying the target device.
224cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
225cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  Returns:
226cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    The path to the installed perf binary on the device.
227cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  """
228cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  android_prebuilt_profiler_helper.InstallOnDevice(device, 'perf')
229cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  # Make sure kernel pointers are not hidden.
230116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  device.WriteFile('/proc/sys/kernel/kptr_restrict', '0', as_root=True)
231cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return android_prebuilt_profiler_helper.GetDevicePath('perf')
232f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
233f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
234f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)def GetToolchainBinaryPath(library_file, binary_name):
235f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  """Return the path to an Android toolchain binary on the host.
236f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
237f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  Args:
238f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    library_file: ELF library which is used to identify the used ABI,
239f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        architecture and toolchain.
240f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    binary_name: Binary to search for, e.g., 'objdump'
241f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  Returns:
242f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    Full path to binary or None if the binary was not found.
243f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  """
244f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  # Mapping from ELF machine identifiers to GNU toolchain names.
245f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  toolchain_configs = {
246f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    'x86': 'i686-linux-android',
247f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    'MIPS': 'mipsel-linux-android',
248f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    'ARM': 'arm-linux-androideabi',
249f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    'x86-64': 'x86_64-linux-android',
250f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    'AArch64': 'aarch64-linux-android',
251f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
252f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  toolchain_config = toolchain_configs[_ElfMachineId(library_file)]
253f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  host_os = platform.uname()[0].lower()
254f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  host_machine = platform.uname()[4]
255f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
256f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  elf_comment = _ElfSectionAsString(library_file, '.comment')
257f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  toolchain_version = re.match(r'.*GCC: \(GNU\) ([\w.]+)',
258f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                               elf_comment, re.DOTALL)
259f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if not toolchain_version:
260f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return None
261f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  toolchain_version = toolchain_version.group(1)
262f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
263f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  path = os.path.join(util.GetChromiumSrcDir(), 'third_party', 'android_tools',
264f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                      'ndk', 'toolchains',
265f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                      '%s-%s' % (toolchain_config, toolchain_version),
266f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                      'prebuilt', '%s-%s' % (host_os, host_machine), 'bin',
267f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                      '%s-%s' % (toolchain_config, binary_name))
268f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  path = os.path.abspath(path)
269f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return path if os.path.exists(path) else None
270