Пример #1
0
 def test_executable_and_constants(self):
     maps = ProcMaps.load_file(cStringIO.StringIO(self._TEST_PROCMAPS))
     selected = [0, 1, 2, 3, 4, 6, 7, 9]
     for index, entry in enumerate(
             maps.iter(ProcMaps.executable_and_constants)):
         self.assertEqual(entry.as_dict(),
                          self._expected_as_dict(selected[index]))
Пример #2
0
    def load(prepared_data_dir):
        symbols_in_process = RuntimeSymbolsInProcess()

        with open(os.path.join(prepared_data_dir, _MAPS_FILENAME),
                  mode='r') as f:
            symbols_in_process._maps = ProcMaps.load_file(f)
        with open(os.path.join(prepared_data_dir, _FILES_FILENAME),
                  mode='r') as f:
            files = json.load(f)

        # pylint: disable=W0212
        for vma in symbols_in_process._maps.iter(
                ProcMaps.executable_and_constants):
            file_entry = files.get(vma.name)
            if not file_entry:
                continue

            static_symbols = StaticSymbolsInFile(vma.name)

            nm_entry = file_entry.get('nm')
            if nm_entry and nm_entry['format'] == 'bsd':
                with open(os.path.join(prepared_data_dir, nm_entry['file']),
                          'r') as f:
                    static_symbols.load_nm_bsd(f, nm_entry['mangled'])

            readelf_entry = file_entry.get('readelf-e')
            if readelf_entry:
                with open(
                        os.path.join(prepared_data_dir, readelf_entry['file']),
                        'r') as f:
                    static_symbols.load_readelf_ew(f)

            decodedline_file_entry = file_entry.get(
                'readelf-debug-decodedline-file')
            if decodedline_file_entry:
                with open(
                        os.path.join(prepared_data_dir,
                                     decodedline_file_entry['file']),
                        'r') as f:
                    static_symbols.load_readelf_debug_decodedline_file(f)

            symbols_in_process._static_symbols_in_filse[
                vma.name] = static_symbols

        return symbols_in_process
Пример #3
0
  def load(prepared_data_dir):
    symbols_in_process = RuntimeSymbolsInProcess()

    with open(os.path.join(prepared_data_dir, _MAPS_FILENAME), mode='r') as f:
      symbols_in_process._maps = ProcMaps.load_file(f)
    with open(os.path.join(prepared_data_dir, _FILES_FILENAME), mode='r') as f:
      files = json.load(f)

    # pylint: disable=W0212
    for vma in symbols_in_process._maps.iter(ProcMaps.executable_and_constants):
      file_entry = files.get(vma.name)
      if not file_entry:
        continue

      static_symbols = StaticSymbolsInFile(vma.name)

      nm_entry = file_entry.get('nm')
      if nm_entry and nm_entry['format'] == 'bsd':
        with open(os.path.join(prepared_data_dir, nm_entry['file']), 'r') as f:
          static_symbols.load_nm_bsd(f, nm_entry['mangled'])

      readelf_entry = file_entry.get('readelf-e')
      if readelf_entry:
        with open(os.path.join(prepared_data_dir, readelf_entry['file']),
                  'r') as f:
          static_symbols.load_readelf_ew(f)

      decodedline_file_entry = file_entry.get('readelf-debug-decodedline-file')
      if decodedline_file_entry:
        with open(os.path.join(prepared_data_dir,
                               decodedline_file_entry['file']), 'r') as f:
          static_symbols.load_readelf_debug_decodedline_file(f)

      symbols_in_process._static_symbols_in_filse[vma.name] = static_symbols

    return symbols_in_process
Пример #4
0
 def test_executable_and_constants(self):
   maps = ProcMaps.load_file(cStringIO.StringIO(self._TEST_PROCMAPS))
   selected = [3, 4, 6, 7]
   for index, entry in enumerate(maps.iter(ProcMaps.executable_and_constants)):
     self.assertEqual(entry.as_dict(),
                      self._expected_as_dict(selected[index]))
Пример #5
0
 def test_load(self):
   maps = ProcMaps.load_file(cStringIO.StringIO(self._TEST_PROCMAPS))
   for index, entry in enumerate(maps):
     self.assertEqual(entry.as_dict(), self._expected_as_dict(index))
Пример #6
0
 def test_load(self):
     maps = ProcMaps.load_file(cStringIO.StringIO(self._TEST_PROCMAPS))
     for index, entry in enumerate(maps):
         self.assertEqual(entry.as_dict(), self._expected_as_dict(index))
Пример #7
0
 def test_executable(self):
     maps = ProcMaps.load_file(cStringIO.StringIO(self._TEST_PROCMAPS))
     selected = [3, 6]
     for index, entry in enumerate(maps.iter(ProcMaps.executable)):
         self.assertEqual(entry.as_dict(),
                          self._expected_as_dict(selected[index]))
Пример #8
0
 def test_constants(self):
     maps = ProcMaps.load_file(cStringIO.StringIO(self._TEST_PROCMAPS))
     selected = [4, 7]
     for index, entry in enumerate(maps.iter(ProcMaps.constants)):
         self.assertEqual(entry.as_dict(),
                          self._expected_as_dict(selected[index]))
def prepare_symbol_info(maps_path,
                        output_dir_path=None,
                        alternative_dirs=None,
                        use_tempdir=False,
                        use_source_file_name=False):
    """Prepares (collects) symbol information files for find_runtime_symbols.

  1) If |output_dir_path| is specified, it tries collecting symbol information
  files in the given directory |output_dir_path|.
  1-a) If |output_dir_path| doesn't exist, create the directory and use it.
  1-b) If |output_dir_path| is an empty directory, use it.
  1-c) If |output_dir_path| is a directory which has 'files.json', assumes that
       files are already collected and just ignores it.
  1-d) Otherwise, depends on |use_tempdir|.

  2) If |output_dir_path| is not specified, it tries to create a new directory
  depending on 'maps_path'.

  If it cannot create a new directory, creates a temporary directory depending
  on |use_tempdir|.  If |use_tempdir| is False, returns None.

  Args:
      maps_path: A path to a file which contains '/proc/<pid>/maps'.
      alternative_dirs: A mapping from a directory '/path/on/target' where the
          target process runs to a directory '/path/on/host' where the script
          reads the binary.  Considered to be used for Android binaries.
      output_dir_path: A path to a directory where files are prepared.
      use_tempdir: If True, it creates a temporary directory when it cannot
          create a new directory.
      use_source_file_name: If True, it adds reduced result of 'readelf -wL'
          to find source file names.

  Returns:
      A pair of a path to the prepared directory and a boolean representing
      if it created a temporary directory or not.
  """
    alternative_dirs = alternative_dirs or {}
    if not output_dir_path:
        matched = re.match('^(.*)\.maps$', os.path.basename(maps_path))
        if matched:
            output_dir_path = matched.group(1) + '.pre'
    if not output_dir_path:
        matched = re.match('^/proc/(.*)/maps$', os.path.realpath(maps_path))
        if matched:
            output_dir_path = matched.group(1) + '.pre'
    if not output_dir_path:
        output_dir_path = os.path.basename(maps_path) + '.pre'
    # TODO(dmikurube): Find another candidate for output_dir_path.

    used_tempdir = False
    LOGGER.info('Data for profiling will be collected in "%s".' %
                output_dir_path)
    if os.path.exists(output_dir_path):
        if os.path.isdir(output_dir_path) and not os.listdir(output_dir_path):
            LOGGER.warn('Using an empty existing directory "%s".' %
                        output_dir_path)
        else:
            LOGGER.warn('A file or a directory exists at "%s".' %
                        output_dir_path)
            if os.path.exists(os.path.join(output_dir_path, 'files.json')):
                LOGGER.warn('Using the existing directory "%s".' %
                            output_dir_path)
                return output_dir_path, used_tempdir
            else:
                if use_tempdir:
                    output_dir_path = tempfile.mkdtemp()
                    used_tempdir = True
                    LOGGER.warn('Using a temporary directory "%s".' %
                                output_dir_path)
                else:
                    LOGGER.warn('The directory "%s" is not available.' %
                                output_dir_path)
                    return None, used_tempdir
    else:
        LOGGER.info('Creating a new directory "%s".' % output_dir_path)
        try:
            os.mkdir(output_dir_path)
        except OSError:
            LOGGER.warn('A directory "%s" cannot be created.' %
                        output_dir_path)
            if use_tempdir:
                output_dir_path = tempfile.mkdtemp()
                used_tempdir = True
                LOGGER.warn('Using a temporary directory "%s".' %
                            output_dir_path)
            else:
                LOGGER.warn('The directory "%s" is not available.' %
                            output_dir_path)
                return None, used_tempdir

    shutil.copyfile(maps_path, os.path.join(output_dir_path, 'maps'))

    with open(maps_path, mode='r') as f:
        maps = ProcMaps.load_file(f)

    LOGGER.debug('Listing up symbols.')
    files = {}
    for entry in maps.iter(ProcMaps.executable):
        LOGGER.debug('  %016x-%016x +%06x %s' %
                     (entry.begin, entry.end, entry.offset, entry.name))
        binary_path = entry.name
        for target_path, host_path in alternative_dirs.iteritems():
            if entry.name.startswith(target_path):
                binary_path = entry.name.replace(target_path, host_path, 1)
        nm_filename = _dump_command_result(
            'nm -n --format bsd %s | c++filt' % binary_path, output_dir_path,
            os.path.basename(binary_path), '.nm')
        if not nm_filename:
            continue
        readelf_e_filename = _dump_command_result(
            'readelf -eW %s' % binary_path, output_dir_path,
            os.path.basename(binary_path), '.readelf-e')
        if not readelf_e_filename:
            continue
        readelf_debug_decodedline_file = None
        if use_source_file_name:
            readelf_debug_decodedline_file = _dump_command_result(
                'readelf -wL %s | %s' % (binary_path, REDUCE_DEBUGLINE_PATH),
                output_dir_path, os.path.basename(binary_path), '.readelf-wL')

        files[entry.name] = {}
        files[entry.name]['nm'] = {
            'file': os.path.basename(nm_filename),
            'format': 'bsd',
            'mangled': False
        }
        files[entry.name]['readelf-e'] = {
            'file': os.path.basename(readelf_e_filename)
        }
        if readelf_debug_decodedline_file:
            files[entry.name]['readelf-debug-decodedline-file'] = {
                'file': os.path.basename(readelf_debug_decodedline_file)
            }

        files[entry.name]['size'] = os.stat(binary_path).st_size

        with open(binary_path, 'rb') as entry_f:
            md5 = hashlib.md5()
            sha1 = hashlib.sha1()
            chunk = entry_f.read(1024 * 1024)
            while chunk:
                md5.update(chunk)
                sha1.update(chunk)
                chunk = entry_f.read(1024 * 1024)
            files[entry.name]['sha1'] = sha1.hexdigest()
            files[entry.name]['md5'] = md5.hexdigest()

    with open(os.path.join(output_dir_path, 'files.json'), 'w') as f:
        json.dump(files, f, indent=2, sort_keys=True)

    LOGGER.info('Collected symbol information at "%s".' % output_dir_path)
    return output_dir_path, used_tempdir
Пример #10
0
def prepare_symbol_info(maps_path,
                        output_dir_path=None,
                        alternative_dirs=None,
                        use_tempdir=False,
                        use_source_file_name=False):
  """Prepares (collects) symbol information files for find_runtime_symbols.

  1) If |output_dir_path| is specified, it tries collecting symbol information
  files in the given directory |output_dir_path|.
  1-a) If |output_dir_path| doesn't exist, create the directory and use it.
  1-b) If |output_dir_path| is an empty directory, use it.
  1-c) If |output_dir_path| is a directory which has 'files.json', assumes that
       files are already collected and just ignores it.
  1-d) Otherwise, depends on |use_tempdir|.

  2) If |output_dir_path| is not specified, it tries to create a new directory
  depending on 'maps_path'.

  If it cannot create a new directory, creates a temporary directory depending
  on |use_tempdir|.  If |use_tempdir| is False, returns None.

  Args:
      maps_path: A path to a file which contains '/proc/<pid>/maps'.
      alternative_dirs: A mapping from a directory '/path/on/target' where the
          target process runs to a directory '/path/on/host' where the script
          reads the binary.  Considered to be used for Android binaries.
      output_dir_path: A path to a directory where files are prepared.
      use_tempdir: If True, it creates a temporary directory when it cannot
          create a new directory.
      use_source_file_name: If True, it adds reduced result of 'readelf -wL'
          to find source file names.

  Returns:
      A pair of a path to the prepared directory and a boolean representing
      if it created a temporary directory or not.
  """
  alternative_dirs = alternative_dirs or {}
  if not output_dir_path:
    matched = re.match('^(.*)\.maps$', os.path.basename(maps_path))
    if matched:
      output_dir_path = matched.group(1) + '.pre'
  if not output_dir_path:
    matched = re.match('^/proc/(.*)/maps$', os.path.realpath(maps_path))
    if matched:
      output_dir_path = matched.group(1) + '.pre'
  if not output_dir_path:
    output_dir_path = os.path.basename(maps_path) + '.pre'
  # TODO(dmikurube): Find another candidate for output_dir_path.

  used_tempdir = False
  LOGGER.info('Data for profiling will be collected in "%s".' % output_dir_path)
  if os.path.exists(output_dir_path):
    if os.path.isdir(output_dir_path) and not os.listdir(output_dir_path):
      LOGGER.warn('Using an empty existing directory "%s".' % output_dir_path)
    else:
      LOGGER.warn('A file or a directory exists at "%s".' % output_dir_path)
      if os.path.exists(os.path.join(output_dir_path, 'files.json')):
        LOGGER.warn('Using the existing directory "%s".' % output_dir_path)
        return output_dir_path, used_tempdir
      else:
        if use_tempdir:
          output_dir_path = tempfile.mkdtemp()
          used_tempdir = True
          LOGGER.warn('Using a temporary directory "%s".' % output_dir_path)
        else:
          LOGGER.warn('The directory "%s" is not available.' % output_dir_path)
          return None, used_tempdir
  else:
    LOGGER.info('Creating a new directory "%s".' % output_dir_path)
    try:
      os.mkdir(output_dir_path)
    except OSError:
      LOGGER.warn('A directory "%s" cannot be created.' % output_dir_path)
      if use_tempdir:
        output_dir_path = tempfile.mkdtemp()
        used_tempdir = True
        LOGGER.warn('Using a temporary directory "%s".' % output_dir_path)
      else:
        LOGGER.warn('The directory "%s" is not available.' % output_dir_path)
        return None, used_tempdir

  shutil.copyfile(maps_path, os.path.join(output_dir_path, 'maps'))

  with open(maps_path, mode='r') as f:
    maps = ProcMaps.load_file(f)

  LOGGER.debug('Listing up symbols.')
  files = {}
  for entry in maps.iter(ProcMaps.executable):
    LOGGER.debug('  %016x-%016x +%06x %s' % (
        entry.begin, entry.end, entry.offset, entry.name))
    binary_path = entry.name
    for target_path, host_path in alternative_dirs.iteritems():
      if entry.name.startswith(target_path):
        binary_path = entry.name.replace(target_path, host_path, 1)
    if not (ProcMaps.EXECUTABLE_PATTERN.match(binary_path) or
            (os.path.isfile(binary_path) and os.access(binary_path, os.X_OK))):
      continue
    nm_filename = _dump_command_result(
        'nm -n --format bsd %s | c++filt' % binary_path,
        output_dir_path, os.path.basename(binary_path), '.nm')
    if not nm_filename:
      continue
    readelf_e_filename = _dump_command_result(
        'readelf -eW %s' % binary_path,
        output_dir_path, os.path.basename(binary_path), '.readelf-e')
    if not readelf_e_filename:
      continue
    readelf_debug_decodedline_file = None
    if use_source_file_name:
      readelf_debug_decodedline_file = _dump_command_result(
          'readelf -wL %s | %s' % (binary_path, REDUCE_DEBUGLINE_PATH),
          output_dir_path, os.path.basename(binary_path), '.readelf-wL')

    files[entry.name] = {}
    files[entry.name]['nm'] = {
        'file': os.path.basename(nm_filename),
        'format': 'bsd',
        'mangled': False}
    files[entry.name]['readelf-e'] = {
        'file': os.path.basename(readelf_e_filename)}
    if readelf_debug_decodedline_file:
      files[entry.name]['readelf-debug-decodedline-file'] = {
          'file': os.path.basename(readelf_debug_decodedline_file)}

    files[entry.name]['size'] = os.stat(binary_path).st_size

    with open(binary_path, 'rb') as entry_f:
      md5 = hashlib.md5()
      sha1 = hashlib.sha1()
      chunk = entry_f.read(1024 * 1024)
      while chunk:
        md5.update(chunk)
        sha1.update(chunk)
        chunk = entry_f.read(1024 * 1024)
      files[entry.name]['sha1'] = sha1.hexdigest()
      files[entry.name]['md5'] = md5.hexdigest()

  with open(os.path.join(output_dir_path, 'files.json'), 'w') as f:
    json.dump(files, f, indent=2, sort_keys=True)

  LOGGER.info('Collected symbol information at "%s".' % output_dir_path)
  return output_dir_path, used_tempdir