vndk-def: Split DT_NEEDED and dlopen() into two layers.
Test: ./tests/test_elf_link_data.py Change-Id: I746b07a422ea53c38e3f05d259814edf120ded22
This commit is contained in:
88
vndk/tools/definition-tool/tests/test_elf_link_data.py
Executable file
88
vndk/tools/definition-tool/tests/test_elf_link_data.py
Executable file
@@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
import unittest
|
||||
|
||||
from vndk_definition_tool import ELFLinkData, PT_SYSTEM, PT_VENDOR
|
||||
|
||||
|
||||
class ELFLinkDataTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.x = ELFLinkData(PT_SYSTEM, '/system/lib/libx.so', None)
|
||||
self.y = ELFLinkData(PT_SYSTEM, '/system/lib/liby.so', None)
|
||||
self.z = ELFLinkData(PT_SYSTEM, '/system/lib/libz.so', None)
|
||||
self.w = ELFLinkData(PT_SYSTEM, '/system/lib/libw.so', None)
|
||||
self.v = ELFLinkData(PT_VENDOR, '/vendor/lib/libv.so', None)
|
||||
|
||||
self.x.add_dep(self.y, ELFLinkData.NEEDED)
|
||||
self.x.add_dep(self.z, ELFLinkData.DLOPEN)
|
||||
|
||||
self.z.add_dep(self.w, ELFLinkData.NEEDED)
|
||||
self.z.add_dep(self.w, ELFLinkData.DLOPEN)
|
||||
|
||||
def test_add_dep_and_accessors(self):
|
||||
self.assertIn(self.y, self.x.dt_deps)
|
||||
self.assertIn(self.x, self.y.dt_users)
|
||||
self.assertNotIn(self.y, self.x.dl_deps)
|
||||
self.assertNotIn(self.x, self.y.dl_users)
|
||||
|
||||
self.assertIn(self.z, self.x.dl_deps)
|
||||
self.assertIn(self.x, self.z.dl_users)
|
||||
self.assertNotIn(self.z, self.x.dt_deps)
|
||||
self.assertNotIn(self.x, self.z.dt_users)
|
||||
|
||||
def test_remove_dep(self):
|
||||
self.assertIn(self.y, self.x.dt_deps)
|
||||
self.assertIn(self.x, self.y.dt_users)
|
||||
|
||||
with self.assertRaises(KeyError):
|
||||
self.x.remove_dep(self.y, ELFLinkData.DLOPEN)
|
||||
self.assertIn(self.y, self.x.dt_deps)
|
||||
self.assertIn(self.x, self.y.dt_users)
|
||||
|
||||
self.x.remove_dep(self.y, ELFLinkData.NEEDED)
|
||||
self.assertNotIn(self.y, self.x.dt_deps)
|
||||
self.assertNotIn(self.x, self.y.dt_users)
|
||||
|
||||
def test_num_deps(self):
|
||||
self.assertEqual(2, self.x.num_deps)
|
||||
self.assertEqual(0, self.y.num_deps)
|
||||
self.assertEqual(0, self.w.num_deps)
|
||||
self.assertEqual(0, self.v.num_deps)
|
||||
|
||||
# NEEDED and DLOPEN are counted twice.
|
||||
self.assertEqual(2, self.z.num_deps)
|
||||
|
||||
def test_num_users(self):
|
||||
self.assertEqual(0, self.x.num_users)
|
||||
self.assertEqual(1, self.y.num_users)
|
||||
self.assertEqual(1, self.z.num_users)
|
||||
self.assertEqual(0, self.v.num_users)
|
||||
|
||||
# NEEDED and DLOPEN are counted twice.
|
||||
self.assertEqual(2, self.w.num_users)
|
||||
|
||||
def test_has_dep(self):
|
||||
self.assertTrue(self.x.has_dep(self.y))
|
||||
self.assertTrue(self.x.has_dep(self.z))
|
||||
self.assertFalse(self.x.has_dep(self.x))
|
||||
self.assertFalse(self.x.has_dep(self.w))
|
||||
|
||||
def test_has_user(self):
|
||||
self.assertTrue(self.y.has_user(self.x))
|
||||
self.assertTrue(self.z.has_user(self.x))
|
||||
self.assertFalse(self.x.has_user(self.x))
|
||||
self.assertFalse(self.w.has_user(self.x))
|
||||
|
||||
def test_is_system_lib(self):
|
||||
self.assertTrue(self.x.is_system_lib())
|
||||
self.assertFalse(self.v.is_system_lib())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -4,6 +4,7 @@ from __future__ import print_function
|
||||
|
||||
import argparse
|
||||
import collections
|
||||
import itertools
|
||||
import os
|
||||
import re
|
||||
import stat
|
||||
@@ -539,19 +540,71 @@ class ELFResolver(object):
|
||||
|
||||
|
||||
class ELFLinkData(object):
|
||||
NEEDED = 0 # Dependencies recorded in DT_NEEDED entries.
|
||||
DLOPEN = 1 # Dependencies introduced by dlopen().
|
||||
|
||||
def __init__(self, partition, path, elf):
|
||||
self.partition = partition
|
||||
self.path = path
|
||||
self.elf = elf
|
||||
self.deps = set()
|
||||
self.users = set()
|
||||
self._deps = (set(), set())
|
||||
self._users = (set(), set())
|
||||
self.is_ndk = NDK_LIBS.is_ndk(path)
|
||||
self.unresolved_symbols = set()
|
||||
self.linked_symbols = dict()
|
||||
|
||||
def add_dep(self, dst):
|
||||
self.deps.add(dst)
|
||||
dst.users.add(self)
|
||||
def add_dep(self, dst, ty):
|
||||
self._deps[ty].add(dst)
|
||||
dst._users[ty].add(self)
|
||||
|
||||
def remove_dep(self, dst, ty):
|
||||
self._deps[ty].remove(dst)
|
||||
dst._users[ty].remove(self)
|
||||
|
||||
@property
|
||||
def num_deps(self):
|
||||
"""Get the number of dependencies. If a library is linked by both
|
||||
NEEDED and DLOPEN relationship, then it will be counted twice."""
|
||||
return sum(len(deps) for deps in self._deps)
|
||||
|
||||
@property
|
||||
def deps(self):
|
||||
return itertools.chain.from_iterable(self._deps)
|
||||
|
||||
@property
|
||||
def dt_deps(self):
|
||||
return self._deps[self.NEEDED]
|
||||
|
||||
@property
|
||||
def dl_deps(self):
|
||||
return self._deps[self.DLOPEN]
|
||||
|
||||
@property
|
||||
def num_users(self):
|
||||
"""Get the number of users. If a library is linked by both NEEDED and
|
||||
DLOPEN relationship, then it will be counted twice."""
|
||||
return sum(len(users) for users in self._users)
|
||||
|
||||
@property
|
||||
def users(self):
|
||||
return itertools.chain.from_iterable(self._users)
|
||||
|
||||
@property
|
||||
def dt_users(self):
|
||||
return self._users[self.NEEDED]
|
||||
|
||||
@property
|
||||
def dl_users(self):
|
||||
return self._users[self.DLOPEN]
|
||||
|
||||
def has_dep(self, dst):
|
||||
return any(dst in deps for deps in self._deps)
|
||||
|
||||
def has_user(self, dst):
|
||||
return any(dst in users for users in self._users)
|
||||
|
||||
def is_system_lib(self):
|
||||
return self.partition == PT_SYSTEM
|
||||
|
||||
|
||||
def sorted_lib_path_list(libs):
|
||||
@@ -575,12 +628,12 @@ class ELFLinker(object):
|
||||
self.lib_pt[partition][path] = node
|
||||
return node
|
||||
|
||||
def add_dep(self, src_path, dst_path):
|
||||
def add_dep(self, src_path, dst_path, ty):
|
||||
for lib_set in (self.lib32, self.lib64):
|
||||
src = lib_set.get(src_path)
|
||||
dst = lib_set.get(dst_path)
|
||||
if src and dst:
|
||||
src.add_dep(dst)
|
||||
src.add_dep(dst, ty)
|
||||
|
||||
def map_path_to_lib(self, path):
|
||||
for lib_set in (self.lib32, self.lib64):
|
||||
@@ -631,7 +684,8 @@ class ELFLinker(object):
|
||||
for line in f:
|
||||
match = patt.match(line)
|
||||
if match:
|
||||
self.add_dep(match.group(1), match.group(2))
|
||||
self.add_dep(match.group(1), match.group(2),
|
||||
ELFLinkData.DLOPEN)
|
||||
|
||||
def _find_exported_symbol(self, symbol, libs):
|
||||
"""Find the shared library with the exported symbol."""
|
||||
@@ -660,7 +714,7 @@ class ELFLinker(object):
|
||||
print('warning: {}: Missing needed library: {} Tried: {}'
|
||||
.format(lib.path, dt_needed, candidates), file=sys.stderr)
|
||||
continue
|
||||
lib.add_dep(dep)
|
||||
lib.add_dep(dep, ELFLinkData.NEEDED)
|
||||
imported_libs.append(dep)
|
||||
return imported_libs
|
||||
|
||||
@@ -1025,7 +1079,7 @@ class VNDKCommand(ELFGraphCommand):
|
||||
|
||||
def _warn_incorrect_partition_lib_set(self, lib_set, partition, error_msg):
|
||||
for lib in lib_set.values():
|
||||
if not lib.users:
|
||||
if not lib.num_users:
|
||||
continue
|
||||
if all((user.partition != partition for user in lib.users)):
|
||||
print(error_msg.format(lib.path), file=sys.stderr)
|
||||
|
||||
Reference in New Issue
Block a user