xref: /optee_os/scripts/symbolize.py (revision 531963a54f28d480bec3fd23e9af7efd94806a0d)
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