blob: 71e8d2a42f6ae5efcf8af2463651c9c02287576b [file] [log] [blame]
# Copyright 2014 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Unittests for the parseelf.py module."""
import os
from chromite.lib import cros_test_lib
from chromite.lib import osutils
from chromite.lib import parseelf
from chromite.lib import unittest_lib
class ELFParsingTest(cros_test_lib.TempDirTestCase):
"""Test the ELF parsing functions."""
_ldpaths = {"interp": [], "env": [], "conf": []}
def testIsLib(self) -> None:
"""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"])
def testNotIsLib(self) -> None:
"""Verify '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"])
def testUnsupportedFiles(self) -> None:
"""Tests unsupported files are ignored."""
osutils.WriteFile(os.path.join(self.tempdir, "foo.so"), "foo")
self.assertEqual(
None, parseelf.ParseELF(self.tempdir, "foo.so", self._ldpaths)
)
osutils.WriteFile(os.path.join(self.tempdir, "foo.so"), "\x7fELF-foo")
self.assertEqual(
None, parseelf.ParseELF(self.tempdir, "foo.so", self._ldpaths)
)
def testParsedSymbols(self) -> None:
"""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.assertEqual(elf["imp_sym"], set([b"fa", b"fb", b"fc"]))
self.assertIn(b"fx", elf["exp_sym"])
self.assertIn(b"fy", elf["exp_sym"])
self.assertIn(b"fz", elf["exp_sym"])
def testLibDependencies(self) -> None:
"""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"])
def testRelativeLibPaths(self) -> None:
"""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(str(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]))
)