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