1733a15f2SJerome Forissier#!/usr/bin/env python 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 9733a15f2SJerome Forissierimport glob 10157e6213SJerome Forissierimport os 11733a15f2SJerome Forissierimport re 12733a15f2SJerome Forissierimport subprocess 13733a15f2SJerome Forissierimport sys 14733a15f2SJerome Forissier 15733a15f2SJerome ForissierCALL_STACK_RE = re.compile('Call stack:') 16a2b984bdSJoakim Bech# This gets the address from lines looking like this: 17a2b984bdSJoakim Bech# E/TC:0 0x001044a8 186e7c2e91SJerome ForissierSTACK_ADDR_RE = re.compile( 19*531963a5SJens Wiklander r'[UEIDFM]/(TC|LD):(\?*|[0-9]*) [0-9]* +(?P<addr>0x[0-9a-f]+)') 206e7c2e91SJerome ForissierABORT_ADDR_RE = re.compile(r'-abort at address (?P<addr>0x[0-9a-f]+)') 21444c203eSJerome ForissierREGION_RE = re.compile(r'region +[0-9]+: va (?P<addr>0x[0-9a-f]+) ' 226e7c2e91SJerome Forissier r'pa 0x[0-9a-f]+ size (?P<size>0x[0-9a-f]+)' 23*531963a5SJens Wiklander r'( flags .{4} (\[(?P<elf_idx>[0-9]+)\])?)?') 24ae252462SJerome ForissierELF_LIST_RE = re.compile(r'\[(?P<idx>[0-9]+)\] (?P<uuid>[0-9a-f\-]+)' 256e7c2e91SJerome Forissier r' @ (?P<load_addr>0x[0-9a-f\-]+)') 26c90b6663SSumit GargFUNC_GRAPH_RE = re.compile(r'Function graph') 27c90b6663SSumit GargGRAPH_ADDR_RE = re.compile(r'(?P<addr>0x[0-9a-f]+)') 28c90b6663SSumit GargGRAPH_RE = re.compile(r'}') 29733a15f2SJerome Forissier 30733a15f2SJerome Forissierepilog = ''' 310c5bedb5SJerome ForissierThis scripts reads an OP-TEE abort or panic message from stdin and adds debug 320c5bedb5SJerome Forissierinformation to the output, such as '<function> at <file>:<line>' next to each 330c5bedb5SJerome Forissieraddress in the call stack. Any message generated by OP-TEE and containing a 340c5bedb5SJerome Forissiercall stack can in principle be processed by this script. This currently 350c5bedb5SJerome Forissierincludes aborts and panics from the TEE core as well as from any TA. 360c5bedb5SJerome ForissierThe paths provided on the command line are used to locate the appropriate ELF 370c5bedb5SJerome Forissierbinary (tee.elf or Trusted Application). The GNU binutils (addr2line, objdump, 38f9089765SJerome Forissiernm) are used to extract the debug info. If the CROSS_COMPILE environment 39f9089765SJerome Forissiervariable is set, it is used as a prefix to the binutils tools. That is, the 40f9089765SJerome Forissierscript will invoke $(CROSS_COMPILE)addr2line etc. If it is not set however, 41f9089765SJerome Forissierthe prefix will be determined automatically for each ELF file based on its 42f9089765SJerome Forissierarchitecture (arm-linux-gnueabihf-, aarch64-linux-gnu-). The resulting command 43f9089765SJerome Forissieris then expected to be found in the user's PATH. 44733a15f2SJerome Forissier 450c5bedb5SJerome ForissierOP-TEE abort and panic messages are sent to the secure console. They look like 460c5bedb5SJerome Forissierthe following: 47733a15f2SJerome Forissier 480c5bedb5SJerome Forissier E/TC:0 User TA data-abort at address 0xffffdecd (alignment fault) 49733a15f2SJerome Forissier ... 500c5bedb5SJerome Forissier E/TC:0 Call stack: 510c5bedb5SJerome Forissier E/TC:0 0x4000549e 520c5bedb5SJerome Forissier E/TC:0 0x40001f4b 530c5bedb5SJerome Forissier E/TC:0 0x4000273f 540c5bedb5SJerome Forissier E/TC:0 0x40005da7 55733a15f2SJerome Forissier 56733a15f2SJerome ForissierInspired by a script of the same name by the Chromium project. 57733a15f2SJerome Forissier 58733a15f2SJerome ForissierSample usage: 59733a15f2SJerome Forissier 60733a15f2SJerome Forissier $ scripts/symbolize.py -d out/arm-plat-hikey/core -d ../optee_test/out/ta/* 61733a15f2SJerome Forissier <paste whole dump here> 62733a15f2SJerome Forissier ^D 63c90b6663SSumit Garg 64c90b6663SSumit GargAlso, this script reads function graph generated for OP-TEE user TA from 65c90b6663SSumit Garg/tmp/ftrace-<ta_uuid>.out file and resolves function addresses to corresponding 66c90b6663SSumit Gargsymbols. 67c90b6663SSumit Garg 68c90b6663SSumit GargSample usage: 69c90b6663SSumit Garg 70c90b6663SSumit Garg $ cat /tmp/ftrace-<ta_uuid>.out | scripts/symbolize.py -d <ta_uuid>.elf 71c90b6663SSumit Garg <paste function graph here> 72c90b6663SSumit Garg ^D 73733a15f2SJerome Forissier''' 74733a15f2SJerome Forissier 75ae252462SJerome Forissier 76733a15f2SJerome Forissierdef get_args(): 77733a15f2SJerome Forissier parser = argparse.ArgumentParser( 78733a15f2SJerome Forissier formatter_class=argparse.RawDescriptionHelpFormatter, 79c90b6663SSumit Garg description='Symbolizes OP-TEE abort dumps or function graphs', 80733a15f2SJerome Forissier epilog=epilog) 81733a15f2SJerome Forissier parser.add_argument('-d', '--dir', action='append', nargs='+', 821d8c2a48SJerome Forissier help='Search for ELF file in DIR. tee.elf is needed ' 831d8c2a48SJerome Forissier 'to decode a TEE Core or pseudo-TA abort, while ' 841d8c2a48SJerome Forissier '<TA_uuid>.elf is required if a user-mode TA has ' 851d8c2a48SJerome Forissier 'crashed. For convenience, ELF files may also be ' 861d8c2a48SJerome Forissier 'given.') 875f7df507SJerome Forissier parser.add_argument('-s', '--strip_path', nargs='?', 881d8c2a48SJerome Forissier help='Strip STRIP_PATH from file paths (default: ' 891d8c2a48SJerome Forissier 'current directory, use -s with no argument to show ' 901d8c2a48SJerome Forissier 'full paths)', default=os.getcwd()) 91733a15f2SJerome Forissier 92733a15f2SJerome Forissier return parser.parse_args() 93733a15f2SJerome Forissier 94ae252462SJerome Forissier 95733a15f2SJerome Forissierclass Symbolizer(object): 96733a15f2SJerome Forissier def __init__(self, out, dirs, strip_path): 97733a15f2SJerome Forissier self._out = out 98733a15f2SJerome Forissier self._dirs = dirs 99733a15f2SJerome Forissier self._strip_path = strip_path 100733a15f2SJerome Forissier self._addr2line = None 101733a15f2SJerome Forissier self.reset() 102733a15f2SJerome Forissier 1031cbf777bSJerome Forissier def my_Popen(self, cmd): 1041cbf777bSJerome Forissier try: 1051cbf777bSJerome Forissier return subprocess.Popen(cmd, stdin=subprocess.PIPE, 1061cbf777bSJerome Forissier stdout=subprocess.PIPE) 1071cbf777bSJerome Forissier except OSError as e: 1081cbf777bSJerome Forissier if e.errno == os.errno.ENOENT: 1091cbf777bSJerome Forissier print >> sys.stderr, "*** Error:", cmd[0] + \ 1101cbf777bSJerome Forissier ": command not found" 1111cbf777bSJerome Forissier sys.exit(1) 1121cbf777bSJerome Forissier 113733a15f2SJerome Forissier def get_elf(self, elf_or_uuid): 114733a15f2SJerome Forissier if not elf_or_uuid.endswith('.elf'): 115733a15f2SJerome Forissier elf_or_uuid += '.elf' 116733a15f2SJerome Forissier for d in self._dirs: 117157e6213SJerome Forissier if d.endswith(elf_or_uuid) and os.path.isfile(d): 118157e6213SJerome Forissier return d 119733a15f2SJerome Forissier elf = glob.glob(d + '/' + elf_or_uuid) 120733a15f2SJerome Forissier if elf: 121733a15f2SJerome Forissier return elf[0] 122733a15f2SJerome Forissier 123d720431cSJerome Forissier def set_arch(self): 124d720431cSJerome Forissier if self._arch: 125d720431cSJerome Forissier return 1266e7c2e91SJerome Forissier self._arch = os.getenv('CROSS_COMPILE') 1278a6d4a8bSEtienne Carriere if self._arch: 1288a6d4a8bSEtienne Carriere return 129ae252462SJerome Forissier elf = self.get_elf(self._elfs[0][0]) 130ae252462SJerome Forissier if elf is None: 131ae252462SJerome Forissier return 132ae252462SJerome Forissier p = subprocess.Popen(['file', self.get_elf(self._elfs[0][0])], 133d720431cSJerome Forissier stdout=subprocess.PIPE) 134d720431cSJerome Forissier output = p.stdout.readlines() 135d720431cSJerome Forissier p.terminate() 136d720431cSJerome Forissier if 'ARM aarch64,' in output[0]: 137d720431cSJerome Forissier self._arch = 'aarch64-linux-gnu-' 138d720431cSJerome Forissier elif 'ARM,' in output[0]: 139d720431cSJerome Forissier self._arch = 'arm-linux-gnueabihf-' 140d720431cSJerome Forissier 141142c5cccSJerome Forissier def arch_prefix(self, cmd): 142d720431cSJerome Forissier self.set_arch() 143ae252462SJerome Forissier if self._arch is None: 144ae252462SJerome Forissier return '' 145d720431cSJerome Forissier return self._arch + cmd 146142c5cccSJerome Forissier 147ae252462SJerome Forissier def spawn_addr2line(self, elf_name): 148ae252462SJerome Forissier if elf_name is None: 149ae252462SJerome Forissier return 150ae252462SJerome Forissier if self._addr2line_elf_name is elf_name: 151ae252462SJerome Forissier return 152ae252462SJerome Forissier if self._addr2line: 153ae252462SJerome Forissier self._addr2line.terminate 154ae252462SJerome Forissier self._addr2line = None 155ae252462SJerome Forissier elf = self.get_elf(elf_name) 156733a15f2SJerome Forissier if not elf: 157733a15f2SJerome Forissier return 158142c5cccSJerome Forissier cmd = self.arch_prefix('addr2line') 159142c5cccSJerome Forissier if not cmd: 160733a15f2SJerome Forissier return 1611cbf777bSJerome Forissier self._addr2line = self.my_Popen([cmd, '-f', '-p', '-e', elf]) 162ae252462SJerome Forissier self._addr2line_elf_name = elf_name 163ae252462SJerome Forissier 164ae252462SJerome Forissier # If addr falls into a region that maps a TA ELF file, return the load 165ae252462SJerome Forissier # address of that file. 166ae252462SJerome Forissier def elf_load_addr(self, addr): 167ae252462SJerome Forissier if self._regions: 168ae252462SJerome Forissier for r in self._regions: 169ae252462SJerome Forissier r_addr = int(r[0], 16) 170ae252462SJerome Forissier r_size = int(r[1], 16) 171ae252462SJerome Forissier i_addr = int(addr, 16) 172ae252462SJerome Forissier if (i_addr >= r_addr and i_addr < (r_addr + r_size)): 173ae252462SJerome Forissier # Found region 174ae252462SJerome Forissier elf_idx = r[2] 175ae252462SJerome Forissier if elf_idx is not None: 176ae252462SJerome Forissier return self._elfs[int(elf_idx)][1] 177ae252462SJerome Forissier return None 178ae252462SJerome Forissier else: 179ae252462SJerome Forissier # tee.elf 180ae252462SJerome Forissier return '0x0' 181ae252462SJerome Forissier 182ae252462SJerome Forissier def elf_for_addr(self, addr): 183ae252462SJerome Forissier l_addr = self.elf_load_addr(addr) 184ae252462SJerome Forissier if l_addr is None: 185ae252462SJerome Forissier return None 186ae252462SJerome Forissier if l_addr is '0x0': 187ae252462SJerome Forissier return 'tee.elf' 188ae252462SJerome Forissier for k in self._elfs: 189ae252462SJerome Forissier e = self._elfs[k] 190ae252462SJerome Forissier if int(e[1], 16) == int(l_addr, 16): 191ae252462SJerome Forissier return e[0] 192ae252462SJerome Forissier return None 193733a15f2SJerome Forissier 194142c5cccSJerome Forissier def subtract_load_addr(self, addr): 195ae252462SJerome Forissier l_addr = self.elf_load_addr(addr) 196ae252462SJerome Forissier if l_addr is None: 197ae252462SJerome Forissier return None 198ae252462SJerome Forissier if int(l_addr, 16) > int(addr, 16): 199142c5cccSJerome Forissier return '' 200ae252462SJerome Forissier return '0x{:x}'.format(int(addr, 16) - int(l_addr, 16)) 201142c5cccSJerome Forissier 202142c5cccSJerome Forissier def resolve(self, addr): 203142c5cccSJerome Forissier reladdr = self.subtract_load_addr(addr) 204ae252462SJerome Forissier self.spawn_addr2line(self.elf_for_addr(addr)) 205142c5cccSJerome Forissier if not reladdr or not self._addr2line: 206733a15f2SJerome Forissier return '???' 207733a15f2SJerome Forissier try: 208733a15f2SJerome Forissier print >> self._addr2line.stdin, reladdr 209733a15f2SJerome Forissier ret = self._addr2line.stdout.readline().rstrip('\n') 210733a15f2SJerome Forissier except IOError: 211733a15f2SJerome Forissier ret = '!!!' 212733a15f2SJerome Forissier return ret 213733a15f2SJerome Forissier 214142c5cccSJerome Forissier def symbol_plus_offset(self, addr): 215142c5cccSJerome Forissier ret = '' 216142c5cccSJerome Forissier prevsize = 0 217142c5cccSJerome Forissier reladdr = self.subtract_load_addr(addr) 218ae252462SJerome Forissier elf_name = self.elf_for_addr(addr) 219ae252462SJerome Forissier if elf_name is None: 220ae252462SJerome Forissier return '' 221ae252462SJerome Forissier elf = self.get_elf(elf_name) 222142c5cccSJerome Forissier cmd = self.arch_prefix('nm') 223142c5cccSJerome Forissier if not reladdr or not elf or not cmd: 224142c5cccSJerome Forissier return '' 22530999126SJerome Forissier ireladdr = int(reladdr, 16) 2261cbf777bSJerome Forissier nm = self.my_Popen([cmd, '--numeric-sort', '--print-size', elf]) 227142c5cccSJerome Forissier for line in iter(nm.stdout.readline, ''): 228142c5cccSJerome Forissier try: 229142c5cccSJerome Forissier addr, size, _, name = line.split() 2301d8c2a48SJerome Forissier except ValueError: 231142c5cccSJerome Forissier # Size is missing 232b4815427SJerome Forissier try: 233142c5cccSJerome Forissier addr, _, name = line.split() 234142c5cccSJerome Forissier size = '0' 2351d8c2a48SJerome Forissier except ValueError: 236b4815427SJerome Forissier # E.g., undefined (external) symbols (line = "U symbol") 237b4815427SJerome Forissier continue 238142c5cccSJerome Forissier iaddr = int(addr, 16) 239142c5cccSJerome Forissier isize = int(size, 16) 240142c5cccSJerome Forissier if iaddr == ireladdr: 241142c5cccSJerome Forissier ret = name 242142c5cccSJerome Forissier break 243142c5cccSJerome Forissier if iaddr < ireladdr and iaddr + isize >= ireladdr: 244142c5cccSJerome Forissier offs = ireladdr - iaddr 245142c5cccSJerome Forissier ret = name + '+' + str(offs) 246142c5cccSJerome Forissier break 247142c5cccSJerome Forissier if iaddr > ireladdr and prevsize == 0: 248142c5cccSJerome Forissier offs = iaddr + ireladdr 249142c5cccSJerome Forissier ret = prevname + '+' + str(offs) 250142c5cccSJerome Forissier break 251142c5cccSJerome Forissier prevsize = size 252142c5cccSJerome Forissier prevname = name 253142c5cccSJerome Forissier nm.terminate() 254142c5cccSJerome Forissier return ret 255142c5cccSJerome Forissier 256142c5cccSJerome Forissier def section_plus_offset(self, addr): 257142c5cccSJerome Forissier ret = '' 258142c5cccSJerome Forissier reladdr = self.subtract_load_addr(addr) 259ae252462SJerome Forissier elf_name = self.elf_for_addr(addr) 260ae252462SJerome Forissier if elf_name is None: 261ae252462SJerome Forissier return '' 262ae252462SJerome Forissier elf = self.get_elf(elf_name) 263142c5cccSJerome Forissier cmd = self.arch_prefix('objdump') 264142c5cccSJerome Forissier if not reladdr or not elf or not cmd: 265142c5cccSJerome Forissier return '' 26630999126SJerome Forissier iaddr = int(reladdr, 16) 2671cbf777bSJerome Forissier objdump = self.my_Popen([cmd, '--section-headers', elf]) 268142c5cccSJerome Forissier for line in iter(objdump.stdout.readline, ''): 269142c5cccSJerome Forissier try: 270142c5cccSJerome Forissier idx, name, size, vma, lma, offs, algn = line.split() 2711d8c2a48SJerome Forissier except ValueError: 272ae252462SJerome Forissier continue 273142c5cccSJerome Forissier ivma = int(vma, 16) 274142c5cccSJerome Forissier isize = int(size, 16) 275142c5cccSJerome Forissier if ivma == iaddr: 276142c5cccSJerome Forissier ret = name 277142c5cccSJerome Forissier break 278142c5cccSJerome Forissier if ivma < iaddr and ivma + isize >= iaddr: 279142c5cccSJerome Forissier offs = iaddr - ivma 280142c5cccSJerome Forissier ret = name + '+' + str(offs) 281142c5cccSJerome Forissier break 282142c5cccSJerome Forissier objdump.terminate() 283142c5cccSJerome Forissier return ret 284142c5cccSJerome Forissier 285142c5cccSJerome Forissier def process_abort(self, line): 286142c5cccSJerome Forissier ret = '' 287142c5cccSJerome Forissier match = re.search(ABORT_ADDR_RE, line) 288142c5cccSJerome Forissier addr = match.group('addr') 289142c5cccSJerome Forissier pre = match.start('addr') 290142c5cccSJerome Forissier post = match.end('addr') 291142c5cccSJerome Forissier sym = self.symbol_plus_offset(addr) 292142c5cccSJerome Forissier sec = self.section_plus_offset(addr) 293142c5cccSJerome Forissier if sym or sec: 294142c5cccSJerome Forissier ret += line[:pre] 295142c5cccSJerome Forissier ret += addr 296142c5cccSJerome Forissier if sym: 297142c5cccSJerome Forissier ret += ' ' + sym 298142c5cccSJerome Forissier if sec: 299142c5cccSJerome Forissier ret += ' ' + sec 300142c5cccSJerome Forissier ret += line[post:] 301142c5cccSJerome Forissier return ret 302142c5cccSJerome Forissier 30330999126SJerome Forissier # Return all ELF sections with the ALLOC flag 304ae252462SJerome Forissier def read_sections(self, elf_name): 305ae252462SJerome Forissier if elf_name is None: 30630999126SJerome Forissier return 307ae252462SJerome Forissier if elf_name in self._sections: 308ae252462SJerome Forissier return 309ae252462SJerome Forissier elf = self.get_elf(elf_name) 31030999126SJerome Forissier cmd = self.arch_prefix('objdump') 31130999126SJerome Forissier if not elf or not cmd: 31230999126SJerome Forissier return 313ae252462SJerome Forissier self._sections[elf_name] = [] 3141cbf777bSJerome Forissier objdump = self.my_Popen([cmd, '--section-headers', elf]) 31530999126SJerome Forissier for line in iter(objdump.stdout.readline, ''): 31630999126SJerome Forissier try: 31730999126SJerome Forissier _, name, size, vma, _, _, _ = line.split() 3181d8c2a48SJerome Forissier except ValueError: 31930999126SJerome Forissier if 'ALLOC' in line: 320ae252462SJerome Forissier self._sections[elf_name].append([name, int(vma, 16), 321ae252462SJerome Forissier int(size, 16)]) 32230999126SJerome Forissier 32330999126SJerome Forissier def overlaps(self, section, addr, size): 32430999126SJerome Forissier sec_addr = section[1] 32530999126SJerome Forissier sec_size = section[2] 32630999126SJerome Forissier if not size or not sec_size: 32730999126SJerome Forissier return False 328ae252462SJerome Forissier return ((addr <= (sec_addr + sec_size - 1)) and 329ae252462SJerome Forissier ((addr + size - 1) >= sec_addr)) 33030999126SJerome Forissier 331ae252462SJerome Forissier def sections_in_region(self, addr, size, elf_idx): 33230999126SJerome Forissier ret = '' 33330999126SJerome Forissier addr = self.subtract_load_addr(addr) 33430999126SJerome Forissier if not addr: 33530999126SJerome Forissier return '' 33630999126SJerome Forissier iaddr = int(addr, 16) 33730999126SJerome Forissier isize = int(size, 16) 338ae252462SJerome Forissier elf = self._elfs[int(elf_idx)][0] 339ae252462SJerome Forissier if elf is None: 340ae252462SJerome Forissier return '' 341ae252462SJerome Forissier self.read_sections(elf) 342ae252462SJerome Forissier if elf not in self._sections: 343ae252462SJerome Forissier return '' 344ae252462SJerome Forissier for s in self._sections[elf]: 34530999126SJerome Forissier if self.overlaps(s, iaddr, isize): 34630999126SJerome Forissier ret += ' ' + s[0] 34730999126SJerome Forissier return ret 34830999126SJerome Forissier 349733a15f2SJerome Forissier def reset(self): 350733a15f2SJerome Forissier self._call_stack_found = False 351733a15f2SJerome Forissier if self._addr2line: 352733a15f2SJerome Forissier self._addr2line.terminate() 353733a15f2SJerome Forissier self._addr2line = None 354ae252462SJerome Forissier self._addr2line_elf_name = None 355d720431cSJerome Forissier self._arch = None 356142c5cccSJerome Forissier self._saved_abort_line = '' 357ae252462SJerome Forissier self._sections = {} # {elf_name: [[name, addr, size], ...], ...} 358ae252462SJerome Forissier self._regions = [] # [[addr, size, elf_idx, saved line], ...] 359ae252462SJerome Forissier self._elfs = {0: ["tee.elf", 0]} # {idx: [uuid, load_addr], ...} 360c90b6663SSumit Garg self._func_graph_found = False 361c90b6663SSumit Garg self._func_graph_skip_line = True 362733a15f2SJerome Forissier 363095567e5SJerome Forissier def pretty_print_path(self, path): 364095567e5SJerome Forissier if self._strip_path: 365095567e5SJerome Forissier return re.sub(re.escape(self._strip_path) + '/*', '', path) 366095567e5SJerome Forissier return path 367095567e5SJerome Forissier 368733a15f2SJerome Forissier def write(self, line): 369733a15f2SJerome Forissier if self._call_stack_found: 370733a15f2SJerome Forissier match = re.search(STACK_ADDR_RE, line) 371733a15f2SJerome Forissier if match: 372733a15f2SJerome Forissier addr = match.group('addr') 373733a15f2SJerome Forissier pre = match.start('addr') 374733a15f2SJerome Forissier post = match.end('addr') 375733a15f2SJerome Forissier self._out.write(line[:pre]) 376733a15f2SJerome Forissier self._out.write(addr) 377733a15f2SJerome Forissier res = self.resolve(addr) 378095567e5SJerome Forissier res = self.pretty_print_path(res) 379733a15f2SJerome Forissier self._out.write(' ' + res) 380733a15f2SJerome Forissier self._out.write(line[post:]) 381733a15f2SJerome Forissier return 382733a15f2SJerome Forissier else: 383733a15f2SJerome Forissier self.reset() 384c90b6663SSumit Garg if self._func_graph_found: 385c90b6663SSumit Garg match = re.search(GRAPH_ADDR_RE, line) 386c90b6663SSumit Garg match_re = re.search(GRAPH_RE, line) 387c90b6663SSumit Garg if match: 388c90b6663SSumit Garg addr = match.group('addr') 389c90b6663SSumit Garg pre = match.start('addr') 390c90b6663SSumit Garg post = match.end('addr') 391c90b6663SSumit Garg self._out.write(line[:pre]) 392c90b6663SSumit Garg res = self.resolve(addr) 393c90b6663SSumit Garg res_arr = re.split(' ', res) 394c90b6663SSumit Garg self._out.write(res_arr[0]) 395c90b6663SSumit Garg self._out.write(line[post:]) 396c90b6663SSumit Garg self._func_graph_skip_line = False 397c90b6663SSumit Garg return 398c90b6663SSumit Garg elif match_re: 399c90b6663SSumit Garg self._out.write(line) 400c90b6663SSumit Garg return 401c90b6663SSumit Garg elif self._func_graph_skip_line: 402c90b6663SSumit Garg return 403c90b6663SSumit Garg else: 404c90b6663SSumit Garg self.reset() 40530999126SJerome Forissier match = re.search(REGION_RE, line) 40630999126SJerome Forissier if match: 407ae252462SJerome Forissier # Region table: save info for later processing once 408ae252462SJerome Forissier # we know which UUID corresponds to which ELF index 40930999126SJerome Forissier addr = match.group('addr') 41030999126SJerome Forissier size = match.group('size') 411ae252462SJerome Forissier elf_idx = match.group('elf_idx') 412ae252462SJerome Forissier self._regions.append([addr, size, elf_idx, line]) 413ae252462SJerome Forissier return 414ae252462SJerome Forissier match = re.search(ELF_LIST_RE, line) 415ae252462SJerome Forissier if match: 416ae252462SJerome Forissier # ELF list: save info for later. Region table and ELF list 417ae252462SJerome Forissier # will be displayed when the call stack is reached 418ae252462SJerome Forissier i = int(match.group('idx')) 419ae252462SJerome Forissier self._elfs[i] = [match.group('uuid'), match.group('load_addr'), 420ae252462SJerome Forissier line] 42130999126SJerome Forissier return 422733a15f2SJerome Forissier match = re.search(CALL_STACK_RE, line) 423733a15f2SJerome Forissier if match: 424733a15f2SJerome Forissier self._call_stack_found = True 425ae252462SJerome Forissier if self._regions: 426ae252462SJerome Forissier for r in self._regions: 427ae252462SJerome Forissier r_addr = r[0] 428ae252462SJerome Forissier r_size = r[1] 429ae252462SJerome Forissier elf_idx = r[2] 430ae252462SJerome Forissier saved_line = r[3] 431ae252462SJerome Forissier if elf_idx is None: 432ae252462SJerome Forissier self._out.write(saved_line) 433ae252462SJerome Forissier else: 434ae252462SJerome Forissier self._out.write(saved_line.strip() + 435ae252462SJerome Forissier self.sections_in_region(r_addr, 436ae252462SJerome Forissier r_size, 437ae252462SJerome Forissier elf_idx) + 438ae252462SJerome Forissier '\n') 439ae252462SJerome Forissier if self._elfs: 440ae252462SJerome Forissier for k in self._elfs: 441ae252462SJerome Forissier e = self._elfs[k] 442ae252462SJerome Forissier if (len(e) >= 3): 4431e6f2ea0SJerome Forissier # TA executable or library 444095567e5SJerome Forissier self._out.write(e[2].strip()) 445095567e5SJerome Forissier elf = self.get_elf(e[0]) 446095567e5SJerome Forissier if elf: 447095567e5SJerome Forissier rpath = os.path.realpath(elf) 448095567e5SJerome Forissier path = self.pretty_print_path(rpath) 449095567e5SJerome Forissier self._out.write(' (' + path + ')') 450095567e5SJerome Forissier self._out.write('\n') 451142c5cccSJerome Forissier # Here is a good place to resolve the abort address because we 452142c5cccSJerome Forissier # have all the information we need 453142c5cccSJerome Forissier if self._saved_abort_line: 454142c5cccSJerome Forissier self._out.write(self.process_abort(self._saved_abort_line)) 455c90b6663SSumit Garg match = re.search(FUNC_GRAPH_RE, line) 456c90b6663SSumit Garg if match: 457c90b6663SSumit Garg self._func_graph_found = True 458142c5cccSJerome Forissier match = re.search(ABORT_ADDR_RE, line) 459142c5cccSJerome Forissier if match: 46027b83ad2SJerome Forissier self.reset() 461142c5cccSJerome Forissier # At this point the arch and TA load address are unknown. 462142c5cccSJerome Forissier # Save the line so We can translate the abort address later. 463142c5cccSJerome Forissier self._saved_abort_line = line 464733a15f2SJerome Forissier self._out.write(line) 465733a15f2SJerome Forissier 466733a15f2SJerome Forissier def flush(self): 467733a15f2SJerome Forissier self._out.flush() 468733a15f2SJerome Forissier 469ae252462SJerome Forissier 470733a15f2SJerome Forissierdef main(): 471733a15f2SJerome Forissier args = get_args() 472733a15f2SJerome Forissier if args.dir: 473733a15f2SJerome Forissier # Flatten list in case -d is used several times *and* with multiple 474733a15f2SJerome Forissier # arguments 475733a15f2SJerome Forissier args.dirs = [item for sublist in args.dir for item in sublist] 476733a15f2SJerome Forissier else: 477733a15f2SJerome Forissier args.dirs = [] 478733a15f2SJerome Forissier symbolizer = Symbolizer(sys.stdout, args.dirs, args.strip_path) 479733a15f2SJerome Forissier 480733a15f2SJerome Forissier for line in sys.stdin: 481733a15f2SJerome Forissier symbolizer.write(line) 482733a15f2SJerome Forissier symbolizer.flush() 483733a15f2SJerome Forissier 4841d8c2a48SJerome Forissier 485733a15f2SJerome Forissierif __name__ == "__main__": 486733a15f2SJerome Forissier main() 487