xref: /optee_os/scripts/symbolize.py (revision 1d8c2a48d5238322f692f52ab67800a6374c1e6d)
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
18a2b984bdSJoakim BechSTACK_ADDR_RE = re.compile(r'[UEIDFM]/T[AC]:.*(?P<addr>0x[0-9a-f]+)')
19142c5cccSJerome ForissierABORT_ADDR_RE = re.compile('-abort at address (?P<addr>0x[0-9a-f]+)')
2030999126SJerome ForissierREGION_RE = re.compile('region [0-9]+: va (?P<addr>0x[0-9a-f]+) '
21ae252462SJerome Forissier                       'pa 0x[0-9a-f]+ size (?P<size>0x[0-9a-f]+)'
22ae252462SJerome Forissier                       '( flags .{6} (\[(?P<elf_idx>[0-9]+)\])?)?')
23ae252462SJerome ForissierELF_LIST_RE = re.compile(r'\[(?P<idx>[0-9]+)\] (?P<uuid>[0-9a-f\-]+)'
24ae252462SJerome Forissier                         ' @ (?P<load_addr>0x[0-9a-f\-]+)')
25733a15f2SJerome Forissier
26733a15f2SJerome Forissierepilog = '''
270c5bedb5SJerome ForissierThis scripts reads an OP-TEE abort or panic message from stdin and adds debug
280c5bedb5SJerome Forissierinformation to the output, such as '<function> at <file>:<line>' next to each
290c5bedb5SJerome Forissieraddress in the call stack. Any message generated by OP-TEE and containing a
300c5bedb5SJerome Forissiercall stack can in principle be processed by this script. This currently
310c5bedb5SJerome Forissierincludes aborts and panics from the TEE core as well as from any TA.
320c5bedb5SJerome ForissierThe paths provided on the command line are used to locate the appropriate ELF
330c5bedb5SJerome Forissierbinary (tee.elf or Trusted Application). The GNU binutils (addr2line, objdump,
340c5bedb5SJerome Forissiernm) are used to extract the debug info.
35733a15f2SJerome Forissier
360c5bedb5SJerome ForissierOP-TEE abort and panic messages are sent to the secure console. They look like
370c5bedb5SJerome Forissierthe following:
38733a15f2SJerome Forissier
390c5bedb5SJerome Forissier  E/TC:0 User TA data-abort at address 0xffffdecd (alignment fault)
40733a15f2SJerome Forissier  ...
410c5bedb5SJerome Forissier  E/TC:0 Call stack:
420c5bedb5SJerome Forissier  E/TC:0  0x4000549e
430c5bedb5SJerome Forissier  E/TC:0  0x40001f4b
440c5bedb5SJerome Forissier  E/TC:0  0x4000273f
450c5bedb5SJerome Forissier  E/TC:0  0x40005da7
46733a15f2SJerome Forissier
47733a15f2SJerome ForissierInspired by a script of the same name by the Chromium project.
48733a15f2SJerome Forissier
49733a15f2SJerome ForissierSample usage:
50733a15f2SJerome Forissier
51733a15f2SJerome Forissier  $ scripts/symbolize.py -d out/arm-plat-hikey/core -d ../optee_test/out/ta/*
52733a15f2SJerome Forissier  <paste whole dump here>
53733a15f2SJerome Forissier  ^D
54733a15f2SJerome Forissier'''
55733a15f2SJerome Forissier
56ae252462SJerome Forissier
57733a15f2SJerome Forissierdef get_args():
58733a15f2SJerome Forissier    parser = argparse.ArgumentParser(
59733a15f2SJerome Forissier                formatter_class=argparse.RawDescriptionHelpFormatter,
60733a15f2SJerome Forissier                description='Symbolizes OP-TEE abort dumps',
61733a15f2SJerome Forissier                epilog=epilog)
62733a15f2SJerome Forissier    parser.add_argument('-d', '--dir', action='append', nargs='+',
63*1d8c2a48SJerome Forissier                        help='Search for ELF file in DIR. tee.elf is needed '
64*1d8c2a48SJerome Forissier                        'to decode a TEE Core or pseudo-TA abort, while '
65*1d8c2a48SJerome Forissier                        '<TA_uuid>.elf is required if a user-mode TA has '
66*1d8c2a48SJerome Forissier                        'crashed. For convenience, ELF files may also be '
67*1d8c2a48SJerome Forissier                        'given.')
685f7df507SJerome Forissier    parser.add_argument('-s', '--strip_path', nargs='?',
69*1d8c2a48SJerome Forissier                        help='Strip STRIP_PATH from file paths (default: '
70*1d8c2a48SJerome Forissier                        'current directory, use -s with no argument to show '
71*1d8c2a48SJerome Forissier                        'full paths)', default=os.getcwd())
72733a15f2SJerome Forissier
73733a15f2SJerome Forissier    return parser.parse_args()
74733a15f2SJerome Forissier
75ae252462SJerome Forissier
76733a15f2SJerome Forissierclass Symbolizer(object):
77733a15f2SJerome Forissier    def __init__(self, out, dirs, strip_path):
78733a15f2SJerome Forissier        self._out = out
79733a15f2SJerome Forissier        self._dirs = dirs
80733a15f2SJerome Forissier        self._strip_path = strip_path
81733a15f2SJerome Forissier        self._addr2line = None
82733a15f2SJerome Forissier        self.reset()
83733a15f2SJerome Forissier
84733a15f2SJerome Forissier    def get_elf(self, elf_or_uuid):
85733a15f2SJerome Forissier        if not elf_or_uuid.endswith('.elf'):
86733a15f2SJerome Forissier            elf_or_uuid += '.elf'
87733a15f2SJerome Forissier        for d in self._dirs:
88157e6213SJerome Forissier            if d.endswith(elf_or_uuid) and os.path.isfile(d):
89157e6213SJerome Forissier                return d
90733a15f2SJerome Forissier            elf = glob.glob(d + '/' + elf_or_uuid)
91733a15f2SJerome Forissier            if elf:
92733a15f2SJerome Forissier                return elf[0]
93733a15f2SJerome Forissier
94d720431cSJerome Forissier    def set_arch(self):
95d720431cSJerome Forissier        if self._arch:
96d720431cSJerome Forissier            return
97ae252462SJerome Forissier        elf = self.get_elf(self._elfs[0][0])
98ae252462SJerome Forissier        if elf is None:
99ae252462SJerome Forissier            return
100ae252462SJerome Forissier        p = subprocess.Popen(['file', self.get_elf(self._elfs[0][0])],
101d720431cSJerome Forissier                             stdout=subprocess.PIPE)
102d720431cSJerome Forissier        output = p.stdout.readlines()
103d720431cSJerome Forissier        p.terminate()
104d720431cSJerome Forissier        if 'ARM aarch64,' in output[0]:
105d720431cSJerome Forissier            self._arch = 'aarch64-linux-gnu-'
106d720431cSJerome Forissier        elif 'ARM,' in output[0]:
107d720431cSJerome Forissier            self._arch = 'arm-linux-gnueabihf-'
108d720431cSJerome Forissier
109142c5cccSJerome Forissier    def arch_prefix(self, cmd):
110d720431cSJerome Forissier        self.set_arch()
111ae252462SJerome Forissier        if self._arch is None:
112ae252462SJerome Forissier            return ''
113d720431cSJerome Forissier        return self._arch + cmd
114142c5cccSJerome Forissier
115ae252462SJerome Forissier    def spawn_addr2line(self, elf_name):
116ae252462SJerome Forissier        if elf_name is None:
117ae252462SJerome Forissier            return
118ae252462SJerome Forissier        if self._addr2line_elf_name is elf_name:
119ae252462SJerome Forissier            return
120ae252462SJerome Forissier        if self._addr2line:
121ae252462SJerome Forissier            self._addr2line.terminate
122ae252462SJerome Forissier            self._addr2line = None
123ae252462SJerome Forissier        elf = self.get_elf(elf_name)
124733a15f2SJerome Forissier        if not elf:
125733a15f2SJerome Forissier            return
126142c5cccSJerome Forissier        cmd = self.arch_prefix('addr2line')
127142c5cccSJerome Forissier        if not cmd:
128733a15f2SJerome Forissier            return
129733a15f2SJerome Forissier        self._addr2line = subprocess.Popen([cmd, '-f', '-p', '-e', elf],
130733a15f2SJerome Forissier                                           stdin=subprocess.PIPE,
131733a15f2SJerome Forissier                                           stdout=subprocess.PIPE)
132ae252462SJerome Forissier        self._addr2line_elf_name = elf_name
133ae252462SJerome Forissier
134ae252462SJerome Forissier    # If addr falls into a region that maps a TA ELF file, return the load
135ae252462SJerome Forissier    # address of that file.
136ae252462SJerome Forissier    def elf_load_addr(self, addr):
137ae252462SJerome Forissier        if self._regions:
138ae252462SJerome Forissier            for r in self._regions:
139ae252462SJerome Forissier                r_addr = int(r[0], 16)
140ae252462SJerome Forissier                r_size = int(r[1], 16)
141ae252462SJerome Forissier                i_addr = int(addr, 16)
142ae252462SJerome Forissier                if (i_addr >= r_addr and i_addr < (r_addr + r_size)):
143ae252462SJerome Forissier                    # Found region
144ae252462SJerome Forissier                    elf_idx = r[2]
145ae252462SJerome Forissier                    if elf_idx is not None:
146ae252462SJerome Forissier                        return self._elfs[int(elf_idx)][1]
147ae252462SJerome Forissier            return None
148ae252462SJerome Forissier        else:
149ae252462SJerome Forissier            # tee.elf
150ae252462SJerome Forissier            return '0x0'
151ae252462SJerome Forissier
152ae252462SJerome Forissier    def elf_for_addr(self, addr):
153ae252462SJerome Forissier        l_addr = self.elf_load_addr(addr)
154ae252462SJerome Forissier        if l_addr is None:
155ae252462SJerome Forissier            return None
156ae252462SJerome Forissier        if l_addr is '0x0':
157ae252462SJerome Forissier            return 'tee.elf'
158ae252462SJerome Forissier        for k in self._elfs:
159ae252462SJerome Forissier            e = self._elfs[k]
160ae252462SJerome Forissier            if int(e[1], 16) == int(l_addr, 16):
161ae252462SJerome Forissier                return e[0]
162ae252462SJerome Forissier        return None
163733a15f2SJerome Forissier
164142c5cccSJerome Forissier    def subtract_load_addr(self, addr):
165ae252462SJerome Forissier        l_addr = self.elf_load_addr(addr)
166ae252462SJerome Forissier        if l_addr is None:
167ae252462SJerome Forissier            return None
168ae252462SJerome Forissier        if int(l_addr, 16) > int(addr, 16):
169142c5cccSJerome Forissier            return ''
170ae252462SJerome Forissier        return '0x{:x}'.format(int(addr, 16) - int(l_addr, 16))
171142c5cccSJerome Forissier
172142c5cccSJerome Forissier    def resolve(self, addr):
173142c5cccSJerome Forissier        reladdr = self.subtract_load_addr(addr)
174ae252462SJerome Forissier        self.spawn_addr2line(self.elf_for_addr(addr))
175142c5cccSJerome Forissier        if not reladdr or not self._addr2line:
176733a15f2SJerome Forissier            return '???'
177733a15f2SJerome Forissier        try:
178733a15f2SJerome Forissier            print >> self._addr2line.stdin, reladdr
179733a15f2SJerome Forissier            ret = self._addr2line.stdout.readline().rstrip('\n')
180733a15f2SJerome Forissier        except IOError:
181733a15f2SJerome Forissier            ret = '!!!'
182733a15f2SJerome Forissier        return ret
183733a15f2SJerome Forissier
184142c5cccSJerome Forissier    def symbol_plus_offset(self, addr):
185142c5cccSJerome Forissier        ret = ''
186142c5cccSJerome Forissier        prevsize = 0
187142c5cccSJerome Forissier        reladdr = self.subtract_load_addr(addr)
188ae252462SJerome Forissier        elf_name = self.elf_for_addr(addr)
189ae252462SJerome Forissier        if elf_name is None:
190ae252462SJerome Forissier            return ''
191ae252462SJerome Forissier        elf = self.get_elf(elf_name)
192142c5cccSJerome Forissier        cmd = self.arch_prefix('nm')
193142c5cccSJerome Forissier        if not reladdr or not elf or not cmd:
194142c5cccSJerome Forissier            return ''
19530999126SJerome Forissier        ireladdr = int(reladdr, 16)
196142c5cccSJerome Forissier        nm = subprocess.Popen([cmd, '--numeric-sort', '--print-size', elf],
197142c5cccSJerome Forissier                              stdin=subprocess.PIPE,
198142c5cccSJerome Forissier                              stdout=subprocess.PIPE)
199142c5cccSJerome Forissier        for line in iter(nm.stdout.readline, ''):
200142c5cccSJerome Forissier            try:
201142c5cccSJerome Forissier                addr, size, _, name = line.split()
202*1d8c2a48SJerome Forissier            except ValueError:
203142c5cccSJerome Forissier                # Size is missing
204b4815427SJerome Forissier                try:
205142c5cccSJerome Forissier                    addr, _, name = line.split()
206142c5cccSJerome Forissier                    size = '0'
207*1d8c2a48SJerome Forissier                except ValueError:
208b4815427SJerome Forissier                    # E.g., undefined (external) symbols (line = "U symbol")
209b4815427SJerome Forissier                    continue
210142c5cccSJerome Forissier            iaddr = int(addr, 16)
211142c5cccSJerome Forissier            isize = int(size, 16)
212142c5cccSJerome Forissier            if iaddr == ireladdr:
213142c5cccSJerome Forissier                ret = name
214142c5cccSJerome Forissier                break
215142c5cccSJerome Forissier            if iaddr < ireladdr and iaddr + isize >= ireladdr:
216142c5cccSJerome Forissier                offs = ireladdr - iaddr
217142c5cccSJerome Forissier                ret = name + '+' + str(offs)
218142c5cccSJerome Forissier                break
219142c5cccSJerome Forissier            if iaddr > ireladdr and prevsize == 0:
220142c5cccSJerome Forissier                offs = iaddr + ireladdr
221142c5cccSJerome Forissier                ret = prevname + '+' + str(offs)
222142c5cccSJerome Forissier                break
223142c5cccSJerome Forissier            prevsize = size
224142c5cccSJerome Forissier            prevname = name
225142c5cccSJerome Forissier        nm.terminate()
226142c5cccSJerome Forissier        return ret
227142c5cccSJerome Forissier
228142c5cccSJerome Forissier    def section_plus_offset(self, addr):
229142c5cccSJerome Forissier        ret = ''
230142c5cccSJerome Forissier        reladdr = self.subtract_load_addr(addr)
231ae252462SJerome Forissier        elf_name = self.elf_for_addr(addr)
232ae252462SJerome Forissier        if elf_name is None:
233ae252462SJerome Forissier            return ''
234ae252462SJerome Forissier        elf = self.get_elf(elf_name)
235142c5cccSJerome Forissier        cmd = self.arch_prefix('objdump')
236142c5cccSJerome Forissier        if not reladdr or not elf or not cmd:
237142c5cccSJerome Forissier            return ''
23830999126SJerome Forissier        iaddr = int(reladdr, 16)
239142c5cccSJerome Forissier        objdump = subprocess.Popen([cmd, '--section-headers', elf],
240142c5cccSJerome Forissier                                   stdin=subprocess.PIPE,
241142c5cccSJerome Forissier                                   stdout=subprocess.PIPE)
242142c5cccSJerome Forissier        for line in iter(objdump.stdout.readline, ''):
243142c5cccSJerome Forissier            try:
244142c5cccSJerome Forissier                idx, name, size, vma, lma, offs, algn = line.split()
245*1d8c2a48SJerome Forissier            except ValueError:
246ae252462SJerome Forissier                continue
247142c5cccSJerome Forissier            ivma = int(vma, 16)
248142c5cccSJerome Forissier            isize = int(size, 16)
249142c5cccSJerome Forissier            if ivma == iaddr:
250142c5cccSJerome Forissier                ret = name
251142c5cccSJerome Forissier                break
252142c5cccSJerome Forissier            if ivma < iaddr and ivma + isize >= iaddr:
253142c5cccSJerome Forissier                offs = iaddr - ivma
254142c5cccSJerome Forissier                ret = name + '+' + str(offs)
255142c5cccSJerome Forissier                break
256142c5cccSJerome Forissier        objdump.terminate()
257142c5cccSJerome Forissier        return ret
258142c5cccSJerome Forissier
259142c5cccSJerome Forissier    def process_abort(self, line):
260142c5cccSJerome Forissier        ret = ''
261142c5cccSJerome Forissier        match = re.search(ABORT_ADDR_RE, line)
262142c5cccSJerome Forissier        addr = match.group('addr')
263142c5cccSJerome Forissier        pre = match.start('addr')
264142c5cccSJerome Forissier        post = match.end('addr')
265142c5cccSJerome Forissier        sym = self.symbol_plus_offset(addr)
266142c5cccSJerome Forissier        sec = self.section_plus_offset(addr)
267142c5cccSJerome Forissier        if sym or sec:
268142c5cccSJerome Forissier            ret += line[:pre]
269142c5cccSJerome Forissier            ret += addr
270142c5cccSJerome Forissier            if sym:
271142c5cccSJerome Forissier                ret += ' ' + sym
272142c5cccSJerome Forissier            if sec:
273142c5cccSJerome Forissier                ret += ' ' + sec
274142c5cccSJerome Forissier            ret += line[post:]
275142c5cccSJerome Forissier        return ret
276142c5cccSJerome Forissier
27730999126SJerome Forissier    # Return all ELF sections with the ALLOC flag
278ae252462SJerome Forissier    def read_sections(self, elf_name):
279ae252462SJerome Forissier        if elf_name is None:
28030999126SJerome Forissier            return
281ae252462SJerome Forissier        if elf_name in self._sections:
282ae252462SJerome Forissier            return
283ae252462SJerome Forissier        elf = self.get_elf(elf_name)
28430999126SJerome Forissier        cmd = self.arch_prefix('objdump')
28530999126SJerome Forissier        if not elf or not cmd:
28630999126SJerome Forissier            return
287ae252462SJerome Forissier        self._sections[elf_name] = []
28830999126SJerome Forissier        objdump = subprocess.Popen([cmd, '--section-headers', elf],
28930999126SJerome Forissier                                   stdin=subprocess.PIPE,
29030999126SJerome Forissier                                   stdout=subprocess.PIPE)
29130999126SJerome Forissier        for line in iter(objdump.stdout.readline, ''):
29230999126SJerome Forissier            try:
29330999126SJerome Forissier                _, name, size, vma, _, _, _ = line.split()
294*1d8c2a48SJerome Forissier            except ValueError:
29530999126SJerome Forissier                if 'ALLOC' in line:
296ae252462SJerome Forissier                    self._sections[elf_name].append([name, int(vma, 16),
297ae252462SJerome Forissier                                                     int(size, 16)])
29830999126SJerome Forissier
29930999126SJerome Forissier    def overlaps(self, section, addr, size):
30030999126SJerome Forissier        sec_addr = section[1]
30130999126SJerome Forissier        sec_size = section[2]
30230999126SJerome Forissier        if not size or not sec_size:
30330999126SJerome Forissier            return False
304ae252462SJerome Forissier        return ((addr <= (sec_addr + sec_size - 1)) and
305ae252462SJerome Forissier                ((addr + size - 1) >= sec_addr))
30630999126SJerome Forissier
307ae252462SJerome Forissier    def sections_in_region(self, addr, size, elf_idx):
30830999126SJerome Forissier        ret = ''
30930999126SJerome Forissier        addr = self.subtract_load_addr(addr)
31030999126SJerome Forissier        if not addr:
31130999126SJerome Forissier            return ''
31230999126SJerome Forissier        iaddr = int(addr, 16)
31330999126SJerome Forissier        isize = int(size, 16)
314ae252462SJerome Forissier        elf = self._elfs[int(elf_idx)][0]
315ae252462SJerome Forissier        if elf is None:
316ae252462SJerome Forissier            return ''
317ae252462SJerome Forissier        self.read_sections(elf)
318ae252462SJerome Forissier        if elf not in self._sections:
319ae252462SJerome Forissier            return ''
320ae252462SJerome Forissier        for s in self._sections[elf]:
32130999126SJerome Forissier            if self.overlaps(s, iaddr, isize):
32230999126SJerome Forissier                ret += ' ' + s[0]
32330999126SJerome Forissier        return ret
32430999126SJerome Forissier
325733a15f2SJerome Forissier    def reset(self):
326733a15f2SJerome Forissier        self._call_stack_found = False
327733a15f2SJerome Forissier        if self._addr2line:
328733a15f2SJerome Forissier            self._addr2line.terminate()
329733a15f2SJerome Forissier            self._addr2line = None
330ae252462SJerome Forissier        self._addr2line_elf_name = None
331d720431cSJerome Forissier        self._arch = None
332142c5cccSJerome Forissier        self._saved_abort_line = ''
333ae252462SJerome Forissier        self._sections = {}  # {elf_name: [[name, addr, size], ...], ...}
334ae252462SJerome Forissier        self._regions = []   # [[addr, size, elf_idx, saved line], ...]
335ae252462SJerome Forissier        self._elfs = {0: ["tee.elf", 0]}  # {idx: [uuid, load_addr], ...}
336733a15f2SJerome Forissier
337095567e5SJerome Forissier    def pretty_print_path(self, path):
338095567e5SJerome Forissier        if self._strip_path:
339095567e5SJerome Forissier            return re.sub(re.escape(self._strip_path) + '/*', '', path)
340095567e5SJerome Forissier        return path
341095567e5SJerome Forissier
342733a15f2SJerome Forissier    def write(self, line):
343733a15f2SJerome Forissier            if self._call_stack_found:
344733a15f2SJerome Forissier                match = re.search(STACK_ADDR_RE, line)
345733a15f2SJerome Forissier                if match:
346733a15f2SJerome Forissier                    addr = match.group('addr')
347733a15f2SJerome Forissier                    pre = match.start('addr')
348733a15f2SJerome Forissier                    post = match.end('addr')
349733a15f2SJerome Forissier                    self._out.write(line[:pre])
350733a15f2SJerome Forissier                    self._out.write(addr)
351733a15f2SJerome Forissier                    res = self.resolve(addr)
352095567e5SJerome Forissier                    res = self.pretty_print_path(res)
353733a15f2SJerome Forissier                    self._out.write(' ' + res)
354733a15f2SJerome Forissier                    self._out.write(line[post:])
355733a15f2SJerome Forissier                    return
356733a15f2SJerome Forissier                else:
357733a15f2SJerome Forissier                    self.reset()
35830999126SJerome Forissier            match = re.search(REGION_RE, line)
35930999126SJerome Forissier            if match:
360ae252462SJerome Forissier                # Region table: save info for later processing once
361ae252462SJerome Forissier                # we know which UUID corresponds to which ELF index
36230999126SJerome Forissier                addr = match.group('addr')
36330999126SJerome Forissier                size = match.group('size')
364ae252462SJerome Forissier                elf_idx = match.group('elf_idx')
365ae252462SJerome Forissier                self._regions.append([addr, size, elf_idx, line])
366ae252462SJerome Forissier                return
367ae252462SJerome Forissier            match = re.search(ELF_LIST_RE, line)
368ae252462SJerome Forissier            if match:
369ae252462SJerome Forissier                # ELF list: save info for later. Region table and ELF list
370ae252462SJerome Forissier                # will be displayed when the call stack is reached
371ae252462SJerome Forissier                i = int(match.group('idx'))
372ae252462SJerome Forissier                self._elfs[i] = [match.group('uuid'), match.group('load_addr'),
373ae252462SJerome Forissier                                 line]
37430999126SJerome Forissier                return
375733a15f2SJerome Forissier            match = re.search(CALL_STACK_RE, line)
376733a15f2SJerome Forissier            if match:
377733a15f2SJerome Forissier                self._call_stack_found = True
378ae252462SJerome Forissier                if self._regions:
379ae252462SJerome Forissier                    for r in self._regions:
380ae252462SJerome Forissier                        r_addr = r[0]
381ae252462SJerome Forissier                        r_size = r[1]
382ae252462SJerome Forissier                        elf_idx = r[2]
383ae252462SJerome Forissier                        saved_line = r[3]
384ae252462SJerome Forissier                        if elf_idx is None:
385ae252462SJerome Forissier                            self._out.write(saved_line)
386ae252462SJerome Forissier                        else:
387ae252462SJerome Forissier                            self._out.write(saved_line.strip() +
388ae252462SJerome Forissier                                            self.sections_in_region(r_addr,
389ae252462SJerome Forissier                                                                    r_size,
390ae252462SJerome Forissier                                                                    elf_idx) +
391ae252462SJerome Forissier                                            '\n')
392ae252462SJerome Forissier                if self._elfs:
393ae252462SJerome Forissier                    for k in self._elfs:
394ae252462SJerome Forissier                        e = self._elfs[k]
395ae252462SJerome Forissier                        if (len(e) >= 3):
3961e6f2ea0SJerome Forissier                            # TA executable or library
397095567e5SJerome Forissier                            self._out.write(e[2].strip())
398095567e5SJerome Forissier                            elf = self.get_elf(e[0])
399095567e5SJerome Forissier                            if elf:
400095567e5SJerome Forissier                                rpath = os.path.realpath(elf)
401095567e5SJerome Forissier                                path = self.pretty_print_path(rpath)
402095567e5SJerome Forissier                                self._out.write(' (' + path + ')')
403095567e5SJerome Forissier                            self._out.write('\n')
404142c5cccSJerome Forissier                # Here is a good place to resolve the abort address because we
405142c5cccSJerome Forissier                # have all the information we need
406142c5cccSJerome Forissier                if self._saved_abort_line:
407142c5cccSJerome Forissier                    self._out.write(self.process_abort(self._saved_abort_line))
408142c5cccSJerome Forissier            match = re.search(ABORT_ADDR_RE, line)
409142c5cccSJerome Forissier            if match:
41027b83ad2SJerome Forissier                self.reset()
411142c5cccSJerome Forissier                # At this point the arch and TA load address are unknown.
412142c5cccSJerome Forissier                # Save the line so We can translate the abort address later.
413142c5cccSJerome Forissier                self._saved_abort_line = line
414733a15f2SJerome Forissier            self._out.write(line)
415733a15f2SJerome Forissier
416733a15f2SJerome Forissier    def flush(self):
417733a15f2SJerome Forissier        self._out.flush()
418733a15f2SJerome Forissier
419ae252462SJerome Forissier
420733a15f2SJerome Forissierdef main():
421733a15f2SJerome Forissier    args = get_args()
422733a15f2SJerome Forissier    if args.dir:
423733a15f2SJerome Forissier        # Flatten list in case -d is used several times *and* with multiple
424733a15f2SJerome Forissier        # arguments
425733a15f2SJerome Forissier        args.dirs = [item for sublist in args.dir for item in sublist]
426733a15f2SJerome Forissier    else:
427733a15f2SJerome Forissier        args.dirs = []
428733a15f2SJerome Forissier    symbolizer = Symbolizer(sys.stdout, args.dirs, args.strip_path)
429733a15f2SJerome Forissier
430733a15f2SJerome Forissier    for line in sys.stdin:
431733a15f2SJerome Forissier        symbolizer.write(line)
432733a15f2SJerome Forissier    symbolizer.flush()
433733a15f2SJerome Forissier
434*1d8c2a48SJerome Forissier
435733a15f2SJerome Forissierif __name__ == "__main__":
436733a15f2SJerome Forissier    main()
437