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 25from .module_info import CompileInfoLoader 26from .hdi import HdiParser 27from .sa import SAParser 28from .innerapi import InnerAPILoader 29 30 31class ElfFileWithDepsInfo(ElfFile): 32 def __init__(self, file, prefix): 33 super(ElfFileWithDepsInfo, self).__init__(file, prefix) 34 self["deps"] = [] 35 self["dependedBy"] = [] 36 37 def __eq__(self, other): 38 if not isinstance(other, ElfFileWithDepsInfo): 39 return NotImplemented 40 41 return self["id"] == other["id"] 42 43 def __repr__(self): 44 return self.__str__() 45 46 def __str__(self): 47 return "%s:%d deps(%d) dependedBy(%d)" % (self["name"], self["id"], len(self["deps"]), len(self["dependedBy"])) 48 49 def depends_on(self, mod): 50 for dep in self["deps"]: 51 if dep["callee"] == mod: 52 return True 53 return False 54 55 56class Dependency(dict): 57 def __init__(self, idx, caller, callee): 58 self["id"] = idx 59 self["caller_id"] = caller["id"] 60 self["callee_id"] = callee["id"] 61 self["caller"] = caller 62 self["callee"] = callee 63 self["external"] = False 64 self["calls"] = 0 65 66 def __eq__(self, other): 67 if not isinstance(other, Dependency): 68 return NotImplemented 69 70 return self["id"] == other["id"] 71 72 def __repr__(self): 73 return self.__str__() 74 75 def __str__(self): 76 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"]) 77 78 79class ElfFileMgr(object): 80 def __init__(self, product_out_path=None, elf_file_class=None, dependence_class=None): 81 self._elf_files = [] 82 self._path_dict = {} 83 self._basename_dict = {} 84 if elf_file_class: 85 self._elf_file_class = elf_file_class 86 else: 87 self._elf_file_class = ElfFileWithDepsInfo 88 89 self._deps = [] 90 if dependence_class: 91 self._dependence_class = dependence_class 92 else: 93 self._dependence_class = Dependency 94 self._dep_idx = 1 95 self._elf_idx = 1 96 97 self._not_found_depened_files = [] 98 99 walker = ELFWalker(product_out_path) 100 self._prefix = walker.get_product_images_path() 101 self._product_out_path = walker.get_product_out_path() 102 self._link_file_map = walker.get_link_file_map() 103 104 def scan_all_files(self): 105 walker = ELFWalker(self._product_out_path) 106 107 self._scan_all_elf_files(walker) 108 self._build_deps_tree() 109 110 self._max_depth = 0 111 self._max_total_depends = 0 112 113 print("Load compile information now ...") 114 CompileInfoLoader.load(self, self._product_out_path) 115 HdiParser.load(self, self._product_out_path) 116 SAParser.load(self, self._product_out_path) 117 118 def get_product_images_path(self): 119 return self._prefix 120 121 def get_product_out_path(self): 122 return self._product_out_path 123 124 def add_elf_file(self, elf): 125 # Append to array in order 126 elf["id"] = self._elf_idx 127 self._elf_idx = self._elf_idx + 1 128 self._elf_files.append(elf) 129 130 # Add to dictionary with path as key 131 self._path_dict[elf["path"]] = elf 132 133 # Add to dictionary with basename as key 134 if elf["name"] in self._basename_dict: 135 self._basename_dict[elf["name"]].append(elf) 136 else: 137 self._basename_dict[elf["name"]] = [elf] 138 139 def add_dependence(self, caller, callee): 140 dep = self._dependence_class(self._dep_idx, caller, callee) 141 caller["deps"].append(dep) 142 callee["dependedBy"].append(dep) 143 144 self._deps.append(dep) 145 self._dep_idx = self._dep_idx + 1 146 return dep 147 148 def get_elf_by_path(self, path): 149 if path not in self._path_dict and path.find("/lib64/") > 0: 150 path = path.replace("/lib64/", "/lib/") 151 if path in self._path_dict: 152 return self._path_dict[path] 153 if path.find("/platformsdk/") > 0: 154 return None 155 156 if path.startswith("system/lib64/"): 157 path = path.replace("system/lib64/", "system/lib64/platformsdk/") 158 elif path.startswith("system/lib/"): 159 path = path.replace("system/lib/", "system/lib/platformsdk/") 160 else: 161 return None 162 163 if path not in self._path_dict and path.find("/lib64/") > 0: 164 path = path.replace("/lib64/", "/lib/") 165 if path in self._path_dict: 166 return self._path_dict[path] 167 return None 168 169 def get_elf_by_idx(self, idx): 170 if idx < 1 or idx > len(self._elf_files): 171 return None 172 return self._elf_files[idx - 1] 173 174 def get_elf_by_name(self, name): 175 if name in self._basename_dict: 176 return self._basename_dict[name][0] 177 178 return self.__get_link_file(name) 179 180 def get_all(self): 181 return self._elf_files 182 183 def get_all_deps(self): 184 return self._deps 185 186 def _scan_all_elf_files(self, walker): 187 print("Scanning %d ELF files now ..." % len(walker.get_elf_files())) 188 for f in walker.get_elf_files(): 189 elf = self._elf_file_class(f, self._prefix) 190 if elf["path"] in self._path_dict: 191 print("Warning: duplicate " + elf.get_file() + ' skipped.') 192 continue 193 194 # Ignore these files 195 if elf["name"] in ["hdc_std"]: 196 continue 197 198 self.add_elf_file(elf) 199 200 # Reorder libraries with same name as defined by LD_LIBRARY_PATH 201 for bname, val in self._basename_dict.items(): 202 if len(val) < 2: 203 continue 204 self._basename_dict[bname] = self.__reorder_library(val) 205 206 def __reorder_library(self, val): 207 orders = [] 208 idx = 0 209 for p in val: 210 orders.append((self.__get_library_order(p["path"]), idx)) 211 idx = idx + 1 212 orders.sort() 213 214 res = [] 215 for item in orders: 216 res.append(val[item[1]]) 217 218 return res 219 220 def __get_library_order(self, path): 221 if not path.startswith("/"): 222 path = "/" + path 223 if path.find("/lib64/") > 0: 224 path_order = "/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" 225 else: 226 path_order = "/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" 227 228 if path.rfind("/") < 0: 229 return 1000 230 231 path = path[:path.rfind("/")] 232 paths = path_order.split(':') 233 idx = 0 234 for p in paths: 235 if p == path: 236 return idx 237 idx = idx + 1 238 return 1000 239 240 def _build_deps_tree(self): 241 print("Build dependence tree for %d ELF files now ..." % len(self._elf_files)) 242 for elf in self._elf_files: 243 self.__build_deps_tree_for_one_elf(elf) 244 print(" Got %d dependencies" % self._dep_idx) 245 246 def __build_deps_tree_for_one_elf(self, elf): 247 for lib in elf.library_depends(): 248 dep_elf = self.get_elf_by_name(lib) 249 if not dep_elf: 250 self._not_found_depened_files.append({"caller": elf["name"], "callee": lib}) 251 print("Warning: can not find depended library [" + lib + "] for " + elf["name"]) 252 break 253 254 self.add_dependence(elf, dep_elf) 255 256 def __get_link_file(self, name): 257 for src, target in self._link_file_map.items(): 258 tmp_name = os.path.basename(src) 259 if name != tmp_name: 260 continue 261 tmp_name = os.path.dirname(src) 262 tmp_name = os.path.join(tmp_name, target) 263 if name in ["libc.so"]: 264 tmp_name = os.path.normpath(tmp_name) 265 norm_prefix = os.path.normpath(self._prefix) + "/" 266 link_elf = ElfFile(tmp_name, norm_prefix) 267 else: 268 link_elf = ElfFile(tmp_name, self._prefix) 269 return self.get_elf_by_path(link_elf["path"]) 270 271 272if __name__ == '__main__': 273 mgr = ElfFileMgr("./demo/archinfo/assets/rk3568/3.2.7.5") 274 mgr.scan_all_files() 275 elf = mgr.get_elf_by_path("system/lib/libskia_ohos.z.so") 276 print("Get skia now ...") 277 278 res = mgr.get_elf_by_path("system/lib/platformsdk/libhmicui18n.z.so") 279 print(res) 280