• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2#coding=utf-8
3
4#
5# Copyright (c) 2022 Huawei Device Co., Ltd.
6# Licensed under the Apache License, Version 2.0 (the "License");
7# you may not use this file except in compliance with the License.
8# You may obtain a copy of the License at
9#
10#     http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS,
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15# See the License for the specific language governing permissions and
16# limitations under the License.
17#
18
19import string
20import sys
21import os
22
23from .elf_file import ElfFile
24from .elf_walker import ELFWalker
25
26class ElfFileWithDepsInfo(ElfFile):
27	def __init__(self, file, prefix):
28		super(ElfFileWithDepsInfo, self).__init__(file, prefix)
29		self["deps"] = []
30		self["dependedBy"] = []
31
32	def __eq__(self, other):
33		if not isinstance(other, ElfFileWithDepsInfo):
34			return NotImplemented
35
36		return self["id"] == other["id"]
37
38	def dependsOn(self, mod):
39		for dep in self["deps"]:
40			if dep["callee"] == mod:
41				return True
42		return False
43
44	def __repr__(self):
45		return self.__str__()
46
47	def __str__(self):
48		return "%s:%d deps(%d) dependedBy(%d)" % (self["name"], self["id"], len(self["deps"]), len(self["dependedBy"]))
49
50class Dependency(dict):
51	def __init__(self, idx, caller, callee):
52		self["id"] = idx
53		self["caller_id"] = caller["id"]
54		self["callee_id"] = callee["id"]
55		self["caller"] = caller
56		self["callee"] = callee
57		self["external"] = False
58		self["calls"] = 0
59
60	def __eq__(self, other):
61		if not isinstance(other, Dependency):
62			return NotImplemented
63
64		return self["id"] == other["id"]#and self["name"] == other["name"]
65
66	def __repr__(self):
67		return self.__str__()
68
69	def __str__(self):
70		return "(%s:%s[%d] -%d:%d-> %s:%s[%d])" % (self["caller"]["componentName"], self["caller"]["name"], self["caller"]["id"], int(self["external"]), self["calls"], self["callee"]["componentName"], self["callee"]["name"], self["callee"]["id"])
71
72from .module_info import CompileInfoLoader
73from .hdi import HdiParser
74from .sa import SAParser
75from .innerapi import InnerAPILoader
76
77class ElfFileMgr(object):
78	def __init__(self, product_out_path=None, elfFileClass=None, dependenceClass = None):
79		self._elfFiles = []
80		self._path_dict = {}
81		self._basename_dict = {}
82		if elfFileClass:
83			self._elfFileClass = elfFileClass
84		else:
85			self._elfFileClass = ElfFileWithDepsInfo
86
87		self._deps = []
88		if dependenceClass:
89			self._dependenceClass = dependenceClass
90		else:
91			self._dependenceClass = Dependency
92		self._depIdx = 1
93		self._elfIdx = 1
94
95		self._not_found_depened_files = []
96
97		walker = ELFWalker(product_out_path)
98		self._prefix = walker.get_product_images_path()
99		self._product_out_path = walker.get_product_out_path()
100		self._link_file_map = walker.get_link_file_map()
101
102	def scan_all_files(self):
103		walker = ELFWalker(self._product_out_path)
104
105		self._scan_all_elf_files(walker)
106		self._build_deps_tree()
107
108		self._maxDepth = 0
109		self._maxTotalDepends = 0
110
111		print("Load compile information now ...")
112		CompileInfoLoader.load(self, self._product_out_path)
113		HdiParser.load(self, self._product_out_path)
114		SAParser.load(self, self._product_out_path)
115
116	def get_product_images_path(self):
117		return self._prefix
118
119	def get_product_out_path(self):
120		return self._product_out_path
121
122	def add_elf_file(self, elf):
123		# Append to array in order
124		elf["id"] = self._elfIdx
125		self._elfIdx = self._elfIdx + 1
126		self._elfFiles.append(elf)
127
128		# Add to dictionary with path as key
129		self._path_dict[elf["path"]] = elf
130
131		# Add to dictionary with basename as key
132		if elf["name"] in self._basename_dict:
133			self._basename_dict[elf["name"]].append(elf)
134		else:
135			self._basename_dict[elf["name"]] = [ elf ]
136
137	def _scan_all_elf_files(self, walker):
138		print("Scanning %d ELF files now ..." % len(walker.get_elf_files()))
139		for f in walker.get_elf_files():
140			elf = self._elfFileClass(f, self._prefix)
141			if elf["path"] in self._path_dict:
142				print("Warning: duplicate " + elf.get_file() + ' skipped.')
143				continue
144
145			# Ignore these files
146			if elf["name"] in [ "ld-musl-aarch64.so.1", "ld-musl-arm.so.1", "hdc_std" ]:
147				continue
148
149			self.add_elf_file(elf)
150
151		# Reorder libraries with same name as defined by LD_LIBRARY_PATH
152		for bname, val in self._basename_dict.items():
153			if len(val) < 2:
154				continue
155			self._basename_dict[bname] = self.__reorder_library(val)
156
157	def __reorder_library(self, val):
158		orders = []
159		idx = 0
160		for p in val:
161			orders.append((self.__get_library_order(p["path"]), idx))
162			idx = idx + 1
163		orders.sort()
164
165		res = []
166		for item in orders:
167			res.append(val[item[1]])
168
169		return res
170
171	def __get_library_order(self, path):
172		if not path.startswith("/"):
173			path = "/" + path
174		if path.find("/lib64/") > 0:
175			pathOrder = "/system/lib64:/vendor/lib64:/vendor/lib64/chipsetsdk:/system/lib64/ndk:/system/lib64/chipset-pub-sdk:/system/lib64/chipset-sdk:/system/lib64/platformsdk:/system/lib64/priv-platformsdk:/system/lib64/priv-module:/system/lib64/module:/system/lib64/module/data:/system/lib64/module/multimedia:/system/lib:/vendor/lib:/system/lib/ndk:/system/lib/chipset-pub-sdk:/system/lib/chipset-sdk:/system/lib/platformsdk:/system/lib/priv-platformsdk:/system/lib/priv-module:/system/lib/module:/system/lib/module/data:/system/lib/module/multimedia:/lib64:/lib:/usr/local/lib:/usr/lib"
176		else:
177			pathOrder = "/system/lib:/vendor/lib:/vendor/lib/chipsetsdk:/system/lib/ndk:/system/lib/chipset-pub-sdk:/system/lib/chipset-sdk:/system/lib/platformsdk:/system/lib/priv-platformsdk:/system/lib/priv-module:/system/lib/module:/system/lib/module/data:/system/lib/module/multimedia:/lib:/usr/local/lib:/usr/lib"
178
179		if path.rfind("/") < 0:
180			return 1000
181
182		path = path[:path.rfind("/")]
183		paths = pathOrder.split(':')
184		idx = 0
185		for p in paths:
186			if p == path:
187				return idx
188			idx = idx + 1
189		return 1000
190
191
192	def _build_deps_tree(self):
193		print("Build dependence tree for %d ELF files now ..." % len(self._elfFiles))
194		for elf in self._elfFiles:
195			self.__build_deps_tree_for_one_elf(elf)
196		print("    Got %d dependencies" % self._depIdx)
197
198	def add_dependence(self, caller, callee):
199		dep = self._dependenceClass(self._depIdx, caller, callee)
200		caller["deps"].append(dep)
201		callee["dependedBy"].append(dep)
202
203		self._deps.append(dep)
204		self._depIdx = self._depIdx + 1
205		return dep
206
207	def __build_deps_tree_for_one_elf(self, elf):
208		for lib in elf.library_depends():
209			dep_elf = self.get_elf_by_name(lib)
210			if not dep_elf:
211				self._not_found_depened_files.append({"caller": elf["name"], "callee": lib})
212				print("Warning: can not find depended library [" + lib + "] for " + elf["name"])
213				break
214
215			self.add_dependence(elf, dep_elf)
216
217	def get_elf_by_path(self, path):
218		if path not in self._path_dict and path.find("/lib64/") > 0:
219			path = path.replace("/lib64/", "/lib/")
220		if path in self._path_dict:
221			return self._path_dict[path]
222		if path.find("/platformsdk/") > 0:
223			return None
224
225		if path.startswith("system/lib64/"):
226			path = path.replace("system/lib64/", "system/lib64/platformsdk/")
227		elif path.startswith("system/lib/"):
228			path = path.replace("system/lib/", "system/lib/platformsdk/")
229		else:
230			return None
231
232		if path not in self._path_dict and path.find("/lib64/") > 0:
233			path = path.replace("/lib64/", "/lib/")
234		if path in self._path_dict:
235			return self._path_dict[path]
236		return None
237
238	def get_elf_by_idx(self, idx):
239		if idx < 1 or idx > len(self._elfFiles):
240			return None
241		return self._elfFiles[idx - 1]
242
243	def __get_link_file(self, name):
244		for src, target in self._link_file_map.items():
245			tmp_name = os.path.basename(src)
246			if name != tmp_name:
247				continue
248			tmp_name = os.path.dirname(src)
249			tmp_name = os.path.join(tmp_name, target)
250			link_elf = ElfFile(tmp_name, self._prefix)
251			return self.get_elf_by_path(link_elf["path"])
252
253	def get_elf_by_name(self, name):
254		if name in self._basename_dict:
255			return self._basename_dict[name][0]
256
257		return self.__get_link_file(name)
258
259	def get_all(self):
260		return self._elfFiles
261
262	def get_all_deps(self):
263		return self._deps
264
265if __name__ == '__main__':
266	mgr = ElfFileMgr("/home/z00325844/demo/archinfo/assets/rk3568/3.2.7.5")
267	mgr.scan_all_files()
268	elf = mgr.get_elf_by_path("system/lib/libskia_ohos.z.so")
269	print("Get skia now ...")
270
271	res = mgr.get_elf_by_path("system/lib/platformsdk/libhmicui18n.z.so")
272	print(res)
273