1bbaeed4dSRouven Czerwinski#!/usr/bin/env python3 21bb92983SJerome Forissier# SPDX-License-Identifier: BSD-2-Clause 3733a15f2SJerome Forissier# 4733a15f2SJerome Forissier# Copyright (c) 2017, Linaro Limited 5733a15f2SJerome Forissier# 6733a15f2SJerome Forissier 7733a15f2SJerome Forissier 8733a15f2SJerome Forissierimport argparse 9bbaeed4dSRouven Czerwinskiimport errno 10733a15f2SJerome Forissierimport glob 11157e6213SJerome Forissierimport os 12733a15f2SJerome Forissierimport re 13733a15f2SJerome Forissierimport subprocess 14733a15f2SJerome Forissierimport sys 156b4fc675SJerome Forissierimport termios 16733a15f2SJerome Forissier 17733a15f2SJerome ForissierCALL_STACK_RE = re.compile('Call stack:') 18d77929ecSSumit GargTEE_LOAD_ADDR_RE = re.compile(r'TEE load address @ (?P<load_addr>0x[0-9a-f]+)') 19a2b984bdSJoakim Bech# This gets the address from lines looking like this: 20a2b984bdSJoakim Bech# E/TC:0 0x001044a8 216e7c2e91SJerome ForissierSTACK_ADDR_RE = re.compile( 22531963a5SJens Wiklander r'[UEIDFM]/(TC|LD):(\?*|[0-9]*) [0-9]* +(?P<addr>0x[0-9a-f]+)') 236e7c2e91SJerome ForissierABORT_ADDR_RE = re.compile(r'-abort at address (?P<addr>0x[0-9a-f]+)') 24*99e82b1fSJerome ForissierTA_PANIC_RE = re.compile(r'TA panicked with code (?P<code>0x[0-9a-f]+)') 25444c203eSJerome ForissierREGION_RE = re.compile(r'region +[0-9]+: va (?P<addr>0x[0-9a-f]+) ' 266e7c2e91SJerome Forissier r'pa 0x[0-9a-f]+ size (?P<size>0x[0-9a-f]+)' 27531963a5SJens Wiklander r'( flags .{4} (\[(?P<elf_idx>[0-9]+)\])?)?') 28ae252462SJerome ForissierELF_LIST_RE = re.compile(r'\[(?P<idx>[0-9]+)\] (?P<uuid>[0-9a-f\-]+)' 296e7c2e91SJerome Forissier r' @ (?P<load_addr>0x[0-9a-f\-]+)') 30c90b6663SSumit GargFUNC_GRAPH_RE = re.compile(r'Function graph') 31c90b6663SSumit GargGRAPH_ADDR_RE = re.compile(r'(?P<addr>0x[0-9a-f]+)') 32c90b6663SSumit GargGRAPH_RE = re.compile(r'}') 33733a15f2SJerome Forissier 34733a15f2SJerome Forissierepilog = ''' 350c5bedb5SJerome ForissierThis scripts reads an OP-TEE abort or panic message from stdin and adds debug 360c5bedb5SJerome Forissierinformation to the output, such as '<function> at <file>:<line>' next to each 370c5bedb5SJerome Forissieraddress in the call stack. Any message generated by OP-TEE and containing a 380c5bedb5SJerome Forissiercall stack can in principle be processed by this script. This currently 390c5bedb5SJerome Forissierincludes aborts and panics from the TEE core as well as from any TA. 400c5bedb5SJerome ForissierThe paths provided on the command line are used to locate the appropriate ELF 410c5bedb5SJerome Forissierbinary (tee.elf or Trusted Application). The GNU binutils (addr2line, objdump, 42f9089765SJerome Forissiernm) are used to extract the debug info. If the CROSS_COMPILE environment 43f9089765SJerome Forissiervariable is set, it is used as a prefix to the binutils tools. That is, the 44f9089765SJerome Forissierscript will invoke $(CROSS_COMPILE)addr2line etc. If it is not set however, 45f9089765SJerome Forissierthe prefix will be determined automatically for each ELF file based on its 46f9089765SJerome Forissierarchitecture (arm-linux-gnueabihf-, aarch64-linux-gnu-). The resulting command 47f9089765SJerome Forissieris then expected to be found in the user's PATH. 48733a15f2SJerome Forissier 490c5bedb5SJerome ForissierOP-TEE abort and panic messages are sent to the secure console. They look like 500c5bedb5SJerome Forissierthe following: 51733a15f2SJerome Forissier 520c5bedb5SJerome Forissier E/TC:0 User TA data-abort at address 0xffffdecd (alignment fault) 53733a15f2SJerome Forissier ... 540c5bedb5SJerome Forissier E/TC:0 Call stack: 550c5bedb5SJerome Forissier E/TC:0 0x4000549e 560c5bedb5SJerome Forissier E/TC:0 0x40001f4b 570c5bedb5SJerome Forissier E/TC:0 0x4000273f 580c5bedb5SJerome Forissier E/TC:0 0x40005da7 59733a15f2SJerome Forissier 60733a15f2SJerome ForissierInspired by a script of the same name by the Chromium project. 61733a15f2SJerome Forissier 62733a15f2SJerome ForissierSample usage: 63733a15f2SJerome Forissier 64733a15f2SJerome Forissier $ scripts/symbolize.py -d out/arm-plat-hikey/core -d ../optee_test/out/ta/* 65733a15f2SJerome Forissier <paste whole dump here> 66733a15f2SJerome Forissier ^D 67c90b6663SSumit Garg 68c90b6663SSumit GargAlso, this script reads function graph generated for OP-TEE user TA from 69c90b6663SSumit Garg/tmp/ftrace-<ta_uuid>.out file and resolves function addresses to corresponding 70c90b6663SSumit Gargsymbols. 71c90b6663SSumit Garg 72c90b6663SSumit GargSample usage: 73c90b6663SSumit Garg 74c90b6663SSumit Garg $ cat /tmp/ftrace-<ta_uuid>.out | scripts/symbolize.py -d <ta_uuid>.elf 75c90b6663SSumit Garg <paste function graph here> 76c90b6663SSumit Garg ^D 77733a15f2SJerome Forissier''' 78733a15f2SJerome Forissier 79*99e82b1fSJerome Forissiertee_result_names = { 80*99e82b1fSJerome Forissier '0xf0100001': 'TEE_ERROR_CORRUPT_OBJECT', 81*99e82b1fSJerome Forissier '0xf0100002': 'TEE_ERROR_CORRUPT_OBJECT_2', 82*99e82b1fSJerome Forissier '0xf0100003': 'TEE_ERROR_STORAGE_NOT_AVAILABLE', 83*99e82b1fSJerome Forissier '0xf0100004': 'TEE_ERROR_STORAGE_NOT_AVAILABLE_2', 84*99e82b1fSJerome Forissier '0xf0100006': 'TEE_ERROR_CIPHERTEXT_INVALID ', 85*99e82b1fSJerome Forissier '0xffff0000': 'TEE_ERROR_GENERIC', 86*99e82b1fSJerome Forissier '0xffff0001': 'TEE_ERROR_ACCESS_DENIED', 87*99e82b1fSJerome Forissier '0xffff0002': 'TEE_ERROR_CANCEL', 88*99e82b1fSJerome Forissier '0xffff0003': 'TEE_ERROR_ACCESS_CONFLICT', 89*99e82b1fSJerome Forissier '0xffff0004': 'TEE_ERROR_EXCESS_DATA', 90*99e82b1fSJerome Forissier '0xffff0005': 'TEE_ERROR_BAD_FORMAT', 91*99e82b1fSJerome Forissier '0xffff0006': 'TEE_ERROR_BAD_PARAMETERS', 92*99e82b1fSJerome Forissier '0xffff0007': 'TEE_ERROR_BAD_STATE', 93*99e82b1fSJerome Forissier '0xffff0008': 'TEE_ERROR_ITEM_NOT_FOUND', 94*99e82b1fSJerome Forissier '0xffff0009': 'TEE_ERROR_NOT_IMPLEMENTED', 95*99e82b1fSJerome Forissier '0xffff000a': 'TEE_ERROR_NOT_SUPPORTED', 96*99e82b1fSJerome Forissier '0xffff000b': 'TEE_ERROR_NO_DATA', 97*99e82b1fSJerome Forissier '0xffff000c': 'TEE_ERROR_OUT_OF_MEMORY', 98*99e82b1fSJerome Forissier '0xffff000d': 'TEE_ERROR_BUSY', 99*99e82b1fSJerome Forissier '0xffff000e': 'TEE_ERROR_COMMUNICATION', 100*99e82b1fSJerome Forissier '0xffff000f': 'TEE_ERROR_SECURITY', 101*99e82b1fSJerome Forissier '0xffff0010': 'TEE_ERROR_SHORT_BUFFER', 102*99e82b1fSJerome Forissier '0xffff0011': 'TEE_ERROR_EXTERNAL_CANCEL', 103*99e82b1fSJerome Forissier '0xffff300f': 'TEE_ERROR_OVERFLOW', 104*99e82b1fSJerome Forissier '0xffff3024': 'TEE_ERROR_TARGET_DEAD', 105*99e82b1fSJerome Forissier '0xffff3041': 'TEE_ERROR_STORAGE_NO_SPACE', 106*99e82b1fSJerome Forissier '0xffff3071': 'TEE_ERROR_MAC_INVALID', 107*99e82b1fSJerome Forissier '0xffff3072': 'TEE_ERROR_SIGNATURE_INVALID', 108*99e82b1fSJerome Forissier '0xffff5000': 'TEE_ERROR_TIME_NOT_SET', 109*99e82b1fSJerome Forissier '0xffff5001': 'TEE_ERROR_TIME_NEEDS_RESET', 110*99e82b1fSJerome Forissier } 111*99e82b1fSJerome Forissier 112ae252462SJerome Forissier 113733a15f2SJerome Forissierdef get_args(): 114733a15f2SJerome Forissier parser = argparse.ArgumentParser( 115733a15f2SJerome Forissier formatter_class=argparse.RawDescriptionHelpFormatter, 116c90b6663SSumit Garg description='Symbolizes OP-TEE abort dumps or function graphs', 117733a15f2SJerome Forissier epilog=epilog) 118733a15f2SJerome Forissier parser.add_argument('-d', '--dir', action='append', nargs='+', 1191d8c2a48SJerome Forissier help='Search for ELF file in DIR. tee.elf is needed ' 1201d8c2a48SJerome Forissier 'to decode a TEE Core or pseudo-TA abort, while ' 1211d8c2a48SJerome Forissier '<TA_uuid>.elf is required if a user-mode TA has ' 1221d8c2a48SJerome Forissier 'crashed. For convenience, ELF files may also be ' 1231d8c2a48SJerome Forissier 'given.') 1245f7df507SJerome Forissier parser.add_argument('-s', '--strip_path', nargs='?', 1251d8c2a48SJerome Forissier help='Strip STRIP_PATH from file paths (default: ' 1261d8c2a48SJerome Forissier 'current directory, use -s with no argument to show ' 1271d8c2a48SJerome Forissier 'full paths)', default=os.getcwd()) 128733a15f2SJerome Forissier 129733a15f2SJerome Forissier return parser.parse_args() 130733a15f2SJerome Forissier 131ae252462SJerome Forissier 132733a15f2SJerome Forissierclass Symbolizer(object): 133733a15f2SJerome Forissier def __init__(self, out, dirs, strip_path): 134733a15f2SJerome Forissier self._out = out 135733a15f2SJerome Forissier self._dirs = dirs 136733a15f2SJerome Forissier self._strip_path = strip_path 137733a15f2SJerome Forissier self._addr2line = None 138733a15f2SJerome Forissier self.reset() 139733a15f2SJerome Forissier 1401cbf777bSJerome Forissier def my_Popen(self, cmd): 1411cbf777bSJerome Forissier try: 1421cbf777bSJerome Forissier return subprocess.Popen(cmd, stdin=subprocess.PIPE, 14317be223aSJerome Forissier stdout=subprocess.PIPE, 14417be223aSJerome Forissier universal_newlines=True, 145bbaeed4dSRouven Czerwinski bufsize=1) 1461cbf777bSJerome Forissier except OSError as e: 147bbaeed4dSRouven Czerwinski if e.errno == errno.ENOENT: 148bbaeed4dSRouven Czerwinski print("*** Error:{}: command not found".format(cmd[0]), 149bbaeed4dSRouven Czerwinski file=sys.stderr) 1501cbf777bSJerome Forissier sys.exit(1) 1511cbf777bSJerome Forissier 152733a15f2SJerome Forissier def get_elf(self, elf_or_uuid): 153733a15f2SJerome Forissier if not elf_or_uuid.endswith('.elf'): 154733a15f2SJerome Forissier elf_or_uuid += '.elf' 155733a15f2SJerome Forissier for d in self._dirs: 156157e6213SJerome Forissier if d.endswith(elf_or_uuid) and os.path.isfile(d): 157157e6213SJerome Forissier return d 158733a15f2SJerome Forissier elf = glob.glob(d + '/' + elf_or_uuid) 159733a15f2SJerome Forissier if elf: 160733a15f2SJerome Forissier return elf[0] 161733a15f2SJerome Forissier 16224778dedSJerome Forissier def set_arch(self, elf): 1636e7c2e91SJerome Forissier self._arch = os.getenv('CROSS_COMPILE') 1648a6d4a8bSEtienne Carriere if self._arch: 1658a6d4a8bSEtienne Carriere return 1669bb9f377SJerome Forissier p = subprocess.Popen(['file', '-L', elf], stdout=subprocess.PIPE) 167d720431cSJerome Forissier output = p.stdout.readlines() 168d720431cSJerome Forissier p.terminate() 169bbaeed4dSRouven Czerwinski if b'ARM aarch64,' in output[0]: 170d720431cSJerome Forissier self._arch = 'aarch64-linux-gnu-' 171bbaeed4dSRouven Czerwinski elif b'ARM,' in output[0]: 172d720431cSJerome Forissier self._arch = 'arm-linux-gnueabihf-' 173d720431cSJerome Forissier 17424778dedSJerome Forissier def arch_prefix(self, cmd, elf): 17524778dedSJerome Forissier self.set_arch(elf) 176ae252462SJerome Forissier if self._arch is None: 177ae252462SJerome Forissier return '' 178d720431cSJerome Forissier return self._arch + cmd 179142c5cccSJerome Forissier 180ae252462SJerome Forissier def spawn_addr2line(self, elf_name): 181ae252462SJerome Forissier if elf_name is None: 182ae252462SJerome Forissier return 183ae252462SJerome Forissier if self._addr2line_elf_name is elf_name: 184ae252462SJerome Forissier return 185ae252462SJerome Forissier if self._addr2line: 186ae252462SJerome Forissier self._addr2line.terminate 187ae252462SJerome Forissier self._addr2line = None 188ae252462SJerome Forissier elf = self.get_elf(elf_name) 189733a15f2SJerome Forissier if not elf: 190733a15f2SJerome Forissier return 19124778dedSJerome Forissier cmd = self.arch_prefix('addr2line', elf) 192142c5cccSJerome Forissier if not cmd: 193733a15f2SJerome Forissier return 194c0c57c8fSJerome Forissier self._addr2line = self.my_Popen([cmd, '-f', '-p', '-e', elf]) 195ba84a3f5SJerome Forissier self._addr2line_elf_name = elf_name 196ae252462SJerome Forissier 197ae252462SJerome Forissier # If addr falls into a region that maps a TA ELF file, return the load 198ae252462SJerome Forissier # address of that file. 199ae252462SJerome Forissier def elf_load_addr(self, addr): 200ae252462SJerome Forissier if self._regions: 201ae252462SJerome Forissier for r in self._regions: 202ae252462SJerome Forissier r_addr = int(r[0], 16) 203ae252462SJerome Forissier r_size = int(r[1], 16) 204ae252462SJerome Forissier i_addr = int(addr, 16) 205ae252462SJerome Forissier if (i_addr >= r_addr and i_addr < (r_addr + r_size)): 206ae252462SJerome Forissier # Found region 207ae252462SJerome Forissier elf_idx = r[2] 208ae252462SJerome Forissier if elf_idx is not None: 209ae252462SJerome Forissier return self._elfs[int(elf_idx)][1] 210099918f6SSumit Garg # In case address is not found in TA ELF file, fallback to tee.elf 211099918f6SSumit Garg # especially to symbolize mixed (user-space and kernel) addresses 212099918f6SSumit Garg # which is true when syscall ftrace is enabled along with TA 213099918f6SSumit Garg # ftrace. 21491068f86SJerome Forissier return self._tee_load_addr 215ae252462SJerome Forissier else: 216ae252462SJerome Forissier # tee.elf 217105e09c2SJerome Forissier return self._tee_load_addr 218ae252462SJerome Forissier 219ae252462SJerome Forissier def elf_for_addr(self, addr): 220ae252462SJerome Forissier l_addr = self.elf_load_addr(addr) 22191068f86SJerome Forissier if l_addr == self._tee_load_addr: 22291068f86SJerome Forissier return 'tee.elf' 223ae252462SJerome Forissier for k in self._elfs: 224ae252462SJerome Forissier e = self._elfs[k] 225ae252462SJerome Forissier if int(e[1], 16) == int(l_addr, 16): 226ae252462SJerome Forissier return e[0] 227ae252462SJerome Forissier return None 228733a15f2SJerome Forissier 229142c5cccSJerome Forissier def subtract_load_addr(self, addr): 230ae252462SJerome Forissier l_addr = self.elf_load_addr(addr) 231ae252462SJerome Forissier if l_addr is None: 232ae252462SJerome Forissier return None 233ae252462SJerome Forissier if int(l_addr, 16) > int(addr, 16): 234142c5cccSJerome Forissier return '' 235ae252462SJerome Forissier return '0x{:x}'.format(int(addr, 16) - int(l_addr, 16)) 236142c5cccSJerome Forissier 237142c5cccSJerome Forissier def resolve(self, addr): 238142c5cccSJerome Forissier reladdr = self.subtract_load_addr(addr) 239ae252462SJerome Forissier self.spawn_addr2line(self.elf_for_addr(addr)) 240142c5cccSJerome Forissier if not reladdr or not self._addr2line: 241733a15f2SJerome Forissier return '???' 242c0c57c8fSJerome Forissier if self.elf_for_addr(addr) == 'tee.elf': 243c0c57c8fSJerome Forissier reladdr = '0x{:x}'.format(int(reladdr, 16) + 244c0c57c8fSJerome Forissier int(self.first_vma('tee.elf'), 16)) 245733a15f2SJerome Forissier try: 246bbaeed4dSRouven Czerwinski print(reladdr, file=self._addr2line.stdin) 247733a15f2SJerome Forissier ret = self._addr2line.stdout.readline().rstrip('\n') 248733a15f2SJerome Forissier except IOError: 249733a15f2SJerome Forissier ret = '!!!' 250733a15f2SJerome Forissier return ret 251733a15f2SJerome Forissier 2522a0d456fSJerome Forissier # Armv8.5 with Memory Tagging Extension (MTE) 2532a0d456fSJerome Forissier def strip_armv85_mte_tag(self, addr): 2542a0d456fSJerome Forissier i_addr = int(addr, 16) 2552a0d456fSJerome Forissier i_addr &= ~(0xf << 56) 2562a0d456fSJerome Forissier return '0x{:x}'.format(i_addr) 2572a0d456fSJerome Forissier 258142c5cccSJerome Forissier def symbol_plus_offset(self, addr): 259142c5cccSJerome Forissier ret = '' 260142c5cccSJerome Forissier prevsize = 0 2612a0d456fSJerome Forissier addr = self.strip_armv85_mte_tag(addr) 262142c5cccSJerome Forissier reladdr = self.subtract_load_addr(addr) 263ae252462SJerome Forissier elf_name = self.elf_for_addr(addr) 264ae252462SJerome Forissier if elf_name is None: 265ae252462SJerome Forissier return '' 266ae252462SJerome Forissier elf = self.get_elf(elf_name) 26724778dedSJerome Forissier cmd = self.arch_prefix('nm', elf) 268142c5cccSJerome Forissier if not reladdr or not elf or not cmd: 269142c5cccSJerome Forissier return '' 27030999126SJerome Forissier ireladdr = int(reladdr, 16) 2711cbf777bSJerome Forissier nm = self.my_Popen([cmd, '--numeric-sort', '--print-size', elf]) 272142c5cccSJerome Forissier for line in iter(nm.stdout.readline, ''): 273142c5cccSJerome Forissier try: 274142c5cccSJerome Forissier addr, size, _, name = line.split() 2751d8c2a48SJerome Forissier except ValueError: 276142c5cccSJerome Forissier # Size is missing 277b4815427SJerome Forissier try: 278142c5cccSJerome Forissier addr, _, name = line.split() 279142c5cccSJerome Forissier size = '0' 2801d8c2a48SJerome Forissier except ValueError: 281b4815427SJerome Forissier # E.g., undefined (external) symbols (line = "U symbol") 282b4815427SJerome Forissier continue 283142c5cccSJerome Forissier iaddr = int(addr, 16) 284142c5cccSJerome Forissier isize = int(size, 16) 285142c5cccSJerome Forissier if iaddr == ireladdr: 286142c5cccSJerome Forissier ret = name 287142c5cccSJerome Forissier break 288142c5cccSJerome Forissier if iaddr < ireladdr and iaddr + isize >= ireladdr: 289142c5cccSJerome Forissier offs = ireladdr - iaddr 290142c5cccSJerome Forissier ret = name + '+' + str(offs) 291142c5cccSJerome Forissier break 292142c5cccSJerome Forissier if iaddr > ireladdr and prevsize == 0: 293142c5cccSJerome Forissier offs = iaddr + ireladdr 294142c5cccSJerome Forissier ret = prevname + '+' + str(offs) 295142c5cccSJerome Forissier break 296142c5cccSJerome Forissier prevsize = size 297142c5cccSJerome Forissier prevname = name 298142c5cccSJerome Forissier nm.terminate() 299142c5cccSJerome Forissier return ret 300142c5cccSJerome Forissier 301142c5cccSJerome Forissier def section_plus_offset(self, addr): 302142c5cccSJerome Forissier ret = '' 303142c5cccSJerome Forissier reladdr = self.subtract_load_addr(addr) 304ae252462SJerome Forissier elf_name = self.elf_for_addr(addr) 305ae252462SJerome Forissier if elf_name is None: 306ae252462SJerome Forissier return '' 307ae252462SJerome Forissier elf = self.get_elf(elf_name) 30824778dedSJerome Forissier cmd = self.arch_prefix('objdump', elf) 309142c5cccSJerome Forissier if not reladdr or not elf or not cmd: 310142c5cccSJerome Forissier return '' 31130999126SJerome Forissier iaddr = int(reladdr, 16) 3121cbf777bSJerome Forissier objdump = self.my_Popen([cmd, '--section-headers', elf]) 313142c5cccSJerome Forissier for line in iter(objdump.stdout.readline, ''): 314142c5cccSJerome Forissier try: 315142c5cccSJerome Forissier idx, name, size, vma, lma, offs, algn = line.split() 3161d8c2a48SJerome Forissier except ValueError: 317ae252462SJerome Forissier continue 318142c5cccSJerome Forissier ivma = int(vma, 16) 319142c5cccSJerome Forissier isize = int(size, 16) 320142c5cccSJerome Forissier if ivma == iaddr: 321142c5cccSJerome Forissier ret = name 322142c5cccSJerome Forissier break 323142c5cccSJerome Forissier if ivma < iaddr and ivma + isize >= iaddr: 324142c5cccSJerome Forissier offs = iaddr - ivma 325142c5cccSJerome Forissier ret = name + '+' + str(offs) 326142c5cccSJerome Forissier break 327142c5cccSJerome Forissier objdump.terminate() 328142c5cccSJerome Forissier return ret 329142c5cccSJerome Forissier 330142c5cccSJerome Forissier def process_abort(self, line): 331142c5cccSJerome Forissier ret = '' 332142c5cccSJerome Forissier match = re.search(ABORT_ADDR_RE, line) 333142c5cccSJerome Forissier addr = match.group('addr') 334142c5cccSJerome Forissier pre = match.start('addr') 335142c5cccSJerome Forissier post = match.end('addr') 336142c5cccSJerome Forissier sym = self.symbol_plus_offset(addr) 337142c5cccSJerome Forissier sec = self.section_plus_offset(addr) 338142c5cccSJerome Forissier if sym or sec: 339142c5cccSJerome Forissier ret += line[:pre] 340142c5cccSJerome Forissier ret += addr 341142c5cccSJerome Forissier if sym: 342142c5cccSJerome Forissier ret += ' ' + sym 343142c5cccSJerome Forissier if sec: 344142c5cccSJerome Forissier ret += ' ' + sec 345142c5cccSJerome Forissier ret += line[post:] 346142c5cccSJerome Forissier return ret 347142c5cccSJerome Forissier 34830999126SJerome Forissier # Return all ELF sections with the ALLOC flag 349ae252462SJerome Forissier def read_sections(self, elf_name): 350ae252462SJerome Forissier if elf_name is None: 35130999126SJerome Forissier return 352ae252462SJerome Forissier if elf_name in self._sections: 353ae252462SJerome Forissier return 354ae252462SJerome Forissier elf = self.get_elf(elf_name) 355d7c22aceSJerome Forissier if not elf: 356d7c22aceSJerome Forissier return 35724778dedSJerome Forissier cmd = self.arch_prefix('objdump', elf) 35830999126SJerome Forissier if not elf or not cmd: 35930999126SJerome Forissier return 360ae252462SJerome Forissier self._sections[elf_name] = [] 3611cbf777bSJerome Forissier objdump = self.my_Popen([cmd, '--section-headers', elf]) 36230999126SJerome Forissier for line in iter(objdump.stdout.readline, ''): 36330999126SJerome Forissier try: 36430999126SJerome Forissier _, name, size, vma, _, _, _ = line.split() 3651d8c2a48SJerome Forissier except ValueError: 36630999126SJerome Forissier if 'ALLOC' in line: 367ae252462SJerome Forissier self._sections[elf_name].append([name, int(vma, 16), 368ae252462SJerome Forissier int(size, 16)]) 36930999126SJerome Forissier 370c0c57c8fSJerome Forissier def first_vma(self, elf_name): 371c0c57c8fSJerome Forissier self.read_sections(elf_name) 372c0c57c8fSJerome Forissier return '0x{:x}'.format(self._sections[elf_name][0][1]) 373c0c57c8fSJerome Forissier 37430999126SJerome Forissier def overlaps(self, section, addr, size): 37530999126SJerome Forissier sec_addr = section[1] 37630999126SJerome Forissier sec_size = section[2] 37730999126SJerome Forissier if not size or not sec_size: 37830999126SJerome Forissier return False 379ae252462SJerome Forissier return ((addr <= (sec_addr + sec_size - 1)) and 380ae252462SJerome Forissier ((addr + size - 1) >= sec_addr)) 38130999126SJerome Forissier 382ae252462SJerome Forissier def sections_in_region(self, addr, size, elf_idx): 38330999126SJerome Forissier ret = '' 38430999126SJerome Forissier addr = self.subtract_load_addr(addr) 38530999126SJerome Forissier if not addr: 38630999126SJerome Forissier return '' 38730999126SJerome Forissier iaddr = int(addr, 16) 38830999126SJerome Forissier isize = int(size, 16) 389ae252462SJerome Forissier elf = self._elfs[int(elf_idx)][0] 390ae252462SJerome Forissier if elf is None: 391ae252462SJerome Forissier return '' 392ae252462SJerome Forissier self.read_sections(elf) 393ae252462SJerome Forissier if elf not in self._sections: 394ae252462SJerome Forissier return '' 395ae252462SJerome Forissier for s in self._sections[elf]: 39630999126SJerome Forissier if self.overlaps(s, iaddr, isize): 39730999126SJerome Forissier ret += ' ' + s[0] 39830999126SJerome Forissier return ret 39930999126SJerome Forissier 400733a15f2SJerome Forissier def reset(self): 401733a15f2SJerome Forissier self._call_stack_found = False 402733a15f2SJerome Forissier if self._addr2line: 403733a15f2SJerome Forissier self._addr2line.terminate() 404733a15f2SJerome Forissier self._addr2line = None 405ae252462SJerome Forissier self._addr2line_elf_name = None 406d720431cSJerome Forissier self._arch = None 407142c5cccSJerome Forissier self._saved_abort_line = '' 408ae252462SJerome Forissier self._sections = {} # {elf_name: [[name, addr, size], ...], ...} 409ae252462SJerome Forissier self._regions = [] # [[addr, size, elf_idx, saved line], ...] 410ae252462SJerome Forissier self._elfs = {0: ["tee.elf", 0]} # {idx: [uuid, load_addr], ...} 41191068f86SJerome Forissier self._tee_load_addr = '0x0' 412c90b6663SSumit Garg self._func_graph_found = False 413c90b6663SSumit Garg self._func_graph_skip_line = True 414733a15f2SJerome Forissier 415095567e5SJerome Forissier def pretty_print_path(self, path): 416095567e5SJerome Forissier if self._strip_path: 417095567e5SJerome Forissier return re.sub(re.escape(self._strip_path) + '/*', '', path) 418095567e5SJerome Forissier return path 419095567e5SJerome Forissier 420733a15f2SJerome Forissier def write(self, line): 421733a15f2SJerome Forissier if self._call_stack_found: 422733a15f2SJerome Forissier match = re.search(STACK_ADDR_RE, line) 423733a15f2SJerome Forissier if match: 424733a15f2SJerome Forissier addr = match.group('addr') 425733a15f2SJerome Forissier pre = match.start('addr') 426733a15f2SJerome Forissier post = match.end('addr') 427733a15f2SJerome Forissier self._out.write(line[:pre]) 428733a15f2SJerome Forissier self._out.write(addr) 4295500d703SJerome Forissier # The call stack contains return addresses (LR/ELR values). 4305500d703SJerome Forissier # Heuristic: subtract 2 to obtain the call site of the function 4315500d703SJerome Forissier # or the location of the exception. This value works for A64, 4325500d703SJerome Forissier # A32 as well as Thumb. 4335500d703SJerome Forissier pc = 0 4345500d703SJerome Forissier lr = int(addr, 16) 4355500d703SJerome Forissier if lr: 4365500d703SJerome Forissier pc = lr - 2 4375500d703SJerome Forissier res = self.resolve('0x{:x}'.format(pc)) 438095567e5SJerome Forissier res = self.pretty_print_path(res) 439733a15f2SJerome Forissier self._out.write(' ' + res) 440733a15f2SJerome Forissier self._out.write(line[post:]) 441733a15f2SJerome Forissier return 442733a15f2SJerome Forissier else: 443733a15f2SJerome Forissier self.reset() 444c90b6663SSumit Garg if self._func_graph_found: 445c90b6663SSumit Garg match = re.search(GRAPH_ADDR_RE, line) 446c90b6663SSumit Garg match_re = re.search(GRAPH_RE, line) 447c90b6663SSumit Garg if match: 448c90b6663SSumit Garg addr = match.group('addr') 449c90b6663SSumit Garg pre = match.start('addr') 450c90b6663SSumit Garg post = match.end('addr') 451c90b6663SSumit Garg self._out.write(line[:pre]) 452c90b6663SSumit Garg res = self.resolve(addr) 453c90b6663SSumit Garg res_arr = re.split(' ', res) 454c90b6663SSumit Garg self._out.write(res_arr[0]) 455c90b6663SSumit Garg self._out.write(line[post:]) 456c90b6663SSumit Garg self._func_graph_skip_line = False 457c90b6663SSumit Garg return 458c90b6663SSumit Garg elif match_re: 459c90b6663SSumit Garg self._out.write(line) 460c90b6663SSumit Garg return 461c90b6663SSumit Garg elif self._func_graph_skip_line: 462c90b6663SSumit Garg return 463c90b6663SSumit Garg else: 464c90b6663SSumit Garg self.reset() 46530999126SJerome Forissier match = re.search(REGION_RE, line) 46630999126SJerome Forissier if match: 467ae252462SJerome Forissier # Region table: save info for later processing once 468ae252462SJerome Forissier # we know which UUID corresponds to which ELF index 46930999126SJerome Forissier addr = match.group('addr') 47030999126SJerome Forissier size = match.group('size') 471ae252462SJerome Forissier elf_idx = match.group('elf_idx') 472ae252462SJerome Forissier self._regions.append([addr, size, elf_idx, line]) 473ae252462SJerome Forissier return 474ae252462SJerome Forissier match = re.search(ELF_LIST_RE, line) 475ae252462SJerome Forissier if match: 476ae252462SJerome Forissier # ELF list: save info for later. Region table and ELF list 477ae252462SJerome Forissier # will be displayed when the call stack is reached 478ae252462SJerome Forissier i = int(match.group('idx')) 479ae252462SJerome Forissier self._elfs[i] = [match.group('uuid'), match.group('load_addr'), 480ae252462SJerome Forissier line] 48130999126SJerome Forissier return 482*99e82b1fSJerome Forissier match = re.search(TA_PANIC_RE, line) 483*99e82b1fSJerome Forissier if match: 484*99e82b1fSJerome Forissier code = match.group('code') 485*99e82b1fSJerome Forissier if code in tee_result_names: 486*99e82b1fSJerome Forissier line = line.strip() + ' (' + tee_result_names[code] + ')\n' 487*99e82b1fSJerome Forissier self._out.write(line) 488*99e82b1fSJerome Forissier return 489105e09c2SJerome Forissier match = re.search(TEE_LOAD_ADDR_RE, line) 490105e09c2SJerome Forissier if match: 491105e09c2SJerome Forissier self._tee_load_addr = match.group('load_addr') 492733a15f2SJerome Forissier match = re.search(CALL_STACK_RE, line) 493733a15f2SJerome Forissier if match: 494733a15f2SJerome Forissier self._call_stack_found = True 495ae252462SJerome Forissier if self._regions: 496ae252462SJerome Forissier for r in self._regions: 497ae252462SJerome Forissier r_addr = r[0] 498ae252462SJerome Forissier r_size = r[1] 499ae252462SJerome Forissier elf_idx = r[2] 500ae252462SJerome Forissier saved_line = r[3] 501ae252462SJerome Forissier if elf_idx is None: 502ae252462SJerome Forissier self._out.write(saved_line) 503ae252462SJerome Forissier else: 504ae252462SJerome Forissier self._out.write(saved_line.strip() + 505ae252462SJerome Forissier self.sections_in_region(r_addr, 506ae252462SJerome Forissier r_size, 507ae252462SJerome Forissier elf_idx) + 508ae252462SJerome Forissier '\n') 509ae252462SJerome Forissier if self._elfs: 510ae252462SJerome Forissier for k in self._elfs: 511ae252462SJerome Forissier e = self._elfs[k] 512ae252462SJerome Forissier if (len(e) >= 3): 5131e6f2ea0SJerome Forissier # TA executable or library 514095567e5SJerome Forissier self._out.write(e[2].strip()) 515095567e5SJerome Forissier elf = self.get_elf(e[0]) 516095567e5SJerome Forissier if elf: 517095567e5SJerome Forissier rpath = os.path.realpath(elf) 518095567e5SJerome Forissier path = self.pretty_print_path(rpath) 519095567e5SJerome Forissier self._out.write(' (' + path + ')') 520095567e5SJerome Forissier self._out.write('\n') 521142c5cccSJerome Forissier # Here is a good place to resolve the abort address because we 522142c5cccSJerome Forissier # have all the information we need 523142c5cccSJerome Forissier if self._saved_abort_line: 524142c5cccSJerome Forissier self._out.write(self.process_abort(self._saved_abort_line)) 525c90b6663SSumit Garg match = re.search(FUNC_GRAPH_RE, line) 526c90b6663SSumit Garg if match: 527c90b6663SSumit Garg self._func_graph_found = True 528142c5cccSJerome Forissier match = re.search(ABORT_ADDR_RE, line) 529142c5cccSJerome Forissier if match: 53027b83ad2SJerome Forissier self.reset() 531142c5cccSJerome Forissier # At this point the arch and TA load address are unknown. 532142c5cccSJerome Forissier # Save the line so We can translate the abort address later. 533142c5cccSJerome Forissier self._saved_abort_line = line 534733a15f2SJerome Forissier self._out.write(line) 535733a15f2SJerome Forissier 536733a15f2SJerome Forissier def flush(self): 537733a15f2SJerome Forissier self._out.flush() 538733a15f2SJerome Forissier 539ae252462SJerome Forissier 540733a15f2SJerome Forissierdef main(): 541733a15f2SJerome Forissier args = get_args() 542733a15f2SJerome Forissier if args.dir: 543733a15f2SJerome Forissier # Flatten list in case -d is used several times *and* with multiple 544733a15f2SJerome Forissier # arguments 545733a15f2SJerome Forissier args.dirs = [item for sublist in args.dir for item in sublist] 546733a15f2SJerome Forissier else: 547733a15f2SJerome Forissier args.dirs = [] 548733a15f2SJerome Forissier symbolizer = Symbolizer(sys.stdout, args.dirs, args.strip_path) 549733a15f2SJerome Forissier 5506b4fc675SJerome Forissier fd = sys.stdin.fileno() 55120d152b8SJerome Forissier isatty = os.isatty(fd) 55220d152b8SJerome Forissier if isatty: 5536b4fc675SJerome Forissier old = termios.tcgetattr(fd) 5546b4fc675SJerome Forissier new = termios.tcgetattr(fd) 5556b4fc675SJerome Forissier new[3] = new[3] & ~termios.ECHO # lflags 5566b4fc675SJerome Forissier try: 55720d152b8SJerome Forissier if isatty: 5586b4fc675SJerome Forissier termios.tcsetattr(fd, termios.TCSADRAIN, new) 559733a15f2SJerome Forissier for line in sys.stdin: 560733a15f2SJerome Forissier symbolizer.write(line) 5616b4fc675SJerome Forissier finally: 562733a15f2SJerome Forissier symbolizer.flush() 56320d152b8SJerome Forissier if isatty: 5646b4fc675SJerome Forissier termios.tcsetattr(fd, termios.TCSADRAIN, old) 565733a15f2SJerome Forissier 5661d8c2a48SJerome Forissier 567733a15f2SJerome Forissierif __name__ == "__main__": 568733a15f2SJerome Forissier main() 569