blob: d763fb0241e8979d1f88981781ed2ec95218e86d [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 Forissier24778de2020-02-12 14:48:03 +0100128 def set_arch(self, elf):
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100129 self._arch = os.getenv('CROSS_COMPILE')
Etienne Carriere8a6d4a82018-10-01 09:58:31 +0200130 if self._arch:
131 return
Jerome Forissier9bb9f372020-02-18 18:12:31 +0100132 p = subprocess.Popen(['file', '-L', elf], stdout=subprocess.PIPE)
Jerome Forissierae252462018-05-25 15:07:28 +0200133 output = p.stdout.readlines()
134 p.terminate()
Rouven Czerwinskibbaeed42019-08-07 20:07:00 +0200135 if b'ARM aarch64,' in output[0]:
Jerome Forissierae252462018-05-25 15:07:28 +0200136 self._arch = 'aarch64-linux-gnu-'
Rouven Czerwinskibbaeed42019-08-07 20:07:00 +0200137 elif b'ARM,' in output[0]:
Jerome Forissierae252462018-05-25 15:07:28 +0200138 self._arch = 'arm-linux-gnueabihf-'
Jerome Forissierd7204312017-09-04 17:58:52 +0200139
Jerome Forissier24778de2020-02-12 14:48:03 +0100140 def arch_prefix(self, cmd, elf):
141 self.set_arch(elf)
Jerome Forissierae252462018-05-25 15:07:28 +0200142 if self._arch is None:
143 return ''
Jerome Forissierd7204312017-09-04 17:58:52 +0200144 return self._arch + cmd
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200145
Jerome Forissierae252462018-05-25 15:07:28 +0200146 def spawn_addr2line(self, elf_name):
147 if elf_name is None:
148 return
149 if self._addr2line_elf_name is elf_name:
150 return
151 if self._addr2line:
152 self._addr2line.terminate
153 self._addr2line = None
154 elf = self.get_elf(elf_name)
155 if not elf:
156 return
Jerome Forissier24778de2020-02-12 14:48:03 +0100157 cmd = self.arch_prefix('addr2line', elf)
Jerome Forissierae252462018-05-25 15:07:28 +0200158 if not cmd:
159 return
Jerome Forissierc0c57c82020-01-08 14:57:32 +0100160 self._addr2line = self.my_Popen([cmd, '-f', '-p', '-e', elf])
Jerome Forissierba84a3f2020-02-12 14:44:03 +0100161 self._addr2line_elf_name = elf_name
Jerome Forissierae252462018-05-25 15:07:28 +0200162
163 # If addr falls into a region that maps a TA ELF file, return the load
164 # address of that file.
165 def elf_load_addr(self, addr):
166 if self._regions:
167 for r in self._regions:
168 r_addr = int(r[0], 16)
169 r_size = int(r[1], 16)
170 i_addr = int(addr, 16)
171 if (i_addr >= r_addr and i_addr < (r_addr + r_size)):
172 # Found region
173 elf_idx = r[2]
174 if elf_idx is not None:
175 return self._elfs[int(elf_idx)][1]
Sumit Garg099918f2019-09-05 13:23:01 +0530176 # In case address is not found in TA ELF file, fallback to tee.elf
177 # especially to symbolize mixed (user-space and kernel) addresses
178 # which is true when syscall ftrace is enabled along with TA
179 # ftrace.
Jerome Forissier91068f82019-11-26 10:51:45 +0100180 return self._tee_load_addr
Jerome Forissierae252462018-05-25 15:07:28 +0200181 else:
182 # tee.elf
Jerome Forissier105e09c2019-10-16 16:59:35 +0200183 return self._tee_load_addr
Jerome Forissierae252462018-05-25 15:07:28 +0200184
185 def elf_for_addr(self, addr):
186 l_addr = self.elf_load_addr(addr)
Jerome Forissier91068f82019-11-26 10:51:45 +0100187 if l_addr == self._tee_load_addr:
188 return 'tee.elf'
Jerome Forissierae252462018-05-25 15:07:28 +0200189 for k in self._elfs:
190 e = self._elfs[k]
191 if int(e[1], 16) == int(l_addr, 16):
192 return e[0]
193 return None
Jerome Forissier733a15f2017-05-19 17:40:17 +0200194
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200195 def subtract_load_addr(self, addr):
Jerome Forissierae252462018-05-25 15:07:28 +0200196 l_addr = self.elf_load_addr(addr)
197 if l_addr is None:
198 return None
199 if int(l_addr, 16) > int(addr, 16):
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200200 return ''
Jerome Forissierae252462018-05-25 15:07:28 +0200201 return '0x{:x}'.format(int(addr, 16) - int(l_addr, 16))
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200202
203 def resolve(self, addr):
204 reladdr = self.subtract_load_addr(addr)
Jerome Forissierae252462018-05-25 15:07:28 +0200205 self.spawn_addr2line(self.elf_for_addr(addr))
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200206 if not reladdr or not self._addr2line:
Jerome Forissier733a15f2017-05-19 17:40:17 +0200207 return '???'
Jerome Forissierc0c57c82020-01-08 14:57:32 +0100208 if self.elf_for_addr(addr) == 'tee.elf':
209 reladdr = '0x{:x}'.format(int(reladdr, 16) +
210 int(self.first_vma('tee.elf'), 16))
Jerome Forissier733a15f2017-05-19 17:40:17 +0200211 try:
Rouven Czerwinskibbaeed42019-08-07 20:07:00 +0200212 print(reladdr, file=self._addr2line.stdin)
Jerome Forissier733a15f2017-05-19 17:40:17 +0200213 ret = self._addr2line.stdout.readline().rstrip('\n')
214 except IOError:
215 ret = '!!!'
216 return ret
217
Jerome Forissier2a0d4562022-04-29 11:11:29 +0200218 # Armv8.5 with Memory Tagging Extension (MTE)
219 def strip_armv85_mte_tag(self, addr):
220 i_addr = int(addr, 16)
221 i_addr &= ~(0xf << 56)
222 return '0x{:x}'.format(i_addr)
223
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200224 def symbol_plus_offset(self, addr):
225 ret = ''
226 prevsize = 0
Jerome Forissier2a0d4562022-04-29 11:11:29 +0200227 addr = self.strip_armv85_mte_tag(addr)
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200228 reladdr = self.subtract_load_addr(addr)
Jerome Forissierae252462018-05-25 15:07:28 +0200229 elf_name = self.elf_for_addr(addr)
230 if elf_name is None:
231 return ''
232 elf = self.get_elf(elf_name)
Jerome Forissier24778de2020-02-12 14:48:03 +0100233 cmd = self.arch_prefix('nm', elf)
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200234 if not reladdr or not elf or not cmd:
235 return ''
Jerome Forissier30999122017-08-25 18:42:58 +0200236 ireladdr = int(reladdr, 16)
Jerome Forissier1cbf7772018-09-07 17:08:23 +0200237 nm = self.my_Popen([cmd, '--numeric-sort', '--print-size', elf])
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200238 for line in iter(nm.stdout.readline, ''):
239 try:
240 addr, size, _, name = line.split()
Jerome Forissier1d8c2a42018-09-07 17:05:21 +0200241 except ValueError:
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200242 # Size is missing
Jerome Forissierb4815422018-06-20 09:43:33 +0200243 try:
244 addr, _, name = line.split()
245 size = '0'
Jerome Forissier1d8c2a42018-09-07 17:05:21 +0200246 except ValueError:
Jerome Forissierb4815422018-06-20 09:43:33 +0200247 # E.g., undefined (external) symbols (line = "U symbol")
248 continue
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200249 iaddr = int(addr, 16)
250 isize = int(size, 16)
251 if iaddr == ireladdr:
252 ret = name
253 break
254 if iaddr < ireladdr and iaddr + isize >= ireladdr:
255 offs = ireladdr - iaddr
256 ret = name + '+' + str(offs)
257 break
258 if iaddr > ireladdr and prevsize == 0:
259 offs = iaddr + ireladdr
260 ret = prevname + '+' + str(offs)
261 break
262 prevsize = size
263 prevname = name
264 nm.terminate()
265 return ret
266
267 def section_plus_offset(self, addr):
268 ret = ''
269 reladdr = self.subtract_load_addr(addr)
Jerome Forissierae252462018-05-25 15:07:28 +0200270 elf_name = self.elf_for_addr(addr)
271 if elf_name is None:
272 return ''
273 elf = self.get_elf(elf_name)
Jerome Forissier24778de2020-02-12 14:48:03 +0100274 cmd = self.arch_prefix('objdump', elf)
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200275 if not reladdr or not elf or not cmd:
276 return ''
Jerome Forissier30999122017-08-25 18:42:58 +0200277 iaddr = int(reladdr, 16)
Jerome Forissier1cbf7772018-09-07 17:08:23 +0200278 objdump = self.my_Popen([cmd, '--section-headers', elf])
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200279 for line in iter(objdump.stdout.readline, ''):
280 try:
281 idx, name, size, vma, lma, offs, algn = line.split()
Jerome Forissier1d8c2a42018-09-07 17:05:21 +0200282 except ValueError:
Jerome Forissierae252462018-05-25 15:07:28 +0200283 continue
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200284 ivma = int(vma, 16)
285 isize = int(size, 16)
286 if ivma == iaddr:
287 ret = name
288 break
289 if ivma < iaddr and ivma + isize >= iaddr:
290 offs = iaddr - ivma
291 ret = name + '+' + str(offs)
292 break
293 objdump.terminate()
294 return ret
295
296 def process_abort(self, line):
297 ret = ''
298 match = re.search(ABORT_ADDR_RE, line)
299 addr = match.group('addr')
300 pre = match.start('addr')
301 post = match.end('addr')
302 sym = self.symbol_plus_offset(addr)
303 sec = self.section_plus_offset(addr)
304 if sym or sec:
305 ret += line[:pre]
306 ret += addr
307 if sym:
308 ret += ' ' + sym
309 if sec:
310 ret += ' ' + sec
311 ret += line[post:]
312 return ret
313
Jerome Forissier30999122017-08-25 18:42:58 +0200314 # Return all ELF sections with the ALLOC flag
Jerome Forissierae252462018-05-25 15:07:28 +0200315 def read_sections(self, elf_name):
316 if elf_name is None:
Jerome Forissier30999122017-08-25 18:42:58 +0200317 return
Jerome Forissierae252462018-05-25 15:07:28 +0200318 if elf_name in self._sections:
319 return
320 elf = self.get_elf(elf_name)
Jerome Forissierd7c22ac2020-06-22 14:07:38 +0200321 if not elf:
322 return
Jerome Forissier24778de2020-02-12 14:48:03 +0100323 cmd = self.arch_prefix('objdump', elf)
Jerome Forissier30999122017-08-25 18:42:58 +0200324 if not elf or not cmd:
325 return
Jerome Forissierae252462018-05-25 15:07:28 +0200326 self._sections[elf_name] = []
Jerome Forissier1cbf7772018-09-07 17:08:23 +0200327 objdump = self.my_Popen([cmd, '--section-headers', elf])
Jerome Forissier30999122017-08-25 18:42:58 +0200328 for line in iter(objdump.stdout.readline, ''):
329 try:
330 _, name, size, vma, _, _, _ = line.split()
Jerome Forissier1d8c2a42018-09-07 17:05:21 +0200331 except ValueError:
Jerome Forissier30999122017-08-25 18:42:58 +0200332 if 'ALLOC' in line:
Jerome Forissierae252462018-05-25 15:07:28 +0200333 self._sections[elf_name].append([name, int(vma, 16),
334 int(size, 16)])
Jerome Forissier30999122017-08-25 18:42:58 +0200335
Jerome Forissierc0c57c82020-01-08 14:57:32 +0100336 def first_vma(self, elf_name):
337 self.read_sections(elf_name)
338 return '0x{:x}'.format(self._sections[elf_name][0][1])
339
Jerome Forissier30999122017-08-25 18:42:58 +0200340 def overlaps(self, section, addr, size):
341 sec_addr = section[1]
342 sec_size = section[2]
343 if not size or not sec_size:
344 return False
Jerome Forissierae252462018-05-25 15:07:28 +0200345 return ((addr <= (sec_addr + sec_size - 1)) and
346 ((addr + size - 1) >= sec_addr))
Jerome Forissier30999122017-08-25 18:42:58 +0200347
Jerome Forissierae252462018-05-25 15:07:28 +0200348 def sections_in_region(self, addr, size, elf_idx):
Jerome Forissier30999122017-08-25 18:42:58 +0200349 ret = ''
350 addr = self.subtract_load_addr(addr)
351 if not addr:
352 return ''
353 iaddr = int(addr, 16)
354 isize = int(size, 16)
Jerome Forissierae252462018-05-25 15:07:28 +0200355 elf = self._elfs[int(elf_idx)][0]
356 if elf is None:
357 return ''
358 self.read_sections(elf)
359 if elf not in self._sections:
360 return ''
361 for s in self._sections[elf]:
Jerome Forissier30999122017-08-25 18:42:58 +0200362 if self.overlaps(s, iaddr, isize):
363 ret += ' ' + s[0]
364 return ret
365
Jerome Forissier733a15f2017-05-19 17:40:17 +0200366 def reset(self):
367 self._call_stack_found = False
Jerome Forissier733a15f2017-05-19 17:40:17 +0200368 if self._addr2line:
369 self._addr2line.terminate()
370 self._addr2line = None
Jerome Forissierae252462018-05-25 15:07:28 +0200371 self._addr2line_elf_name = None
Jerome Forissierd7204312017-09-04 17:58:52 +0200372 self._arch = None
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200373 self._saved_abort_line = ''
Jerome Forissierae252462018-05-25 15:07:28 +0200374 self._sections = {} # {elf_name: [[name, addr, size], ...], ...}
375 self._regions = [] # [[addr, size, elf_idx, saved line], ...]
376 self._elfs = {0: ["tee.elf", 0]} # {idx: [uuid, load_addr], ...}
Jerome Forissier91068f82019-11-26 10:51:45 +0100377 self._tee_load_addr = '0x0'
Sumit Gargc90b6662019-03-28 18:24:21 +0530378 self._func_graph_found = False
379 self._func_graph_skip_line = True
Jerome Forissier733a15f2017-05-19 17:40:17 +0200380
Jerome Forissier095567e2018-05-29 17:42:34 +0200381 def pretty_print_path(self, path):
382 if self._strip_path:
383 return re.sub(re.escape(self._strip_path) + '/*', '', path)
384 return path
385
Jerome Forissier733a15f2017-05-19 17:40:17 +0200386 def write(self, line):
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100387 if self._call_stack_found:
388 match = re.search(STACK_ADDR_RE, line)
Jerome Forissier30999122017-08-25 18:42:58 +0200389 if match:
390 addr = match.group('addr')
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100391 pre = match.start('addr')
392 post = match.end('addr')
393 self._out.write(line[:pre])
394 self._out.write(addr)
Jerome Forissier5500d702020-07-31 11:30:54 +0200395 # The call stack contains return addresses (LR/ELR values).
396 # Heuristic: subtract 2 to obtain the call site of the function
397 # or the location of the exception. This value works for A64,
398 # A32 as well as Thumb.
399 pc = 0
400 lr = int(addr, 16)
401 if lr:
402 pc = lr - 2
403 res = self.resolve('0x{:x}'.format(pc))
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100404 res = self.pretty_print_path(res)
405 self._out.write(' ' + res)
406 self._out.write(line[post:])
Jerome Forissierae252462018-05-25 15:07:28 +0200407 return
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100408 else:
Jerome Forissier27b83ad2017-10-06 13:37:35 +0200409 self.reset()
Sumit Gargc90b6662019-03-28 18:24:21 +0530410 if self._func_graph_found:
411 match = re.search(GRAPH_ADDR_RE, line)
412 match_re = re.search(GRAPH_RE, line)
413 if match:
414 addr = match.group('addr')
415 pre = match.start('addr')
416 post = match.end('addr')
417 self._out.write(line[:pre])
418 res = self.resolve(addr)
419 res_arr = re.split(' ', res)
420 self._out.write(res_arr[0])
421 self._out.write(line[post:])
422 self._func_graph_skip_line = False
423 return
424 elif match_re:
425 self._out.write(line)
426 return
427 elif self._func_graph_skip_line:
428 return
429 else:
430 self.reset()
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100431 match = re.search(REGION_RE, line)
432 if match:
433 # Region table: save info for later processing once
434 # we know which UUID corresponds to which ELF index
435 addr = match.group('addr')
436 size = match.group('size')
437 elf_idx = match.group('elf_idx')
438 self._regions.append([addr, size, elf_idx, line])
439 return
440 match = re.search(ELF_LIST_RE, line)
441 if match:
442 # ELF list: save info for later. Region table and ELF list
443 # will be displayed when the call stack is reached
444 i = int(match.group('idx'))
445 self._elfs[i] = [match.group('uuid'), match.group('load_addr'),
446 line]
447 return
Jerome Forissier105e09c2019-10-16 16:59:35 +0200448 match = re.search(TEE_LOAD_ADDR_RE, line)
449 if match:
450 self._tee_load_addr = match.group('load_addr')
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100451 match = re.search(CALL_STACK_RE, line)
452 if match:
453 self._call_stack_found = True
454 if self._regions:
455 for r in self._regions:
456 r_addr = r[0]
457 r_size = r[1]
458 elf_idx = r[2]
459 saved_line = r[3]
460 if elf_idx is None:
461 self._out.write(saved_line)
462 else:
463 self._out.write(saved_line.strip() +
464 self.sections_in_region(r_addr,
465 r_size,
466 elf_idx) +
467 '\n')
468 if self._elfs:
469 for k in self._elfs:
470 e = self._elfs[k]
471 if (len(e) >= 3):
472 # TA executable or library
473 self._out.write(e[2].strip())
474 elf = self.get_elf(e[0])
475 if elf:
476 rpath = os.path.realpath(elf)
477 path = self.pretty_print_path(rpath)
478 self._out.write(' (' + path + ')')
479 self._out.write('\n')
480 # Here is a good place to resolve the abort address because we
481 # have all the information we need
482 if self._saved_abort_line:
483 self._out.write(self.process_abort(self._saved_abort_line))
Sumit Gargc90b6662019-03-28 18:24:21 +0530484 match = re.search(FUNC_GRAPH_RE, line)
485 if match:
486 self._func_graph_found = True
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100487 match = re.search(ABORT_ADDR_RE, line)
488 if match:
489 self.reset()
490 # At this point the arch and TA load address are unknown.
491 # Save the line so We can translate the abort address later.
492 self._saved_abort_line = line
493 self._out.write(line)
Jerome Forissier733a15f2017-05-19 17:40:17 +0200494
495 def flush(self):
496 self._out.flush()
497
Jerome Forissierae252462018-05-25 15:07:28 +0200498
Jerome Forissier733a15f2017-05-19 17:40:17 +0200499def main():
500 args = get_args()
501 if args.dir:
502 # Flatten list in case -d is used several times *and* with multiple
503 # arguments
504 args.dirs = [item for sublist in args.dir for item in sublist]
505 else:
506 args.dirs = []
507 symbolizer = Symbolizer(sys.stdout, args.dirs, args.strip_path)
508
Jerome Forissier6b4fc672019-09-23 09:49:32 +0200509 fd = sys.stdin.fileno()
Jerome Forissier20d152b2019-09-25 20:28:33 +0200510 isatty = os.isatty(fd)
511 if isatty:
512 old = termios.tcgetattr(fd)
513 new = termios.tcgetattr(fd)
514 new[3] = new[3] & ~termios.ECHO # lflags
Jerome Forissier6b4fc672019-09-23 09:49:32 +0200515 try:
Jerome Forissier20d152b2019-09-25 20:28:33 +0200516 if isatty:
517 termios.tcsetattr(fd, termios.TCSADRAIN, new)
Jerome Forissier6b4fc672019-09-23 09:49:32 +0200518 for line in sys.stdin:
519 symbolizer.write(line)
520 finally:
521 symbolizer.flush()
Jerome Forissier20d152b2019-09-25 20:28:33 +0200522 if isatty:
523 termios.tcsetattr(fd, termios.TCSADRAIN, old)
Jerome Forissier733a15f2017-05-19 17:40:17 +0200524
Jerome Forissier1d8c2a42018-09-07 17:05:21 +0200525
Jerome Forissier733a15f2017-05-19 17:40:17 +0200526if __name__ == "__main__":
527 main()