blob: a6224755867ef3c1c5d9575f9256e3e3230cbb61 [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 Forissierba84a3f2020-02-12 14:44:03 +0100167 self._addr2line_elf_name = elf_name
Jerome Forissierae252462018-05-25 15:07:28 +0200168
169 # If addr falls into a region that maps a TA ELF file, return the load
170 # address of that file.
171 def elf_load_addr(self, addr):
172 if self._regions:
173 for r in self._regions:
174 r_addr = int(r[0], 16)
175 r_size = int(r[1], 16)
176 i_addr = int(addr, 16)
177 if (i_addr >= r_addr and i_addr < (r_addr + r_size)):
178 # Found region
179 elf_idx = r[2]
180 if elf_idx is not None:
181 return self._elfs[int(elf_idx)][1]
Sumit Garg099918f2019-09-05 13:23:01 +0530182 # In case address is not found in TA ELF file, fallback to tee.elf
183 # especially to symbolize mixed (user-space and kernel) addresses
184 # which is true when syscall ftrace is enabled along with TA
185 # ftrace.
Jerome Forissier91068f82019-11-26 10:51:45 +0100186 return self._tee_load_addr
Jerome Forissierae252462018-05-25 15:07:28 +0200187 else:
188 # tee.elf
Jerome Forissier105e09c2019-10-16 16:59:35 +0200189 return self._tee_load_addr
Jerome Forissierae252462018-05-25 15:07:28 +0200190
191 def elf_for_addr(self, addr):
192 l_addr = self.elf_load_addr(addr)
Jerome Forissier91068f82019-11-26 10:51:45 +0100193 if l_addr == self._tee_load_addr:
194 return 'tee.elf'
Jerome Forissierae252462018-05-25 15:07:28 +0200195 for k in self._elfs:
196 e = self._elfs[k]
197 if int(e[1], 16) == int(l_addr, 16):
198 return e[0]
199 return None
Jerome Forissier733a15f2017-05-19 17:40:17 +0200200
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200201 def subtract_load_addr(self, addr):
Jerome Forissierae252462018-05-25 15:07:28 +0200202 l_addr = self.elf_load_addr(addr)
203 if l_addr is None:
204 return None
205 if int(l_addr, 16) > int(addr, 16):
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200206 return ''
Jerome Forissierae252462018-05-25 15:07:28 +0200207 return '0x{:x}'.format(int(addr, 16) - int(l_addr, 16))
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200208
209 def resolve(self, addr):
210 reladdr = self.subtract_load_addr(addr)
Jerome Forissierae252462018-05-25 15:07:28 +0200211 self.spawn_addr2line(self.elf_for_addr(addr))
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200212 if not reladdr or not self._addr2line:
Jerome Forissier733a15f2017-05-19 17:40:17 +0200213 return '???'
Jerome Forissierc0c57c82020-01-08 14:57:32 +0100214 if self.elf_for_addr(addr) == 'tee.elf':
215 reladdr = '0x{:x}'.format(int(reladdr, 16) +
216 int(self.first_vma('tee.elf'), 16))
Jerome Forissier733a15f2017-05-19 17:40:17 +0200217 try:
Rouven Czerwinskibbaeed42019-08-07 20:07:00 +0200218 print(reladdr, file=self._addr2line.stdin)
Jerome Forissier733a15f2017-05-19 17:40:17 +0200219 ret = self._addr2line.stdout.readline().rstrip('\n')
220 except IOError:
221 ret = '!!!'
222 return ret
223
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200224 def symbol_plus_offset(self, addr):
225 ret = ''
226 prevsize = 0
227 reladdr = self.subtract_load_addr(addr)
Jerome Forissierae252462018-05-25 15:07:28 +0200228 elf_name = self.elf_for_addr(addr)
229 if elf_name is None:
230 return ''
231 elf = self.get_elf(elf_name)
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200232 cmd = self.arch_prefix('nm')
233 if not reladdr or not elf or not cmd:
234 return ''
Jerome Forissier30999122017-08-25 18:42:58 +0200235 ireladdr = int(reladdr, 16)
Jerome Forissier1cbf7772018-09-07 17:08:23 +0200236 nm = self.my_Popen([cmd, '--numeric-sort', '--print-size', elf])
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200237 for line in iter(nm.stdout.readline, ''):
238 try:
239 addr, size, _, name = line.split()
Jerome Forissier1d8c2a42018-09-07 17:05:21 +0200240 except ValueError:
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200241 # Size is missing
Jerome Forissierb4815422018-06-20 09:43:33 +0200242 try:
243 addr, _, name = line.split()
244 size = '0'
Jerome Forissier1d8c2a42018-09-07 17:05:21 +0200245 except ValueError:
Jerome Forissierb4815422018-06-20 09:43:33 +0200246 # E.g., undefined (external) symbols (line = "U symbol")
247 continue
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200248 iaddr = int(addr, 16)
249 isize = int(size, 16)
250 if iaddr == ireladdr:
251 ret = name
252 break
253 if iaddr < ireladdr and iaddr + isize >= ireladdr:
254 offs = ireladdr - iaddr
255 ret = name + '+' + str(offs)
256 break
257 if iaddr > ireladdr and prevsize == 0:
258 offs = iaddr + ireladdr
259 ret = prevname + '+' + str(offs)
260 break
261 prevsize = size
262 prevname = name
263 nm.terminate()
264 return ret
265
266 def section_plus_offset(self, addr):
267 ret = ''
268 reladdr = self.subtract_load_addr(addr)
Jerome Forissierae252462018-05-25 15:07:28 +0200269 elf_name = self.elf_for_addr(addr)
270 if elf_name is None:
271 return ''
272 elf = self.get_elf(elf_name)
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200273 cmd = self.arch_prefix('objdump')
274 if not reladdr or not elf or not cmd:
275 return ''
Jerome Forissier30999122017-08-25 18:42:58 +0200276 iaddr = int(reladdr, 16)
Jerome Forissier1cbf7772018-09-07 17:08:23 +0200277 objdump = self.my_Popen([cmd, '--section-headers', elf])
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200278 for line in iter(objdump.stdout.readline, ''):
279 try:
280 idx, name, size, vma, lma, offs, algn = line.split()
Jerome Forissier1d8c2a42018-09-07 17:05:21 +0200281 except ValueError:
Jerome Forissierae252462018-05-25 15:07:28 +0200282 continue
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200283 ivma = int(vma, 16)
284 isize = int(size, 16)
285 if ivma == iaddr:
286 ret = name
287 break
288 if ivma < iaddr and ivma + isize >= iaddr:
289 offs = iaddr - ivma
290 ret = name + '+' + str(offs)
291 break
292 objdump.terminate()
293 return ret
294
295 def process_abort(self, line):
296 ret = ''
297 match = re.search(ABORT_ADDR_RE, line)
298 addr = match.group('addr')
299 pre = match.start('addr')
300 post = match.end('addr')
301 sym = self.symbol_plus_offset(addr)
302 sec = self.section_plus_offset(addr)
303 if sym or sec:
304 ret += line[:pre]
305 ret += addr
306 if sym:
307 ret += ' ' + sym
308 if sec:
309 ret += ' ' + sec
310 ret += line[post:]
311 return ret
312
Jerome Forissier30999122017-08-25 18:42:58 +0200313 # Return all ELF sections with the ALLOC flag
Jerome Forissierae252462018-05-25 15:07:28 +0200314 def read_sections(self, elf_name):
315 if elf_name is None:
Jerome Forissier30999122017-08-25 18:42:58 +0200316 return
Jerome Forissierae252462018-05-25 15:07:28 +0200317 if elf_name in self._sections:
318 return
319 elf = self.get_elf(elf_name)
Jerome Forissier30999122017-08-25 18:42:58 +0200320 cmd = self.arch_prefix('objdump')
321 if not elf or not cmd:
322 return
Jerome Forissierae252462018-05-25 15:07:28 +0200323 self._sections[elf_name] = []
Jerome Forissier1cbf7772018-09-07 17:08:23 +0200324 objdump = self.my_Popen([cmd, '--section-headers', elf])
Jerome Forissier30999122017-08-25 18:42:58 +0200325 for line in iter(objdump.stdout.readline, ''):
326 try:
327 _, name, size, vma, _, _, _ = line.split()
Jerome Forissier1d8c2a42018-09-07 17:05:21 +0200328 except ValueError:
Jerome Forissier30999122017-08-25 18:42:58 +0200329 if 'ALLOC' in line:
Jerome Forissierae252462018-05-25 15:07:28 +0200330 self._sections[elf_name].append([name, int(vma, 16),
331 int(size, 16)])
Jerome Forissier30999122017-08-25 18:42:58 +0200332
Jerome Forissierc0c57c82020-01-08 14:57:32 +0100333 def first_vma(self, elf_name):
334 self.read_sections(elf_name)
335 return '0x{:x}'.format(self._sections[elf_name][0][1])
336
Jerome Forissier30999122017-08-25 18:42:58 +0200337 def overlaps(self, section, addr, size):
338 sec_addr = section[1]
339 sec_size = section[2]
340 if not size or not sec_size:
341 return False
Jerome Forissierae252462018-05-25 15:07:28 +0200342 return ((addr <= (sec_addr + sec_size - 1)) and
343 ((addr + size - 1) >= sec_addr))
Jerome Forissier30999122017-08-25 18:42:58 +0200344
Jerome Forissierae252462018-05-25 15:07:28 +0200345 def sections_in_region(self, addr, size, elf_idx):
Jerome Forissier30999122017-08-25 18:42:58 +0200346 ret = ''
347 addr = self.subtract_load_addr(addr)
348 if not addr:
349 return ''
350 iaddr = int(addr, 16)
351 isize = int(size, 16)
Jerome Forissierae252462018-05-25 15:07:28 +0200352 elf = self._elfs[int(elf_idx)][0]
353 if elf is None:
354 return ''
355 self.read_sections(elf)
356 if elf not in self._sections:
357 return ''
358 for s in self._sections[elf]:
Jerome Forissier30999122017-08-25 18:42:58 +0200359 if self.overlaps(s, iaddr, isize):
360 ret += ' ' + s[0]
361 return ret
362
Jerome Forissier733a15f2017-05-19 17:40:17 +0200363 def reset(self):
364 self._call_stack_found = False
Jerome Forissier733a15f2017-05-19 17:40:17 +0200365 if self._addr2line:
366 self._addr2line.terminate()
367 self._addr2line = None
Jerome Forissierae252462018-05-25 15:07:28 +0200368 self._addr2line_elf_name = None
Jerome Forissierd7204312017-09-04 17:58:52 +0200369 self._arch = None
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200370 self._saved_abort_line = ''
Jerome Forissierae252462018-05-25 15:07:28 +0200371 self._sections = {} # {elf_name: [[name, addr, size], ...], ...}
372 self._regions = [] # [[addr, size, elf_idx, saved line], ...]
373 self._elfs = {0: ["tee.elf", 0]} # {idx: [uuid, load_addr], ...}
Jerome Forissier91068f82019-11-26 10:51:45 +0100374 self._tee_load_addr = '0x0'
Sumit Gargc90b6662019-03-28 18:24:21 +0530375 self._func_graph_found = False
376 self._func_graph_skip_line = True
Jerome Forissier733a15f2017-05-19 17:40:17 +0200377
Jerome Forissier095567e2018-05-29 17:42:34 +0200378 def pretty_print_path(self, path):
379 if self._strip_path:
380 return re.sub(re.escape(self._strip_path) + '/*', '', path)
381 return path
382
Jerome Forissier733a15f2017-05-19 17:40:17 +0200383 def write(self, line):
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100384 if self._call_stack_found:
385 match = re.search(STACK_ADDR_RE, line)
Jerome Forissier30999122017-08-25 18:42:58 +0200386 if match:
387 addr = match.group('addr')
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100388 pre = match.start('addr')
389 post = match.end('addr')
390 self._out.write(line[:pre])
391 self._out.write(addr)
392 res = self.resolve(addr)
393 res = self.pretty_print_path(res)
394 self._out.write(' ' + res)
395 self._out.write(line[post:])
Jerome Forissierae252462018-05-25 15:07:28 +0200396 return
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100397 else:
Jerome Forissier27b83ad2017-10-06 13:37:35 +0200398 self.reset()
Sumit Gargc90b6662019-03-28 18:24:21 +0530399 if self._func_graph_found:
400 match = re.search(GRAPH_ADDR_RE, line)
401 match_re = re.search(GRAPH_RE, line)
402 if match:
403 addr = match.group('addr')
404 pre = match.start('addr')
405 post = match.end('addr')
406 self._out.write(line[:pre])
407 res = self.resolve(addr)
408 res_arr = re.split(' ', res)
409 self._out.write(res_arr[0])
410 self._out.write(line[post:])
411 self._func_graph_skip_line = False
412 return
413 elif match_re:
414 self._out.write(line)
415 return
416 elif self._func_graph_skip_line:
417 return
418 else:
419 self.reset()
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100420 match = re.search(REGION_RE, line)
421 if match:
422 # Region table: save info for later processing once
423 # we know which UUID corresponds to which ELF index
424 addr = match.group('addr')
425 size = match.group('size')
426 elf_idx = match.group('elf_idx')
427 self._regions.append([addr, size, elf_idx, line])
428 return
429 match = re.search(ELF_LIST_RE, line)
430 if match:
431 # ELF list: save info for later. Region table and ELF list
432 # will be displayed when the call stack is reached
433 i = int(match.group('idx'))
434 self._elfs[i] = [match.group('uuid'), match.group('load_addr'),
435 line]
436 return
Jerome Forissier105e09c2019-10-16 16:59:35 +0200437 match = re.search(TEE_LOAD_ADDR_RE, line)
438 if match:
439 self._tee_load_addr = match.group('load_addr')
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100440 match = re.search(CALL_STACK_RE, line)
441 if match:
442 self._call_stack_found = True
443 if self._regions:
444 for r in self._regions:
445 r_addr = r[0]
446 r_size = r[1]
447 elf_idx = r[2]
448 saved_line = r[3]
449 if elf_idx is None:
450 self._out.write(saved_line)
451 else:
452 self._out.write(saved_line.strip() +
453 self.sections_in_region(r_addr,
454 r_size,
455 elf_idx) +
456 '\n')
457 if self._elfs:
458 for k in self._elfs:
459 e = self._elfs[k]
460 if (len(e) >= 3):
461 # TA executable or library
462 self._out.write(e[2].strip())
463 elf = self.get_elf(e[0])
464 if elf:
465 rpath = os.path.realpath(elf)
466 path = self.pretty_print_path(rpath)
467 self._out.write(' (' + path + ')')
468 self._out.write('\n')
469 # Here is a good place to resolve the abort address because we
470 # have all the information we need
471 if self._saved_abort_line:
472 self._out.write(self.process_abort(self._saved_abort_line))
Sumit Gargc90b6662019-03-28 18:24:21 +0530473 match = re.search(FUNC_GRAPH_RE, line)
474 if match:
475 self._func_graph_found = True
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100476 match = re.search(ABORT_ADDR_RE, line)
477 if match:
478 self.reset()
479 # At this point the arch and TA load address are unknown.
480 # Save the line so We can translate the abort address later.
481 self._saved_abort_line = line
482 self._out.write(line)
Jerome Forissier733a15f2017-05-19 17:40:17 +0200483
484 def flush(self):
485 self._out.flush()
486
Jerome Forissierae252462018-05-25 15:07:28 +0200487
Jerome Forissier733a15f2017-05-19 17:40:17 +0200488def main():
489 args = get_args()
490 if args.dir:
491 # Flatten list in case -d is used several times *and* with multiple
492 # arguments
493 args.dirs = [item for sublist in args.dir for item in sublist]
494 else:
495 args.dirs = []
496 symbolizer = Symbolizer(sys.stdout, args.dirs, args.strip_path)
497
Jerome Forissier6b4fc672019-09-23 09:49:32 +0200498 fd = sys.stdin.fileno()
Jerome Forissier20d152b2019-09-25 20:28:33 +0200499 isatty = os.isatty(fd)
500 if isatty:
501 old = termios.tcgetattr(fd)
502 new = termios.tcgetattr(fd)
503 new[3] = new[3] & ~termios.ECHO # lflags
Jerome Forissier6b4fc672019-09-23 09:49:32 +0200504 try:
Jerome Forissier20d152b2019-09-25 20:28:33 +0200505 if isatty:
506 termios.tcsetattr(fd, termios.TCSADRAIN, new)
Jerome Forissier6b4fc672019-09-23 09:49:32 +0200507 for line in sys.stdin:
508 symbolizer.write(line)
509 finally:
510 symbolizer.flush()
Jerome Forissier20d152b2019-09-25 20:28:33 +0200511 if isatty:
512 termios.tcsetattr(fd, termios.TCSADRAIN, old)
Jerome Forissier733a15f2017-05-19 17:40:17 +0200513
Jerome Forissier1d8c2a42018-09-07 17:05:21 +0200514
Jerome Forissier733a15f2017-05-19 17:40:17 +0200515if __name__ == "__main__":
516 main()