blob: 4f5e226418dbcf9976e949d829484c2341b29a97 [file] [log] [blame]
Rouven Czerwinskibbaeed42019-08-07 20:07:00 +02001#!/usr/bin/env python3
Jerome Forissier1bb92982017-12-15 14:27:02 +01002# SPDX-License-Identifier: BSD-2-Clause
Jerome Forissier733a15f2017-05-19 17:40:17 +02003#
4# Copyright (c) 2017, Linaro Limited
Jerome Forissier733a15f2017-05-19 17:40:17 +02005#
Jerome Forissier733a15f2017-05-19 17:40:17 +02006
7
8import argparse
Rouven Czerwinskibbaeed42019-08-07 20:07:00 +02009import errno
Jerome Forissier733a15f2017-05-19 17:40:17 +020010import glob
Jerome Forissier157e6212017-08-24 15:49:16 +020011import os
Jerome Forissier733a15f2017-05-19 17:40:17 +020012import re
13import subprocess
14import sys
Jerome Forissier6b4fc672019-09-23 09:49:32 +020015import termios
Jerome Forissier733a15f2017-05-19 17:40:17 +020016
Jerome Forissier733a15f2017-05-19 17:40:17 +020017CALL_STACK_RE = re.compile('Call stack:')
Sumit Gargd77929e2019-11-27 21:01:27 +053018TEE_LOAD_ADDR_RE = re.compile(r'TEE load address @ (?P<load_addr>0x[0-9a-f]+)')
Joakim Becha2b984b2017-12-15 14:34:56 +010019# This gets the address from lines looking like this:
20# E/TC:0 0x001044a8
Jerome Forissier6e7c2e92018-11-14 11:02:49 +010021STACK_ADDR_RE = re.compile(
Jens Wiklander531963a2019-05-23 17:42:15 +020022 r'[UEIDFM]/(TC|LD):(\?*|[0-9]*) [0-9]* +(?P<addr>0x[0-9a-f]+)')
Jerome Forissier6e7c2e92018-11-14 11:02:49 +010023ABORT_ADDR_RE = re.compile(r'-abort at address (?P<addr>0x[0-9a-f]+)')
Jerome Forissier444c2032019-03-13 18:00:56 +010024REGION_RE = re.compile(r'region +[0-9]+: va (?P<addr>0x[0-9a-f]+) '
Jerome Forissier6e7c2e92018-11-14 11:02:49 +010025 r'pa 0x[0-9a-f]+ size (?P<size>0x[0-9a-f]+)'
Jens Wiklander531963a2019-05-23 17:42:15 +020026 r'( flags .{4} (\[(?P<elf_idx>[0-9]+)\])?)?')
Jerome Forissierae252462018-05-25 15:07:28 +020027ELF_LIST_RE = re.compile(r'\[(?P<idx>[0-9]+)\] (?P<uuid>[0-9a-f\-]+)'
Jerome Forissier6e7c2e92018-11-14 11:02:49 +010028 r' @ (?P<load_addr>0x[0-9a-f\-]+)')
Sumit Gargc90b6662019-03-28 18:24:21 +053029FUNC_GRAPH_RE = re.compile(r'Function graph')
30GRAPH_ADDR_RE = re.compile(r'(?P<addr>0x[0-9a-f]+)')
31GRAPH_RE = re.compile(r'}')
Jerome Forissier733a15f2017-05-19 17:40:17 +020032
33epilog = '''
Jerome Forissier0c5bedb2018-02-15 17:20:36 +010034This scripts reads an OP-TEE abort or panic message from stdin and adds debug
35information to the output, such as '<function> at <file>:<line>' next to each
36address in the call stack. Any message generated by OP-TEE and containing a
37call stack can in principle be processed by this script. This currently
38includes aborts and panics from the TEE core as well as from any TA.
39The paths provided on the command line are used to locate the appropriate ELF
40binary (tee.elf or Trusted Application). The GNU binutils (addr2line, objdump,
Jerome Forissierf9089762018-10-02 10:12:32 +020041nm) are used to extract the debug info. If the CROSS_COMPILE environment
42variable is set, it is used as a prefix to the binutils tools. That is, the
43script will invoke $(CROSS_COMPILE)addr2line etc. If it is not set however,
44the prefix will be determined automatically for each ELF file based on its
45architecture (arm-linux-gnueabihf-, aarch64-linux-gnu-). The resulting command
46is then expected to be found in the user's PATH.
Jerome Forissier733a15f2017-05-19 17:40:17 +020047
Jerome Forissier0c5bedb2018-02-15 17:20:36 +010048OP-TEE abort and panic messages are sent to the secure console. They look like
49the following:
Jerome Forissier733a15f2017-05-19 17:40:17 +020050
Jerome Forissier0c5bedb2018-02-15 17:20:36 +010051 E/TC:0 User TA data-abort at address 0xffffdecd (alignment fault)
Jerome Forissier733a15f2017-05-19 17:40:17 +020052 ...
Jerome Forissier0c5bedb2018-02-15 17:20:36 +010053 E/TC:0 Call stack:
54 E/TC:0 0x4000549e
55 E/TC:0 0x40001f4b
56 E/TC:0 0x4000273f
57 E/TC:0 0x40005da7
Jerome Forissier733a15f2017-05-19 17:40:17 +020058
59Inspired by a script of the same name by the Chromium project.
60
61Sample usage:
62
63 $ scripts/symbolize.py -d out/arm-plat-hikey/core -d ../optee_test/out/ta/*
64 <paste whole dump here>
65 ^D
Sumit Gargc90b6662019-03-28 18:24:21 +053066
67Also, this script reads function graph generated for OP-TEE user TA from
68/tmp/ftrace-<ta_uuid>.out file and resolves function addresses to corresponding
69symbols.
70
71Sample usage:
72
73 $ cat /tmp/ftrace-<ta_uuid>.out | scripts/symbolize.py -d <ta_uuid>.elf
74 <paste function graph here>
75 ^D
Jerome Forissier733a15f2017-05-19 17:40:17 +020076'''
77
Jerome Forissierae252462018-05-25 15:07:28 +020078
Jerome Forissier733a15f2017-05-19 17:40:17 +020079def get_args():
80 parser = argparse.ArgumentParser(
Jerome Forissier6e7c2e92018-11-14 11:02:49 +010081 formatter_class=argparse.RawDescriptionHelpFormatter,
Sumit Gargc90b6662019-03-28 18:24:21 +053082 description='Symbolizes OP-TEE abort dumps or function graphs',
Jerome Forissier6e7c2e92018-11-14 11:02:49 +010083 epilog=epilog)
Jerome Forissier733a15f2017-05-19 17:40:17 +020084 parser.add_argument('-d', '--dir', action='append', nargs='+',
Jerome Forissier1d8c2a42018-09-07 17:05:21 +020085 help='Search for ELF file in DIR. tee.elf is needed '
86 'to decode a TEE Core or pseudo-TA abort, while '
87 '<TA_uuid>.elf is required if a user-mode TA has '
88 'crashed. For convenience, ELF files may also be '
89 'given.')
Jerome Forissier5f7df502018-02-15 16:57:55 +010090 parser.add_argument('-s', '--strip_path', nargs='?',
Jerome Forissier1d8c2a42018-09-07 17:05:21 +020091 help='Strip STRIP_PATH from file paths (default: '
92 'current directory, use -s with no argument to show '
93 'full paths)', default=os.getcwd())
Jerome Forissier733a15f2017-05-19 17:40:17 +020094
95 return parser.parse_args()
96
Jerome Forissierae252462018-05-25 15:07:28 +020097
Jerome Forissier733a15f2017-05-19 17:40:17 +020098class Symbolizer(object):
99 def __init__(self, out, dirs, strip_path):
100 self._out = out
101 self._dirs = dirs
102 self._strip_path = strip_path
103 self._addr2line = None
Jerome Forissier733a15f2017-05-19 17:40:17 +0200104 self.reset()
105
Jerome Forissier1cbf7772018-09-07 17:08:23 +0200106 def my_Popen(self, cmd):
107 try:
108 return subprocess.Popen(cmd, stdin=subprocess.PIPE,
Jerome Forissier17be2232020-01-29 14:21:06 +0100109 stdout=subprocess.PIPE,
110 universal_newlines=True,
Rouven Czerwinskibbaeed42019-08-07 20:07:00 +0200111 bufsize=1)
Jerome Forissier1cbf7772018-09-07 17:08:23 +0200112 except OSError as e:
Rouven Czerwinskibbaeed42019-08-07 20:07:00 +0200113 if e.errno == errno.ENOENT:
114 print("*** Error:{}: command not found".format(cmd[0]),
115 file=sys.stderr)
Jerome Forissier1cbf7772018-09-07 17:08:23 +0200116 sys.exit(1)
117
Jerome Forissier733a15f2017-05-19 17:40:17 +0200118 def get_elf(self, elf_or_uuid):
119 if not elf_or_uuid.endswith('.elf'):
120 elf_or_uuid += '.elf'
121 for d in self._dirs:
Jerome Forissier157e6212017-08-24 15:49:16 +0200122 if d.endswith(elf_or_uuid) and os.path.isfile(d):
123 return d
Jerome Forissier733a15f2017-05-19 17:40:17 +0200124 elf = glob.glob(d + '/' + elf_or_uuid)
125 if elf:
126 return elf[0]
127
Jerome Forissierd7204312017-09-04 17:58:52 +0200128 def set_arch(self):
129 if self._arch:
130 return
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100131 self._arch = os.getenv('CROSS_COMPILE')
Etienne Carriere8a6d4a82018-10-01 09:58:31 +0200132 if self._arch:
133 return
Jerome Forissierae252462018-05-25 15:07:28 +0200134 elf = self.get_elf(self._elfs[0][0])
135 if elf is None:
136 return
137 p = subprocess.Popen(['file', self.get_elf(self._elfs[0][0])],
138 stdout=subprocess.PIPE)
139 output = p.stdout.readlines()
140 p.terminate()
Rouven Czerwinskibbaeed42019-08-07 20:07:00 +0200141 if b'ARM aarch64,' in output[0]:
Jerome Forissierae252462018-05-25 15:07:28 +0200142 self._arch = 'aarch64-linux-gnu-'
Rouven Czerwinskibbaeed42019-08-07 20:07:00 +0200143 elif b'ARM,' in output[0]:
Jerome Forissierae252462018-05-25 15:07:28 +0200144 self._arch = 'arm-linux-gnueabihf-'
Jerome Forissierd7204312017-09-04 17:58:52 +0200145
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200146 def arch_prefix(self, cmd):
Jerome Forissierd7204312017-09-04 17:58:52 +0200147 self.set_arch()
Jerome Forissierae252462018-05-25 15:07:28 +0200148 if self._arch is None:
149 return ''
Jerome Forissierd7204312017-09-04 17:58:52 +0200150 return self._arch + cmd
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200151
Jerome Forissierae252462018-05-25 15:07:28 +0200152 def spawn_addr2line(self, elf_name):
153 if elf_name is None:
154 return
155 if self._addr2line_elf_name is elf_name:
156 return
157 if self._addr2line:
158 self._addr2line.terminate
159 self._addr2line = None
160 elf = self.get_elf(elf_name)
161 if not elf:
162 return
163 cmd = self.arch_prefix('addr2line')
164 if not cmd:
165 return
Jerome Forissierc0c57c82020-01-08 14:57:32 +0100166 self._addr2line = self.my_Popen([cmd, '-f', '-p', '-e', elf])
Jerome Forissierae252462018-05-25 15:07:28 +0200167
168 # If addr falls into a region that maps a TA ELF file, return the load
169 # address of that file.
170 def elf_load_addr(self, addr):
171 if self._regions:
172 for r in self._regions:
173 r_addr = int(r[0], 16)
174 r_size = int(r[1], 16)
175 i_addr = int(addr, 16)
176 if (i_addr >= r_addr and i_addr < (r_addr + r_size)):
177 # Found region
178 elf_idx = r[2]
179 if elf_idx is not None:
180 return self._elfs[int(elf_idx)][1]
Sumit Garg099918f2019-09-05 13:23:01 +0530181 # In case address is not found in TA ELF file, fallback to tee.elf
182 # especially to symbolize mixed (user-space and kernel) addresses
183 # which is true when syscall ftrace is enabled along with TA
184 # ftrace.
Jerome Forissier91068f82019-11-26 10:51:45 +0100185 return self._tee_load_addr
Jerome Forissierae252462018-05-25 15:07:28 +0200186 else:
187 # tee.elf
Jerome Forissier105e09c2019-10-16 16:59:35 +0200188 return self._tee_load_addr
Jerome Forissierae252462018-05-25 15:07:28 +0200189
190 def elf_for_addr(self, addr):
191 l_addr = self.elf_load_addr(addr)
Jerome Forissier91068f82019-11-26 10:51:45 +0100192 if l_addr == self._tee_load_addr:
193 return 'tee.elf'
Jerome Forissierae252462018-05-25 15:07:28 +0200194 for k in self._elfs:
195 e = self._elfs[k]
196 if int(e[1], 16) == int(l_addr, 16):
197 return e[0]
198 return None
Jerome Forissier733a15f2017-05-19 17:40:17 +0200199
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200200 def subtract_load_addr(self, addr):
Jerome Forissierae252462018-05-25 15:07:28 +0200201 l_addr = self.elf_load_addr(addr)
202 if l_addr is None:
203 return None
204 if int(l_addr, 16) > int(addr, 16):
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200205 return ''
Jerome Forissierae252462018-05-25 15:07:28 +0200206 return '0x{:x}'.format(int(addr, 16) - int(l_addr, 16))
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200207
208 def resolve(self, addr):
209 reladdr = self.subtract_load_addr(addr)
Jerome Forissierae252462018-05-25 15:07:28 +0200210 self.spawn_addr2line(self.elf_for_addr(addr))
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200211 if not reladdr or not self._addr2line:
Jerome Forissier733a15f2017-05-19 17:40:17 +0200212 return '???'
Jerome Forissierc0c57c82020-01-08 14:57:32 +0100213 if self.elf_for_addr(addr) == 'tee.elf':
214 reladdr = '0x{:x}'.format(int(reladdr, 16) +
215 int(self.first_vma('tee.elf'), 16))
Jerome Forissier733a15f2017-05-19 17:40:17 +0200216 try:
Rouven Czerwinskibbaeed42019-08-07 20:07:00 +0200217 print(reladdr, file=self._addr2line.stdin)
Jerome Forissier733a15f2017-05-19 17:40:17 +0200218 ret = self._addr2line.stdout.readline().rstrip('\n')
219 except IOError:
220 ret = '!!!'
221 return ret
222
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200223 def symbol_plus_offset(self, addr):
224 ret = ''
225 prevsize = 0
226 reladdr = self.subtract_load_addr(addr)
Jerome Forissierae252462018-05-25 15:07:28 +0200227 elf_name = self.elf_for_addr(addr)
228 if elf_name is None:
229 return ''
230 elf = self.get_elf(elf_name)
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200231 cmd = self.arch_prefix('nm')
232 if not reladdr or not elf or not cmd:
233 return ''
Jerome Forissier30999122017-08-25 18:42:58 +0200234 ireladdr = int(reladdr, 16)
Jerome Forissier1cbf7772018-09-07 17:08:23 +0200235 nm = self.my_Popen([cmd, '--numeric-sort', '--print-size', elf])
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200236 for line in iter(nm.stdout.readline, ''):
237 try:
238 addr, size, _, name = line.split()
Jerome Forissier1d8c2a42018-09-07 17:05:21 +0200239 except ValueError:
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200240 # Size is missing
Jerome Forissierb4815422018-06-20 09:43:33 +0200241 try:
242 addr, _, name = line.split()
243 size = '0'
Jerome Forissier1d8c2a42018-09-07 17:05:21 +0200244 except ValueError:
Jerome Forissierb4815422018-06-20 09:43:33 +0200245 # E.g., undefined (external) symbols (line = "U symbol")
246 continue
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200247 iaddr = int(addr, 16)
248 isize = int(size, 16)
249 if iaddr == ireladdr:
250 ret = name
251 break
252 if iaddr < ireladdr and iaddr + isize >= ireladdr:
253 offs = ireladdr - iaddr
254 ret = name + '+' + str(offs)
255 break
256 if iaddr > ireladdr and prevsize == 0:
257 offs = iaddr + ireladdr
258 ret = prevname + '+' + str(offs)
259 break
260 prevsize = size
261 prevname = name
262 nm.terminate()
263 return ret
264
265 def section_plus_offset(self, addr):
266 ret = ''
267 reladdr = self.subtract_load_addr(addr)
Jerome Forissierae252462018-05-25 15:07:28 +0200268 elf_name = self.elf_for_addr(addr)
269 if elf_name is None:
270 return ''
271 elf = self.get_elf(elf_name)
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200272 cmd = self.arch_prefix('objdump')
273 if not reladdr or not elf or not cmd:
274 return ''
Jerome Forissier30999122017-08-25 18:42:58 +0200275 iaddr = int(reladdr, 16)
Jerome Forissier1cbf7772018-09-07 17:08:23 +0200276 objdump = self.my_Popen([cmd, '--section-headers', elf])
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200277 for line in iter(objdump.stdout.readline, ''):
278 try:
279 idx, name, size, vma, lma, offs, algn = line.split()
Jerome Forissier1d8c2a42018-09-07 17:05:21 +0200280 except ValueError:
Jerome Forissierae252462018-05-25 15:07:28 +0200281 continue
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200282 ivma = int(vma, 16)
283 isize = int(size, 16)
284 if ivma == iaddr:
285 ret = name
286 break
287 if ivma < iaddr and ivma + isize >= iaddr:
288 offs = iaddr - ivma
289 ret = name + '+' + str(offs)
290 break
291 objdump.terminate()
292 return ret
293
294 def process_abort(self, line):
295 ret = ''
296 match = re.search(ABORT_ADDR_RE, line)
297 addr = match.group('addr')
298 pre = match.start('addr')
299 post = match.end('addr')
300 sym = self.symbol_plus_offset(addr)
301 sec = self.section_plus_offset(addr)
302 if sym or sec:
303 ret += line[:pre]
304 ret += addr
305 if sym:
306 ret += ' ' + sym
307 if sec:
308 ret += ' ' + sec
309 ret += line[post:]
310 return ret
311
Jerome Forissier30999122017-08-25 18:42:58 +0200312 # Return all ELF sections with the ALLOC flag
Jerome Forissierae252462018-05-25 15:07:28 +0200313 def read_sections(self, elf_name):
314 if elf_name is None:
Jerome Forissier30999122017-08-25 18:42:58 +0200315 return
Jerome Forissierae252462018-05-25 15:07:28 +0200316 if elf_name in self._sections:
317 return
318 elf = self.get_elf(elf_name)
Jerome Forissier30999122017-08-25 18:42:58 +0200319 cmd = self.arch_prefix('objdump')
320 if not elf or not cmd:
321 return
Jerome Forissierae252462018-05-25 15:07:28 +0200322 self._sections[elf_name] = []
Jerome Forissier1cbf7772018-09-07 17:08:23 +0200323 objdump = self.my_Popen([cmd, '--section-headers', elf])
Jerome Forissier30999122017-08-25 18:42:58 +0200324 for line in iter(objdump.stdout.readline, ''):
325 try:
326 _, name, size, vma, _, _, _ = line.split()
Jerome Forissier1d8c2a42018-09-07 17:05:21 +0200327 except ValueError:
Jerome Forissier30999122017-08-25 18:42:58 +0200328 if 'ALLOC' in line:
Jerome Forissierae252462018-05-25 15:07:28 +0200329 self._sections[elf_name].append([name, int(vma, 16),
330 int(size, 16)])
Jerome Forissier30999122017-08-25 18:42:58 +0200331
Jerome Forissierc0c57c82020-01-08 14:57:32 +0100332 def first_vma(self, elf_name):
333 self.read_sections(elf_name)
334 return '0x{:x}'.format(self._sections[elf_name][0][1])
335
Jerome Forissier30999122017-08-25 18:42:58 +0200336 def overlaps(self, section, addr, size):
337 sec_addr = section[1]
338 sec_size = section[2]
339 if not size or not sec_size:
340 return False
Jerome Forissierae252462018-05-25 15:07:28 +0200341 return ((addr <= (sec_addr + sec_size - 1)) and
342 ((addr + size - 1) >= sec_addr))
Jerome Forissier30999122017-08-25 18:42:58 +0200343
Jerome Forissierae252462018-05-25 15:07:28 +0200344 def sections_in_region(self, addr, size, elf_idx):
Jerome Forissier30999122017-08-25 18:42:58 +0200345 ret = ''
346 addr = self.subtract_load_addr(addr)
347 if not addr:
348 return ''
349 iaddr = int(addr, 16)
350 isize = int(size, 16)
Jerome Forissierae252462018-05-25 15:07:28 +0200351 elf = self._elfs[int(elf_idx)][0]
352 if elf is None:
353 return ''
354 self.read_sections(elf)
355 if elf not in self._sections:
356 return ''
357 for s in self._sections[elf]:
Jerome Forissier30999122017-08-25 18:42:58 +0200358 if self.overlaps(s, iaddr, isize):
359 ret += ' ' + s[0]
360 return ret
361
Jerome Forissier733a15f2017-05-19 17:40:17 +0200362 def reset(self):
363 self._call_stack_found = False
Jerome Forissier733a15f2017-05-19 17:40:17 +0200364 if self._addr2line:
365 self._addr2line.terminate()
366 self._addr2line = None
Jerome Forissierae252462018-05-25 15:07:28 +0200367 self._addr2line_elf_name = None
Jerome Forissierd7204312017-09-04 17:58:52 +0200368 self._arch = None
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200369 self._saved_abort_line = ''
Jerome Forissierae252462018-05-25 15:07:28 +0200370 self._sections = {} # {elf_name: [[name, addr, size], ...], ...}
371 self._regions = [] # [[addr, size, elf_idx, saved line], ...]
372 self._elfs = {0: ["tee.elf", 0]} # {idx: [uuid, load_addr], ...}
Jerome Forissier91068f82019-11-26 10:51:45 +0100373 self._tee_load_addr = '0x0'
Sumit Gargc90b6662019-03-28 18:24:21 +0530374 self._func_graph_found = False
375 self._func_graph_skip_line = True
Jerome Forissier733a15f2017-05-19 17:40:17 +0200376
Jerome Forissier095567e2018-05-29 17:42:34 +0200377 def pretty_print_path(self, path):
378 if self._strip_path:
379 return re.sub(re.escape(self._strip_path) + '/*', '', path)
380 return path
381
Jerome Forissier733a15f2017-05-19 17:40:17 +0200382 def write(self, line):
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100383 if self._call_stack_found:
384 match = re.search(STACK_ADDR_RE, line)
Jerome Forissier30999122017-08-25 18:42:58 +0200385 if match:
386 addr = match.group('addr')
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100387 pre = match.start('addr')
388 post = match.end('addr')
389 self._out.write(line[:pre])
390 self._out.write(addr)
391 res = self.resolve(addr)
392 res = self.pretty_print_path(res)
393 self._out.write(' ' + res)
394 self._out.write(line[post:])
Jerome Forissierae252462018-05-25 15:07:28 +0200395 return
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100396 else:
Jerome Forissier27b83ad2017-10-06 13:37:35 +0200397 self.reset()
Sumit Gargc90b6662019-03-28 18:24:21 +0530398 if self._func_graph_found:
399 match = re.search(GRAPH_ADDR_RE, line)
400 match_re = re.search(GRAPH_RE, line)
401 if match:
402 addr = match.group('addr')
403 pre = match.start('addr')
404 post = match.end('addr')
405 self._out.write(line[:pre])
406 res = self.resolve(addr)
407 res_arr = re.split(' ', res)
408 self._out.write(res_arr[0])
409 self._out.write(line[post:])
410 self._func_graph_skip_line = False
411 return
412 elif match_re:
413 self._out.write(line)
414 return
415 elif self._func_graph_skip_line:
416 return
417 else:
418 self.reset()
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100419 match = re.search(REGION_RE, line)
420 if match:
421 # Region table: save info for later processing once
422 # we know which UUID corresponds to which ELF index
423 addr = match.group('addr')
424 size = match.group('size')
425 elf_idx = match.group('elf_idx')
426 self._regions.append([addr, size, elf_idx, line])
427 return
428 match = re.search(ELF_LIST_RE, line)
429 if match:
430 # ELF list: save info for later. Region table and ELF list
431 # will be displayed when the call stack is reached
432 i = int(match.group('idx'))
433 self._elfs[i] = [match.group('uuid'), match.group('load_addr'),
434 line]
435 return
Jerome Forissier105e09c2019-10-16 16:59:35 +0200436 match = re.search(TEE_LOAD_ADDR_RE, line)
437 if match:
438 self._tee_load_addr = match.group('load_addr')
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100439 match = re.search(CALL_STACK_RE, line)
440 if match:
441 self._call_stack_found = True
442 if self._regions:
443 for r in self._regions:
444 r_addr = r[0]
445 r_size = r[1]
446 elf_idx = r[2]
447 saved_line = r[3]
448 if elf_idx is None:
449 self._out.write(saved_line)
450 else:
451 self._out.write(saved_line.strip() +
452 self.sections_in_region(r_addr,
453 r_size,
454 elf_idx) +
455 '\n')
456 if self._elfs:
457 for k in self._elfs:
458 e = self._elfs[k]
459 if (len(e) >= 3):
460 # TA executable or library
461 self._out.write(e[2].strip())
462 elf = self.get_elf(e[0])
463 if elf:
464 rpath = os.path.realpath(elf)
465 path = self.pretty_print_path(rpath)
466 self._out.write(' (' + path + ')')
467 self._out.write('\n')
468 # Here is a good place to resolve the abort address because we
469 # have all the information we need
470 if self._saved_abort_line:
471 self._out.write(self.process_abort(self._saved_abort_line))
Sumit Gargc90b6662019-03-28 18:24:21 +0530472 match = re.search(FUNC_GRAPH_RE, line)
473 if match:
474 self._func_graph_found = True
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100475 match = re.search(ABORT_ADDR_RE, line)
476 if match:
477 self.reset()
478 # At this point the arch and TA load address are unknown.
479 # Save the line so We can translate the abort address later.
480 self._saved_abort_line = line
481 self._out.write(line)
Jerome Forissier733a15f2017-05-19 17:40:17 +0200482
483 def flush(self):
484 self._out.flush()
485
Jerome Forissierae252462018-05-25 15:07:28 +0200486
Jerome Forissier733a15f2017-05-19 17:40:17 +0200487def main():
488 args = get_args()
489 if args.dir:
490 # Flatten list in case -d is used several times *and* with multiple
491 # arguments
492 args.dirs = [item for sublist in args.dir for item in sublist]
493 else:
494 args.dirs = []
495 symbolizer = Symbolizer(sys.stdout, args.dirs, args.strip_path)
496
Jerome Forissier6b4fc672019-09-23 09:49:32 +0200497 fd = sys.stdin.fileno()
Jerome Forissier20d152b2019-09-25 20:28:33 +0200498 isatty = os.isatty(fd)
499 if isatty:
500 old = termios.tcgetattr(fd)
501 new = termios.tcgetattr(fd)
502 new[3] = new[3] & ~termios.ECHO # lflags
Jerome Forissier6b4fc672019-09-23 09:49:32 +0200503 try:
Jerome Forissier20d152b2019-09-25 20:28:33 +0200504 if isatty:
505 termios.tcsetattr(fd, termios.TCSADRAIN, new)
Jerome Forissier6b4fc672019-09-23 09:49:32 +0200506 for line in sys.stdin:
507 symbolizer.write(line)
508 finally:
509 symbolizer.flush()
Jerome Forissier20d152b2019-09-25 20:28:33 +0200510 if isatty:
511 termios.tcsetattr(fd, termios.TCSADRAIN, old)
Jerome Forissier733a15f2017-05-19 17:40:17 +0200512
Jerome Forissier1d8c2a42018-09-07 17:05:21 +0200513
Jerome Forissier733a15f2017-05-19 17:40:17 +0200514if __name__ == "__main__":
515 main()