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:') 18a2b984bdSJoakim Bech# This gets the address from lines looking like this: 19a2b984bdSJoakim Bech# E/TC:0 0x001044a8 206e7c2e91SJerome ForissierSTACK_ADDR_RE = re.compile( 21531963a5SJens Wiklander r'[UEIDFM]/(TC|LD):(\?*|[0-9]*) [0-9]* +(?P<addr>0x[0-9a-f]+)') 226e7c2e91SJerome ForissierABORT_ADDR_RE = re.compile(r'-abort at address (?P<addr>0x[0-9a-f]+)') 23444c203eSJerome ForissierREGION_RE = re.compile(r'region +[0-9]+: va (?P<addr>0x[0-9a-f]+) ' 246e7c2e91SJerome Forissier r'pa 0x[0-9a-f]+ size (?P<size>0x[0-9a-f]+)' 25531963a5SJens Wiklander r'( flags .{4} (\[(?P<elf_idx>[0-9]+)\])?)?') 26ae252462SJerome ForissierELF_LIST_RE = re.compile(r'\[(?P<idx>[0-9]+)\] (?P<uuid>[0-9a-f\-]+)' 276e7c2e91SJerome Forissier r' @ (?P<load_addr>0x[0-9a-f\-]+)') 28c90b6663SSumit GargFUNC_GRAPH_RE = re.compile(r'Function graph') 29c90b6663SSumit GargGRAPH_ADDR_RE = re.compile(r'(?P<addr>0x[0-9a-f]+)') 30c90b6663SSumit GargGRAPH_RE = re.compile(r'}') 31733a15f2SJerome Forissier 32733a15f2SJerome Forissierepilog = ''' 330c5bedb5SJerome ForissierThis scripts reads an OP-TEE abort or panic message from stdin and adds debug 340c5bedb5SJerome Forissierinformation to the output, such as '<function> at <file>:<line>' next to each 350c5bedb5SJerome Forissieraddress in the call stack. Any message generated by OP-TEE and containing a 360c5bedb5SJerome Forissiercall stack can in principle be processed by this script. This currently 370c5bedb5SJerome Forissierincludes aborts and panics from the TEE core as well as from any TA. 380c5bedb5SJerome ForissierThe paths provided on the command line are used to locate the appropriate ELF 390c5bedb5SJerome Forissierbinary (tee.elf or Trusted Application). The GNU binutils (addr2line, objdump, 40f9089765SJerome Forissiernm) are used to extract the debug info. If the CROSS_COMPILE environment 41f9089765SJerome Forissiervariable is set, it is used as a prefix to the binutils tools. That is, the 42f9089765SJerome Forissierscript will invoke $(CROSS_COMPILE)addr2line etc. If it is not set however, 43f9089765SJerome Forissierthe prefix will be determined automatically for each ELF file based on its 44f9089765SJerome Forissierarchitecture (arm-linux-gnueabihf-, aarch64-linux-gnu-). The resulting command 45f9089765SJerome Forissieris then expected to be found in the user's PATH. 46733a15f2SJerome Forissier 470c5bedb5SJerome ForissierOP-TEE abort and panic messages are sent to the secure console. They look like 480c5bedb5SJerome Forissierthe following: 49733a15f2SJerome Forissier 500c5bedb5SJerome Forissier E/TC:0 User TA data-abort at address 0xffffdecd (alignment fault) 51733a15f2SJerome Forissier ... 520c5bedb5SJerome Forissier E/TC:0 Call stack: 530c5bedb5SJerome Forissier E/TC:0 0x4000549e 540c5bedb5SJerome Forissier E/TC:0 0x40001f4b 550c5bedb5SJerome Forissier E/TC:0 0x4000273f 560c5bedb5SJerome Forissier E/TC:0 0x40005da7 57733a15f2SJerome Forissier 58733a15f2SJerome ForissierInspired by a script of the same name by the Chromium project. 59733a15f2SJerome Forissier 60733a15f2SJerome ForissierSample usage: 61733a15f2SJerome Forissier 62733a15f2SJerome Forissier $ scripts/symbolize.py -d out/arm-plat-hikey/core -d ../optee_test/out/ta/* 63733a15f2SJerome Forissier <paste whole dump here> 64733a15f2SJerome Forissier ^D 65c90b6663SSumit Garg 66c90b6663SSumit GargAlso, this script reads function graph generated for OP-TEE user TA from 67c90b6663SSumit Garg/tmp/ftrace-<ta_uuid>.out file and resolves function addresses to corresponding 68c90b6663SSumit Gargsymbols. 69c90b6663SSumit Garg 70c90b6663SSumit GargSample usage: 71c90b6663SSumit Garg 72c90b6663SSumit Garg $ cat /tmp/ftrace-<ta_uuid>.out | scripts/symbolize.py -d <ta_uuid>.elf 73c90b6663SSumit Garg <paste function graph here> 74c90b6663SSumit Garg ^D 75733a15f2SJerome Forissier''' 76733a15f2SJerome Forissier 77ae252462SJerome Forissier 78733a15f2SJerome Forissierdef get_args(): 79733a15f2SJerome Forissier parser = argparse.ArgumentParser( 80733a15f2SJerome Forissier formatter_class=argparse.RawDescriptionHelpFormatter, 81c90b6663SSumit Garg description='Symbolizes OP-TEE abort dumps or function graphs', 82733a15f2SJerome Forissier epilog=epilog) 83733a15f2SJerome Forissier parser.add_argument('-d', '--dir', action='append', nargs='+', 841d8c2a48SJerome Forissier help='Search for ELF file in DIR. tee.elf is needed ' 851d8c2a48SJerome Forissier 'to decode a TEE Core or pseudo-TA abort, while ' 861d8c2a48SJerome Forissier '<TA_uuid>.elf is required if a user-mode TA has ' 871d8c2a48SJerome Forissier 'crashed. For convenience, ELF files may also be ' 881d8c2a48SJerome Forissier 'given.') 895f7df507SJerome Forissier parser.add_argument('-s', '--strip_path', nargs='?', 901d8c2a48SJerome Forissier help='Strip STRIP_PATH from file paths (default: ' 911d8c2a48SJerome Forissier 'current directory, use -s with no argument to show ' 921d8c2a48SJerome Forissier 'full paths)', default=os.getcwd()) 93733a15f2SJerome Forissier 94733a15f2SJerome Forissier return parser.parse_args() 95733a15f2SJerome Forissier 96ae252462SJerome Forissier 97733a15f2SJerome Forissierclass Symbolizer(object): 98733a15f2SJerome Forissier def __init__(self, out, dirs, strip_path): 99733a15f2SJerome Forissier self._out = out 100733a15f2SJerome Forissier self._dirs = dirs 101733a15f2SJerome Forissier self._strip_path = strip_path 102733a15f2SJerome Forissier self._addr2line = None 103733a15f2SJerome Forissier self.reset() 104733a15f2SJerome Forissier 1051cbf777bSJerome Forissier def my_Popen(self, cmd): 1061cbf777bSJerome Forissier try: 1071cbf777bSJerome Forissier return subprocess.Popen(cmd, stdin=subprocess.PIPE, 108bbaeed4dSRouven Czerwinski stdout=subprocess.PIPE, text=True, 109bbaeed4dSRouven Czerwinski bufsize=1) 1101cbf777bSJerome Forissier except OSError as e: 111bbaeed4dSRouven Czerwinski if e.errno == errno.ENOENT: 112bbaeed4dSRouven Czerwinski print("*** Error:{}: command not found".format(cmd[0]), 113bbaeed4dSRouven Czerwinski file=sys.stderr) 1141cbf777bSJerome Forissier sys.exit(1) 1151cbf777bSJerome Forissier 116733a15f2SJerome Forissier def get_elf(self, elf_or_uuid): 117733a15f2SJerome Forissier if not elf_or_uuid.endswith('.elf'): 118733a15f2SJerome Forissier elf_or_uuid += '.elf' 119733a15f2SJerome Forissier for d in self._dirs: 120157e6213SJerome Forissier if d.endswith(elf_or_uuid) and os.path.isfile(d): 121157e6213SJerome Forissier return d 122733a15f2SJerome Forissier elf = glob.glob(d + '/' + elf_or_uuid) 123733a15f2SJerome Forissier if elf: 124733a15f2SJerome Forissier return elf[0] 125733a15f2SJerome Forissier 126d720431cSJerome Forissier def set_arch(self): 127d720431cSJerome Forissier if self._arch: 128d720431cSJerome Forissier return 1296e7c2e91SJerome Forissier self._arch = os.getenv('CROSS_COMPILE') 1308a6d4a8bSEtienne Carriere if self._arch: 1318a6d4a8bSEtienne Carriere return 132ae252462SJerome Forissier elf = self.get_elf(self._elfs[0][0]) 133ae252462SJerome Forissier if elf is None: 134ae252462SJerome Forissier return 135ae252462SJerome Forissier p = subprocess.Popen(['file', self.get_elf(self._elfs[0][0])], 136d720431cSJerome Forissier stdout=subprocess.PIPE) 137d720431cSJerome Forissier output = p.stdout.readlines() 138d720431cSJerome Forissier p.terminate() 139bbaeed4dSRouven Czerwinski if b'ARM aarch64,' in output[0]: 140d720431cSJerome Forissier self._arch = 'aarch64-linux-gnu-' 141bbaeed4dSRouven Czerwinski elif b'ARM,' in output[0]: 142d720431cSJerome Forissier self._arch = 'arm-linux-gnueabihf-' 143d720431cSJerome Forissier 144142c5cccSJerome Forissier def arch_prefix(self, cmd): 145d720431cSJerome Forissier self.set_arch() 146ae252462SJerome Forissier if self._arch is None: 147ae252462SJerome Forissier return '' 148d720431cSJerome Forissier return self._arch + cmd 149142c5cccSJerome Forissier 150ae252462SJerome Forissier def spawn_addr2line(self, elf_name): 151ae252462SJerome Forissier if elf_name is None: 152ae252462SJerome Forissier return 153ae252462SJerome Forissier if self._addr2line_elf_name is elf_name: 154ae252462SJerome Forissier return 155ae252462SJerome Forissier if self._addr2line: 156ae252462SJerome Forissier self._addr2line.terminate 157ae252462SJerome Forissier self._addr2line = None 158ae252462SJerome Forissier elf = self.get_elf(elf_name) 159733a15f2SJerome Forissier if not elf: 160733a15f2SJerome Forissier return 161142c5cccSJerome Forissier cmd = self.arch_prefix('addr2line') 162142c5cccSJerome Forissier if not cmd: 163733a15f2SJerome Forissier return 1641cbf777bSJerome Forissier self._addr2line = self.my_Popen([cmd, '-f', '-p', '-e', elf]) 165ae252462SJerome Forissier self._addr2line_elf_name = elf_name 166ae252462SJerome Forissier 167ae252462SJerome Forissier # If addr falls into a region that maps a TA ELF file, return the load 168ae252462SJerome Forissier # address of that file. 169ae252462SJerome Forissier def elf_load_addr(self, addr): 170ae252462SJerome Forissier if self._regions: 171ae252462SJerome Forissier for r in self._regions: 172ae252462SJerome Forissier r_addr = int(r[0], 16) 173ae252462SJerome Forissier r_size = int(r[1], 16) 174ae252462SJerome Forissier i_addr = int(addr, 16) 175ae252462SJerome Forissier if (i_addr >= r_addr and i_addr < (r_addr + r_size)): 176ae252462SJerome Forissier # Found region 177ae252462SJerome Forissier elf_idx = r[2] 178ae252462SJerome Forissier if elf_idx is not None: 179ae252462SJerome Forissier return self._elfs[int(elf_idx)][1] 180ae252462SJerome Forissier return None 181ae252462SJerome Forissier else: 182ae252462SJerome Forissier # tee.elf 183ae252462SJerome Forissier return '0x0' 184ae252462SJerome Forissier 185ae252462SJerome Forissier def elf_for_addr(self, addr): 186ae252462SJerome Forissier l_addr = self.elf_load_addr(addr) 187ae252462SJerome Forissier if l_addr is None: 188ae252462SJerome Forissier return None 189ae252462SJerome Forissier if l_addr is '0x0': 190ae252462SJerome Forissier return 'tee.elf' 191ae252462SJerome Forissier for k in self._elfs: 192ae252462SJerome Forissier e = self._elfs[k] 193ae252462SJerome Forissier if int(e[1], 16) == int(l_addr, 16): 194ae252462SJerome Forissier return e[0] 195ae252462SJerome Forissier return None 196733a15f2SJerome Forissier 197142c5cccSJerome Forissier def subtract_load_addr(self, addr): 198ae252462SJerome Forissier l_addr = self.elf_load_addr(addr) 199ae252462SJerome Forissier if l_addr is None: 200ae252462SJerome Forissier return None 201ae252462SJerome Forissier if int(l_addr, 16) > int(addr, 16): 202142c5cccSJerome Forissier return '' 203ae252462SJerome Forissier return '0x{:x}'.format(int(addr, 16) - int(l_addr, 16)) 204142c5cccSJerome Forissier 205142c5cccSJerome Forissier def resolve(self, addr): 206142c5cccSJerome Forissier reladdr = self.subtract_load_addr(addr) 207ae252462SJerome Forissier self.spawn_addr2line(self.elf_for_addr(addr)) 208142c5cccSJerome Forissier if not reladdr or not self._addr2line: 209733a15f2SJerome Forissier return '???' 210733a15f2SJerome Forissier try: 211bbaeed4dSRouven Czerwinski print(reladdr, file=self._addr2line.stdin) 212733a15f2SJerome Forissier ret = self._addr2line.stdout.readline().rstrip('\n') 213733a15f2SJerome Forissier except IOError: 214733a15f2SJerome Forissier ret = '!!!' 215733a15f2SJerome Forissier return ret 216733a15f2SJerome Forissier 217142c5cccSJerome Forissier def symbol_plus_offset(self, addr): 218142c5cccSJerome Forissier ret = '' 219142c5cccSJerome Forissier prevsize = 0 220142c5cccSJerome Forissier reladdr = self.subtract_load_addr(addr) 221ae252462SJerome Forissier elf_name = self.elf_for_addr(addr) 222ae252462SJerome Forissier if elf_name is None: 223ae252462SJerome Forissier return '' 224ae252462SJerome Forissier elf = self.get_elf(elf_name) 225142c5cccSJerome Forissier cmd = self.arch_prefix('nm') 226142c5cccSJerome Forissier if not reladdr or not elf or not cmd: 227142c5cccSJerome Forissier return '' 22830999126SJerome Forissier ireladdr = int(reladdr, 16) 2291cbf777bSJerome Forissier nm = self.my_Popen([cmd, '--numeric-sort', '--print-size', elf]) 230142c5cccSJerome Forissier for line in iter(nm.stdout.readline, ''): 231142c5cccSJerome Forissier try: 232142c5cccSJerome Forissier addr, size, _, name = line.split() 2331d8c2a48SJerome Forissier except ValueError: 234142c5cccSJerome Forissier # Size is missing 235b4815427SJerome Forissier try: 236142c5cccSJerome Forissier addr, _, name = line.split() 237142c5cccSJerome Forissier size = '0' 2381d8c2a48SJerome Forissier except ValueError: 239b4815427SJerome Forissier # E.g., undefined (external) symbols (line = "U symbol") 240b4815427SJerome Forissier continue 241142c5cccSJerome Forissier iaddr = int(addr, 16) 242142c5cccSJerome Forissier isize = int(size, 16) 243142c5cccSJerome Forissier if iaddr == ireladdr: 244142c5cccSJerome Forissier ret = name 245142c5cccSJerome Forissier break 246142c5cccSJerome Forissier if iaddr < ireladdr and iaddr + isize >= ireladdr: 247142c5cccSJerome Forissier offs = ireladdr - iaddr 248142c5cccSJerome Forissier ret = name + '+' + str(offs) 249142c5cccSJerome Forissier break 250142c5cccSJerome Forissier if iaddr > ireladdr and prevsize == 0: 251142c5cccSJerome Forissier offs = iaddr + ireladdr 252142c5cccSJerome Forissier ret = prevname + '+' + str(offs) 253142c5cccSJerome Forissier break 254142c5cccSJerome Forissier prevsize = size 255142c5cccSJerome Forissier prevname = name 256142c5cccSJerome Forissier nm.terminate() 257142c5cccSJerome Forissier return ret 258142c5cccSJerome Forissier 259142c5cccSJerome Forissier def section_plus_offset(self, addr): 260142c5cccSJerome Forissier ret = '' 261142c5cccSJerome Forissier reladdr = self.subtract_load_addr(addr) 262ae252462SJerome Forissier elf_name = self.elf_for_addr(addr) 263ae252462SJerome Forissier if elf_name is None: 264ae252462SJerome Forissier return '' 265ae252462SJerome Forissier elf = self.get_elf(elf_name) 266142c5cccSJerome Forissier cmd = self.arch_prefix('objdump') 267142c5cccSJerome Forissier if not reladdr or not elf or not cmd: 268142c5cccSJerome Forissier return '' 26930999126SJerome Forissier iaddr = int(reladdr, 16) 2701cbf777bSJerome Forissier objdump = self.my_Popen([cmd, '--section-headers', elf]) 271142c5cccSJerome Forissier for line in iter(objdump.stdout.readline, ''): 272142c5cccSJerome Forissier try: 273142c5cccSJerome Forissier idx, name, size, vma, lma, offs, algn = line.split() 2741d8c2a48SJerome Forissier except ValueError: 275ae252462SJerome Forissier continue 276142c5cccSJerome Forissier ivma = int(vma, 16) 277142c5cccSJerome Forissier isize = int(size, 16) 278142c5cccSJerome Forissier if ivma == iaddr: 279142c5cccSJerome Forissier ret = name 280142c5cccSJerome Forissier break 281142c5cccSJerome Forissier if ivma < iaddr and ivma + isize >= iaddr: 282142c5cccSJerome Forissier offs = iaddr - ivma 283142c5cccSJerome Forissier ret = name + '+' + str(offs) 284142c5cccSJerome Forissier break 285142c5cccSJerome Forissier objdump.terminate() 286142c5cccSJerome Forissier return ret 287142c5cccSJerome Forissier 288142c5cccSJerome Forissier def process_abort(self, line): 289142c5cccSJerome Forissier ret = '' 290142c5cccSJerome Forissier match = re.search(ABORT_ADDR_RE, line) 291142c5cccSJerome Forissier addr = match.group('addr') 292142c5cccSJerome Forissier pre = match.start('addr') 293142c5cccSJerome Forissier post = match.end('addr') 294142c5cccSJerome Forissier sym = self.symbol_plus_offset(addr) 295142c5cccSJerome Forissier sec = self.section_plus_offset(addr) 296142c5cccSJerome Forissier if sym or sec: 297142c5cccSJerome Forissier ret += line[:pre] 298142c5cccSJerome Forissier ret += addr 299142c5cccSJerome Forissier if sym: 300142c5cccSJerome Forissier ret += ' ' + sym 301142c5cccSJerome Forissier if sec: 302142c5cccSJerome Forissier ret += ' ' + sec 303142c5cccSJerome Forissier ret += line[post:] 304142c5cccSJerome Forissier return ret 305142c5cccSJerome Forissier 30630999126SJerome Forissier # Return all ELF sections with the ALLOC flag 307ae252462SJerome Forissier def read_sections(self, elf_name): 308ae252462SJerome Forissier if elf_name is None: 30930999126SJerome Forissier return 310ae252462SJerome Forissier if elf_name in self._sections: 311ae252462SJerome Forissier return 312ae252462SJerome Forissier elf = self.get_elf(elf_name) 31330999126SJerome Forissier cmd = self.arch_prefix('objdump') 31430999126SJerome Forissier if not elf or not cmd: 31530999126SJerome Forissier return 316ae252462SJerome Forissier self._sections[elf_name] = [] 3171cbf777bSJerome Forissier objdump = self.my_Popen([cmd, '--section-headers', elf]) 31830999126SJerome Forissier for line in iter(objdump.stdout.readline, ''): 31930999126SJerome Forissier try: 32030999126SJerome Forissier _, name, size, vma, _, _, _ = line.split() 3211d8c2a48SJerome Forissier except ValueError: 32230999126SJerome Forissier if 'ALLOC' in line: 323ae252462SJerome Forissier self._sections[elf_name].append([name, int(vma, 16), 324ae252462SJerome Forissier int(size, 16)]) 32530999126SJerome Forissier 32630999126SJerome Forissier def overlaps(self, section, addr, size): 32730999126SJerome Forissier sec_addr = section[1] 32830999126SJerome Forissier sec_size = section[2] 32930999126SJerome Forissier if not size or not sec_size: 33030999126SJerome Forissier return False 331ae252462SJerome Forissier return ((addr <= (sec_addr + sec_size - 1)) and 332ae252462SJerome Forissier ((addr + size - 1) >= sec_addr)) 33330999126SJerome Forissier 334ae252462SJerome Forissier def sections_in_region(self, addr, size, elf_idx): 33530999126SJerome Forissier ret = '' 33630999126SJerome Forissier addr = self.subtract_load_addr(addr) 33730999126SJerome Forissier if not addr: 33830999126SJerome Forissier return '' 33930999126SJerome Forissier iaddr = int(addr, 16) 34030999126SJerome Forissier isize = int(size, 16) 341ae252462SJerome Forissier elf = self._elfs[int(elf_idx)][0] 342ae252462SJerome Forissier if elf is None: 343ae252462SJerome Forissier return '' 344ae252462SJerome Forissier self.read_sections(elf) 345ae252462SJerome Forissier if elf not in self._sections: 346ae252462SJerome Forissier return '' 347ae252462SJerome Forissier for s in self._sections[elf]: 34830999126SJerome Forissier if self.overlaps(s, iaddr, isize): 34930999126SJerome Forissier ret += ' ' + s[0] 35030999126SJerome Forissier return ret 35130999126SJerome Forissier 352733a15f2SJerome Forissier def reset(self): 353733a15f2SJerome Forissier self._call_stack_found = False 354733a15f2SJerome Forissier if self._addr2line: 355733a15f2SJerome Forissier self._addr2line.terminate() 356733a15f2SJerome Forissier self._addr2line = None 357ae252462SJerome Forissier self._addr2line_elf_name = None 358d720431cSJerome Forissier self._arch = None 359142c5cccSJerome Forissier self._saved_abort_line = '' 360ae252462SJerome Forissier self._sections = {} # {elf_name: [[name, addr, size], ...], ...} 361ae252462SJerome Forissier self._regions = [] # [[addr, size, elf_idx, saved line], ...] 362ae252462SJerome Forissier self._elfs = {0: ["tee.elf", 0]} # {idx: [uuid, load_addr], ...} 363c90b6663SSumit Garg self._func_graph_found = False 364c90b6663SSumit Garg self._func_graph_skip_line = True 365733a15f2SJerome Forissier 366095567e5SJerome Forissier def pretty_print_path(self, path): 367095567e5SJerome Forissier if self._strip_path: 368095567e5SJerome Forissier return re.sub(re.escape(self._strip_path) + '/*', '', path) 369095567e5SJerome Forissier return path 370095567e5SJerome Forissier 371733a15f2SJerome Forissier def write(self, line): 372733a15f2SJerome Forissier if self._call_stack_found: 373733a15f2SJerome Forissier match = re.search(STACK_ADDR_RE, line) 374733a15f2SJerome Forissier if match: 375733a15f2SJerome Forissier addr = match.group('addr') 376733a15f2SJerome Forissier pre = match.start('addr') 377733a15f2SJerome Forissier post = match.end('addr') 378733a15f2SJerome Forissier self._out.write(line[:pre]) 379733a15f2SJerome Forissier self._out.write(addr) 380733a15f2SJerome Forissier res = self.resolve(addr) 381095567e5SJerome Forissier res = self.pretty_print_path(res) 382733a15f2SJerome Forissier self._out.write(' ' + res) 383733a15f2SJerome Forissier self._out.write(line[post:]) 384733a15f2SJerome Forissier return 385733a15f2SJerome Forissier else: 386733a15f2SJerome Forissier self.reset() 387c90b6663SSumit Garg if self._func_graph_found: 388c90b6663SSumit Garg match = re.search(GRAPH_ADDR_RE, line) 389c90b6663SSumit Garg match_re = re.search(GRAPH_RE, line) 390c90b6663SSumit Garg if match: 391c90b6663SSumit Garg addr = match.group('addr') 392c90b6663SSumit Garg pre = match.start('addr') 393c90b6663SSumit Garg post = match.end('addr') 394c90b6663SSumit Garg self._out.write(line[:pre]) 395c90b6663SSumit Garg res = self.resolve(addr) 396c90b6663SSumit Garg res_arr = re.split(' ', res) 397c90b6663SSumit Garg self._out.write(res_arr[0]) 398c90b6663SSumit Garg self._out.write(line[post:]) 399c90b6663SSumit Garg self._func_graph_skip_line = False 400c90b6663SSumit Garg return 401c90b6663SSumit Garg elif match_re: 402c90b6663SSumit Garg self._out.write(line) 403c90b6663SSumit Garg return 404c90b6663SSumit Garg elif self._func_graph_skip_line: 405c90b6663SSumit Garg return 406c90b6663SSumit Garg else: 407c90b6663SSumit Garg self.reset() 40830999126SJerome Forissier match = re.search(REGION_RE, line) 40930999126SJerome Forissier if match: 410ae252462SJerome Forissier # Region table: save info for later processing once 411ae252462SJerome Forissier # we know which UUID corresponds to which ELF index 41230999126SJerome Forissier addr = match.group('addr') 41330999126SJerome Forissier size = match.group('size') 414ae252462SJerome Forissier elf_idx = match.group('elf_idx') 415ae252462SJerome Forissier self._regions.append([addr, size, elf_idx, line]) 416ae252462SJerome Forissier return 417ae252462SJerome Forissier match = re.search(ELF_LIST_RE, line) 418ae252462SJerome Forissier if match: 419ae252462SJerome Forissier # ELF list: save info for later. Region table and ELF list 420ae252462SJerome Forissier # will be displayed when the call stack is reached 421ae252462SJerome Forissier i = int(match.group('idx')) 422ae252462SJerome Forissier self._elfs[i] = [match.group('uuid'), match.group('load_addr'), 423ae252462SJerome Forissier line] 42430999126SJerome Forissier return 425733a15f2SJerome Forissier match = re.search(CALL_STACK_RE, line) 426733a15f2SJerome Forissier if match: 427733a15f2SJerome Forissier self._call_stack_found = True 428ae252462SJerome Forissier if self._regions: 429ae252462SJerome Forissier for r in self._regions: 430ae252462SJerome Forissier r_addr = r[0] 431ae252462SJerome Forissier r_size = r[1] 432ae252462SJerome Forissier elf_idx = r[2] 433ae252462SJerome Forissier saved_line = r[3] 434ae252462SJerome Forissier if elf_idx is None: 435ae252462SJerome Forissier self._out.write(saved_line) 436ae252462SJerome Forissier else: 437ae252462SJerome Forissier self._out.write(saved_line.strip() + 438ae252462SJerome Forissier self.sections_in_region(r_addr, 439ae252462SJerome Forissier r_size, 440ae252462SJerome Forissier elf_idx) + 441ae252462SJerome Forissier '\n') 442ae252462SJerome Forissier if self._elfs: 443ae252462SJerome Forissier for k in self._elfs: 444ae252462SJerome Forissier e = self._elfs[k] 445ae252462SJerome Forissier if (len(e) >= 3): 4461e6f2ea0SJerome Forissier # TA executable or library 447095567e5SJerome Forissier self._out.write(e[2].strip()) 448095567e5SJerome Forissier elf = self.get_elf(e[0]) 449095567e5SJerome Forissier if elf: 450095567e5SJerome Forissier rpath = os.path.realpath(elf) 451095567e5SJerome Forissier path = self.pretty_print_path(rpath) 452095567e5SJerome Forissier self._out.write(' (' + path + ')') 453095567e5SJerome Forissier self._out.write('\n') 454142c5cccSJerome Forissier # Here is a good place to resolve the abort address because we 455142c5cccSJerome Forissier # have all the information we need 456142c5cccSJerome Forissier if self._saved_abort_line: 457142c5cccSJerome Forissier self._out.write(self.process_abort(self._saved_abort_line)) 458c90b6663SSumit Garg match = re.search(FUNC_GRAPH_RE, line) 459c90b6663SSumit Garg if match: 460c90b6663SSumit Garg self._func_graph_found = True 461142c5cccSJerome Forissier match = re.search(ABORT_ADDR_RE, line) 462142c5cccSJerome Forissier if match: 46327b83ad2SJerome Forissier self.reset() 464142c5cccSJerome Forissier # At this point the arch and TA load address are unknown. 465142c5cccSJerome Forissier # Save the line so We can translate the abort address later. 466142c5cccSJerome Forissier self._saved_abort_line = line 467733a15f2SJerome Forissier self._out.write(line) 468733a15f2SJerome Forissier 469733a15f2SJerome Forissier def flush(self): 470733a15f2SJerome Forissier self._out.flush() 471733a15f2SJerome Forissier 472ae252462SJerome Forissier 473733a15f2SJerome Forissierdef main(): 474733a15f2SJerome Forissier args = get_args() 475733a15f2SJerome Forissier if args.dir: 476733a15f2SJerome Forissier # Flatten list in case -d is used several times *and* with multiple 477733a15f2SJerome Forissier # arguments 478733a15f2SJerome Forissier args.dirs = [item for sublist in args.dir for item in sublist] 479733a15f2SJerome Forissier else: 480733a15f2SJerome Forissier args.dirs = [] 481733a15f2SJerome Forissier symbolizer = Symbolizer(sys.stdout, args.dirs, args.strip_path) 482733a15f2SJerome Forissier 4836b4fc675SJerome Forissier fd = sys.stdin.fileno() 484*20d152b8SJerome Forissier isatty = os.isatty(fd) 485*20d152b8SJerome Forissier if isatty: 4866b4fc675SJerome Forissier old = termios.tcgetattr(fd) 4876b4fc675SJerome Forissier new = termios.tcgetattr(fd) 4886b4fc675SJerome Forissier new[3] = new[3] & ~termios.ECHO # lflags 4896b4fc675SJerome Forissier try: 490*20d152b8SJerome Forissier if isatty: 4916b4fc675SJerome Forissier termios.tcsetattr(fd, termios.TCSADRAIN, new) 492733a15f2SJerome Forissier for line in sys.stdin: 493733a15f2SJerome Forissier symbolizer.write(line) 4946b4fc675SJerome Forissier finally: 495733a15f2SJerome Forissier symbolizer.flush() 496*20d152b8SJerome Forissier if isatty: 4976b4fc675SJerome Forissier termios.tcsetattr(fd, termios.TCSADRAIN, old) 498733a15f2SJerome Forissier 4991d8c2a48SJerome Forissier 500733a15f2SJerome Forissierif __name__ == "__main__": 501733a15f2SJerome Forissier main() 502