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( 22*17a66904SJens Wiklander r'[UEIDFM]/(TC|LD):([0-9]+ )?(\?*|[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]+)') 2499e82b1fSJerome 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 460309f58dSAlvin Changarchitecture. The resulting command is then expected to be found in the user's 470309f58dSAlvin ChangPATH. 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 7999e82b1fSJerome Forissiertee_result_names = { 8099e82b1fSJerome Forissier '0xf0100001': 'TEE_ERROR_CORRUPT_OBJECT', 8199e82b1fSJerome Forissier '0xf0100002': 'TEE_ERROR_CORRUPT_OBJECT_2', 8299e82b1fSJerome Forissier '0xf0100003': 'TEE_ERROR_STORAGE_NOT_AVAILABLE', 8399e82b1fSJerome Forissier '0xf0100004': 'TEE_ERROR_STORAGE_NOT_AVAILABLE_2', 8499e82b1fSJerome Forissier '0xf0100006': 'TEE_ERROR_CIPHERTEXT_INVALID ', 8599e82b1fSJerome Forissier '0xffff0000': 'TEE_ERROR_GENERIC', 8699e82b1fSJerome Forissier '0xffff0001': 'TEE_ERROR_ACCESS_DENIED', 8799e82b1fSJerome Forissier '0xffff0002': 'TEE_ERROR_CANCEL', 8899e82b1fSJerome Forissier '0xffff0003': 'TEE_ERROR_ACCESS_CONFLICT', 8999e82b1fSJerome Forissier '0xffff0004': 'TEE_ERROR_EXCESS_DATA', 9099e82b1fSJerome Forissier '0xffff0005': 'TEE_ERROR_BAD_FORMAT', 9199e82b1fSJerome Forissier '0xffff0006': 'TEE_ERROR_BAD_PARAMETERS', 9299e82b1fSJerome Forissier '0xffff0007': 'TEE_ERROR_BAD_STATE', 9399e82b1fSJerome Forissier '0xffff0008': 'TEE_ERROR_ITEM_NOT_FOUND', 9499e82b1fSJerome Forissier '0xffff0009': 'TEE_ERROR_NOT_IMPLEMENTED', 9599e82b1fSJerome Forissier '0xffff000a': 'TEE_ERROR_NOT_SUPPORTED', 9699e82b1fSJerome Forissier '0xffff000b': 'TEE_ERROR_NO_DATA', 9799e82b1fSJerome Forissier '0xffff000c': 'TEE_ERROR_OUT_OF_MEMORY', 9899e82b1fSJerome Forissier '0xffff000d': 'TEE_ERROR_BUSY', 9999e82b1fSJerome Forissier '0xffff000e': 'TEE_ERROR_COMMUNICATION', 10099e82b1fSJerome Forissier '0xffff000f': 'TEE_ERROR_SECURITY', 10199e82b1fSJerome Forissier '0xffff0010': 'TEE_ERROR_SHORT_BUFFER', 10299e82b1fSJerome Forissier '0xffff0011': 'TEE_ERROR_EXTERNAL_CANCEL', 10399e82b1fSJerome Forissier '0xffff300f': 'TEE_ERROR_OVERFLOW', 10499e82b1fSJerome Forissier '0xffff3024': 'TEE_ERROR_TARGET_DEAD', 10599e82b1fSJerome Forissier '0xffff3041': 'TEE_ERROR_STORAGE_NO_SPACE', 10699e82b1fSJerome Forissier '0xffff3071': 'TEE_ERROR_MAC_INVALID', 10799e82b1fSJerome Forissier '0xffff3072': 'TEE_ERROR_SIGNATURE_INVALID', 10899e82b1fSJerome Forissier '0xffff5000': 'TEE_ERROR_TIME_NOT_SET', 10999e82b1fSJerome Forissier '0xffff5001': 'TEE_ERROR_TIME_NEEDS_RESET', 11099e82b1fSJerome Forissier } 11199e82b1fSJerome 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-' 1730309f58dSAlvin Chang elif b'RISC-V,' in output[0]: 1740309f58dSAlvin Chang if b'32-bit' in output[0]: 1750309f58dSAlvin Chang self._arch = 'riscv32-unknown-linux-gnu-' 1760309f58dSAlvin Chang elif b'64-bit' in output[0]: 1770309f58dSAlvin Chang self._arch = 'riscv64-unknown-linux-gnu-' 178d720431cSJerome Forissier 17924778dedSJerome Forissier def arch_prefix(self, cmd, elf): 18024778dedSJerome Forissier self.set_arch(elf) 181ae252462SJerome Forissier if self._arch is None: 182ae252462SJerome Forissier return '' 183d720431cSJerome Forissier return self._arch + cmd 184142c5cccSJerome Forissier 185ae252462SJerome Forissier def spawn_addr2line(self, elf_name): 186ae252462SJerome Forissier if elf_name is None: 187ae252462SJerome Forissier return 188ae252462SJerome Forissier if self._addr2line_elf_name is elf_name: 189ae252462SJerome Forissier return 190ae252462SJerome Forissier if self._addr2line: 191ae252462SJerome Forissier self._addr2line.terminate 192ae252462SJerome Forissier self._addr2line = None 193ae252462SJerome Forissier elf = self.get_elf(elf_name) 194733a15f2SJerome Forissier if not elf: 195733a15f2SJerome Forissier return 19624778dedSJerome Forissier cmd = self.arch_prefix('addr2line', elf) 197142c5cccSJerome Forissier if not cmd: 198733a15f2SJerome Forissier return 199c0c57c8fSJerome Forissier self._addr2line = self.my_Popen([cmd, '-f', '-p', '-e', elf]) 200ba84a3f5SJerome Forissier self._addr2line_elf_name = elf_name 201ae252462SJerome Forissier 202ae252462SJerome Forissier # If addr falls into a region that maps a TA ELF file, return the load 203ae252462SJerome Forissier # address of that file. 204ae252462SJerome Forissier def elf_load_addr(self, addr): 205ae252462SJerome Forissier if self._regions: 206ae252462SJerome Forissier for r in self._regions: 207ae252462SJerome Forissier r_addr = int(r[0], 16) 208ae252462SJerome Forissier r_size = int(r[1], 16) 209ae252462SJerome Forissier i_addr = int(addr, 16) 210ae252462SJerome Forissier if (i_addr >= r_addr and i_addr < (r_addr + r_size)): 211ae252462SJerome Forissier # Found region 212ae252462SJerome Forissier elf_idx = r[2] 213ae252462SJerome Forissier if elf_idx is not None: 214ae252462SJerome Forissier return self._elfs[int(elf_idx)][1] 215099918f6SSumit Garg # In case address is not found in TA ELF file, fallback to tee.elf 216099918f6SSumit Garg # especially to symbolize mixed (user-space and kernel) addresses 217099918f6SSumit Garg # which is true when syscall ftrace is enabled along with TA 218099918f6SSumit Garg # ftrace. 21991068f86SJerome Forissier return self._tee_load_addr 220ae252462SJerome Forissier else: 221ae252462SJerome Forissier # tee.elf 222105e09c2SJerome Forissier return self._tee_load_addr 223ae252462SJerome Forissier 224ae252462SJerome Forissier def elf_for_addr(self, addr): 225ae252462SJerome Forissier l_addr = self.elf_load_addr(addr) 22691068f86SJerome Forissier if l_addr == self._tee_load_addr: 22791068f86SJerome Forissier return 'tee.elf' 228ae252462SJerome Forissier for k in self._elfs: 229ae252462SJerome Forissier e = self._elfs[k] 230ae252462SJerome Forissier if int(e[1], 16) == int(l_addr, 16): 231ae252462SJerome Forissier return e[0] 232ae252462SJerome Forissier return None 233733a15f2SJerome Forissier 234142c5cccSJerome Forissier def subtract_load_addr(self, addr): 235ae252462SJerome Forissier l_addr = self.elf_load_addr(addr) 236ae252462SJerome Forissier if l_addr is None: 237ae252462SJerome Forissier return None 238ae252462SJerome Forissier if int(l_addr, 16) > int(addr, 16): 239142c5cccSJerome Forissier return '' 240ae252462SJerome Forissier return '0x{:x}'.format(int(addr, 16) - int(l_addr, 16)) 241142c5cccSJerome Forissier 242142c5cccSJerome Forissier def resolve(self, addr): 243142c5cccSJerome Forissier reladdr = self.subtract_load_addr(addr) 244ae252462SJerome Forissier self.spawn_addr2line(self.elf_for_addr(addr)) 245142c5cccSJerome Forissier if not reladdr or not self._addr2line: 246733a15f2SJerome Forissier return '???' 247c0c57c8fSJerome Forissier if self.elf_for_addr(addr) == 'tee.elf': 248c0c57c8fSJerome Forissier reladdr = '0x{:x}'.format(int(reladdr, 16) + 249c0c57c8fSJerome Forissier int(self.first_vma('tee.elf'), 16)) 250733a15f2SJerome Forissier try: 251bbaeed4dSRouven Czerwinski print(reladdr, file=self._addr2line.stdin) 252733a15f2SJerome Forissier ret = self._addr2line.stdout.readline().rstrip('\n') 253733a15f2SJerome Forissier except IOError: 254733a15f2SJerome Forissier ret = '!!!' 255733a15f2SJerome Forissier return ret 256733a15f2SJerome Forissier 257142c5cccSJerome Forissier def symbol_plus_offset(self, addr): 258142c5cccSJerome Forissier ret = '' 259142c5cccSJerome Forissier prevsize = 0 260142c5cccSJerome Forissier reladdr = self.subtract_load_addr(addr) 261ae252462SJerome Forissier elf_name = self.elf_for_addr(addr) 262ae252462SJerome Forissier if elf_name is None: 263ae252462SJerome Forissier return '' 264ae252462SJerome Forissier elf = self.get_elf(elf_name) 265d33360e5SKun Lai if elf is None: 266d33360e5SKun Lai return '' 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) 308d33360e5SKun Lai if elf is None: 309d33360e5SKun Lai return '' 31024778dedSJerome Forissier cmd = self.arch_prefix('objdump', elf) 311142c5cccSJerome Forissier if not reladdr or not elf or not cmd: 312142c5cccSJerome Forissier return '' 31330999126SJerome Forissier iaddr = int(reladdr, 16) 3141cbf777bSJerome Forissier objdump = self.my_Popen([cmd, '--section-headers', elf]) 315142c5cccSJerome Forissier for line in iter(objdump.stdout.readline, ''): 316142c5cccSJerome Forissier try: 317142c5cccSJerome Forissier idx, name, size, vma, lma, offs, algn = line.split() 3181d8c2a48SJerome Forissier except ValueError: 319ae252462SJerome Forissier continue 320142c5cccSJerome Forissier ivma = int(vma, 16) 321142c5cccSJerome Forissier isize = int(size, 16) 322142c5cccSJerome Forissier if ivma == iaddr: 323142c5cccSJerome Forissier ret = name 324142c5cccSJerome Forissier break 325142c5cccSJerome Forissier if ivma < iaddr and ivma + isize >= iaddr: 326142c5cccSJerome Forissier offs = iaddr - ivma 327142c5cccSJerome Forissier ret = name + '+' + str(offs) 328142c5cccSJerome Forissier break 329142c5cccSJerome Forissier objdump.terminate() 330142c5cccSJerome Forissier return ret 331142c5cccSJerome Forissier 332142c5cccSJerome Forissier def process_abort(self, line): 333142c5cccSJerome Forissier ret = '' 334142c5cccSJerome Forissier match = re.search(ABORT_ADDR_RE, line) 335142c5cccSJerome Forissier addr = match.group('addr') 336142c5cccSJerome Forissier pre = match.start('addr') 337142c5cccSJerome Forissier post = match.end('addr') 338142c5cccSJerome Forissier sym = self.symbol_plus_offset(addr) 339142c5cccSJerome Forissier sec = self.section_plus_offset(addr) 340142c5cccSJerome Forissier if sym or sec: 341142c5cccSJerome Forissier ret += line[:pre] 342142c5cccSJerome Forissier ret += addr 343142c5cccSJerome Forissier if sym: 344142c5cccSJerome Forissier ret += ' ' + sym 345142c5cccSJerome Forissier if sec: 346142c5cccSJerome Forissier ret += ' ' + sec 347142c5cccSJerome Forissier ret += line[post:] 348142c5cccSJerome Forissier return ret 349142c5cccSJerome Forissier 35030999126SJerome Forissier # Return all ELF sections with the ALLOC flag 351ae252462SJerome Forissier def read_sections(self, elf_name): 352ae252462SJerome Forissier if elf_name is None: 35330999126SJerome Forissier return 354ae252462SJerome Forissier if elf_name in self._sections: 355ae252462SJerome Forissier return 356ae252462SJerome Forissier elf = self.get_elf(elf_name) 357d7c22aceSJerome Forissier if not elf: 358d7c22aceSJerome Forissier return 35924778dedSJerome Forissier cmd = self.arch_prefix('objdump', elf) 36030999126SJerome Forissier if not elf or not cmd: 36130999126SJerome Forissier return 362ae252462SJerome Forissier self._sections[elf_name] = [] 3631cbf777bSJerome Forissier objdump = self.my_Popen([cmd, '--section-headers', elf]) 36430999126SJerome Forissier for line in iter(objdump.stdout.readline, ''): 36530999126SJerome Forissier try: 36630999126SJerome Forissier _, name, size, vma, _, _, _ = line.split() 3671d8c2a48SJerome Forissier except ValueError: 36830999126SJerome Forissier if 'ALLOC' in line: 369ae252462SJerome Forissier self._sections[elf_name].append([name, int(vma, 16), 370ae252462SJerome Forissier int(size, 16)]) 37130999126SJerome Forissier 372c0c57c8fSJerome Forissier def first_vma(self, elf_name): 373c0c57c8fSJerome Forissier self.read_sections(elf_name) 374c0c57c8fSJerome Forissier return '0x{:x}'.format(self._sections[elf_name][0][1]) 375c0c57c8fSJerome Forissier 37630999126SJerome Forissier def overlaps(self, section, addr, size): 37730999126SJerome Forissier sec_addr = section[1] 37830999126SJerome Forissier sec_size = section[2] 37930999126SJerome Forissier if not size or not sec_size: 38030999126SJerome Forissier return False 381ae252462SJerome Forissier return ((addr <= (sec_addr + sec_size - 1)) and 382ae252462SJerome Forissier ((addr + size - 1) >= sec_addr)) 38330999126SJerome Forissier 384ae252462SJerome Forissier def sections_in_region(self, addr, size, elf_idx): 38530999126SJerome Forissier ret = '' 38630999126SJerome Forissier addr = self.subtract_load_addr(addr) 38730999126SJerome Forissier if not addr: 38830999126SJerome Forissier return '' 38930999126SJerome Forissier iaddr = int(addr, 16) 39030999126SJerome Forissier isize = int(size, 16) 391ae252462SJerome Forissier elf = self._elfs[int(elf_idx)][0] 392ae252462SJerome Forissier if elf is None: 393ae252462SJerome Forissier return '' 394ae252462SJerome Forissier self.read_sections(elf) 395ae252462SJerome Forissier if elf not in self._sections: 396ae252462SJerome Forissier return '' 397ae252462SJerome Forissier for s in self._sections[elf]: 39830999126SJerome Forissier if self.overlaps(s, iaddr, isize): 39930999126SJerome Forissier ret += ' ' + s[0] 40030999126SJerome Forissier return ret 40130999126SJerome Forissier 402733a15f2SJerome Forissier def reset(self): 403733a15f2SJerome Forissier self._call_stack_found = False 404733a15f2SJerome Forissier if self._addr2line: 405733a15f2SJerome Forissier self._addr2line.terminate() 406733a15f2SJerome Forissier self._addr2line = None 407ae252462SJerome Forissier self._addr2line_elf_name = None 408d720431cSJerome Forissier self._arch = None 409142c5cccSJerome Forissier self._saved_abort_line = '' 410ae252462SJerome Forissier self._sections = {} # {elf_name: [[name, addr, size], ...], ...} 411ae252462SJerome Forissier self._regions = [] # [[addr, size, elf_idx, saved line], ...] 412ae252462SJerome Forissier self._elfs = {0: ["tee.elf", 0]} # {idx: [uuid, load_addr], ...} 41391068f86SJerome Forissier self._tee_load_addr = '0x0' 414c90b6663SSumit Garg self._func_graph_found = False 415c90b6663SSumit Garg self._func_graph_skip_line = True 416733a15f2SJerome Forissier 417095567e5SJerome Forissier def pretty_print_path(self, path): 418095567e5SJerome Forissier if self._strip_path: 419095567e5SJerome Forissier return re.sub(re.escape(self._strip_path) + '/*', '', path) 420095567e5SJerome Forissier return path 421095567e5SJerome Forissier 422733a15f2SJerome Forissier def write(self, line): 423733a15f2SJerome Forissier if self._call_stack_found: 424733a15f2SJerome Forissier match = re.search(STACK_ADDR_RE, line) 425733a15f2SJerome Forissier if match: 426733a15f2SJerome Forissier addr = match.group('addr') 427733a15f2SJerome Forissier pre = match.start('addr') 428733a15f2SJerome Forissier post = match.end('addr') 429733a15f2SJerome Forissier self._out.write(line[:pre]) 430733a15f2SJerome Forissier self._out.write(addr) 4315500d703SJerome Forissier # The call stack contains return addresses (LR/ELR values). 4325500d703SJerome Forissier # Heuristic: subtract 2 to obtain the call site of the function 4335500d703SJerome Forissier # or the location of the exception. This value works for A64, 4345500d703SJerome Forissier # A32 as well as Thumb. 4355500d703SJerome Forissier pc = 0 4365500d703SJerome Forissier lr = int(addr, 16) 4375500d703SJerome Forissier if lr: 4385500d703SJerome Forissier pc = lr - 2 4395500d703SJerome Forissier res = self.resolve('0x{:x}'.format(pc)) 440095567e5SJerome Forissier res = self.pretty_print_path(res) 441733a15f2SJerome Forissier self._out.write(' ' + res) 442733a15f2SJerome Forissier self._out.write(line[post:]) 443733a15f2SJerome Forissier return 444733a15f2SJerome Forissier else: 445733a15f2SJerome Forissier self.reset() 446c90b6663SSumit Garg if self._func_graph_found: 447c90b6663SSumit Garg match = re.search(GRAPH_ADDR_RE, line) 448c90b6663SSumit Garg match_re = re.search(GRAPH_RE, line) 449c90b6663SSumit Garg if match: 450c90b6663SSumit Garg addr = match.group('addr') 451c90b6663SSumit Garg pre = match.start('addr') 452c90b6663SSumit Garg post = match.end('addr') 453c90b6663SSumit Garg self._out.write(line[:pre]) 454c90b6663SSumit Garg res = self.resolve(addr) 455c90b6663SSumit Garg res_arr = re.split(' ', res) 456c90b6663SSumit Garg self._out.write(res_arr[0]) 457c90b6663SSumit Garg self._out.write(line[post:]) 458c90b6663SSumit Garg self._func_graph_skip_line = False 459c90b6663SSumit Garg return 460c90b6663SSumit Garg elif match_re: 461c90b6663SSumit Garg self._out.write(line) 462c90b6663SSumit Garg return 463c90b6663SSumit Garg elif self._func_graph_skip_line: 464c90b6663SSumit Garg return 465c90b6663SSumit Garg else: 466c90b6663SSumit Garg self.reset() 46730999126SJerome Forissier match = re.search(REGION_RE, line) 46830999126SJerome Forissier if match: 469ae252462SJerome Forissier # Region table: save info for later processing once 470ae252462SJerome Forissier # we know which UUID corresponds to which ELF index 47130999126SJerome Forissier addr = match.group('addr') 47230999126SJerome Forissier size = match.group('size') 473ae252462SJerome Forissier elf_idx = match.group('elf_idx') 474ae252462SJerome Forissier self._regions.append([addr, size, elf_idx, line]) 475ae252462SJerome Forissier return 476ae252462SJerome Forissier match = re.search(ELF_LIST_RE, line) 477ae252462SJerome Forissier if match: 478ae252462SJerome Forissier # ELF list: save info for later. Region table and ELF list 479ae252462SJerome Forissier # will be displayed when the call stack is reached 480ae252462SJerome Forissier i = int(match.group('idx')) 481ae252462SJerome Forissier self._elfs[i] = [match.group('uuid'), match.group('load_addr'), 482ae252462SJerome Forissier line] 48330999126SJerome Forissier return 48499e82b1fSJerome Forissier match = re.search(TA_PANIC_RE, line) 48599e82b1fSJerome Forissier if match: 48699e82b1fSJerome Forissier code = match.group('code') 48799e82b1fSJerome Forissier if code in tee_result_names: 48899e82b1fSJerome Forissier line = line.strip() + ' (' + tee_result_names[code] + ')\n' 48999e82b1fSJerome Forissier self._out.write(line) 49099e82b1fSJerome Forissier return 491105e09c2SJerome Forissier match = re.search(TEE_LOAD_ADDR_RE, line) 492105e09c2SJerome Forissier if match: 493105e09c2SJerome Forissier self._tee_load_addr = match.group('load_addr') 494733a15f2SJerome Forissier match = re.search(CALL_STACK_RE, line) 495733a15f2SJerome Forissier if match: 496733a15f2SJerome Forissier self._call_stack_found = True 497ae252462SJerome Forissier if self._regions: 498ae252462SJerome Forissier for r in self._regions: 499ae252462SJerome Forissier r_addr = r[0] 500ae252462SJerome Forissier r_size = r[1] 501ae252462SJerome Forissier elf_idx = r[2] 502ae252462SJerome Forissier saved_line = r[3] 503ae252462SJerome Forissier if elf_idx is None: 504ae252462SJerome Forissier self._out.write(saved_line) 505ae252462SJerome Forissier else: 506ae252462SJerome Forissier self._out.write(saved_line.strip() + 507ae252462SJerome Forissier self.sections_in_region(r_addr, 508ae252462SJerome Forissier r_size, 509ae252462SJerome Forissier elf_idx) + 510ae252462SJerome Forissier '\n') 511ae252462SJerome Forissier if self._elfs: 512ae252462SJerome Forissier for k in self._elfs: 513ae252462SJerome Forissier e = self._elfs[k] 514ae252462SJerome Forissier if (len(e) >= 3): 5151e6f2ea0SJerome Forissier # TA executable or library 516095567e5SJerome Forissier self._out.write(e[2].strip()) 517095567e5SJerome Forissier elf = self.get_elf(e[0]) 518095567e5SJerome Forissier if elf: 519095567e5SJerome Forissier rpath = os.path.realpath(elf) 520095567e5SJerome Forissier path = self.pretty_print_path(rpath) 521095567e5SJerome Forissier self._out.write(' (' + path + ')') 522095567e5SJerome Forissier self._out.write('\n') 523142c5cccSJerome Forissier # Here is a good place to resolve the abort address because we 524142c5cccSJerome Forissier # have all the information we need 525142c5cccSJerome Forissier if self._saved_abort_line: 526142c5cccSJerome Forissier self._out.write(self.process_abort(self._saved_abort_line)) 527c90b6663SSumit Garg match = re.search(FUNC_GRAPH_RE, line) 528c90b6663SSumit Garg if match: 529c90b6663SSumit Garg self._func_graph_found = True 530142c5cccSJerome Forissier match = re.search(ABORT_ADDR_RE, line) 531142c5cccSJerome Forissier if match: 53227b83ad2SJerome Forissier self.reset() 533142c5cccSJerome Forissier # At this point the arch and TA load address are unknown. 534142c5cccSJerome Forissier # Save the line so We can translate the abort address later. 535142c5cccSJerome Forissier self._saved_abort_line = line 536733a15f2SJerome Forissier self._out.write(line) 537733a15f2SJerome Forissier 538733a15f2SJerome Forissier def flush(self): 539733a15f2SJerome Forissier self._out.flush() 540733a15f2SJerome Forissier 541ae252462SJerome Forissier 542733a15f2SJerome Forissierdef main(): 543733a15f2SJerome Forissier args = get_args() 544733a15f2SJerome Forissier if args.dir: 545733a15f2SJerome Forissier # Flatten list in case -d is used several times *and* with multiple 546733a15f2SJerome Forissier # arguments 547733a15f2SJerome Forissier args.dirs = [item for sublist in args.dir for item in sublist] 548733a15f2SJerome Forissier else: 549733a15f2SJerome Forissier args.dirs = [] 550733a15f2SJerome Forissier symbolizer = Symbolizer(sys.stdout, args.dirs, args.strip_path) 551733a15f2SJerome Forissier 5526b4fc675SJerome Forissier fd = sys.stdin.fileno() 55320d152b8SJerome Forissier isatty = os.isatty(fd) 55420d152b8SJerome Forissier if isatty: 5556b4fc675SJerome Forissier old = termios.tcgetattr(fd) 5566b4fc675SJerome Forissier new = termios.tcgetattr(fd) 5576b4fc675SJerome Forissier new[3] = new[3] & ~termios.ECHO # lflags 5586b4fc675SJerome Forissier try: 55920d152b8SJerome Forissier if isatty: 5606b4fc675SJerome Forissier termios.tcsetattr(fd, termios.TCSADRAIN, new) 561733a15f2SJerome Forissier for line in sys.stdin: 562733a15f2SJerome Forissier symbolizer.write(line) 5636b4fc675SJerome Forissier finally: 564733a15f2SJerome Forissier symbolizer.flush() 56520d152b8SJerome Forissier if isatty: 5666b4fc675SJerome Forissier termios.tcsetattr(fd, termios.TCSADRAIN, old) 567733a15f2SJerome Forissier 5681d8c2a48SJerome Forissier 569733a15f2SJerome Forissierif __name__ == "__main__": 570733a15f2SJerome Forissier main() 571