blob: 206e820714b6fecba7b9169482d5325598a018df [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,
Rouven Czerwinskibbaeed42019-08-07 20:07:00 +0200109 stdout=subprocess.PIPE, text=True,
110 bufsize=1)
Jerome Forissier1cbf7772018-09-07 17:08:23 +0200111 except OSError as e:
Rouven Czerwinskibbaeed42019-08-07 20:07:00 +0200112 if e.errno == errno.ENOENT:
113 print("*** Error:{}: command not found".format(cmd[0]),
114 file=sys.stderr)
Jerome Forissier1cbf7772018-09-07 17:08:23 +0200115 sys.exit(1)
116
Jerome Forissier733a15f2017-05-19 17:40:17 +0200117 def get_elf(self, elf_or_uuid):
118 if not elf_or_uuid.endswith('.elf'):
119 elf_or_uuid += '.elf'
120 for d in self._dirs:
Jerome Forissier157e6212017-08-24 15:49:16 +0200121 if d.endswith(elf_or_uuid) and os.path.isfile(d):
122 return d
Jerome Forissier733a15f2017-05-19 17:40:17 +0200123 elf = glob.glob(d + '/' + elf_or_uuid)
124 if elf:
125 return elf[0]
126
Jerome Forissierd7204312017-09-04 17:58:52 +0200127 def set_arch(self):
128 if self._arch:
129 return
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100130 self._arch = os.getenv('CROSS_COMPILE')
Etienne Carriere8a6d4a82018-10-01 09:58:31 +0200131 if self._arch:
132 return
Jerome Forissierae252462018-05-25 15:07:28 +0200133 elf = self.get_elf(self._elfs[0][0])
134 if elf is None:
135 return
136 p = subprocess.Popen(['file', self.get_elf(self._elfs[0][0])],
137 stdout=subprocess.PIPE)
138 output = p.stdout.readlines()
139 p.terminate()
Rouven Czerwinskibbaeed42019-08-07 20:07:00 +0200140 if b'ARM aarch64,' in output[0]:
Jerome Forissierae252462018-05-25 15:07:28 +0200141 self._arch = 'aarch64-linux-gnu-'
Rouven Czerwinskibbaeed42019-08-07 20:07:00 +0200142 elif b'ARM,' in output[0]:
Jerome Forissierae252462018-05-25 15:07:28 +0200143 self._arch = 'arm-linux-gnueabihf-'
Jerome Forissierd7204312017-09-04 17:58:52 +0200144
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200145 def arch_prefix(self, cmd):
Jerome Forissierd7204312017-09-04 17:58:52 +0200146 self.set_arch()
Jerome Forissierae252462018-05-25 15:07:28 +0200147 if self._arch is None:
148 return ''
Jerome Forissierd7204312017-09-04 17:58:52 +0200149 return self._arch + cmd
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200150
Jerome Forissierae252462018-05-25 15:07:28 +0200151 def spawn_addr2line(self, elf_name):
152 if elf_name is None:
153 return
154 if self._addr2line_elf_name is elf_name:
155 return
156 if self._addr2line:
157 self._addr2line.terminate
158 self._addr2line = None
159 elf = self.get_elf(elf_name)
160 if not elf:
161 return
162 cmd = self.arch_prefix('addr2line')
163 if not cmd:
164 return
Jerome Forissierc0c57c82020-01-08 14:57:32 +0100165 self._addr2line = self.my_Popen([cmd, '-f', '-p', '-e', elf])
Jerome Forissierae252462018-05-25 15:07:28 +0200166
167 # If addr falls into a region that maps a TA ELF file, return the load
168 # address of that file.
169 def elf_load_addr(self, addr):
170 if self._regions:
171 for r in self._regions:
172 r_addr = int(r[0], 16)
173 r_size = int(r[1], 16)
174 i_addr = int(addr, 16)
175 if (i_addr >= r_addr and i_addr < (r_addr + r_size)):
176 # Found region
177 elf_idx = r[2]
178 if elf_idx is not None:
179 return self._elfs[int(elf_idx)][1]
Sumit Garg099918f2019-09-05 13:23:01 +0530180 # In case address is not found in TA ELF file, fallback to tee.elf
181 # especially to symbolize mixed (user-space and kernel) addresses
182 # which is true when syscall ftrace is enabled along with TA
183 # ftrace.
Jerome Forissier91068f82019-11-26 10:51:45 +0100184 return self._tee_load_addr
Jerome Forissierae252462018-05-25 15:07:28 +0200185 else:
186 # tee.elf
Jerome Forissier105e09c2019-10-16 16:59:35 +0200187 return self._tee_load_addr
Jerome Forissierae252462018-05-25 15:07:28 +0200188
189 def elf_for_addr(self, addr):
190 l_addr = self.elf_load_addr(addr)
Jerome Forissier91068f82019-11-26 10:51:45 +0100191 if l_addr == self._tee_load_addr:
192 return 'tee.elf'
Jerome Forissierae252462018-05-25 15:07:28 +0200193 for k in self._elfs:
194 e = self._elfs[k]
195 if int(e[1], 16) == int(l_addr, 16):
196 return e[0]
197 return None
Jerome Forissier733a15f2017-05-19 17:40:17 +0200198
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200199 def subtract_load_addr(self, addr):
Jerome Forissierae252462018-05-25 15:07:28 +0200200 l_addr = self.elf_load_addr(addr)
201 if l_addr is None:
202 return None
203 if int(l_addr, 16) > int(addr, 16):
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200204 return ''
Jerome Forissierae252462018-05-25 15:07:28 +0200205 return '0x{:x}'.format(int(addr, 16) - int(l_addr, 16))
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200206
207 def resolve(self, addr):
208 reladdr = self.subtract_load_addr(addr)
Jerome Forissierae252462018-05-25 15:07:28 +0200209 self.spawn_addr2line(self.elf_for_addr(addr))
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200210 if not reladdr or not self._addr2line:
Jerome Forissier733a15f2017-05-19 17:40:17 +0200211 return '???'
Jerome Forissierc0c57c82020-01-08 14:57:32 +0100212 if self.elf_for_addr(addr) == 'tee.elf':
213 reladdr = '0x{:x}'.format(int(reladdr, 16) +
214 int(self.first_vma('tee.elf'), 16))
Jerome Forissier733a15f2017-05-19 17:40:17 +0200215 try:
Rouven Czerwinskibbaeed42019-08-07 20:07:00 +0200216 print(reladdr, file=self._addr2line.stdin)
Jerome Forissier733a15f2017-05-19 17:40:17 +0200217 ret = self._addr2line.stdout.readline().rstrip('\n')
218 except IOError:
219 ret = '!!!'
220 return ret
221
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200222 def symbol_plus_offset(self, addr):
223 ret = ''
224 prevsize = 0
225 reladdr = self.subtract_load_addr(addr)
Jerome Forissierae252462018-05-25 15:07:28 +0200226 elf_name = self.elf_for_addr(addr)
227 if elf_name is None:
228 return ''
229 elf = self.get_elf(elf_name)
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200230 cmd = self.arch_prefix('nm')
231 if not reladdr or not elf or not cmd:
232 return ''
Jerome Forissier30999122017-08-25 18:42:58 +0200233 ireladdr = int(reladdr, 16)
Jerome Forissier1cbf7772018-09-07 17:08:23 +0200234 nm = self.my_Popen([cmd, '--numeric-sort', '--print-size', elf])
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200235 for line in iter(nm.stdout.readline, ''):
236 try:
237 addr, size, _, name = line.split()
Jerome Forissier1d8c2a42018-09-07 17:05:21 +0200238 except ValueError:
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200239 # Size is missing
Jerome Forissierb4815422018-06-20 09:43:33 +0200240 try:
241 addr, _, name = line.split()
242 size = '0'
Jerome Forissier1d8c2a42018-09-07 17:05:21 +0200243 except ValueError:
Jerome Forissierb4815422018-06-20 09:43:33 +0200244 # E.g., undefined (external) symbols (line = "U symbol")
245 continue
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200246 iaddr = int(addr, 16)
247 isize = int(size, 16)
248 if iaddr == ireladdr:
249 ret = name
250 break
251 if iaddr < ireladdr and iaddr + isize >= ireladdr:
252 offs = ireladdr - iaddr
253 ret = name + '+' + str(offs)
254 break
255 if iaddr > ireladdr and prevsize == 0:
256 offs = iaddr + ireladdr
257 ret = prevname + '+' + str(offs)
258 break
259 prevsize = size
260 prevname = name
261 nm.terminate()
262 return ret
263
264 def section_plus_offset(self, addr):
265 ret = ''
266 reladdr = self.subtract_load_addr(addr)
Jerome Forissierae252462018-05-25 15:07:28 +0200267 elf_name = self.elf_for_addr(addr)
268 if elf_name is None:
269 return ''
270 elf = self.get_elf(elf_name)
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200271 cmd = self.arch_prefix('objdump')
272 if not reladdr or not elf or not cmd:
273 return ''
Jerome Forissier30999122017-08-25 18:42:58 +0200274 iaddr = int(reladdr, 16)
Jerome Forissier1cbf7772018-09-07 17:08:23 +0200275 objdump = self.my_Popen([cmd, '--section-headers', elf])
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200276 for line in iter(objdump.stdout.readline, ''):
277 try:
278 idx, name, size, vma, lma, offs, algn = line.split()
Jerome Forissier1d8c2a42018-09-07 17:05:21 +0200279 except ValueError:
Jerome Forissierae252462018-05-25 15:07:28 +0200280 continue
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200281 ivma = int(vma, 16)
282 isize = int(size, 16)
283 if ivma == iaddr:
284 ret = name
285 break
286 if ivma < iaddr and ivma + isize >= iaddr:
287 offs = iaddr - ivma
288 ret = name + '+' + str(offs)
289 break
290 objdump.terminate()
291 return ret
292
293 def process_abort(self, line):
294 ret = ''
295 match = re.search(ABORT_ADDR_RE, line)
296 addr = match.group('addr')
297 pre = match.start('addr')
298 post = match.end('addr')
299 sym = self.symbol_plus_offset(addr)
300 sec = self.section_plus_offset(addr)
301 if sym or sec:
302 ret += line[:pre]
303 ret += addr
304 if sym:
305 ret += ' ' + sym
306 if sec:
307 ret += ' ' + sec
308 ret += line[post:]
309 return ret
310
Jerome Forissier30999122017-08-25 18:42:58 +0200311 # Return all ELF sections with the ALLOC flag
Jerome Forissierae252462018-05-25 15:07:28 +0200312 def read_sections(self, elf_name):
313 if elf_name is None:
Jerome Forissier30999122017-08-25 18:42:58 +0200314 return
Jerome Forissierae252462018-05-25 15:07:28 +0200315 if elf_name in self._sections:
316 return
317 elf = self.get_elf(elf_name)
Jerome Forissier30999122017-08-25 18:42:58 +0200318 cmd = self.arch_prefix('objdump')
319 if not elf or not cmd:
320 return
Jerome Forissierae252462018-05-25 15:07:28 +0200321 self._sections[elf_name] = []
Jerome Forissier1cbf7772018-09-07 17:08:23 +0200322 objdump = self.my_Popen([cmd, '--section-headers', elf])
Jerome Forissier30999122017-08-25 18:42:58 +0200323 for line in iter(objdump.stdout.readline, ''):
324 try:
325 _, name, size, vma, _, _, _ = line.split()
Jerome Forissier1d8c2a42018-09-07 17:05:21 +0200326 except ValueError:
Jerome Forissier30999122017-08-25 18:42:58 +0200327 if 'ALLOC' in line:
Jerome Forissierae252462018-05-25 15:07:28 +0200328 self._sections[elf_name].append([name, int(vma, 16),
329 int(size, 16)])
Jerome Forissier30999122017-08-25 18:42:58 +0200330
Jerome Forissierc0c57c82020-01-08 14:57:32 +0100331 def first_vma(self, elf_name):
332 self.read_sections(elf_name)
333 return '0x{:x}'.format(self._sections[elf_name][0][1])
334
Jerome Forissier30999122017-08-25 18:42:58 +0200335 def overlaps(self, section, addr, size):
336 sec_addr = section[1]
337 sec_size = section[2]
338 if not size or not sec_size:
339 return False
Jerome Forissierae252462018-05-25 15:07:28 +0200340 return ((addr <= (sec_addr + sec_size - 1)) and
341 ((addr + size - 1) >= sec_addr))
Jerome Forissier30999122017-08-25 18:42:58 +0200342
Jerome Forissierae252462018-05-25 15:07:28 +0200343 def sections_in_region(self, addr, size, elf_idx):
Jerome Forissier30999122017-08-25 18:42:58 +0200344 ret = ''
345 addr = self.subtract_load_addr(addr)
346 if not addr:
347 return ''
348 iaddr = int(addr, 16)
349 isize = int(size, 16)
Jerome Forissierae252462018-05-25 15:07:28 +0200350 elf = self._elfs[int(elf_idx)][0]
351 if elf is None:
352 return ''
353 self.read_sections(elf)
354 if elf not in self._sections:
355 return ''
356 for s in self._sections[elf]:
Jerome Forissier30999122017-08-25 18:42:58 +0200357 if self.overlaps(s, iaddr, isize):
358 ret += ' ' + s[0]
359 return ret
360
Jerome Forissier733a15f2017-05-19 17:40:17 +0200361 def reset(self):
362 self._call_stack_found = False
Jerome Forissier733a15f2017-05-19 17:40:17 +0200363 if self._addr2line:
364 self._addr2line.terminate()
365 self._addr2line = None
Jerome Forissierae252462018-05-25 15:07:28 +0200366 self._addr2line_elf_name = None
Jerome Forissierd7204312017-09-04 17:58:52 +0200367 self._arch = None
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200368 self._saved_abort_line = ''
Jerome Forissierae252462018-05-25 15:07:28 +0200369 self._sections = {} # {elf_name: [[name, addr, size], ...], ...}
370 self._regions = [] # [[addr, size, elf_idx, saved line], ...]
371 self._elfs = {0: ["tee.elf", 0]} # {idx: [uuid, load_addr], ...}
Jerome Forissier91068f82019-11-26 10:51:45 +0100372 self._tee_load_addr = '0x0'
Sumit Gargc90b6662019-03-28 18:24:21 +0530373 self._func_graph_found = False
374 self._func_graph_skip_line = True
Jerome Forissier733a15f2017-05-19 17:40:17 +0200375
Jerome Forissier095567e2018-05-29 17:42:34 +0200376 def pretty_print_path(self, path):
377 if self._strip_path:
378 return re.sub(re.escape(self._strip_path) + '/*', '', path)
379 return path
380
Jerome Forissier733a15f2017-05-19 17:40:17 +0200381 def write(self, line):
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100382 if self._call_stack_found:
383 match = re.search(STACK_ADDR_RE, line)
Jerome Forissier30999122017-08-25 18:42:58 +0200384 if match:
385 addr = match.group('addr')
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100386 pre = match.start('addr')
387 post = match.end('addr')
388 self._out.write(line[:pre])
389 self._out.write(addr)
390 res = self.resolve(addr)
391 res = self.pretty_print_path(res)
392 self._out.write(' ' + res)
393 self._out.write(line[post:])
Jerome Forissierae252462018-05-25 15:07:28 +0200394 return
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100395 else:
Jerome Forissier27b83ad2017-10-06 13:37:35 +0200396 self.reset()
Sumit Gargc90b6662019-03-28 18:24:21 +0530397 if self._func_graph_found:
398 match = re.search(GRAPH_ADDR_RE, line)
399 match_re = re.search(GRAPH_RE, line)
400 if match:
401 addr = match.group('addr')
402 pre = match.start('addr')
403 post = match.end('addr')
404 self._out.write(line[:pre])
405 res = self.resolve(addr)
406 res_arr = re.split(' ', res)
407 self._out.write(res_arr[0])
408 self._out.write(line[post:])
409 self._func_graph_skip_line = False
410 return
411 elif match_re:
412 self._out.write(line)
413 return
414 elif self._func_graph_skip_line:
415 return
416 else:
417 self.reset()
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100418 match = re.search(REGION_RE, line)
419 if match:
420 # Region table: save info for later processing once
421 # we know which UUID corresponds to which ELF index
422 addr = match.group('addr')
423 size = match.group('size')
424 elf_idx = match.group('elf_idx')
425 self._regions.append([addr, size, elf_idx, line])
426 return
427 match = re.search(ELF_LIST_RE, line)
428 if match:
429 # ELF list: save info for later. Region table and ELF list
430 # will be displayed when the call stack is reached
431 i = int(match.group('idx'))
432 self._elfs[i] = [match.group('uuid'), match.group('load_addr'),
433 line]
434 return
Jerome Forissier105e09c2019-10-16 16:59:35 +0200435 match = re.search(TEE_LOAD_ADDR_RE, line)
436 if match:
437 self._tee_load_addr = match.group('load_addr')
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100438 match = re.search(CALL_STACK_RE, line)
439 if match:
440 self._call_stack_found = True
441 if self._regions:
442 for r in self._regions:
443 r_addr = r[0]
444 r_size = r[1]
445 elf_idx = r[2]
446 saved_line = r[3]
447 if elf_idx is None:
448 self._out.write(saved_line)
449 else:
450 self._out.write(saved_line.strip() +
451 self.sections_in_region(r_addr,
452 r_size,
453 elf_idx) +
454 '\n')
455 if self._elfs:
456 for k in self._elfs:
457 e = self._elfs[k]
458 if (len(e) >= 3):
459 # TA executable or library
460 self._out.write(e[2].strip())
461 elf = self.get_elf(e[0])
462 if elf:
463 rpath = os.path.realpath(elf)
464 path = self.pretty_print_path(rpath)
465 self._out.write(' (' + path + ')')
466 self._out.write('\n')
467 # Here is a good place to resolve the abort address because we
468 # have all the information we need
469 if self._saved_abort_line:
470 self._out.write(self.process_abort(self._saved_abort_line))
Sumit Gargc90b6662019-03-28 18:24:21 +0530471 match = re.search(FUNC_GRAPH_RE, line)
472 if match:
473 self._func_graph_found = True
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100474 match = re.search(ABORT_ADDR_RE, line)
475 if match:
476 self.reset()
477 # At this point the arch and TA load address are unknown.
478 # Save the line so We can translate the abort address later.
479 self._saved_abort_line = line
480 self._out.write(line)
Jerome Forissier733a15f2017-05-19 17:40:17 +0200481
482 def flush(self):
483 self._out.flush()
484
Jerome Forissierae252462018-05-25 15:07:28 +0200485
Jerome Forissier733a15f2017-05-19 17:40:17 +0200486def main():
487 args = get_args()
488 if args.dir:
489 # Flatten list in case -d is used several times *and* with multiple
490 # arguments
491 args.dirs = [item for sublist in args.dir for item in sublist]
492 else:
493 args.dirs = []
494 symbolizer = Symbolizer(sys.stdout, args.dirs, args.strip_path)
495
Jerome Forissier6b4fc672019-09-23 09:49:32 +0200496 fd = sys.stdin.fileno()
Jerome Forissier20d152b2019-09-25 20:28:33 +0200497 isatty = os.isatty(fd)
498 if isatty:
499 old = termios.tcgetattr(fd)
500 new = termios.tcgetattr(fd)
501 new[3] = new[3] & ~termios.ECHO # lflags
Jerome Forissier6b4fc672019-09-23 09:49:32 +0200502 try:
Jerome Forissier20d152b2019-09-25 20:28:33 +0200503 if isatty:
504 termios.tcsetattr(fd, termios.TCSADRAIN, new)
Jerome Forissier6b4fc672019-09-23 09:49:32 +0200505 for line in sys.stdin:
506 symbolizer.write(line)
507 finally:
508 symbolizer.flush()
Jerome Forissier20d152b2019-09-25 20:28:33 +0200509 if isatty:
510 termios.tcsetattr(fd, termios.TCSADRAIN, old)
Jerome Forissier733a15f2017-05-19 17:40:17 +0200511
Jerome Forissier1d8c2a42018-09-07 17:05:21 +0200512
Jerome Forissier733a15f2017-05-19 17:40:17 +0200513if __name__ == "__main__":
514 main()