xref: /optee_os/scripts/symbolize.py (revision f9089765b4360daae4ab64fd150638c81d805e95)
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,
34*f9089765SJerome Forissiernm) are used to extract the debug info. If the CROSS_COMPILE environment
35*f9089765SJerome Forissiervariable is set, it is used as a prefix to the binutils tools. That is, the
36*f9089765SJerome Forissierscript will invoke $(CROSS_COMPILE)addr2line etc. If it is not set however,
37*f9089765SJerome Forissierthe prefix will be determined automatically for each ELF file based on its
38*f9089765SJerome Forissierarchitecture (arm-linux-gnueabihf-, aarch64-linux-gnu-). The resulting command
39*f9089765SJerome Forissieris then expected to be found in the user's PATH.
40733a15f2SJerome Forissier
410c5bedb5SJerome ForissierOP-TEE abort and panic messages are sent to the secure console. They look like
420c5bedb5SJerome Forissierthe following:
43733a15f2SJerome Forissier
440c5bedb5SJerome Forissier  E/TC:0 User TA data-abort at address 0xffffdecd (alignment fault)
45733a15f2SJerome Forissier  ...
460c5bedb5SJerome Forissier  E/TC:0 Call stack:
470c5bedb5SJerome Forissier  E/TC:0  0x4000549e
480c5bedb5SJerome Forissier  E/TC:0  0x40001f4b
490c5bedb5SJerome Forissier  E/TC:0  0x4000273f
500c5bedb5SJerome Forissier  E/TC:0  0x40005da7
51733a15f2SJerome Forissier
52733a15f2SJerome ForissierInspired by a script of the same name by the Chromium project.
53733a15f2SJerome Forissier
54733a15f2SJerome ForissierSample usage:
55733a15f2SJerome Forissier
56733a15f2SJerome Forissier  $ scripts/symbolize.py -d out/arm-plat-hikey/core -d ../optee_test/out/ta/*
57733a15f2SJerome Forissier  <paste whole dump here>
58733a15f2SJerome Forissier  ^D
59733a15f2SJerome Forissier'''
60733a15f2SJerome Forissier
61ae252462SJerome Forissier
62733a15f2SJerome Forissierdef get_args():
63733a15f2SJerome Forissier    parser = argparse.ArgumentParser(
64733a15f2SJerome Forissier                formatter_class=argparse.RawDescriptionHelpFormatter,
65733a15f2SJerome Forissier                description='Symbolizes OP-TEE abort dumps',
66733a15f2SJerome Forissier                epilog=epilog)
67733a15f2SJerome Forissier    parser.add_argument('-d', '--dir', action='append', nargs='+',
681d8c2a48SJerome Forissier                        help='Search for ELF file in DIR. tee.elf is needed '
691d8c2a48SJerome Forissier                        'to decode a TEE Core or pseudo-TA abort, while '
701d8c2a48SJerome Forissier                        '<TA_uuid>.elf is required if a user-mode TA has '
711d8c2a48SJerome Forissier                        'crashed. For convenience, ELF files may also be '
721d8c2a48SJerome Forissier                        'given.')
735f7df507SJerome Forissier    parser.add_argument('-s', '--strip_path', nargs='?',
741d8c2a48SJerome Forissier                        help='Strip STRIP_PATH from file paths (default: '
751d8c2a48SJerome Forissier                        'current directory, use -s with no argument to show '
761d8c2a48SJerome Forissier                        'full paths)', default=os.getcwd())
77733a15f2SJerome Forissier
78733a15f2SJerome Forissier    return parser.parse_args()
79733a15f2SJerome Forissier
80ae252462SJerome Forissier
81733a15f2SJerome Forissierclass Symbolizer(object):
82733a15f2SJerome Forissier    def __init__(self, out, dirs, strip_path):
83733a15f2SJerome Forissier        self._out = out
84733a15f2SJerome Forissier        self._dirs = dirs
85733a15f2SJerome Forissier        self._strip_path = strip_path
86733a15f2SJerome Forissier        self._addr2line = None
87733a15f2SJerome Forissier        self.reset()
88733a15f2SJerome Forissier
891cbf777bSJerome Forissier    def my_Popen(self, cmd):
901cbf777bSJerome Forissier        try:
911cbf777bSJerome Forissier            return subprocess.Popen(cmd, stdin=subprocess.PIPE,
921cbf777bSJerome Forissier                                    stdout=subprocess.PIPE)
931cbf777bSJerome Forissier        except OSError as e:
941cbf777bSJerome Forissier            if e.errno == os.errno.ENOENT:
951cbf777bSJerome Forissier                print >> sys.stderr, "*** Error:", cmd[0] + \
961cbf777bSJerome Forissier                    ": command not found"
971cbf777bSJerome Forissier                sys.exit(1)
981cbf777bSJerome Forissier
99733a15f2SJerome Forissier    def get_elf(self, elf_or_uuid):
100733a15f2SJerome Forissier        if not elf_or_uuid.endswith('.elf'):
101733a15f2SJerome Forissier            elf_or_uuid += '.elf'
102733a15f2SJerome Forissier        for d in self._dirs:
103157e6213SJerome Forissier            if d.endswith(elf_or_uuid) and os.path.isfile(d):
104157e6213SJerome Forissier                return d
105733a15f2SJerome Forissier            elf = glob.glob(d + '/' + elf_or_uuid)
106733a15f2SJerome Forissier            if elf:
107733a15f2SJerome Forissier                return elf[0]
108733a15f2SJerome Forissier
109d720431cSJerome Forissier    def set_arch(self):
110d720431cSJerome Forissier        if self._arch:
111d720431cSJerome Forissier            return
1128a6d4a8bSEtienne Carriere        self._arch = os.getenv('CROSS_COMPILE');
1138a6d4a8bSEtienne Carriere        if self._arch:
1148a6d4a8bSEtienne Carriere            return
115ae252462SJerome Forissier        elf = self.get_elf(self._elfs[0][0])
116ae252462SJerome Forissier        if elf is None:
117ae252462SJerome Forissier            return
118ae252462SJerome Forissier        p = subprocess.Popen(['file', self.get_elf(self._elfs[0][0])],
119d720431cSJerome Forissier                             stdout=subprocess.PIPE)
120d720431cSJerome Forissier        output = p.stdout.readlines()
121d720431cSJerome Forissier        p.terminate()
122d720431cSJerome Forissier        if 'ARM aarch64,' in output[0]:
123d720431cSJerome Forissier            self._arch = 'aarch64-linux-gnu-'
124d720431cSJerome Forissier        elif 'ARM,' in output[0]:
125d720431cSJerome Forissier            self._arch = 'arm-linux-gnueabihf-'
126d720431cSJerome Forissier
127142c5cccSJerome Forissier    def arch_prefix(self, cmd):
128d720431cSJerome Forissier        self.set_arch()
129ae252462SJerome Forissier        if self._arch is None:
130ae252462SJerome Forissier            return ''
131d720431cSJerome Forissier        return self._arch + cmd
132142c5cccSJerome Forissier
133ae252462SJerome Forissier    def spawn_addr2line(self, elf_name):
134ae252462SJerome Forissier        if elf_name is None:
135ae252462SJerome Forissier            return
136ae252462SJerome Forissier        if self._addr2line_elf_name is elf_name:
137ae252462SJerome Forissier            return
138ae252462SJerome Forissier        if self._addr2line:
139ae252462SJerome Forissier            self._addr2line.terminate
140ae252462SJerome Forissier            self._addr2line = None
141ae252462SJerome Forissier        elf = self.get_elf(elf_name)
142733a15f2SJerome Forissier        if not elf:
143733a15f2SJerome Forissier            return
144142c5cccSJerome Forissier        cmd = self.arch_prefix('addr2line')
145142c5cccSJerome Forissier        if not cmd:
146733a15f2SJerome Forissier            return
1471cbf777bSJerome Forissier        self._addr2line = self.my_Popen([cmd, '-f', '-p', '-e', elf])
148ae252462SJerome Forissier        self._addr2line_elf_name = elf_name
149ae252462SJerome Forissier
150ae252462SJerome Forissier    # If addr falls into a region that maps a TA ELF file, return the load
151ae252462SJerome Forissier    # address of that file.
152ae252462SJerome Forissier    def elf_load_addr(self, addr):
153ae252462SJerome Forissier        if self._regions:
154ae252462SJerome Forissier            for r in self._regions:
155ae252462SJerome Forissier                r_addr = int(r[0], 16)
156ae252462SJerome Forissier                r_size = int(r[1], 16)
157ae252462SJerome Forissier                i_addr = int(addr, 16)
158ae252462SJerome Forissier                if (i_addr >= r_addr and i_addr < (r_addr + r_size)):
159ae252462SJerome Forissier                    # Found region
160ae252462SJerome Forissier                    elf_idx = r[2]
161ae252462SJerome Forissier                    if elf_idx is not None:
162ae252462SJerome Forissier                        return self._elfs[int(elf_idx)][1]
163ae252462SJerome Forissier            return None
164ae252462SJerome Forissier        else:
165ae252462SJerome Forissier            # tee.elf
166ae252462SJerome Forissier            return '0x0'
167ae252462SJerome Forissier
168ae252462SJerome Forissier    def elf_for_addr(self, addr):
169ae252462SJerome Forissier        l_addr = self.elf_load_addr(addr)
170ae252462SJerome Forissier        if l_addr is None:
171ae252462SJerome Forissier            return None
172ae252462SJerome Forissier        if l_addr is '0x0':
173ae252462SJerome Forissier            return 'tee.elf'
174ae252462SJerome Forissier        for k in self._elfs:
175ae252462SJerome Forissier            e = self._elfs[k]
176ae252462SJerome Forissier            if int(e[1], 16) == int(l_addr, 16):
177ae252462SJerome Forissier                return e[0]
178ae252462SJerome Forissier        return None
179733a15f2SJerome Forissier
180142c5cccSJerome Forissier    def subtract_load_addr(self, addr):
181ae252462SJerome Forissier        l_addr = self.elf_load_addr(addr)
182ae252462SJerome Forissier        if l_addr is None:
183ae252462SJerome Forissier            return None
184ae252462SJerome Forissier        if int(l_addr, 16) > int(addr, 16):
185142c5cccSJerome Forissier            return ''
186ae252462SJerome Forissier        return '0x{:x}'.format(int(addr, 16) - int(l_addr, 16))
187142c5cccSJerome Forissier
188142c5cccSJerome Forissier    def resolve(self, addr):
189142c5cccSJerome Forissier        reladdr = self.subtract_load_addr(addr)
190ae252462SJerome Forissier        self.spawn_addr2line(self.elf_for_addr(addr))
191142c5cccSJerome Forissier        if not reladdr or not self._addr2line:
192733a15f2SJerome Forissier            return '???'
193733a15f2SJerome Forissier        try:
194733a15f2SJerome Forissier            print >> self._addr2line.stdin, reladdr
195733a15f2SJerome Forissier            ret = self._addr2line.stdout.readline().rstrip('\n')
196733a15f2SJerome Forissier        except IOError:
197733a15f2SJerome Forissier            ret = '!!!'
198733a15f2SJerome Forissier        return ret
199733a15f2SJerome Forissier
200142c5cccSJerome Forissier    def symbol_plus_offset(self, addr):
201142c5cccSJerome Forissier        ret = ''
202142c5cccSJerome Forissier        prevsize = 0
203142c5cccSJerome Forissier        reladdr = self.subtract_load_addr(addr)
204ae252462SJerome Forissier        elf_name = self.elf_for_addr(addr)
205ae252462SJerome Forissier        if elf_name is None:
206ae252462SJerome Forissier            return ''
207ae252462SJerome Forissier        elf = self.get_elf(elf_name)
208142c5cccSJerome Forissier        cmd = self.arch_prefix('nm')
209142c5cccSJerome Forissier        if not reladdr or not elf or not cmd:
210142c5cccSJerome Forissier            return ''
21130999126SJerome Forissier        ireladdr = int(reladdr, 16)
2121cbf777bSJerome Forissier        nm = self.my_Popen([cmd, '--numeric-sort', '--print-size', elf])
213142c5cccSJerome Forissier        for line in iter(nm.stdout.readline, ''):
214142c5cccSJerome Forissier            try:
215142c5cccSJerome Forissier                addr, size, _, name = line.split()
2161d8c2a48SJerome Forissier            except ValueError:
217142c5cccSJerome Forissier                # Size is missing
218b4815427SJerome Forissier                try:
219142c5cccSJerome Forissier                    addr, _, name = line.split()
220142c5cccSJerome Forissier                    size = '0'
2211d8c2a48SJerome Forissier                except ValueError:
222b4815427SJerome Forissier                    # E.g., undefined (external) symbols (line = "U symbol")
223b4815427SJerome Forissier                    continue
224142c5cccSJerome Forissier            iaddr = int(addr, 16)
225142c5cccSJerome Forissier            isize = int(size, 16)
226142c5cccSJerome Forissier            if iaddr == ireladdr:
227142c5cccSJerome Forissier                ret = name
228142c5cccSJerome Forissier                break
229142c5cccSJerome Forissier            if iaddr < ireladdr and iaddr + isize >= ireladdr:
230142c5cccSJerome Forissier                offs = ireladdr - iaddr
231142c5cccSJerome Forissier                ret = name + '+' + str(offs)
232142c5cccSJerome Forissier                break
233142c5cccSJerome Forissier            if iaddr > ireladdr and prevsize == 0:
234142c5cccSJerome Forissier                offs = iaddr + ireladdr
235142c5cccSJerome Forissier                ret = prevname + '+' + str(offs)
236142c5cccSJerome Forissier                break
237142c5cccSJerome Forissier            prevsize = size
238142c5cccSJerome Forissier            prevname = name
239142c5cccSJerome Forissier        nm.terminate()
240142c5cccSJerome Forissier        return ret
241142c5cccSJerome Forissier
242142c5cccSJerome Forissier    def section_plus_offset(self, addr):
243142c5cccSJerome Forissier        ret = ''
244142c5cccSJerome Forissier        reladdr = self.subtract_load_addr(addr)
245ae252462SJerome Forissier        elf_name = self.elf_for_addr(addr)
246ae252462SJerome Forissier        if elf_name is None:
247ae252462SJerome Forissier            return ''
248ae252462SJerome Forissier        elf = self.get_elf(elf_name)
249142c5cccSJerome Forissier        cmd = self.arch_prefix('objdump')
250142c5cccSJerome Forissier        if not reladdr or not elf or not cmd:
251142c5cccSJerome Forissier            return ''
25230999126SJerome Forissier        iaddr = int(reladdr, 16)
2531cbf777bSJerome Forissier        objdump = self.my_Popen([cmd, '--section-headers', elf])
254142c5cccSJerome Forissier        for line in iter(objdump.stdout.readline, ''):
255142c5cccSJerome Forissier            try:
256142c5cccSJerome Forissier                idx, name, size, vma, lma, offs, algn = line.split()
2571d8c2a48SJerome Forissier            except ValueError:
258ae252462SJerome Forissier                continue
259142c5cccSJerome Forissier            ivma = int(vma, 16)
260142c5cccSJerome Forissier            isize = int(size, 16)
261142c5cccSJerome Forissier            if ivma == iaddr:
262142c5cccSJerome Forissier                ret = name
263142c5cccSJerome Forissier                break
264142c5cccSJerome Forissier            if ivma < iaddr and ivma + isize >= iaddr:
265142c5cccSJerome Forissier                offs = iaddr - ivma
266142c5cccSJerome Forissier                ret = name + '+' + str(offs)
267142c5cccSJerome Forissier                break
268142c5cccSJerome Forissier        objdump.terminate()
269142c5cccSJerome Forissier        return ret
270142c5cccSJerome Forissier
271142c5cccSJerome Forissier    def process_abort(self, line):
272142c5cccSJerome Forissier        ret = ''
273142c5cccSJerome Forissier        match = re.search(ABORT_ADDR_RE, line)
274142c5cccSJerome Forissier        addr = match.group('addr')
275142c5cccSJerome Forissier        pre = match.start('addr')
276142c5cccSJerome Forissier        post = match.end('addr')
277142c5cccSJerome Forissier        sym = self.symbol_plus_offset(addr)
278142c5cccSJerome Forissier        sec = self.section_plus_offset(addr)
279142c5cccSJerome Forissier        if sym or sec:
280142c5cccSJerome Forissier            ret += line[:pre]
281142c5cccSJerome Forissier            ret += addr
282142c5cccSJerome Forissier            if sym:
283142c5cccSJerome Forissier                ret += ' ' + sym
284142c5cccSJerome Forissier            if sec:
285142c5cccSJerome Forissier                ret += ' ' + sec
286142c5cccSJerome Forissier            ret += line[post:]
287142c5cccSJerome Forissier        return ret
288142c5cccSJerome Forissier
28930999126SJerome Forissier    # Return all ELF sections with the ALLOC flag
290ae252462SJerome Forissier    def read_sections(self, elf_name):
291ae252462SJerome Forissier        if elf_name is None:
29230999126SJerome Forissier            return
293ae252462SJerome Forissier        if elf_name in self._sections:
294ae252462SJerome Forissier            return
295ae252462SJerome Forissier        elf = self.get_elf(elf_name)
29630999126SJerome Forissier        cmd = self.arch_prefix('objdump')
29730999126SJerome Forissier        if not elf or not cmd:
29830999126SJerome Forissier            return
299ae252462SJerome Forissier        self._sections[elf_name] = []
3001cbf777bSJerome Forissier        objdump = self.my_Popen([cmd, '--section-headers', elf])
30130999126SJerome Forissier        for line in iter(objdump.stdout.readline, ''):
30230999126SJerome Forissier            try:
30330999126SJerome Forissier                _, name, size, vma, _, _, _ = line.split()
3041d8c2a48SJerome Forissier            except ValueError:
30530999126SJerome Forissier                if 'ALLOC' in line:
306ae252462SJerome Forissier                    self._sections[elf_name].append([name, int(vma, 16),
307ae252462SJerome Forissier                                                     int(size, 16)])
30830999126SJerome Forissier
30930999126SJerome Forissier    def overlaps(self, section, addr, size):
31030999126SJerome Forissier        sec_addr = section[1]
31130999126SJerome Forissier        sec_size = section[2]
31230999126SJerome Forissier        if not size or not sec_size:
31330999126SJerome Forissier            return False
314ae252462SJerome Forissier        return ((addr <= (sec_addr + sec_size - 1)) and
315ae252462SJerome Forissier                ((addr + size - 1) >= sec_addr))
31630999126SJerome Forissier
317ae252462SJerome Forissier    def sections_in_region(self, addr, size, elf_idx):
31830999126SJerome Forissier        ret = ''
31930999126SJerome Forissier        addr = self.subtract_load_addr(addr)
32030999126SJerome Forissier        if not addr:
32130999126SJerome Forissier            return ''
32230999126SJerome Forissier        iaddr = int(addr, 16)
32330999126SJerome Forissier        isize = int(size, 16)
324ae252462SJerome Forissier        elf = self._elfs[int(elf_idx)][0]
325ae252462SJerome Forissier        if elf is None:
326ae252462SJerome Forissier            return ''
327ae252462SJerome Forissier        self.read_sections(elf)
328ae252462SJerome Forissier        if elf not in self._sections:
329ae252462SJerome Forissier            return ''
330ae252462SJerome Forissier        for s in self._sections[elf]:
33130999126SJerome Forissier            if self.overlaps(s, iaddr, isize):
33230999126SJerome Forissier                ret += ' ' + s[0]
33330999126SJerome Forissier        return ret
33430999126SJerome Forissier
335733a15f2SJerome Forissier    def reset(self):
336733a15f2SJerome Forissier        self._call_stack_found = False
337733a15f2SJerome Forissier        if self._addr2line:
338733a15f2SJerome Forissier            self._addr2line.terminate()
339733a15f2SJerome Forissier            self._addr2line = None
340ae252462SJerome Forissier        self._addr2line_elf_name = None
341d720431cSJerome Forissier        self._arch = None
342142c5cccSJerome Forissier        self._saved_abort_line = ''
343ae252462SJerome Forissier        self._sections = {}  # {elf_name: [[name, addr, size], ...], ...}
344ae252462SJerome Forissier        self._regions = []   # [[addr, size, elf_idx, saved line], ...]
345ae252462SJerome Forissier        self._elfs = {0: ["tee.elf", 0]}  # {idx: [uuid, load_addr], ...}
346733a15f2SJerome Forissier
347095567e5SJerome Forissier    def pretty_print_path(self, path):
348095567e5SJerome Forissier        if self._strip_path:
349095567e5SJerome Forissier            return re.sub(re.escape(self._strip_path) + '/*', '', path)
350095567e5SJerome Forissier        return path
351095567e5SJerome Forissier
352733a15f2SJerome Forissier    def write(self, line):
353733a15f2SJerome Forissier            if self._call_stack_found:
354733a15f2SJerome Forissier                match = re.search(STACK_ADDR_RE, line)
355733a15f2SJerome Forissier                if match:
356733a15f2SJerome Forissier                    addr = match.group('addr')
357733a15f2SJerome Forissier                    pre = match.start('addr')
358733a15f2SJerome Forissier                    post = match.end('addr')
359733a15f2SJerome Forissier                    self._out.write(line[:pre])
360733a15f2SJerome Forissier                    self._out.write(addr)
361733a15f2SJerome Forissier                    res = self.resolve(addr)
362095567e5SJerome Forissier                    res = self.pretty_print_path(res)
363733a15f2SJerome Forissier                    self._out.write(' ' + res)
364733a15f2SJerome Forissier                    self._out.write(line[post:])
365733a15f2SJerome Forissier                    return
366733a15f2SJerome Forissier                else:
367733a15f2SJerome Forissier                    self.reset()
36830999126SJerome Forissier            match = re.search(REGION_RE, line)
36930999126SJerome Forissier            if match:
370ae252462SJerome Forissier                # Region table: save info for later processing once
371ae252462SJerome Forissier                # we know which UUID corresponds to which ELF index
37230999126SJerome Forissier                addr = match.group('addr')
37330999126SJerome Forissier                size = match.group('size')
374ae252462SJerome Forissier                elf_idx = match.group('elf_idx')
375ae252462SJerome Forissier                self._regions.append([addr, size, elf_idx, line])
376ae252462SJerome Forissier                return
377ae252462SJerome Forissier            match = re.search(ELF_LIST_RE, line)
378ae252462SJerome Forissier            if match:
379ae252462SJerome Forissier                # ELF list: save info for later. Region table and ELF list
380ae252462SJerome Forissier                # will be displayed when the call stack is reached
381ae252462SJerome Forissier                i = int(match.group('idx'))
382ae252462SJerome Forissier                self._elfs[i] = [match.group('uuid'), match.group('load_addr'),
383ae252462SJerome Forissier                                 line]
38430999126SJerome Forissier                return
385733a15f2SJerome Forissier            match = re.search(CALL_STACK_RE, line)
386733a15f2SJerome Forissier            if match:
387733a15f2SJerome Forissier                self._call_stack_found = True
388ae252462SJerome Forissier                if self._regions:
389ae252462SJerome Forissier                    for r in self._regions:
390ae252462SJerome Forissier                        r_addr = r[0]
391ae252462SJerome Forissier                        r_size = r[1]
392ae252462SJerome Forissier                        elf_idx = r[2]
393ae252462SJerome Forissier                        saved_line = r[3]
394ae252462SJerome Forissier                        if elf_idx is None:
395ae252462SJerome Forissier                            self._out.write(saved_line)
396ae252462SJerome Forissier                        else:
397ae252462SJerome Forissier                            self._out.write(saved_line.strip() +
398ae252462SJerome Forissier                                            self.sections_in_region(r_addr,
399ae252462SJerome Forissier                                                                    r_size,
400ae252462SJerome Forissier                                                                    elf_idx) +
401ae252462SJerome Forissier                                            '\n')
402ae252462SJerome Forissier                if self._elfs:
403ae252462SJerome Forissier                    for k in self._elfs:
404ae252462SJerome Forissier                        e = self._elfs[k]
405ae252462SJerome Forissier                        if (len(e) >= 3):
4061e6f2ea0SJerome Forissier                            # TA executable or library
407095567e5SJerome Forissier                            self._out.write(e[2].strip())
408095567e5SJerome Forissier                            elf = self.get_elf(e[0])
409095567e5SJerome Forissier                            if elf:
410095567e5SJerome Forissier                                rpath = os.path.realpath(elf)
411095567e5SJerome Forissier                                path = self.pretty_print_path(rpath)
412095567e5SJerome Forissier                                self._out.write(' (' + path + ')')
413095567e5SJerome Forissier                            self._out.write('\n')
414142c5cccSJerome Forissier                # Here is a good place to resolve the abort address because we
415142c5cccSJerome Forissier                # have all the information we need
416142c5cccSJerome Forissier                if self._saved_abort_line:
417142c5cccSJerome Forissier                    self._out.write(self.process_abort(self._saved_abort_line))
418142c5cccSJerome Forissier            match = re.search(ABORT_ADDR_RE, line)
419142c5cccSJerome Forissier            if match:
42027b83ad2SJerome Forissier                self.reset()
421142c5cccSJerome Forissier                # At this point the arch and TA load address are unknown.
422142c5cccSJerome Forissier                # Save the line so We can translate the abort address later.
423142c5cccSJerome Forissier                self._saved_abort_line = line
424733a15f2SJerome Forissier            self._out.write(line)
425733a15f2SJerome Forissier
426733a15f2SJerome Forissier    def flush(self):
427733a15f2SJerome Forissier        self._out.flush()
428733a15f2SJerome Forissier
429ae252462SJerome Forissier
430733a15f2SJerome Forissierdef main():
431733a15f2SJerome Forissier    args = get_args()
432733a15f2SJerome Forissier    if args.dir:
433733a15f2SJerome Forissier        # Flatten list in case -d is used several times *and* with multiple
434733a15f2SJerome Forissier        # arguments
435733a15f2SJerome Forissier        args.dirs = [item for sublist in args.dir for item in sublist]
436733a15f2SJerome Forissier    else:
437733a15f2SJerome Forissier        args.dirs = []
438733a15f2SJerome Forissier    symbolizer = Symbolizer(sys.stdout, args.dirs, args.strip_path)
439733a15f2SJerome Forissier
440733a15f2SJerome Forissier    for line in sys.stdin:
441733a15f2SJerome Forissier        symbolizer.write(line)
442733a15f2SJerome Forissier    symbolizer.flush()
443733a15f2SJerome Forissier
4441d8c2a48SJerome Forissier
445733a15f2SJerome Forissierif __name__ == "__main__":
446733a15f2SJerome Forissier    main()
447