xref: /optee_os/scripts/symbolize.py (revision bbaeed4dc6258006e846543197b8aff95d80abbf)
1*bbaeed4dSRouven 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
9*bbaeed4dSRouven Czerwinskiimport errno
10733a15f2SJerome Forissierimport glob
11157e6213SJerome Forissierimport os
12733a15f2SJerome Forissierimport re
13733a15f2SJerome Forissierimport subprocess
14733a15f2SJerome Forissierimport sys
15733a15f2SJerome Forissier
16733a15f2SJerome ForissierCALL_STACK_RE = re.compile('Call stack:')
17a2b984bdSJoakim Bech# This gets the address from lines looking like this:
18a2b984bdSJoakim Bech# E/TC:0  0x001044a8
196e7c2e91SJerome ForissierSTACK_ADDR_RE = re.compile(
20531963a5SJens Wiklander    r'[UEIDFM]/(TC|LD):(\?*|[0-9]*) [0-9]* +(?P<addr>0x[0-9a-f]+)')
216e7c2e91SJerome ForissierABORT_ADDR_RE = re.compile(r'-abort at address (?P<addr>0x[0-9a-f]+)')
22444c203eSJerome ForissierREGION_RE = re.compile(r'region +[0-9]+: va (?P<addr>0x[0-9a-f]+) '
236e7c2e91SJerome Forissier                       r'pa 0x[0-9a-f]+ size (?P<size>0x[0-9a-f]+)'
24531963a5SJens Wiklander                       r'( flags .{4} (\[(?P<elf_idx>[0-9]+)\])?)?')
25ae252462SJerome ForissierELF_LIST_RE = re.compile(r'\[(?P<idx>[0-9]+)\] (?P<uuid>[0-9a-f\-]+)'
266e7c2e91SJerome Forissier                         r' @ (?P<load_addr>0x[0-9a-f\-]+)')
27c90b6663SSumit GargFUNC_GRAPH_RE = re.compile(r'Function graph')
28c90b6663SSumit GargGRAPH_ADDR_RE = re.compile(r'(?P<addr>0x[0-9a-f]+)')
29c90b6663SSumit GargGRAPH_RE = re.compile(r'}')
30733a15f2SJerome Forissier
31733a15f2SJerome Forissierepilog = '''
320c5bedb5SJerome ForissierThis scripts reads an OP-TEE abort or panic message from stdin and adds debug
330c5bedb5SJerome Forissierinformation to the output, such as '<function> at <file>:<line>' next to each
340c5bedb5SJerome Forissieraddress in the call stack. Any message generated by OP-TEE and containing a
350c5bedb5SJerome Forissiercall stack can in principle be processed by this script. This currently
360c5bedb5SJerome Forissierincludes aborts and panics from the TEE core as well as from any TA.
370c5bedb5SJerome ForissierThe paths provided on the command line are used to locate the appropriate ELF
380c5bedb5SJerome Forissierbinary (tee.elf or Trusted Application). The GNU binutils (addr2line, objdump,
39f9089765SJerome Forissiernm) are used to extract the debug info. If the CROSS_COMPILE environment
40f9089765SJerome Forissiervariable is set, it is used as a prefix to the binutils tools. That is, the
41f9089765SJerome Forissierscript will invoke $(CROSS_COMPILE)addr2line etc. If it is not set however,
42f9089765SJerome Forissierthe prefix will be determined automatically for each ELF file based on its
43f9089765SJerome Forissierarchitecture (arm-linux-gnueabihf-, aarch64-linux-gnu-). The resulting command
44f9089765SJerome Forissieris then expected to be found in the user's PATH.
45733a15f2SJerome Forissier
460c5bedb5SJerome ForissierOP-TEE abort and panic messages are sent to the secure console. They look like
470c5bedb5SJerome Forissierthe following:
48733a15f2SJerome Forissier
490c5bedb5SJerome Forissier  E/TC:0 User TA data-abort at address 0xffffdecd (alignment fault)
50733a15f2SJerome Forissier  ...
510c5bedb5SJerome Forissier  E/TC:0 Call stack:
520c5bedb5SJerome Forissier  E/TC:0  0x4000549e
530c5bedb5SJerome Forissier  E/TC:0  0x40001f4b
540c5bedb5SJerome Forissier  E/TC:0  0x4000273f
550c5bedb5SJerome Forissier  E/TC:0  0x40005da7
56733a15f2SJerome Forissier
57733a15f2SJerome ForissierInspired by a script of the same name by the Chromium project.
58733a15f2SJerome Forissier
59733a15f2SJerome ForissierSample usage:
60733a15f2SJerome Forissier
61733a15f2SJerome Forissier  $ scripts/symbolize.py -d out/arm-plat-hikey/core -d ../optee_test/out/ta/*
62733a15f2SJerome Forissier  <paste whole dump here>
63733a15f2SJerome Forissier  ^D
64c90b6663SSumit Garg
65c90b6663SSumit GargAlso, this script reads function graph generated for OP-TEE user TA from
66c90b6663SSumit Garg/tmp/ftrace-<ta_uuid>.out file and resolves function addresses to corresponding
67c90b6663SSumit Gargsymbols.
68c90b6663SSumit Garg
69c90b6663SSumit GargSample usage:
70c90b6663SSumit Garg
71c90b6663SSumit Garg  $ cat /tmp/ftrace-<ta_uuid>.out | scripts/symbolize.py -d <ta_uuid>.elf
72c90b6663SSumit Garg  <paste function graph here>
73c90b6663SSumit Garg  ^D
74733a15f2SJerome Forissier'''
75733a15f2SJerome Forissier
76ae252462SJerome Forissier
77733a15f2SJerome Forissierdef get_args():
78733a15f2SJerome Forissier    parser = argparse.ArgumentParser(
79733a15f2SJerome Forissier        formatter_class=argparse.RawDescriptionHelpFormatter,
80c90b6663SSumit Garg        description='Symbolizes OP-TEE abort dumps or function graphs',
81733a15f2SJerome Forissier        epilog=epilog)
82733a15f2SJerome Forissier    parser.add_argument('-d', '--dir', action='append', nargs='+',
831d8c2a48SJerome Forissier                        help='Search for ELF file in DIR. tee.elf is needed '
841d8c2a48SJerome Forissier                        'to decode a TEE Core or pseudo-TA abort, while '
851d8c2a48SJerome Forissier                        '<TA_uuid>.elf is required if a user-mode TA has '
861d8c2a48SJerome Forissier                        'crashed. For convenience, ELF files may also be '
871d8c2a48SJerome Forissier                        'given.')
885f7df507SJerome Forissier    parser.add_argument('-s', '--strip_path', nargs='?',
891d8c2a48SJerome Forissier                        help='Strip STRIP_PATH from file paths (default: '
901d8c2a48SJerome Forissier                        'current directory, use -s with no argument to show '
911d8c2a48SJerome Forissier                        'full paths)', default=os.getcwd())
92733a15f2SJerome Forissier
93733a15f2SJerome Forissier    return parser.parse_args()
94733a15f2SJerome Forissier
95ae252462SJerome Forissier
96733a15f2SJerome Forissierclass Symbolizer(object):
97733a15f2SJerome Forissier    def __init__(self, out, dirs, strip_path):
98733a15f2SJerome Forissier        self._out = out
99733a15f2SJerome Forissier        self._dirs = dirs
100733a15f2SJerome Forissier        self._strip_path = strip_path
101733a15f2SJerome Forissier        self._addr2line = None
102733a15f2SJerome Forissier        self.reset()
103733a15f2SJerome Forissier
1041cbf777bSJerome Forissier    def my_Popen(self, cmd):
1051cbf777bSJerome Forissier        try:
1061cbf777bSJerome Forissier            return subprocess.Popen(cmd, stdin=subprocess.PIPE,
107*bbaeed4dSRouven Czerwinski                                    stdout=subprocess.PIPE, text=True,
108*bbaeed4dSRouven Czerwinski                                    bufsize=1)
1091cbf777bSJerome Forissier        except OSError as e:
110*bbaeed4dSRouven Czerwinski            if e.errno == errno.ENOENT:
111*bbaeed4dSRouven Czerwinski                print("*** Error:{}: command not found".format(cmd[0]),
112*bbaeed4dSRouven Czerwinski                      file=sys.stderr)
1131cbf777bSJerome Forissier                sys.exit(1)
1141cbf777bSJerome Forissier
115733a15f2SJerome Forissier    def get_elf(self, elf_or_uuid):
116733a15f2SJerome Forissier        if not elf_or_uuid.endswith('.elf'):
117733a15f2SJerome Forissier            elf_or_uuid += '.elf'
118733a15f2SJerome Forissier        for d in self._dirs:
119157e6213SJerome Forissier            if d.endswith(elf_or_uuid) and os.path.isfile(d):
120157e6213SJerome Forissier                return d
121733a15f2SJerome Forissier            elf = glob.glob(d + '/' + elf_or_uuid)
122733a15f2SJerome Forissier            if elf:
123733a15f2SJerome Forissier                return elf[0]
124733a15f2SJerome Forissier
125d720431cSJerome Forissier    def set_arch(self):
126d720431cSJerome Forissier        if self._arch:
127d720431cSJerome Forissier            return
1286e7c2e91SJerome Forissier        self._arch = os.getenv('CROSS_COMPILE')
1298a6d4a8bSEtienne Carriere        if self._arch:
1308a6d4a8bSEtienne Carriere            return
131ae252462SJerome Forissier        elf = self.get_elf(self._elfs[0][0])
132ae252462SJerome Forissier        if elf is None:
133ae252462SJerome Forissier            return
134ae252462SJerome Forissier        p = subprocess.Popen(['file', self.get_elf(self._elfs[0][0])],
135d720431cSJerome Forissier                             stdout=subprocess.PIPE)
136d720431cSJerome Forissier        output = p.stdout.readlines()
137d720431cSJerome Forissier        p.terminate()
138*bbaeed4dSRouven Czerwinski        if b'ARM aarch64,' in output[0]:
139d720431cSJerome Forissier            self._arch = 'aarch64-linux-gnu-'
140*bbaeed4dSRouven Czerwinski        elif b'ARM,' in output[0]:
141d720431cSJerome Forissier            self._arch = 'arm-linux-gnueabihf-'
142d720431cSJerome Forissier
143142c5cccSJerome Forissier    def arch_prefix(self, cmd):
144d720431cSJerome Forissier        self.set_arch()
145ae252462SJerome Forissier        if self._arch is None:
146ae252462SJerome Forissier            return ''
147d720431cSJerome Forissier        return self._arch + cmd
148142c5cccSJerome Forissier
149ae252462SJerome Forissier    def spawn_addr2line(self, elf_name):
150ae252462SJerome Forissier        if elf_name is None:
151ae252462SJerome Forissier            return
152ae252462SJerome Forissier        if self._addr2line_elf_name is elf_name:
153ae252462SJerome Forissier            return
154ae252462SJerome Forissier        if self._addr2line:
155ae252462SJerome Forissier            self._addr2line.terminate
156ae252462SJerome Forissier            self._addr2line = None
157ae252462SJerome Forissier        elf = self.get_elf(elf_name)
158733a15f2SJerome Forissier        if not elf:
159733a15f2SJerome Forissier            return
160142c5cccSJerome Forissier        cmd = self.arch_prefix('addr2line')
161142c5cccSJerome Forissier        if not cmd:
162733a15f2SJerome Forissier            return
1631cbf777bSJerome Forissier        self._addr2line = self.my_Popen([cmd, '-f', '-p', '-e', elf])
164ae252462SJerome Forissier        self._addr2line_elf_name = elf_name
165ae252462SJerome Forissier
166ae252462SJerome Forissier    # If addr falls into a region that maps a TA ELF file, return the load
167ae252462SJerome Forissier    # address of that file.
168ae252462SJerome Forissier    def elf_load_addr(self, addr):
169ae252462SJerome Forissier        if self._regions:
170ae252462SJerome Forissier            for r in self._regions:
171ae252462SJerome Forissier                r_addr = int(r[0], 16)
172ae252462SJerome Forissier                r_size = int(r[1], 16)
173ae252462SJerome Forissier                i_addr = int(addr, 16)
174ae252462SJerome Forissier                if (i_addr >= r_addr and i_addr < (r_addr + r_size)):
175ae252462SJerome Forissier                    # Found region
176ae252462SJerome Forissier                    elf_idx = r[2]
177ae252462SJerome Forissier                    if elf_idx is not None:
178ae252462SJerome Forissier                        return self._elfs[int(elf_idx)][1]
179ae252462SJerome Forissier            return None
180ae252462SJerome Forissier        else:
181ae252462SJerome Forissier            # tee.elf
182ae252462SJerome Forissier            return '0x0'
183ae252462SJerome Forissier
184ae252462SJerome Forissier    def elf_for_addr(self, addr):
185ae252462SJerome Forissier        l_addr = self.elf_load_addr(addr)
186ae252462SJerome Forissier        if l_addr is None:
187ae252462SJerome Forissier            return None
188ae252462SJerome Forissier        if l_addr is '0x0':
189ae252462SJerome Forissier            return 'tee.elf'
190ae252462SJerome Forissier        for k in self._elfs:
191ae252462SJerome Forissier            e = self._elfs[k]
192ae252462SJerome Forissier            if int(e[1], 16) == int(l_addr, 16):
193ae252462SJerome Forissier                return e[0]
194ae252462SJerome Forissier        return None
195733a15f2SJerome Forissier
196142c5cccSJerome Forissier    def subtract_load_addr(self, addr):
197ae252462SJerome Forissier        l_addr = self.elf_load_addr(addr)
198ae252462SJerome Forissier        if l_addr is None:
199ae252462SJerome Forissier            return None
200ae252462SJerome Forissier        if int(l_addr, 16) > int(addr, 16):
201142c5cccSJerome Forissier            return ''
202ae252462SJerome Forissier        return '0x{:x}'.format(int(addr, 16) - int(l_addr, 16))
203142c5cccSJerome Forissier
204142c5cccSJerome Forissier    def resolve(self, addr):
205142c5cccSJerome Forissier        reladdr = self.subtract_load_addr(addr)
206ae252462SJerome Forissier        self.spawn_addr2line(self.elf_for_addr(addr))
207142c5cccSJerome Forissier        if not reladdr or not self._addr2line:
208733a15f2SJerome Forissier            return '???'
209733a15f2SJerome Forissier        try:
210*bbaeed4dSRouven Czerwinski            print(reladdr, file=self._addr2line.stdin)
211733a15f2SJerome Forissier            ret = self._addr2line.stdout.readline().rstrip('\n')
212733a15f2SJerome Forissier        except IOError:
213733a15f2SJerome Forissier            ret = '!!!'
214733a15f2SJerome Forissier        return ret
215733a15f2SJerome Forissier
216142c5cccSJerome Forissier    def symbol_plus_offset(self, addr):
217142c5cccSJerome Forissier        ret = ''
218142c5cccSJerome Forissier        prevsize = 0
219142c5cccSJerome Forissier        reladdr = self.subtract_load_addr(addr)
220ae252462SJerome Forissier        elf_name = self.elf_for_addr(addr)
221ae252462SJerome Forissier        if elf_name is None:
222ae252462SJerome Forissier            return ''
223ae252462SJerome Forissier        elf = self.get_elf(elf_name)
224142c5cccSJerome Forissier        cmd = self.arch_prefix('nm')
225142c5cccSJerome Forissier        if not reladdr or not elf or not cmd:
226142c5cccSJerome Forissier            return ''
22730999126SJerome Forissier        ireladdr = int(reladdr, 16)
2281cbf777bSJerome Forissier        nm = self.my_Popen([cmd, '--numeric-sort', '--print-size', elf])
229142c5cccSJerome Forissier        for line in iter(nm.stdout.readline, ''):
230142c5cccSJerome Forissier            try:
231142c5cccSJerome Forissier                addr, size, _, name = line.split()
2321d8c2a48SJerome Forissier            except ValueError:
233142c5cccSJerome Forissier                # Size is missing
234b4815427SJerome Forissier                try:
235142c5cccSJerome Forissier                    addr, _, name = line.split()
236142c5cccSJerome Forissier                    size = '0'
2371d8c2a48SJerome Forissier                except ValueError:
238b4815427SJerome Forissier                    # E.g., undefined (external) symbols (line = "U symbol")
239b4815427SJerome Forissier                    continue
240142c5cccSJerome Forissier            iaddr = int(addr, 16)
241142c5cccSJerome Forissier            isize = int(size, 16)
242142c5cccSJerome Forissier            if iaddr == ireladdr:
243142c5cccSJerome Forissier                ret = name
244142c5cccSJerome Forissier                break
245142c5cccSJerome Forissier            if iaddr < ireladdr and iaddr + isize >= ireladdr:
246142c5cccSJerome Forissier                offs = ireladdr - iaddr
247142c5cccSJerome Forissier                ret = name + '+' + str(offs)
248142c5cccSJerome Forissier                break
249142c5cccSJerome Forissier            if iaddr > ireladdr and prevsize == 0:
250142c5cccSJerome Forissier                offs = iaddr + ireladdr
251142c5cccSJerome Forissier                ret = prevname + '+' + str(offs)
252142c5cccSJerome Forissier                break
253142c5cccSJerome Forissier            prevsize = size
254142c5cccSJerome Forissier            prevname = name
255142c5cccSJerome Forissier        nm.terminate()
256142c5cccSJerome Forissier        return ret
257142c5cccSJerome Forissier
258142c5cccSJerome Forissier    def section_plus_offset(self, addr):
259142c5cccSJerome Forissier        ret = ''
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)
265142c5cccSJerome Forissier        cmd = self.arch_prefix('objdump')
266142c5cccSJerome Forissier        if not reladdr or not elf or not cmd:
267142c5cccSJerome Forissier            return ''
26830999126SJerome Forissier        iaddr = int(reladdr, 16)
2691cbf777bSJerome Forissier        objdump = self.my_Popen([cmd, '--section-headers', elf])
270142c5cccSJerome Forissier        for line in iter(objdump.stdout.readline, ''):
271142c5cccSJerome Forissier            try:
272142c5cccSJerome Forissier                idx, name, size, vma, lma, offs, algn = line.split()
2731d8c2a48SJerome Forissier            except ValueError:
274ae252462SJerome Forissier                continue
275142c5cccSJerome Forissier            ivma = int(vma, 16)
276142c5cccSJerome Forissier            isize = int(size, 16)
277142c5cccSJerome Forissier            if ivma == iaddr:
278142c5cccSJerome Forissier                ret = name
279142c5cccSJerome Forissier                break
280142c5cccSJerome Forissier            if ivma < iaddr and ivma + isize >= iaddr:
281142c5cccSJerome Forissier                offs = iaddr - ivma
282142c5cccSJerome Forissier                ret = name + '+' + str(offs)
283142c5cccSJerome Forissier                break
284142c5cccSJerome Forissier        objdump.terminate()
285142c5cccSJerome Forissier        return ret
286142c5cccSJerome Forissier
287142c5cccSJerome Forissier    def process_abort(self, line):
288142c5cccSJerome Forissier        ret = ''
289142c5cccSJerome Forissier        match = re.search(ABORT_ADDR_RE, line)
290142c5cccSJerome Forissier        addr = match.group('addr')
291142c5cccSJerome Forissier        pre = match.start('addr')
292142c5cccSJerome Forissier        post = match.end('addr')
293142c5cccSJerome Forissier        sym = self.symbol_plus_offset(addr)
294142c5cccSJerome Forissier        sec = self.section_plus_offset(addr)
295142c5cccSJerome Forissier        if sym or sec:
296142c5cccSJerome Forissier            ret += line[:pre]
297142c5cccSJerome Forissier            ret += addr
298142c5cccSJerome Forissier            if sym:
299142c5cccSJerome Forissier                ret += ' ' + sym
300142c5cccSJerome Forissier            if sec:
301142c5cccSJerome Forissier                ret += ' ' + sec
302142c5cccSJerome Forissier            ret += line[post:]
303142c5cccSJerome Forissier        return ret
304142c5cccSJerome Forissier
30530999126SJerome Forissier    # Return all ELF sections with the ALLOC flag
306ae252462SJerome Forissier    def read_sections(self, elf_name):
307ae252462SJerome Forissier        if elf_name is None:
30830999126SJerome Forissier            return
309ae252462SJerome Forissier        if elf_name in self._sections:
310ae252462SJerome Forissier            return
311ae252462SJerome Forissier        elf = self.get_elf(elf_name)
31230999126SJerome Forissier        cmd = self.arch_prefix('objdump')
31330999126SJerome Forissier        if not elf or not cmd:
31430999126SJerome Forissier            return
315ae252462SJerome Forissier        self._sections[elf_name] = []
3161cbf777bSJerome Forissier        objdump = self.my_Popen([cmd, '--section-headers', elf])
31730999126SJerome Forissier        for line in iter(objdump.stdout.readline, ''):
31830999126SJerome Forissier            try:
31930999126SJerome Forissier                _, name, size, vma, _, _, _ = line.split()
3201d8c2a48SJerome Forissier            except ValueError:
32130999126SJerome Forissier                if 'ALLOC' in line:
322ae252462SJerome Forissier                    self._sections[elf_name].append([name, int(vma, 16),
323ae252462SJerome Forissier                                                     int(size, 16)])
32430999126SJerome Forissier
32530999126SJerome Forissier    def overlaps(self, section, addr, size):
32630999126SJerome Forissier        sec_addr = section[1]
32730999126SJerome Forissier        sec_size = section[2]
32830999126SJerome Forissier        if not size or not sec_size:
32930999126SJerome Forissier            return False
330ae252462SJerome Forissier        return ((addr <= (sec_addr + sec_size - 1)) and
331ae252462SJerome Forissier                ((addr + size - 1) >= sec_addr))
33230999126SJerome Forissier
333ae252462SJerome Forissier    def sections_in_region(self, addr, size, elf_idx):
33430999126SJerome Forissier        ret = ''
33530999126SJerome Forissier        addr = self.subtract_load_addr(addr)
33630999126SJerome Forissier        if not addr:
33730999126SJerome Forissier            return ''
33830999126SJerome Forissier        iaddr = int(addr, 16)
33930999126SJerome Forissier        isize = int(size, 16)
340ae252462SJerome Forissier        elf = self._elfs[int(elf_idx)][0]
341ae252462SJerome Forissier        if elf is None:
342ae252462SJerome Forissier            return ''
343ae252462SJerome Forissier        self.read_sections(elf)
344ae252462SJerome Forissier        if elf not in self._sections:
345ae252462SJerome Forissier            return ''
346ae252462SJerome Forissier        for s in self._sections[elf]:
34730999126SJerome Forissier            if self.overlaps(s, iaddr, isize):
34830999126SJerome Forissier                ret += ' ' + s[0]
34930999126SJerome Forissier        return ret
35030999126SJerome Forissier
351733a15f2SJerome Forissier    def reset(self):
352733a15f2SJerome Forissier        self._call_stack_found = False
353733a15f2SJerome Forissier        if self._addr2line:
354733a15f2SJerome Forissier            self._addr2line.terminate()
355733a15f2SJerome Forissier            self._addr2line = None
356ae252462SJerome Forissier        self._addr2line_elf_name = None
357d720431cSJerome Forissier        self._arch = None
358142c5cccSJerome Forissier        self._saved_abort_line = ''
359ae252462SJerome Forissier        self._sections = {}  # {elf_name: [[name, addr, size], ...], ...}
360ae252462SJerome Forissier        self._regions = []   # [[addr, size, elf_idx, saved line], ...]
361ae252462SJerome Forissier        self._elfs = {0: ["tee.elf", 0]}  # {idx: [uuid, load_addr], ...}
362c90b6663SSumit Garg        self._func_graph_found = False
363c90b6663SSumit Garg        self._func_graph_skip_line = True
364733a15f2SJerome Forissier
365095567e5SJerome Forissier    def pretty_print_path(self, path):
366095567e5SJerome Forissier        if self._strip_path:
367095567e5SJerome Forissier            return re.sub(re.escape(self._strip_path) + '/*', '', path)
368095567e5SJerome Forissier        return path
369095567e5SJerome Forissier
370733a15f2SJerome Forissier    def write(self, line):
371733a15f2SJerome Forissier        if self._call_stack_found:
372733a15f2SJerome Forissier            match = re.search(STACK_ADDR_RE, line)
373733a15f2SJerome Forissier            if match:
374733a15f2SJerome Forissier                addr = match.group('addr')
375733a15f2SJerome Forissier                pre = match.start('addr')
376733a15f2SJerome Forissier                post = match.end('addr')
377733a15f2SJerome Forissier                self._out.write(line[:pre])
378733a15f2SJerome Forissier                self._out.write(addr)
379733a15f2SJerome Forissier                res = self.resolve(addr)
380095567e5SJerome Forissier                res = self.pretty_print_path(res)
381733a15f2SJerome Forissier                self._out.write(' ' + res)
382733a15f2SJerome Forissier                self._out.write(line[post:])
383733a15f2SJerome Forissier                return
384733a15f2SJerome Forissier            else:
385733a15f2SJerome Forissier                self.reset()
386c90b6663SSumit Garg        if self._func_graph_found:
387c90b6663SSumit Garg            match = re.search(GRAPH_ADDR_RE, line)
388c90b6663SSumit Garg            match_re = re.search(GRAPH_RE, line)
389c90b6663SSumit Garg            if match:
390c90b6663SSumit Garg                addr = match.group('addr')
391c90b6663SSumit Garg                pre = match.start('addr')
392c90b6663SSumit Garg                post = match.end('addr')
393c90b6663SSumit Garg                self._out.write(line[:pre])
394c90b6663SSumit Garg                res = self.resolve(addr)
395c90b6663SSumit Garg                res_arr = re.split(' ', res)
396c90b6663SSumit Garg                self._out.write(res_arr[0])
397c90b6663SSumit Garg                self._out.write(line[post:])
398c90b6663SSumit Garg                self._func_graph_skip_line = False
399c90b6663SSumit Garg                return
400c90b6663SSumit Garg            elif match_re:
401c90b6663SSumit Garg                self._out.write(line)
402c90b6663SSumit Garg                return
403c90b6663SSumit Garg            elif self._func_graph_skip_line:
404c90b6663SSumit Garg                return
405c90b6663SSumit Garg            else:
406c90b6663SSumit Garg                self.reset()
40730999126SJerome Forissier        match = re.search(REGION_RE, line)
40830999126SJerome Forissier        if match:
409ae252462SJerome Forissier            # Region table: save info for later processing once
410ae252462SJerome Forissier            # we know which UUID corresponds to which ELF index
41130999126SJerome Forissier            addr = match.group('addr')
41230999126SJerome Forissier            size = match.group('size')
413ae252462SJerome Forissier            elf_idx = match.group('elf_idx')
414ae252462SJerome Forissier            self._regions.append([addr, size, elf_idx, line])
415ae252462SJerome Forissier            return
416ae252462SJerome Forissier        match = re.search(ELF_LIST_RE, line)
417ae252462SJerome Forissier        if match:
418ae252462SJerome Forissier            # ELF list: save info for later. Region table and ELF list
419ae252462SJerome Forissier            # will be displayed when the call stack is reached
420ae252462SJerome Forissier            i = int(match.group('idx'))
421ae252462SJerome Forissier            self._elfs[i] = [match.group('uuid'), match.group('load_addr'),
422ae252462SJerome Forissier                             line]
42330999126SJerome Forissier            return
424733a15f2SJerome Forissier        match = re.search(CALL_STACK_RE, line)
425733a15f2SJerome Forissier        if match:
426733a15f2SJerome Forissier            self._call_stack_found = True
427ae252462SJerome Forissier            if self._regions:
428ae252462SJerome Forissier                for r in self._regions:
429ae252462SJerome Forissier                    r_addr = r[0]
430ae252462SJerome Forissier                    r_size = r[1]
431ae252462SJerome Forissier                    elf_idx = r[2]
432ae252462SJerome Forissier                    saved_line = r[3]
433ae252462SJerome Forissier                    if elf_idx is None:
434ae252462SJerome Forissier                        self._out.write(saved_line)
435ae252462SJerome Forissier                    else:
436ae252462SJerome Forissier                        self._out.write(saved_line.strip() +
437ae252462SJerome Forissier                                        self.sections_in_region(r_addr,
438ae252462SJerome Forissier                                                                r_size,
439ae252462SJerome Forissier                                                                elf_idx) +
440ae252462SJerome Forissier                                        '\n')
441ae252462SJerome Forissier            if self._elfs:
442ae252462SJerome Forissier                for k in self._elfs:
443ae252462SJerome Forissier                    e = self._elfs[k]
444ae252462SJerome Forissier                    if (len(e) >= 3):
4451e6f2ea0SJerome Forissier                        # TA executable or library
446095567e5SJerome Forissier                        self._out.write(e[2].strip())
447095567e5SJerome Forissier                        elf = self.get_elf(e[0])
448095567e5SJerome Forissier                        if elf:
449095567e5SJerome Forissier                            rpath = os.path.realpath(elf)
450095567e5SJerome Forissier                            path = self.pretty_print_path(rpath)
451095567e5SJerome Forissier                            self._out.write(' (' + path + ')')
452095567e5SJerome Forissier                        self._out.write('\n')
453142c5cccSJerome Forissier            # Here is a good place to resolve the abort address because we
454142c5cccSJerome Forissier            # have all the information we need
455142c5cccSJerome Forissier            if self._saved_abort_line:
456142c5cccSJerome Forissier                self._out.write(self.process_abort(self._saved_abort_line))
457c90b6663SSumit Garg        match = re.search(FUNC_GRAPH_RE, line)
458c90b6663SSumit Garg        if match:
459c90b6663SSumit Garg            self._func_graph_found = True
460142c5cccSJerome Forissier        match = re.search(ABORT_ADDR_RE, line)
461142c5cccSJerome Forissier        if match:
46227b83ad2SJerome Forissier            self.reset()
463142c5cccSJerome Forissier            # At this point the arch and TA load address are unknown.
464142c5cccSJerome Forissier            # Save the line so We can translate the abort address later.
465142c5cccSJerome Forissier            self._saved_abort_line = line
466733a15f2SJerome Forissier        self._out.write(line)
467733a15f2SJerome Forissier
468733a15f2SJerome Forissier    def flush(self):
469733a15f2SJerome Forissier        self._out.flush()
470733a15f2SJerome Forissier
471ae252462SJerome Forissier
472733a15f2SJerome Forissierdef main():
473733a15f2SJerome Forissier    args = get_args()
474733a15f2SJerome Forissier    if args.dir:
475733a15f2SJerome Forissier        # Flatten list in case -d is used several times *and* with multiple
476733a15f2SJerome Forissier        # arguments
477733a15f2SJerome Forissier        args.dirs = [item for sublist in args.dir for item in sublist]
478733a15f2SJerome Forissier    else:
479733a15f2SJerome Forissier        args.dirs = []
480733a15f2SJerome Forissier    symbolizer = Symbolizer(sys.stdout, args.dirs, args.strip_path)
481733a15f2SJerome Forissier
482733a15f2SJerome Forissier    for line in sys.stdin:
483733a15f2SJerome Forissier        symbolizer.write(line)
484733a15f2SJerome Forissier    symbolizer.flush()
485733a15f2SJerome Forissier
4861d8c2a48SJerome Forissier
487733a15f2SJerome Forissierif __name__ == "__main__":
488733a15f2SJerome Forissier    main()
489