コード例 #1
0
ファイル: parseelf_unittest.py プロジェクト: sjg20/chromite
    def testParsedSymbols(self):
        """Tests the list of imported/exported symbols."""
        unittest_lib.BuildELF(os.path.join(self.tempdir, 'libabc.so'),
                              defined_symbols=['fa', 'fb', 'fc'])
        unittest_lib.BuildELF(os.path.join(self.tempdir, 'libxyz.so'),
                              defined_symbols=['fx', 'fy', 'fz'],
                              undefined_symbols=['fa', 'fb', 'fc'],
                              used_libs=['abc'])

        # Test without symbols.
        elf = parseelf.ParseELF(self.tempdir,
                                'libxyz.so',
                                self._ldpaths,
                                parse_symbols=False)
        self.assertFalse('imp_sym' in elf)
        self.assertFalse('exp_sym' in elf)

        # Test with symbols by default.
        elf = parseelf.ParseELF(self.tempdir, 'libxyz.so', self._ldpaths)
        self.assertTrue('imp_sym' in elf)
        self.assertTrue('exp_sym' in elf)
        self.assertEquals(elf['imp_sym'], set(['fa', 'fb', 'fc']))
        self.assertEquals(
            set(k for k, (_, _, st_shndx) in elf['exp_sym'].iteritems()
                if st_shndx == 'SHT_DYNSYM'), set(['fx', 'fy', 'fz']))
        for sym in ['fx', 'fy', 'fz']:
            self.assertEquals('STB_GLOBAL', elf['exp_sym'][sym][0])
コード例 #2
0
    def testParsedSymbols(self):
        """Tests the list of imported/exported symbols."""
        unittest_lib.BuildELF(os.path.join(self.tempdir, 'libabc.so'),
                              defined_symbols=['fa', 'fb', 'fc'])
        unittest_lib.BuildELF(os.path.join(self.tempdir, 'libxyz.so'),
                              defined_symbols=['fx', 'fy', 'fz'],
                              undefined_symbols=['fa', 'fb', 'fc'],
                              used_libs=['abc'])

        # Test without symbols.
        elf = parseelf.ParseELF(self.tempdir,
                                'libxyz.so',
                                self._ldpaths,
                                parse_symbols=False)
        self.assertFalse('imp_sym' in elf)
        self.assertFalse('exp_sym' in elf)

        # Test with symbols by default.
        elf = parseelf.ParseELF(self.tempdir,
                                'libxyz.so',
                                self._ldpaths,
                                parse_symbols=True)
        self.assertTrue('imp_sym' in elf)
        self.assertTrue('exp_sym' in elf)
        self.assertEquals(elf['imp_sym'], set(['fa', 'fb', 'fc']))
        self.assertIn('fx', elf['exp_sym'])
        self.assertIn('fy', elf['exp_sym'])
        self.assertIn('fz', elf['exp_sym'])
コード例 #3
0
ファイル: parseelf_unittest.py プロジェクト: sjg20/chromite
    def testUnsupportedFiles(self):
        """Tests unsupported files are ignored."""
        osutils.WriteFile(os.path.join(self.tempdir, 'foo.so'), 'foo')
        self.assertEquals(
            None, parseelf.ParseELF(self.tempdir, 'foo.so', self._ldpaths))

        osutils.WriteFile(os.path.join(self.tempdir, 'foo.so'), '\x7fELF-foo')
        self.assertEquals(
            None, parseelf.ParseELF(self.tempdir, 'foo.so', self._ldpaths))
コード例 #4
0
ファイル: parseelf_unittest.py プロジェクト: sjg20/chromite
    def testLibDependencies(self):
        """Tests the list direct dependencies."""
        # Dependencies:
        #   u -> abc
        #   v -> abc
        #   prog -> u,v
        unittest_lib.BuildELF(os.path.join(self.tempdir, 'libabc.so'),
                              defined_symbols=['fa', 'fb', 'fc'])
        unittest_lib.BuildELF(os.path.join(self.tempdir, 'libu.so'),
                              defined_symbols=['fu'],
                              undefined_symbols=['fa'],
                              used_libs=['abc'])
        unittest_lib.BuildELF(os.path.join(self.tempdir, 'libv.so'),
                              defined_symbols=['fv'],
                              undefined_symbols=['fb'],
                              used_libs=['abc'])
        unittest_lib.BuildELF(os.path.join(self.tempdir, 'prog'),
                              undefined_symbols=['fu', 'fv'],
                              used_libs=['u', 'v'],
                              executable=True)

        elf_prog = parseelf.ParseELF(self.tempdir, 'prog', self._ldpaths)
        # Check the direct dependencies.
        self.assertTrue('libu.so' in elf_prog['needed'])
        self.assertTrue('libv.so' in elf_prog['needed'])
        self.assertFalse('libabc.so' in elf_prog['needed'])
コード例 #5
0
ファイル: parseelf_unittest.py プロジェクト: sjg20/chromite
 def testNotIsLib(self):
     """Tests the 'is_lib' attribute is inferred correctly for executables."""
     unittest_lib.BuildELF(os.path.join(self.tempdir, 'abc_main'),
                           executable=True)
     elf = parseelf.ParseELF(self.tempdir, 'abc_main', self._ldpaths)
     self.assertTrue('is_lib' in elf)
     self.assertFalse(elf['is_lib'])
コード例 #6
0
ファイル: parseelf_unittest.py プロジェクト: sjg20/chromite
 def testIsLib(self):
     """Tests the 'is_lib' attribute is inferred correctly for libs."""
     unittest_lib.BuildELF(os.path.join(self.tempdir, 'liba.so'),
                           ['func_a'])
     elf = parseelf.ParseELF(self.tempdir, 'liba.so', self._ldpaths)
     self.assertTrue('is_lib' in elf)
     self.assertTrue(elf['is_lib'])
コード例 #7
0
def ParseELFWithArgs(args):
    """Wrapper to parseelf.ParseELF accepting a single arg.

  This wrapper is required to use multiprocessing.Pool.map function.

  Returns:
    A 2-tuple with the passed relative path and the result of ParseELF(). On
    error, when ParseELF() returns None, this function returns None.
  """
    elf = parseelf.ParseELF(*args)
    if elf is None:
        return
    return args[1], elf
コード例 #8
0
 def testRelativeLibPaths(self):
   """Test that the paths reported by ParseELF are relative to root."""
   unittest_lib.BuildELF(os.path.join(self.tempdir, 'liba.so'), ['fa'])
   unittest_lib.BuildELF(os.path.join(self.tempdir, 'prog'),
                         undefined_symbols=['fa'], used_libs=['a'],
                         executable=True)
   elf = parseelf.ParseELF(self.tempdir, 'prog', self._ldpaths)
   for lib in elf['libs'].values():
     for path in ('realpath', 'path'):
       if lib[path] is None:
         continue
       self.assertFalse(lib[path].startswith('/'))
       self.assertFalse(lib[path].startswith(self.tempdir))
       # Linked lib paths should be relative to the working directory or is the
       # ld dynamic loader.
       self.assertTrue(lib[path] == elf['interp'] or
                       os.path.exists(os.path.join(self.tempdir, lib[path])))
コード例 #9
0
    def _GetTypeFromContent(self, rel_path, fobj, fmap):
        """Return the file path based on the file contents.

    This helper function detect the file type based on the contents of the file.

    Args:
      rel_path: The path to the file, used to detect the filetype from the
          contents of the file.
      fobj: a file() object for random access to rel_path.
      fmap: a mmap object mapping the whole rel_path file for reading.
    """

        # Detect if the file is binary based on the presence of non-ASCII chars. We
        # include some the first 32 chars often used in text files but we exclude
        # the rest.
        # Python 2 creates bytes as chars when we want ints (like Python 3).
        # TODO(vapier): Drop this once we require Python 3 everywhere.
        if sys.version_info.major < 3:
            to_ints = lambda s: (ord(x) for x in s)
        else:
            to_ints = lambda s: s
        ascii_chars = set(to_ints(b'\a\b\t\n\v\f\r\x1b'))
        ascii_chars.update(range(32, 128))
        is_binary = any(
            set(to_ints(chunk)) - ascii_chars
            for chunk in iter(lambda: fmap.read(FILE_BUFFER_SIZE), b''))

        # We use the first part of the file in several checks.
        fmap.seek(0)
        first_kib = fmap.read(1024)

        # Binary files.
        if is_binary:
            # The elf argument was not passed, so compute it now if the file is an
            # ELF.
            if first_kib.startswith(b'\x7fELF'):
                return self._GetELFType(
                    parseelf.ParseELF(self._root,
                                      rel_path,
                                      parse_symbols=False))

            if first_kib.startswith(b'MZ\x90\0'):
                return 'binary/dos-bin'

            if len(first_kib) >= 512 and first_kib[510:512] == b'\x55\xaa':
                return 'binary/bootsector/x86'

            # Firmware file depend on the technical details of the device they run on,
            # so there's no easy way to detect them. We use the filename to guess that
            # case.
            if '/firmware/' in rel_path and (
                    rel_path.endswith('.fw')
                    or rel_path[-4:] in ('.bin', '.cis', '.csp', '.dsp')):
                return 'binary/firmware'

            # TZif (timezone) files. See tzfile(5) for details.
            if (first_kib.startswith(b'TZif' + b'\0' * 16)
                    or first_kib.startswith(b'TZif2' + b'\0' * 15)
                    or first_kib.startswith(b'TZif3' + b'\0' * 15)):
                return 'binary/tzfile'

            # Whitelist some binary mime types.
            fobj.seek(0)
            # _mime.descriptor() will close the passed file descriptor.
            mime_type = self._mime.descriptor(os.dup(fobj.fileno()))
            if mime_type.startswith('image/'):
                return 'binary/' + mime_type
            if mime_type in self.MIME_TYPE_MAPPING:
                return self.MIME_TYPE_MAPPING[mime_type]

            # Other binary files.
            return 'binary'

        # Text files.
        # Read the first couple of lines used in the following checks. This will
        # only read the required lines, with the '\n' char at the end of each line
        # except on the last one if it is not present on that line. At this point
        # we know that the file is not empty, so at least one line existst.
        fmap.seek(0)
        first_lines = list(itertools.islice(iter(fmap.readline, b''), 0, 10))
        head_line = first_lines[0]

        # #! or "shebangs". Only those files with a single line are considered
        # shebangs. Some files start with "#!" but are other kind of files, such
        # as python or bash scripts.
        try:
            prog_name, args = SplitShebang(head_line)
            if len(first_lines) == 1:
                return 'text/shebang'

            prog_name = os.path.basename(prog_name)
            args = args.split()
            if prog_name == 'env':
                # If "env" is called, we skip all the arguments passed to env (flags,
                # VAR=value) and treat the program name as the program to use.
                for i, arg in enumerate(args):
                    if arg == '--' and (i + 1) < len(args):
                        prog_name = args[i + 1]
                        break
                    if not arg or arg[0] == '-' or '=' in arg:
                        continue
                    prog_name = arg
                    break

            # Strip the version number from comon programs like "python2.7".
            prog_name = prog_name.rstrip('0123456789-.')

            if prog_name in ('awk', 'bash', 'dash', 'ksh', 'perl', 'python',
                             'sh'):
                return 'text/script/' + prog_name
            # Other unknown script.
            return 'text/script'
        except ValueError:
            pass

        # PEM files.
        if head_line.strip() == b'-----BEGIN CERTIFICATE-----':
            return 'text/pem/cert'
        if head_line.strip() == b'-----BEGIN RSA PRIVATE KEY-----':
            return 'text/pem/rsa-private'

        # Linker script.
        if head_line.strip() == b'/* GNU ld script':
            return 'text/ld-script'

        # Protobuf files.
        if rel_path.endswith('.proto'):
            return 'text/proto'

        if len(first_lines) == 1:
            if re.match(br'[0-9\.]+$', head_line):
                return 'text/oneline/number'
            return 'text/oneline'

        return 'text'