xref: /optee_os/scripts/symbolize.py (revision ba84a3f5c136f3ed3fefe782c9666928b729bb52)
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]+)')
24444c203eSJerome ForissierREGION_RE = re.compile(r'region +[0-9]+: va (?P<addr>0x[0-9a-f]+) '
256e7c2e91SJerome Forissier                       r'pa 0x[0-9a-f]+ size (?P<size>0x[0-9a-f]+)'
26531963a5SJens Wiklander                       r'( flags .{4} (\[(?P<elf_idx>[0-9]+)\])?)?')
27ae252462SJerome ForissierELF_LIST_RE = re.compile(r'\[(?P<idx>[0-9]+)\] (?P<uuid>[0-9a-f\-]+)'
286e7c2e91SJerome Forissier                         r' @ (?P<load_addr>0x[0-9a-f\-]+)')
29c90b6663SSumit GargFUNC_GRAPH_RE = re.compile(r'Function graph')
30c90b6663SSumit GargGRAPH_ADDR_RE = re.compile(r'(?P<addr>0x[0-9a-f]+)')
31c90b6663SSumit GargGRAPH_RE = re.compile(r'}')
32733a15f2SJerome Forissier
33733a15f2SJerome Forissierepilog = '''
340c5bedb5SJerome ForissierThis scripts reads an OP-TEE abort or panic message from stdin and adds debug
350c5bedb5SJerome Forissierinformation to the output, such as '<function> at <file>:<line>' next to each
360c5bedb5SJerome Forissieraddress in the call stack. Any message generated by OP-TEE and containing a
370c5bedb5SJerome Forissiercall stack can in principle be processed by this script. This currently
380c5bedb5SJerome Forissierincludes aborts and panics from the TEE core as well as from any TA.
390c5bedb5SJerome ForissierThe paths provided on the command line are used to locate the appropriate ELF
400c5bedb5SJerome Forissierbinary (tee.elf or Trusted Application). The GNU binutils (addr2line, objdump,
41f9089765SJerome Forissiernm) are used to extract the debug info. If the CROSS_COMPILE environment
42f9089765SJerome Forissiervariable is set, it is used as a prefix to the binutils tools. That is, the
43f9089765SJerome Forissierscript will invoke $(CROSS_COMPILE)addr2line etc. If it is not set however,
44f9089765SJerome Forissierthe prefix will be determined automatically for each ELF file based on its
45f9089765SJerome Forissierarchitecture (arm-linux-gnueabihf-, aarch64-linux-gnu-). The resulting command
46f9089765SJerome Forissieris then expected to be found in the user's PATH.
47733a15f2SJerome Forissier
480c5bedb5SJerome ForissierOP-TEE abort and panic messages are sent to the secure console. They look like
490c5bedb5SJerome Forissierthe following:
50733a15f2SJerome Forissier
510c5bedb5SJerome Forissier  E/TC:0 User TA data-abort at address 0xffffdecd (alignment fault)
52733a15f2SJerome Forissier  ...
530c5bedb5SJerome Forissier  E/TC:0 Call stack:
540c5bedb5SJerome Forissier  E/TC:0  0x4000549e
550c5bedb5SJerome Forissier  E/TC:0  0x40001f4b
560c5bedb5SJerome Forissier  E/TC:0  0x4000273f
570c5bedb5SJerome Forissier  E/TC:0  0x40005da7
58733a15f2SJerome Forissier
59733a15f2SJerome ForissierInspired by a script of the same name by the Chromium project.
60733a15f2SJerome Forissier
61733a15f2SJerome ForissierSample usage:
62733a15f2SJerome Forissier
63733a15f2SJerome Forissier  $ scripts/symbolize.py -d out/arm-plat-hikey/core -d ../optee_test/out/ta/*
64733a15f2SJerome Forissier  <paste whole dump here>
65733a15f2SJerome Forissier  ^D
66c90b6663SSumit Garg
67c90b6663SSumit GargAlso, this script reads function graph generated for OP-TEE user TA from
68c90b6663SSumit Garg/tmp/ftrace-<ta_uuid>.out file and resolves function addresses to corresponding
69c90b6663SSumit Gargsymbols.
70c90b6663SSumit Garg
71c90b6663SSumit GargSample usage:
72c90b6663SSumit Garg
73c90b6663SSumit Garg  $ cat /tmp/ftrace-<ta_uuid>.out | scripts/symbolize.py -d <ta_uuid>.elf
74c90b6663SSumit Garg  <paste function graph here>
75c90b6663SSumit Garg  ^D
76733a15f2SJerome Forissier'''
77733a15f2SJerome Forissier
78ae252462SJerome Forissier
79733a15f2SJerome Forissierdef get_args():
80733a15f2SJerome Forissier    parser = argparse.ArgumentParser(
81733a15f2SJerome Forissier        formatter_class=argparse.RawDescriptionHelpFormatter,
82c90b6663SSumit Garg        description='Symbolizes OP-TEE abort dumps or function graphs',
83733a15f2SJerome Forissier        epilog=epilog)
84733a15f2SJerome Forissier    parser.add_argument('-d', '--dir', action='append', nargs='+',
851d8c2a48SJerome Forissier                        help='Search for ELF file in DIR. tee.elf is needed '
861d8c2a48SJerome Forissier                        'to decode a TEE Core or pseudo-TA abort, while '
871d8c2a48SJerome Forissier                        '<TA_uuid>.elf is required if a user-mode TA has '
881d8c2a48SJerome Forissier                        'crashed. For convenience, ELF files may also be '
891d8c2a48SJerome Forissier                        'given.')
905f7df507SJerome Forissier    parser.add_argument('-s', '--strip_path', nargs='?',
911d8c2a48SJerome Forissier                        help='Strip STRIP_PATH from file paths (default: '
921d8c2a48SJerome Forissier                        'current directory, use -s with no argument to show '
931d8c2a48SJerome Forissier                        'full paths)', default=os.getcwd())
94733a15f2SJerome Forissier
95733a15f2SJerome Forissier    return parser.parse_args()
96733a15f2SJerome Forissier
97ae252462SJerome Forissier
98733a15f2SJerome Forissierclass Symbolizer(object):
99733a15f2SJerome Forissier    def __init__(self, out, dirs, strip_path):
100733a15f2SJerome Forissier        self._out = out
101733a15f2SJerome Forissier        self._dirs = dirs
102733a15f2SJerome Forissier        self._strip_path = strip_path
103733a15f2SJerome Forissier        self._addr2line = None
104733a15f2SJerome Forissier        self.reset()
105733a15f2SJerome Forissier
1061cbf777bSJerome Forissier    def my_Popen(self, cmd):
1071cbf777bSJerome Forissier        try:
1081cbf777bSJerome Forissier            return subprocess.Popen(cmd, stdin=subprocess.PIPE,
10917be223aSJerome Forissier                                    stdout=subprocess.PIPE,
11017be223aSJerome Forissier                                    universal_newlines=True,
111bbaeed4dSRouven Czerwinski                                    bufsize=1)
1121cbf777bSJerome Forissier        except OSError as e:
113bbaeed4dSRouven Czerwinski            if e.errno == errno.ENOENT:
114bbaeed4dSRouven Czerwinski                print("*** Error:{}: command not found".format(cmd[0]),
115bbaeed4dSRouven Czerwinski                      file=sys.stderr)
1161cbf777bSJerome Forissier                sys.exit(1)
1171cbf777bSJerome Forissier
118733a15f2SJerome Forissier    def get_elf(self, elf_or_uuid):
119733a15f2SJerome Forissier        if not elf_or_uuid.endswith('.elf'):
120733a15f2SJerome Forissier            elf_or_uuid += '.elf'
121733a15f2SJerome Forissier        for d in self._dirs:
122157e6213SJerome Forissier            if d.endswith(elf_or_uuid) and os.path.isfile(d):
123157e6213SJerome Forissier                return d
124733a15f2SJerome Forissier            elf = glob.glob(d + '/' + elf_or_uuid)
125733a15f2SJerome Forissier            if elf:
126733a15f2SJerome Forissier                return elf[0]
127733a15f2SJerome Forissier
128d720431cSJerome Forissier    def set_arch(self):
129d720431cSJerome Forissier        if self._arch:
130d720431cSJerome Forissier            return
1316e7c2e91SJerome Forissier        self._arch = os.getenv('CROSS_COMPILE')
1328a6d4a8bSEtienne Carriere        if self._arch:
1338a6d4a8bSEtienne Carriere            return
134ae252462SJerome Forissier        elf = self.get_elf(self._elfs[0][0])
135ae252462SJerome Forissier        if elf is None:
136ae252462SJerome Forissier            return
137ae252462SJerome Forissier        p = subprocess.Popen(['file', self.get_elf(self._elfs[0][0])],
138d720431cSJerome Forissier                             stdout=subprocess.PIPE)
139d720431cSJerome Forissier        output = p.stdout.readlines()
140d720431cSJerome Forissier        p.terminate()
141bbaeed4dSRouven Czerwinski        if b'ARM aarch64,' in output[0]:
142d720431cSJerome Forissier            self._arch = 'aarch64-linux-gnu-'
143bbaeed4dSRouven Czerwinski        elif b'ARM,' in output[0]:
144d720431cSJerome Forissier            self._arch = 'arm-linux-gnueabihf-'
145d720431cSJerome Forissier
146142c5cccSJerome Forissier    def arch_prefix(self, cmd):
147d720431cSJerome Forissier        self.set_arch()
148ae252462SJerome Forissier        if self._arch is None:
149ae252462SJerome Forissier            return ''
150d720431cSJerome Forissier        return self._arch + cmd
151142c5cccSJerome Forissier
152ae252462SJerome Forissier    def spawn_addr2line(self, elf_name):
153ae252462SJerome Forissier        if elf_name is None:
154ae252462SJerome Forissier            return
155ae252462SJerome Forissier        if self._addr2line_elf_name is elf_name:
156ae252462SJerome Forissier            return
157ae252462SJerome Forissier        if self._addr2line:
158ae252462SJerome Forissier            self._addr2line.terminate
159ae252462SJerome Forissier            self._addr2line = None
160ae252462SJerome Forissier        elf = self.get_elf(elf_name)
161733a15f2SJerome Forissier        if not elf:
162733a15f2SJerome Forissier            return
163142c5cccSJerome Forissier        cmd = self.arch_prefix('addr2line')
164142c5cccSJerome Forissier        if not cmd:
165733a15f2SJerome Forissier            return
166c0c57c8fSJerome Forissier        self._addr2line = self.my_Popen([cmd, '-f', '-p', '-e', elf])
167*ba84a3f5SJerome Forissier        self._addr2line_elf_name = elf_name
168ae252462SJerome Forissier
169ae252462SJerome Forissier    # If addr falls into a region that maps a TA ELF file, return the load
170ae252462SJerome Forissier    # address of that file.
171ae252462SJerome Forissier    def elf_load_addr(self, addr):
172ae252462SJerome Forissier        if self._regions:
173ae252462SJerome Forissier            for r in self._regions:
174ae252462SJerome Forissier                r_addr = int(r[0], 16)
175ae252462SJerome Forissier                r_size = int(r[1], 16)
176ae252462SJerome Forissier                i_addr = int(addr, 16)
177ae252462SJerome Forissier                if (i_addr >= r_addr and i_addr < (r_addr + r_size)):
178ae252462SJerome Forissier                    # Found region
179ae252462SJerome Forissier                    elf_idx = r[2]
180ae252462SJerome Forissier                    if elf_idx is not None:
181ae252462SJerome Forissier                        return self._elfs[int(elf_idx)][1]
182099918f6SSumit Garg            # In case address is not found in TA ELF file, fallback to tee.elf
183099918f6SSumit Garg            # especially to symbolize mixed (user-space and kernel) addresses
184099918f6SSumit Garg            # which is true when syscall ftrace is enabled along with TA
185099918f6SSumit Garg            # ftrace.
18691068f86SJerome Forissier            return self._tee_load_addr
187ae252462SJerome Forissier        else:
188ae252462SJerome Forissier            # tee.elf
189105e09c2SJerome Forissier            return self._tee_load_addr
190ae252462SJerome Forissier
191ae252462SJerome Forissier    def elf_for_addr(self, addr):
192ae252462SJerome Forissier        l_addr = self.elf_load_addr(addr)
19391068f86SJerome Forissier        if l_addr == self._tee_load_addr:
19491068f86SJerome Forissier            return 'tee.elf'
195ae252462SJerome Forissier        for k in self._elfs:
196ae252462SJerome Forissier            e = self._elfs[k]
197ae252462SJerome Forissier            if int(e[1], 16) == int(l_addr, 16):
198ae252462SJerome Forissier                return e[0]
199ae252462SJerome Forissier        return None
200733a15f2SJerome Forissier
201142c5cccSJerome Forissier    def subtract_load_addr(self, addr):
202ae252462SJerome Forissier        l_addr = self.elf_load_addr(addr)
203ae252462SJerome Forissier        if l_addr is None:
204ae252462SJerome Forissier            return None
205ae252462SJerome Forissier        if int(l_addr, 16) > int(addr, 16):
206142c5cccSJerome Forissier            return ''
207ae252462SJerome Forissier        return '0x{:x}'.format(int(addr, 16) - int(l_addr, 16))
208142c5cccSJerome Forissier
209142c5cccSJerome Forissier    def resolve(self, addr):
210142c5cccSJerome Forissier        reladdr = self.subtract_load_addr(addr)
211ae252462SJerome Forissier        self.spawn_addr2line(self.elf_for_addr(addr))
212142c5cccSJerome Forissier        if not reladdr or not self._addr2line:
213733a15f2SJerome Forissier            return '???'
214c0c57c8fSJerome Forissier        if self.elf_for_addr(addr) == 'tee.elf':
215c0c57c8fSJerome Forissier            reladdr = '0x{:x}'.format(int(reladdr, 16) +
216c0c57c8fSJerome Forissier                                      int(self.first_vma('tee.elf'), 16))
217733a15f2SJerome Forissier        try:
218bbaeed4dSRouven Czerwinski            print(reladdr, file=self._addr2line.stdin)
219733a15f2SJerome Forissier            ret = self._addr2line.stdout.readline().rstrip('\n')
220733a15f2SJerome Forissier        except IOError:
221733a15f2SJerome Forissier            ret = '!!!'
222733a15f2SJerome Forissier        return ret
223733a15f2SJerome Forissier
224142c5cccSJerome Forissier    def symbol_plus_offset(self, addr):
225142c5cccSJerome Forissier        ret = ''
226142c5cccSJerome Forissier        prevsize = 0
227142c5cccSJerome Forissier        reladdr = self.subtract_load_addr(addr)
228ae252462SJerome Forissier        elf_name = self.elf_for_addr(addr)
229ae252462SJerome Forissier        if elf_name is None:
230ae252462SJerome Forissier            return ''
231ae252462SJerome Forissier        elf = self.get_elf(elf_name)
232142c5cccSJerome Forissier        cmd = self.arch_prefix('nm')
233142c5cccSJerome Forissier        if not reladdr or not elf or not cmd:
234142c5cccSJerome Forissier            return ''
23530999126SJerome Forissier        ireladdr = int(reladdr, 16)
2361cbf777bSJerome Forissier        nm = self.my_Popen([cmd, '--numeric-sort', '--print-size', elf])
237142c5cccSJerome Forissier        for line in iter(nm.stdout.readline, ''):
238142c5cccSJerome Forissier            try:
239142c5cccSJerome Forissier                addr, size, _, name = line.split()
2401d8c2a48SJerome Forissier            except ValueError:
241142c5cccSJerome Forissier                # Size is missing
242b4815427SJerome Forissier                try:
243142c5cccSJerome Forissier                    addr, _, name = line.split()
244142c5cccSJerome Forissier                    size = '0'
2451d8c2a48SJerome Forissier                except ValueError:
246b4815427SJerome Forissier                    # E.g., undefined (external) symbols (line = "U symbol")
247b4815427SJerome Forissier                    continue
248142c5cccSJerome Forissier            iaddr = int(addr, 16)
249142c5cccSJerome Forissier            isize = int(size, 16)
250142c5cccSJerome Forissier            if iaddr == ireladdr:
251142c5cccSJerome Forissier                ret = name
252142c5cccSJerome Forissier                break
253142c5cccSJerome Forissier            if iaddr < ireladdr and iaddr + isize >= ireladdr:
254142c5cccSJerome Forissier                offs = ireladdr - iaddr
255142c5cccSJerome Forissier                ret = name + '+' + str(offs)
256142c5cccSJerome Forissier                break
257142c5cccSJerome Forissier            if iaddr > ireladdr and prevsize == 0:
258142c5cccSJerome Forissier                offs = iaddr + ireladdr
259142c5cccSJerome Forissier                ret = prevname + '+' + str(offs)
260142c5cccSJerome Forissier                break
261142c5cccSJerome Forissier            prevsize = size
262142c5cccSJerome Forissier            prevname = name
263142c5cccSJerome Forissier        nm.terminate()
264142c5cccSJerome Forissier        return ret
265142c5cccSJerome Forissier
266142c5cccSJerome Forissier    def section_plus_offset(self, addr):
267142c5cccSJerome Forissier        ret = ''
268142c5cccSJerome Forissier        reladdr = self.subtract_load_addr(addr)
269ae252462SJerome Forissier        elf_name = self.elf_for_addr(addr)
270ae252462SJerome Forissier        if elf_name is None:
271ae252462SJerome Forissier            return ''
272ae252462SJerome Forissier        elf = self.get_elf(elf_name)
273142c5cccSJerome Forissier        cmd = self.arch_prefix('objdump')
274142c5cccSJerome Forissier        if not reladdr or not elf or not cmd:
275142c5cccSJerome Forissier            return ''
27630999126SJerome Forissier        iaddr = int(reladdr, 16)
2771cbf777bSJerome Forissier        objdump = self.my_Popen([cmd, '--section-headers', elf])
278142c5cccSJerome Forissier        for line in iter(objdump.stdout.readline, ''):
279142c5cccSJerome Forissier            try:
280142c5cccSJerome Forissier                idx, name, size, vma, lma, offs, algn = line.split()
2811d8c2a48SJerome Forissier            except ValueError:
282ae252462SJerome Forissier                continue
283142c5cccSJerome Forissier            ivma = int(vma, 16)
284142c5cccSJerome Forissier            isize = int(size, 16)
285142c5cccSJerome Forissier            if ivma == iaddr:
286142c5cccSJerome Forissier                ret = name
287142c5cccSJerome Forissier                break
288142c5cccSJerome Forissier            if ivma < iaddr and ivma + isize >= iaddr:
289142c5cccSJerome Forissier                offs = iaddr - ivma
290142c5cccSJerome Forissier                ret = name + '+' + str(offs)
291142c5cccSJerome Forissier                break
292142c5cccSJerome Forissier        objdump.terminate()
293142c5cccSJerome Forissier        return ret
294142c5cccSJerome Forissier
295142c5cccSJerome Forissier    def process_abort(self, line):
296142c5cccSJerome Forissier        ret = ''
297142c5cccSJerome Forissier        match = re.search(ABORT_ADDR_RE, line)
298142c5cccSJerome Forissier        addr = match.group('addr')
299142c5cccSJerome Forissier        pre = match.start('addr')
300142c5cccSJerome Forissier        post = match.end('addr')
301142c5cccSJerome Forissier        sym = self.symbol_plus_offset(addr)
302142c5cccSJerome Forissier        sec = self.section_plus_offset(addr)
303142c5cccSJerome Forissier        if sym or sec:
304142c5cccSJerome Forissier            ret += line[:pre]
305142c5cccSJerome Forissier            ret += addr
306142c5cccSJerome Forissier            if sym:
307142c5cccSJerome Forissier                ret += ' ' + sym
308142c5cccSJerome Forissier            if sec:
309142c5cccSJerome Forissier                ret += ' ' + sec
310142c5cccSJerome Forissier            ret += line[post:]
311142c5cccSJerome Forissier        return ret
312142c5cccSJerome Forissier
31330999126SJerome Forissier    # Return all ELF sections with the ALLOC flag
314ae252462SJerome Forissier    def read_sections(self, elf_name):
315ae252462SJerome Forissier        if elf_name is None:
31630999126SJerome Forissier            return
317ae252462SJerome Forissier        if elf_name in self._sections:
318ae252462SJerome Forissier            return
319ae252462SJerome Forissier        elf = self.get_elf(elf_name)
32030999126SJerome Forissier        cmd = self.arch_prefix('objdump')
32130999126SJerome Forissier        if not elf or not cmd:
32230999126SJerome Forissier            return
323ae252462SJerome Forissier        self._sections[elf_name] = []
3241cbf777bSJerome Forissier        objdump = self.my_Popen([cmd, '--section-headers', elf])
32530999126SJerome Forissier        for line in iter(objdump.stdout.readline, ''):
32630999126SJerome Forissier            try:
32730999126SJerome Forissier                _, name, size, vma, _, _, _ = line.split()
3281d8c2a48SJerome Forissier            except ValueError:
32930999126SJerome Forissier                if 'ALLOC' in line:
330ae252462SJerome Forissier                    self._sections[elf_name].append([name, int(vma, 16),
331ae252462SJerome Forissier                                                     int(size, 16)])
33230999126SJerome Forissier
333c0c57c8fSJerome Forissier    def first_vma(self, elf_name):
334c0c57c8fSJerome Forissier        self.read_sections(elf_name)
335c0c57c8fSJerome Forissier        return '0x{:x}'.format(self._sections[elf_name][0][1])
336c0c57c8fSJerome Forissier
33730999126SJerome Forissier    def overlaps(self, section, addr, size):
33830999126SJerome Forissier        sec_addr = section[1]
33930999126SJerome Forissier        sec_size = section[2]
34030999126SJerome Forissier        if not size or not sec_size:
34130999126SJerome Forissier            return False
342ae252462SJerome Forissier        return ((addr <= (sec_addr + sec_size - 1)) and
343ae252462SJerome Forissier                ((addr + size - 1) >= sec_addr))
34430999126SJerome Forissier
345ae252462SJerome Forissier    def sections_in_region(self, addr, size, elf_idx):
34630999126SJerome Forissier        ret = ''
34730999126SJerome Forissier        addr = self.subtract_load_addr(addr)
34830999126SJerome Forissier        if not addr:
34930999126SJerome Forissier            return ''
35030999126SJerome Forissier        iaddr = int(addr, 16)
35130999126SJerome Forissier        isize = int(size, 16)
352ae252462SJerome Forissier        elf = self._elfs[int(elf_idx)][0]
353ae252462SJerome Forissier        if elf is None:
354ae252462SJerome Forissier            return ''
355ae252462SJerome Forissier        self.read_sections(elf)
356ae252462SJerome Forissier        if elf not in self._sections:
357ae252462SJerome Forissier            return ''
358ae252462SJerome Forissier        for s in self._sections[elf]:
35930999126SJerome Forissier            if self.overlaps(s, iaddr, isize):
36030999126SJerome Forissier                ret += ' ' + s[0]
36130999126SJerome Forissier        return ret
36230999126SJerome Forissier
363733a15f2SJerome Forissier    def reset(self):
364733a15f2SJerome Forissier        self._call_stack_found = False
365733a15f2SJerome Forissier        if self._addr2line:
366733a15f2SJerome Forissier            self._addr2line.terminate()
367733a15f2SJerome Forissier            self._addr2line = None
368ae252462SJerome Forissier        self._addr2line_elf_name = None
369d720431cSJerome Forissier        self._arch = None
370142c5cccSJerome Forissier        self._saved_abort_line = ''
371ae252462SJerome Forissier        self._sections = {}  # {elf_name: [[name, addr, size], ...], ...}
372ae252462SJerome Forissier        self._regions = []   # [[addr, size, elf_idx, saved line], ...]
373ae252462SJerome Forissier        self._elfs = {0: ["tee.elf", 0]}  # {idx: [uuid, load_addr], ...}
37491068f86SJerome Forissier        self._tee_load_addr = '0x0'
375c90b6663SSumit Garg        self._func_graph_found = False
376c90b6663SSumit Garg        self._func_graph_skip_line = True
377733a15f2SJerome Forissier
378095567e5SJerome Forissier    def pretty_print_path(self, path):
379095567e5SJerome Forissier        if self._strip_path:
380095567e5SJerome Forissier            return re.sub(re.escape(self._strip_path) + '/*', '', path)
381095567e5SJerome Forissier        return path
382095567e5SJerome Forissier
383733a15f2SJerome Forissier    def write(self, line):
384733a15f2SJerome Forissier        if self._call_stack_found:
385733a15f2SJerome Forissier            match = re.search(STACK_ADDR_RE, line)
386733a15f2SJerome Forissier            if match:
387733a15f2SJerome Forissier                addr = match.group('addr')
388733a15f2SJerome Forissier                pre = match.start('addr')
389733a15f2SJerome Forissier                post = match.end('addr')
390733a15f2SJerome Forissier                self._out.write(line[:pre])
391733a15f2SJerome Forissier                self._out.write(addr)
392733a15f2SJerome Forissier                res = self.resolve(addr)
393095567e5SJerome Forissier                res = self.pretty_print_path(res)
394733a15f2SJerome Forissier                self._out.write(' ' + res)
395733a15f2SJerome Forissier                self._out.write(line[post:])
396733a15f2SJerome Forissier                return
397733a15f2SJerome Forissier            else:
398733a15f2SJerome Forissier                self.reset()
399c90b6663SSumit Garg        if self._func_graph_found:
400c90b6663SSumit Garg            match = re.search(GRAPH_ADDR_RE, line)
401c90b6663SSumit Garg            match_re = re.search(GRAPH_RE, line)
402c90b6663SSumit Garg            if match:
403c90b6663SSumit Garg                addr = match.group('addr')
404c90b6663SSumit Garg                pre = match.start('addr')
405c90b6663SSumit Garg                post = match.end('addr')
406c90b6663SSumit Garg                self._out.write(line[:pre])
407c90b6663SSumit Garg                res = self.resolve(addr)
408c90b6663SSumit Garg                res_arr = re.split(' ', res)
409c90b6663SSumit Garg                self._out.write(res_arr[0])
410c90b6663SSumit Garg                self._out.write(line[post:])
411c90b6663SSumit Garg                self._func_graph_skip_line = False
412c90b6663SSumit Garg                return
413c90b6663SSumit Garg            elif match_re:
414c90b6663SSumit Garg                self._out.write(line)
415c90b6663SSumit Garg                return
416c90b6663SSumit Garg            elif self._func_graph_skip_line:
417c90b6663SSumit Garg                return
418c90b6663SSumit Garg            else:
419c90b6663SSumit Garg                self.reset()
42030999126SJerome Forissier        match = re.search(REGION_RE, line)
42130999126SJerome Forissier        if match:
422ae252462SJerome Forissier            # Region table: save info for later processing once
423ae252462SJerome Forissier            # we know which UUID corresponds to which ELF index
42430999126SJerome Forissier            addr = match.group('addr')
42530999126SJerome Forissier            size = match.group('size')
426ae252462SJerome Forissier            elf_idx = match.group('elf_idx')
427ae252462SJerome Forissier            self._regions.append([addr, size, elf_idx, line])
428ae252462SJerome Forissier            return
429ae252462SJerome Forissier        match = re.search(ELF_LIST_RE, line)
430ae252462SJerome Forissier        if match:
431ae252462SJerome Forissier            # ELF list: save info for later. Region table and ELF list
432ae252462SJerome Forissier            # will be displayed when the call stack is reached
433ae252462SJerome Forissier            i = int(match.group('idx'))
434ae252462SJerome Forissier            self._elfs[i] = [match.group('uuid'), match.group('load_addr'),
435ae252462SJerome Forissier                             line]
43630999126SJerome Forissier            return
437105e09c2SJerome Forissier        match = re.search(TEE_LOAD_ADDR_RE, line)
438105e09c2SJerome Forissier        if match:
439105e09c2SJerome Forissier            self._tee_load_addr = match.group('load_addr')
440733a15f2SJerome Forissier        match = re.search(CALL_STACK_RE, line)
441733a15f2SJerome Forissier        if match:
442733a15f2SJerome Forissier            self._call_stack_found = True
443ae252462SJerome Forissier            if self._regions:
444ae252462SJerome Forissier                for r in self._regions:
445ae252462SJerome Forissier                    r_addr = r[0]
446ae252462SJerome Forissier                    r_size = r[1]
447ae252462SJerome Forissier                    elf_idx = r[2]
448ae252462SJerome Forissier                    saved_line = r[3]
449ae252462SJerome Forissier                    if elf_idx is None:
450ae252462SJerome Forissier                        self._out.write(saved_line)
451ae252462SJerome Forissier                    else:
452ae252462SJerome Forissier                        self._out.write(saved_line.strip() +
453ae252462SJerome Forissier                                        self.sections_in_region(r_addr,
454ae252462SJerome Forissier                                                                r_size,
455ae252462SJerome Forissier                                                                elf_idx) +
456ae252462SJerome Forissier                                        '\n')
457ae252462SJerome Forissier            if self._elfs:
458ae252462SJerome Forissier                for k in self._elfs:
459ae252462SJerome Forissier                    e = self._elfs[k]
460ae252462SJerome Forissier                    if (len(e) >= 3):
4611e6f2ea0SJerome Forissier                        # TA executable or library
462095567e5SJerome Forissier                        self._out.write(e[2].strip())
463095567e5SJerome Forissier                        elf = self.get_elf(e[0])
464095567e5SJerome Forissier                        if elf:
465095567e5SJerome Forissier                            rpath = os.path.realpath(elf)
466095567e5SJerome Forissier                            path = self.pretty_print_path(rpath)
467095567e5SJerome Forissier                            self._out.write(' (' + path + ')')
468095567e5SJerome Forissier                        self._out.write('\n')
469142c5cccSJerome Forissier            # Here is a good place to resolve the abort address because we
470142c5cccSJerome Forissier            # have all the information we need
471142c5cccSJerome Forissier            if self._saved_abort_line:
472142c5cccSJerome Forissier                self._out.write(self.process_abort(self._saved_abort_line))
473c90b6663SSumit Garg        match = re.search(FUNC_GRAPH_RE, line)
474c90b6663SSumit Garg        if match:
475c90b6663SSumit Garg            self._func_graph_found = True
476142c5cccSJerome Forissier        match = re.search(ABORT_ADDR_RE, line)
477142c5cccSJerome Forissier        if match:
47827b83ad2SJerome Forissier            self.reset()
479142c5cccSJerome Forissier            # At this point the arch and TA load address are unknown.
480142c5cccSJerome Forissier            # Save the line so We can translate the abort address later.
481142c5cccSJerome Forissier            self._saved_abort_line = line
482733a15f2SJerome Forissier        self._out.write(line)
483733a15f2SJerome Forissier
484733a15f2SJerome Forissier    def flush(self):
485733a15f2SJerome Forissier        self._out.flush()
486733a15f2SJerome Forissier
487ae252462SJerome Forissier
488733a15f2SJerome Forissierdef main():
489733a15f2SJerome Forissier    args = get_args()
490733a15f2SJerome Forissier    if args.dir:
491733a15f2SJerome Forissier        # Flatten list in case -d is used several times *and* with multiple
492733a15f2SJerome Forissier        # arguments
493733a15f2SJerome Forissier        args.dirs = [item for sublist in args.dir for item in sublist]
494733a15f2SJerome Forissier    else:
495733a15f2SJerome Forissier        args.dirs = []
496733a15f2SJerome Forissier    symbolizer = Symbolizer(sys.stdout, args.dirs, args.strip_path)
497733a15f2SJerome Forissier
4986b4fc675SJerome Forissier    fd = sys.stdin.fileno()
49920d152b8SJerome Forissier    isatty = os.isatty(fd)
50020d152b8SJerome Forissier    if isatty:
5016b4fc675SJerome Forissier        old = termios.tcgetattr(fd)
5026b4fc675SJerome Forissier        new = termios.tcgetattr(fd)
5036b4fc675SJerome Forissier        new[3] = new[3] & ~termios.ECHO  # lflags
5046b4fc675SJerome Forissier    try:
50520d152b8SJerome Forissier        if isatty:
5066b4fc675SJerome Forissier            termios.tcsetattr(fd, termios.TCSADRAIN, new)
507733a15f2SJerome Forissier        for line in sys.stdin:
508733a15f2SJerome Forissier            symbolizer.write(line)
5096b4fc675SJerome Forissier    finally:
510733a15f2SJerome Forissier        symbolizer.flush()
51120d152b8SJerome Forissier        if isatty:
5126b4fc675SJerome Forissier            termios.tcsetattr(fd, termios.TCSADRAIN, old)
513733a15f2SJerome Forissier
5141d8c2a48SJerome Forissier
515733a15f2SJerome Forissierif __name__ == "__main__":
516733a15f2SJerome Forissier    main()
517