xref: /optee_os/scripts/symbolize.py (revision b6bc49caed24fe2705767a8783d449b74714586b)
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*b6bc49caSSumit Garg    r'[UEIDFM]/T[AC]:(\?+|[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]+)')
216e7c2e91SJerome 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]+)'
236e7c2e91SJerome Forissier                       r'( flags .{6} (\[(?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\-]+)')
26733a15f2SJerome Forissier
27733a15f2SJerome Forissierepilog = '''
280c5bedb5SJerome ForissierThis scripts reads an OP-TEE abort or panic message from stdin and adds debug
290c5bedb5SJerome Forissierinformation to the output, such as '<function> at <file>:<line>' next to each
300c5bedb5SJerome Forissieraddress in the call stack. Any message generated by OP-TEE and containing a
310c5bedb5SJerome Forissiercall stack can in principle be processed by this script. This currently
320c5bedb5SJerome Forissierincludes aborts and panics from the TEE core as well as from any TA.
330c5bedb5SJerome ForissierThe paths provided on the command line are used to locate the appropriate ELF
340c5bedb5SJerome Forissierbinary (tee.elf or Trusted Application). The GNU binutils (addr2line, objdump,
35f9089765SJerome Forissiernm) are used to extract the debug info. If the CROSS_COMPILE environment
36f9089765SJerome Forissiervariable is set, it is used as a prefix to the binutils tools. That is, the
37f9089765SJerome Forissierscript will invoke $(CROSS_COMPILE)addr2line etc. If it is not set however,
38f9089765SJerome Forissierthe prefix will be determined automatically for each ELF file based on its
39f9089765SJerome Forissierarchitecture (arm-linux-gnueabihf-, aarch64-linux-gnu-). The resulting command
40f9089765SJerome Forissieris then expected to be found in the user's PATH.
41733a15f2SJerome Forissier
420c5bedb5SJerome ForissierOP-TEE abort and panic messages are sent to the secure console. They look like
430c5bedb5SJerome Forissierthe following:
44733a15f2SJerome Forissier
450c5bedb5SJerome Forissier  E/TC:0 User TA data-abort at address 0xffffdecd (alignment fault)
46733a15f2SJerome Forissier  ...
470c5bedb5SJerome Forissier  E/TC:0 Call stack:
480c5bedb5SJerome Forissier  E/TC:0  0x4000549e
490c5bedb5SJerome Forissier  E/TC:0  0x40001f4b
500c5bedb5SJerome Forissier  E/TC:0  0x4000273f
510c5bedb5SJerome Forissier  E/TC:0  0x40005da7
52733a15f2SJerome Forissier
53733a15f2SJerome ForissierInspired by a script of the same name by the Chromium project.
54733a15f2SJerome Forissier
55733a15f2SJerome ForissierSample usage:
56733a15f2SJerome Forissier
57733a15f2SJerome Forissier  $ scripts/symbolize.py -d out/arm-plat-hikey/core -d ../optee_test/out/ta/*
58733a15f2SJerome Forissier  <paste whole dump here>
59733a15f2SJerome Forissier  ^D
60733a15f2SJerome Forissier'''
61733a15f2SJerome Forissier
62ae252462SJerome Forissier
63733a15f2SJerome Forissierdef get_args():
64733a15f2SJerome Forissier    parser = argparse.ArgumentParser(
65733a15f2SJerome Forissier        formatter_class=argparse.RawDescriptionHelpFormatter,
66733a15f2SJerome Forissier        description='Symbolizes OP-TEE abort dumps',
67733a15f2SJerome Forissier        epilog=epilog)
68733a15f2SJerome Forissier    parser.add_argument('-d', '--dir', action='append', nargs='+',
691d8c2a48SJerome Forissier                        help='Search for ELF file in DIR. tee.elf is needed '
701d8c2a48SJerome Forissier                        'to decode a TEE Core or pseudo-TA abort, while '
711d8c2a48SJerome Forissier                        '<TA_uuid>.elf is required if a user-mode TA has '
721d8c2a48SJerome Forissier                        'crashed. For convenience, ELF files may also be '
731d8c2a48SJerome Forissier                        'given.')
745f7df507SJerome Forissier    parser.add_argument('-s', '--strip_path', nargs='?',
751d8c2a48SJerome Forissier                        help='Strip STRIP_PATH from file paths (default: '
761d8c2a48SJerome Forissier                        'current directory, use -s with no argument to show '
771d8c2a48SJerome Forissier                        'full paths)', default=os.getcwd())
78733a15f2SJerome Forissier
79733a15f2SJerome Forissier    return parser.parse_args()
80733a15f2SJerome Forissier
81ae252462SJerome Forissier
82733a15f2SJerome Forissierclass Symbolizer(object):
83733a15f2SJerome Forissier    def __init__(self, out, dirs, strip_path):
84733a15f2SJerome Forissier        self._out = out
85733a15f2SJerome Forissier        self._dirs = dirs
86733a15f2SJerome Forissier        self._strip_path = strip_path
87733a15f2SJerome Forissier        self._addr2line = None
88733a15f2SJerome Forissier        self.reset()
89733a15f2SJerome Forissier
901cbf777bSJerome Forissier    def my_Popen(self, cmd):
911cbf777bSJerome Forissier        try:
921cbf777bSJerome Forissier            return subprocess.Popen(cmd, stdin=subprocess.PIPE,
931cbf777bSJerome Forissier                                    stdout=subprocess.PIPE)
941cbf777bSJerome Forissier        except OSError as e:
951cbf777bSJerome Forissier            if e.errno == os.errno.ENOENT:
961cbf777bSJerome Forissier                print >> sys.stderr, "*** Error:", cmd[0] + \
971cbf777bSJerome Forissier                    ": command not found"
981cbf777bSJerome Forissier                sys.exit(1)
991cbf777bSJerome Forissier
100733a15f2SJerome Forissier    def get_elf(self, elf_or_uuid):
101733a15f2SJerome Forissier        if not elf_or_uuid.endswith('.elf'):
102733a15f2SJerome Forissier            elf_or_uuid += '.elf'
103733a15f2SJerome Forissier        for d in self._dirs:
104157e6213SJerome Forissier            if d.endswith(elf_or_uuid) and os.path.isfile(d):
105157e6213SJerome Forissier                return d
106733a15f2SJerome Forissier            elf = glob.glob(d + '/' + elf_or_uuid)
107733a15f2SJerome Forissier            if elf:
108733a15f2SJerome Forissier                return elf[0]
109733a15f2SJerome Forissier
110d720431cSJerome Forissier    def set_arch(self):
111d720431cSJerome Forissier        if self._arch:
112d720431cSJerome Forissier            return
1136e7c2e91SJerome Forissier        self._arch = os.getenv('CROSS_COMPILE')
1148a6d4a8bSEtienne Carriere        if self._arch:
1158a6d4a8bSEtienne Carriere            return
116ae252462SJerome Forissier        elf = self.get_elf(self._elfs[0][0])
117ae252462SJerome Forissier        if elf is None:
118ae252462SJerome Forissier            return
119ae252462SJerome Forissier        p = subprocess.Popen(['file', self.get_elf(self._elfs[0][0])],
120d720431cSJerome Forissier                             stdout=subprocess.PIPE)
121d720431cSJerome Forissier        output = p.stdout.readlines()
122d720431cSJerome Forissier        p.terminate()
123d720431cSJerome Forissier        if 'ARM aarch64,' in output[0]:
124d720431cSJerome Forissier            self._arch = 'aarch64-linux-gnu-'
125d720431cSJerome Forissier        elif 'ARM,' in output[0]:
126d720431cSJerome Forissier            self._arch = 'arm-linux-gnueabihf-'
127d720431cSJerome Forissier
128142c5cccSJerome Forissier    def arch_prefix(self, cmd):
129d720431cSJerome Forissier        self.set_arch()
130ae252462SJerome Forissier        if self._arch is None:
131ae252462SJerome Forissier            return ''
132d720431cSJerome Forissier        return self._arch + cmd
133142c5cccSJerome Forissier
134ae252462SJerome Forissier    def spawn_addr2line(self, elf_name):
135ae252462SJerome Forissier        if elf_name is None:
136ae252462SJerome Forissier            return
137ae252462SJerome Forissier        if self._addr2line_elf_name is elf_name:
138ae252462SJerome Forissier            return
139ae252462SJerome Forissier        if self._addr2line:
140ae252462SJerome Forissier            self._addr2line.terminate
141ae252462SJerome Forissier            self._addr2line = None
142ae252462SJerome Forissier        elf = self.get_elf(elf_name)
143733a15f2SJerome Forissier        if not elf:
144733a15f2SJerome Forissier            return
145142c5cccSJerome Forissier        cmd = self.arch_prefix('addr2line')
146142c5cccSJerome Forissier        if not cmd:
147733a15f2SJerome Forissier            return
1481cbf777bSJerome Forissier        self._addr2line = self.my_Popen([cmd, '-f', '-p', '-e', elf])
149ae252462SJerome Forissier        self._addr2line_elf_name = elf_name
150ae252462SJerome Forissier
151ae252462SJerome Forissier    # If addr falls into a region that maps a TA ELF file, return the load
152ae252462SJerome Forissier    # address of that file.
153ae252462SJerome Forissier    def elf_load_addr(self, addr):
154ae252462SJerome Forissier        if self._regions:
155ae252462SJerome Forissier            for r in self._regions:
156ae252462SJerome Forissier                r_addr = int(r[0], 16)
157ae252462SJerome Forissier                r_size = int(r[1], 16)
158ae252462SJerome Forissier                i_addr = int(addr, 16)
159ae252462SJerome Forissier                if (i_addr >= r_addr and i_addr < (r_addr + r_size)):
160ae252462SJerome Forissier                    # Found region
161ae252462SJerome Forissier                    elf_idx = r[2]
162ae252462SJerome Forissier                    if elf_idx is not None:
163ae252462SJerome Forissier                        return self._elfs[int(elf_idx)][1]
164ae252462SJerome Forissier            return None
165ae252462SJerome Forissier        else:
166ae252462SJerome Forissier            # tee.elf
167ae252462SJerome Forissier            return '0x0'
168ae252462SJerome Forissier
169ae252462SJerome Forissier    def elf_for_addr(self, addr):
170ae252462SJerome Forissier        l_addr = self.elf_load_addr(addr)
171ae252462SJerome Forissier        if l_addr is None:
172ae252462SJerome Forissier            return None
173ae252462SJerome Forissier        if l_addr is '0x0':
174ae252462SJerome Forissier            return 'tee.elf'
175ae252462SJerome Forissier        for k in self._elfs:
176ae252462SJerome Forissier            e = self._elfs[k]
177ae252462SJerome Forissier            if int(e[1], 16) == int(l_addr, 16):
178ae252462SJerome Forissier                return e[0]
179ae252462SJerome Forissier        return None
180733a15f2SJerome Forissier
181142c5cccSJerome Forissier    def subtract_load_addr(self, addr):
182ae252462SJerome Forissier        l_addr = self.elf_load_addr(addr)
183ae252462SJerome Forissier        if l_addr is None:
184ae252462SJerome Forissier            return None
185ae252462SJerome Forissier        if int(l_addr, 16) > int(addr, 16):
186142c5cccSJerome Forissier            return ''
187ae252462SJerome Forissier        return '0x{:x}'.format(int(addr, 16) - int(l_addr, 16))
188142c5cccSJerome Forissier
189142c5cccSJerome Forissier    def resolve(self, addr):
190142c5cccSJerome Forissier        reladdr = self.subtract_load_addr(addr)
191ae252462SJerome Forissier        self.spawn_addr2line(self.elf_for_addr(addr))
192142c5cccSJerome Forissier        if not reladdr or not self._addr2line:
193733a15f2SJerome Forissier            return '???'
194733a15f2SJerome Forissier        try:
195733a15f2SJerome Forissier            print >> self._addr2line.stdin, reladdr
196733a15f2SJerome Forissier            ret = self._addr2line.stdout.readline().rstrip('\n')
197733a15f2SJerome Forissier        except IOError:
198733a15f2SJerome Forissier            ret = '!!!'
199733a15f2SJerome Forissier        return ret
200733a15f2SJerome Forissier
201142c5cccSJerome Forissier    def symbol_plus_offset(self, addr):
202142c5cccSJerome Forissier        ret = ''
203142c5cccSJerome Forissier        prevsize = 0
204142c5cccSJerome Forissier        reladdr = self.subtract_load_addr(addr)
205ae252462SJerome Forissier        elf_name = self.elf_for_addr(addr)
206ae252462SJerome Forissier        if elf_name is None:
207ae252462SJerome Forissier            return ''
208ae252462SJerome Forissier        elf = self.get_elf(elf_name)
209142c5cccSJerome Forissier        cmd = self.arch_prefix('nm')
210142c5cccSJerome Forissier        if not reladdr or not elf or not cmd:
211142c5cccSJerome Forissier            return ''
21230999126SJerome Forissier        ireladdr = int(reladdr, 16)
2131cbf777bSJerome Forissier        nm = self.my_Popen([cmd, '--numeric-sort', '--print-size', elf])
214142c5cccSJerome Forissier        for line in iter(nm.stdout.readline, ''):
215142c5cccSJerome Forissier            try:
216142c5cccSJerome Forissier                addr, size, _, name = line.split()
2171d8c2a48SJerome Forissier            except ValueError:
218142c5cccSJerome Forissier                # Size is missing
219b4815427SJerome Forissier                try:
220142c5cccSJerome Forissier                    addr, _, name = line.split()
221142c5cccSJerome Forissier                    size = '0'
2221d8c2a48SJerome Forissier                except ValueError:
223b4815427SJerome Forissier                    # E.g., undefined (external) symbols (line = "U symbol")
224b4815427SJerome Forissier                    continue
225142c5cccSJerome Forissier            iaddr = int(addr, 16)
226142c5cccSJerome Forissier            isize = int(size, 16)
227142c5cccSJerome Forissier            if iaddr == ireladdr:
228142c5cccSJerome Forissier                ret = name
229142c5cccSJerome Forissier                break
230142c5cccSJerome Forissier            if iaddr < ireladdr and iaddr + isize >= ireladdr:
231142c5cccSJerome Forissier                offs = ireladdr - iaddr
232142c5cccSJerome Forissier                ret = name + '+' + str(offs)
233142c5cccSJerome Forissier                break
234142c5cccSJerome Forissier            if iaddr > ireladdr and prevsize == 0:
235142c5cccSJerome Forissier                offs = iaddr + ireladdr
236142c5cccSJerome Forissier                ret = prevname + '+' + str(offs)
237142c5cccSJerome Forissier                break
238142c5cccSJerome Forissier            prevsize = size
239142c5cccSJerome Forissier            prevname = name
240142c5cccSJerome Forissier        nm.terminate()
241142c5cccSJerome Forissier        return ret
242142c5cccSJerome Forissier
243142c5cccSJerome Forissier    def section_plus_offset(self, addr):
244142c5cccSJerome Forissier        ret = ''
245142c5cccSJerome Forissier        reladdr = self.subtract_load_addr(addr)
246ae252462SJerome Forissier        elf_name = self.elf_for_addr(addr)
247ae252462SJerome Forissier        if elf_name is None:
248ae252462SJerome Forissier            return ''
249ae252462SJerome Forissier        elf = self.get_elf(elf_name)
250142c5cccSJerome Forissier        cmd = self.arch_prefix('objdump')
251142c5cccSJerome Forissier        if not reladdr or not elf or not cmd:
252142c5cccSJerome Forissier            return ''
25330999126SJerome Forissier        iaddr = int(reladdr, 16)
2541cbf777bSJerome Forissier        objdump = self.my_Popen([cmd, '--section-headers', elf])
255142c5cccSJerome Forissier        for line in iter(objdump.stdout.readline, ''):
256142c5cccSJerome Forissier            try:
257142c5cccSJerome Forissier                idx, name, size, vma, lma, offs, algn = line.split()
2581d8c2a48SJerome Forissier            except ValueError:
259ae252462SJerome Forissier                continue
260142c5cccSJerome Forissier            ivma = int(vma, 16)
261142c5cccSJerome Forissier            isize = int(size, 16)
262142c5cccSJerome Forissier            if ivma == iaddr:
263142c5cccSJerome Forissier                ret = name
264142c5cccSJerome Forissier                break
265142c5cccSJerome Forissier            if ivma < iaddr and ivma + isize >= iaddr:
266142c5cccSJerome Forissier                offs = iaddr - ivma
267142c5cccSJerome Forissier                ret = name + '+' + str(offs)
268142c5cccSJerome Forissier                break
269142c5cccSJerome Forissier        objdump.terminate()
270142c5cccSJerome Forissier        return ret
271142c5cccSJerome Forissier
272142c5cccSJerome Forissier    def process_abort(self, line):
273142c5cccSJerome Forissier        ret = ''
274142c5cccSJerome Forissier        match = re.search(ABORT_ADDR_RE, line)
275142c5cccSJerome Forissier        addr = match.group('addr')
276142c5cccSJerome Forissier        pre = match.start('addr')
277142c5cccSJerome Forissier        post = match.end('addr')
278142c5cccSJerome Forissier        sym = self.symbol_plus_offset(addr)
279142c5cccSJerome Forissier        sec = self.section_plus_offset(addr)
280142c5cccSJerome Forissier        if sym or sec:
281142c5cccSJerome Forissier            ret += line[:pre]
282142c5cccSJerome Forissier            ret += addr
283142c5cccSJerome Forissier            if sym:
284142c5cccSJerome Forissier                ret += ' ' + sym
285142c5cccSJerome Forissier            if sec:
286142c5cccSJerome Forissier                ret += ' ' + sec
287142c5cccSJerome Forissier            ret += line[post:]
288142c5cccSJerome Forissier        return ret
289142c5cccSJerome Forissier
29030999126SJerome Forissier    # Return all ELF sections with the ALLOC flag
291ae252462SJerome Forissier    def read_sections(self, elf_name):
292ae252462SJerome Forissier        if elf_name is None:
29330999126SJerome Forissier            return
294ae252462SJerome Forissier        if elf_name in self._sections:
295ae252462SJerome Forissier            return
296ae252462SJerome Forissier        elf = self.get_elf(elf_name)
29730999126SJerome Forissier        cmd = self.arch_prefix('objdump')
29830999126SJerome Forissier        if not elf or not cmd:
29930999126SJerome Forissier            return
300ae252462SJerome Forissier        self._sections[elf_name] = []
3011cbf777bSJerome Forissier        objdump = self.my_Popen([cmd, '--section-headers', elf])
30230999126SJerome Forissier        for line in iter(objdump.stdout.readline, ''):
30330999126SJerome Forissier            try:
30430999126SJerome Forissier                _, name, size, vma, _, _, _ = line.split()
3051d8c2a48SJerome Forissier            except ValueError:
30630999126SJerome Forissier                if 'ALLOC' in line:
307ae252462SJerome Forissier                    self._sections[elf_name].append([name, int(vma, 16),
308ae252462SJerome Forissier                                                     int(size, 16)])
30930999126SJerome Forissier
31030999126SJerome Forissier    def overlaps(self, section, addr, size):
31130999126SJerome Forissier        sec_addr = section[1]
31230999126SJerome Forissier        sec_size = section[2]
31330999126SJerome Forissier        if not size or not sec_size:
31430999126SJerome Forissier            return False
315ae252462SJerome Forissier        return ((addr <= (sec_addr + sec_size - 1)) and
316ae252462SJerome Forissier                ((addr + size - 1) >= sec_addr))
31730999126SJerome Forissier
318ae252462SJerome Forissier    def sections_in_region(self, addr, size, elf_idx):
31930999126SJerome Forissier        ret = ''
32030999126SJerome Forissier        addr = self.subtract_load_addr(addr)
32130999126SJerome Forissier        if not addr:
32230999126SJerome Forissier            return ''
32330999126SJerome Forissier        iaddr = int(addr, 16)
32430999126SJerome Forissier        isize = int(size, 16)
325ae252462SJerome Forissier        elf = self._elfs[int(elf_idx)][0]
326ae252462SJerome Forissier        if elf is None:
327ae252462SJerome Forissier            return ''
328ae252462SJerome Forissier        self.read_sections(elf)
329ae252462SJerome Forissier        if elf not in self._sections:
330ae252462SJerome Forissier            return ''
331ae252462SJerome Forissier        for s in self._sections[elf]:
33230999126SJerome Forissier            if self.overlaps(s, iaddr, isize):
33330999126SJerome Forissier                ret += ' ' + s[0]
33430999126SJerome Forissier        return ret
33530999126SJerome Forissier
336733a15f2SJerome Forissier    def reset(self):
337733a15f2SJerome Forissier        self._call_stack_found = False
338733a15f2SJerome Forissier        if self._addr2line:
339733a15f2SJerome Forissier            self._addr2line.terminate()
340733a15f2SJerome Forissier            self._addr2line = None
341ae252462SJerome Forissier        self._addr2line_elf_name = None
342d720431cSJerome Forissier        self._arch = None
343142c5cccSJerome Forissier        self._saved_abort_line = ''
344ae252462SJerome Forissier        self._sections = {}  # {elf_name: [[name, addr, size], ...], ...}
345ae252462SJerome Forissier        self._regions = []   # [[addr, size, elf_idx, saved line], ...]
346ae252462SJerome Forissier        self._elfs = {0: ["tee.elf", 0]}  # {idx: [uuid, load_addr], ...}
347733a15f2SJerome Forissier
348095567e5SJerome Forissier    def pretty_print_path(self, path):
349095567e5SJerome Forissier        if self._strip_path:
350095567e5SJerome Forissier            return re.sub(re.escape(self._strip_path) + '/*', '', path)
351095567e5SJerome Forissier        return path
352095567e5SJerome Forissier
353733a15f2SJerome Forissier    def write(self, line):
354733a15f2SJerome Forissier        if self._call_stack_found:
355733a15f2SJerome Forissier            match = re.search(STACK_ADDR_RE, line)
356733a15f2SJerome Forissier            if match:
357733a15f2SJerome Forissier                addr = match.group('addr')
358733a15f2SJerome Forissier                pre = match.start('addr')
359733a15f2SJerome Forissier                post = match.end('addr')
360733a15f2SJerome Forissier                self._out.write(line[:pre])
361733a15f2SJerome Forissier                self._out.write(addr)
362733a15f2SJerome Forissier                res = self.resolve(addr)
363095567e5SJerome Forissier                res = self.pretty_print_path(res)
364733a15f2SJerome Forissier                self._out.write(' ' + res)
365733a15f2SJerome Forissier                self._out.write(line[post:])
366733a15f2SJerome Forissier                return
367733a15f2SJerome Forissier            else:
368733a15f2SJerome Forissier                self.reset()
36930999126SJerome Forissier        match = re.search(REGION_RE, line)
37030999126SJerome Forissier        if match:
371ae252462SJerome Forissier            # Region table: save info for later processing once
372ae252462SJerome Forissier            # we know which UUID corresponds to which ELF index
37330999126SJerome Forissier            addr = match.group('addr')
37430999126SJerome Forissier            size = match.group('size')
375ae252462SJerome Forissier            elf_idx = match.group('elf_idx')
376ae252462SJerome Forissier            self._regions.append([addr, size, elf_idx, line])
377ae252462SJerome Forissier            return
378ae252462SJerome Forissier        match = re.search(ELF_LIST_RE, line)
379ae252462SJerome Forissier        if match:
380ae252462SJerome Forissier            # ELF list: save info for later. Region table and ELF list
381ae252462SJerome Forissier            # will be displayed when the call stack is reached
382ae252462SJerome Forissier            i = int(match.group('idx'))
383ae252462SJerome Forissier            self._elfs[i] = [match.group('uuid'), match.group('load_addr'),
384ae252462SJerome Forissier                             line]
38530999126SJerome Forissier            return
386733a15f2SJerome Forissier        match = re.search(CALL_STACK_RE, line)
387733a15f2SJerome Forissier        if match:
388733a15f2SJerome Forissier            self._call_stack_found = True
389ae252462SJerome Forissier            if self._regions:
390ae252462SJerome Forissier                for r in self._regions:
391ae252462SJerome Forissier                    r_addr = r[0]
392ae252462SJerome Forissier                    r_size = r[1]
393ae252462SJerome Forissier                    elf_idx = r[2]
394ae252462SJerome Forissier                    saved_line = r[3]
395ae252462SJerome Forissier                    if elf_idx is None:
396ae252462SJerome Forissier                        self._out.write(saved_line)
397ae252462SJerome Forissier                    else:
398ae252462SJerome Forissier                        self._out.write(saved_line.strip() +
399ae252462SJerome Forissier                                        self.sections_in_region(r_addr,
400ae252462SJerome Forissier                                                                r_size,
401ae252462SJerome Forissier                                                                elf_idx) +
402ae252462SJerome Forissier                                        '\n')
403ae252462SJerome Forissier            if self._elfs:
404ae252462SJerome Forissier                for k in self._elfs:
405ae252462SJerome Forissier                    e = self._elfs[k]
406ae252462SJerome Forissier                    if (len(e) >= 3):
4071e6f2ea0SJerome Forissier                        # TA executable or library
408095567e5SJerome Forissier                        self._out.write(e[2].strip())
409095567e5SJerome Forissier                        elf = self.get_elf(e[0])
410095567e5SJerome Forissier                        if elf:
411095567e5SJerome Forissier                            rpath = os.path.realpath(elf)
412095567e5SJerome Forissier                            path = self.pretty_print_path(rpath)
413095567e5SJerome Forissier                            self._out.write(' (' + path + ')')
414095567e5SJerome Forissier                        self._out.write('\n')
415142c5cccSJerome Forissier            # Here is a good place to resolve the abort address because we
416142c5cccSJerome Forissier            # have all the information we need
417142c5cccSJerome Forissier            if self._saved_abort_line:
418142c5cccSJerome Forissier                self._out.write(self.process_abort(self._saved_abort_line))
419142c5cccSJerome Forissier        match = re.search(ABORT_ADDR_RE, line)
420142c5cccSJerome Forissier        if match:
42127b83ad2SJerome Forissier            self.reset()
422142c5cccSJerome Forissier            # At this point the arch and TA load address are unknown.
423142c5cccSJerome Forissier            # Save the line so We can translate the abort address later.
424142c5cccSJerome Forissier            self._saved_abort_line = line
425733a15f2SJerome Forissier        self._out.write(line)
426733a15f2SJerome Forissier
427733a15f2SJerome Forissier    def flush(self):
428733a15f2SJerome Forissier        self._out.flush()
429733a15f2SJerome Forissier
430ae252462SJerome Forissier
431733a15f2SJerome Forissierdef main():
432733a15f2SJerome Forissier    args = get_args()
433733a15f2SJerome Forissier    if args.dir:
434733a15f2SJerome Forissier        # Flatten list in case -d is used several times *and* with multiple
435733a15f2SJerome Forissier        # arguments
436733a15f2SJerome Forissier        args.dirs = [item for sublist in args.dir for item in sublist]
437733a15f2SJerome Forissier    else:
438733a15f2SJerome Forissier        args.dirs = []
439733a15f2SJerome Forissier    symbolizer = Symbolizer(sys.stdout, args.dirs, args.strip_path)
440733a15f2SJerome Forissier
441733a15f2SJerome Forissier    for line in sys.stdin:
442733a15f2SJerome Forissier        symbolizer.write(line)
443733a15f2SJerome Forissier    symbolizer.flush()
444733a15f2SJerome Forissier
4451d8c2a48SJerome Forissier
446733a15f2SJerome Forissierif __name__ == "__main__":
447733a15f2SJerome Forissier    main()
448