blob: 7dbc533d57fe3bbdcb3f1e202730180c0fa7dd6c [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 Forissier99e82b12022-05-05 10:19:22 +020024TA_PANIC_RE = re.compile(r'TA panicked with code (?P<code>0x[0-9a-f]+)')
Jerome Forissier444c2032019-03-13 18:00:56 +010025REGION_RE = re.compile(r'region +[0-9]+: va (?P<addr>0x[0-9a-f]+) '
Jerome Forissier6e7c2e92018-11-14 11:02:49 +010026 r'pa 0x[0-9a-f]+ size (?P<size>0x[0-9a-f]+)'
Jens Wiklander531963a2019-05-23 17:42:15 +020027 r'( flags .{4} (\[(?P<elf_idx>[0-9]+)\])?)?')
Jerome Forissierae252462018-05-25 15:07:28 +020028ELF_LIST_RE = re.compile(r'\[(?P<idx>[0-9]+)\] (?P<uuid>[0-9a-f\-]+)'
Jerome Forissier6e7c2e92018-11-14 11:02:49 +010029 r' @ (?P<load_addr>0x[0-9a-f\-]+)')
Sumit Gargc90b6662019-03-28 18:24:21 +053030FUNC_GRAPH_RE = re.compile(r'Function graph')
31GRAPH_ADDR_RE = re.compile(r'(?P<addr>0x[0-9a-f]+)')
32GRAPH_RE = re.compile(r'}')
Jerome Forissier733a15f2017-05-19 17:40:17 +020033
34epilog = '''
Jerome Forissier0c5bedb2018-02-15 17:20:36 +010035This scripts reads an OP-TEE abort or panic message from stdin and adds debug
36information to the output, such as '<function> at <file>:<line>' next to each
37address in the call stack. Any message generated by OP-TEE and containing a
38call stack can in principle be processed by this script. This currently
39includes aborts and panics from the TEE core as well as from any TA.
40The paths provided on the command line are used to locate the appropriate ELF
41binary (tee.elf or Trusted Application). The GNU binutils (addr2line, objdump,
Jerome Forissierf9089762018-10-02 10:12:32 +020042nm) are used to extract the debug info. If the CROSS_COMPILE environment
43variable is set, it is used as a prefix to the binutils tools. That is, the
44script will invoke $(CROSS_COMPILE)addr2line etc. If it is not set however,
45the prefix will be determined automatically for each ELF file based on its
46architecture (arm-linux-gnueabihf-, aarch64-linux-gnu-). The resulting command
47is then expected to be found in the user's PATH.
Jerome Forissier733a15f2017-05-19 17:40:17 +020048
Jerome Forissier0c5bedb2018-02-15 17:20:36 +010049OP-TEE abort and panic messages are sent to the secure console. They look like
50the following:
Jerome Forissier733a15f2017-05-19 17:40:17 +020051
Jerome Forissier0c5bedb2018-02-15 17:20:36 +010052 E/TC:0 User TA data-abort at address 0xffffdecd (alignment fault)
Jerome Forissier733a15f2017-05-19 17:40:17 +020053 ...
Jerome Forissier0c5bedb2018-02-15 17:20:36 +010054 E/TC:0 Call stack:
55 E/TC:0 0x4000549e
56 E/TC:0 0x40001f4b
57 E/TC:0 0x4000273f
58 E/TC:0 0x40005da7
Jerome Forissier733a15f2017-05-19 17:40:17 +020059
60Inspired by a script of the same name by the Chromium project.
61
62Sample usage:
63
64 $ scripts/symbolize.py -d out/arm-plat-hikey/core -d ../optee_test/out/ta/*
65 <paste whole dump here>
66 ^D
Sumit Gargc90b6662019-03-28 18:24:21 +053067
68Also, this script reads function graph generated for OP-TEE user TA from
69/tmp/ftrace-<ta_uuid>.out file and resolves function addresses to corresponding
70symbols.
71
72Sample usage:
73
74 $ cat /tmp/ftrace-<ta_uuid>.out | scripts/symbolize.py -d <ta_uuid>.elf
75 <paste function graph here>
76 ^D
Jerome Forissier733a15f2017-05-19 17:40:17 +020077'''
78
Jerome Forissier99e82b12022-05-05 10:19:22 +020079tee_result_names = {
80 '0xf0100001': 'TEE_ERROR_CORRUPT_OBJECT',
81 '0xf0100002': 'TEE_ERROR_CORRUPT_OBJECT_2',
82 '0xf0100003': 'TEE_ERROR_STORAGE_NOT_AVAILABLE',
83 '0xf0100004': 'TEE_ERROR_STORAGE_NOT_AVAILABLE_2',
84 '0xf0100006': 'TEE_ERROR_CIPHERTEXT_INVALID ',
85 '0xffff0000': 'TEE_ERROR_GENERIC',
86 '0xffff0001': 'TEE_ERROR_ACCESS_DENIED',
87 '0xffff0002': 'TEE_ERROR_CANCEL',
88 '0xffff0003': 'TEE_ERROR_ACCESS_CONFLICT',
89 '0xffff0004': 'TEE_ERROR_EXCESS_DATA',
90 '0xffff0005': 'TEE_ERROR_BAD_FORMAT',
91 '0xffff0006': 'TEE_ERROR_BAD_PARAMETERS',
92 '0xffff0007': 'TEE_ERROR_BAD_STATE',
93 '0xffff0008': 'TEE_ERROR_ITEM_NOT_FOUND',
94 '0xffff0009': 'TEE_ERROR_NOT_IMPLEMENTED',
95 '0xffff000a': 'TEE_ERROR_NOT_SUPPORTED',
96 '0xffff000b': 'TEE_ERROR_NO_DATA',
97 '0xffff000c': 'TEE_ERROR_OUT_OF_MEMORY',
98 '0xffff000d': 'TEE_ERROR_BUSY',
99 '0xffff000e': 'TEE_ERROR_COMMUNICATION',
100 '0xffff000f': 'TEE_ERROR_SECURITY',
101 '0xffff0010': 'TEE_ERROR_SHORT_BUFFER',
102 '0xffff0011': 'TEE_ERROR_EXTERNAL_CANCEL',
103 '0xffff300f': 'TEE_ERROR_OVERFLOW',
104 '0xffff3024': 'TEE_ERROR_TARGET_DEAD',
105 '0xffff3041': 'TEE_ERROR_STORAGE_NO_SPACE',
106 '0xffff3071': 'TEE_ERROR_MAC_INVALID',
107 '0xffff3072': 'TEE_ERROR_SIGNATURE_INVALID',
108 '0xffff5000': 'TEE_ERROR_TIME_NOT_SET',
109 '0xffff5001': 'TEE_ERROR_TIME_NEEDS_RESET',
110 }
111
Jerome Forissierae252462018-05-25 15:07:28 +0200112
Jerome Forissier733a15f2017-05-19 17:40:17 +0200113def get_args():
114 parser = argparse.ArgumentParser(
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100115 formatter_class=argparse.RawDescriptionHelpFormatter,
Sumit Gargc90b6662019-03-28 18:24:21 +0530116 description='Symbolizes OP-TEE abort dumps or function graphs',
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100117 epilog=epilog)
Jerome Forissier733a15f2017-05-19 17:40:17 +0200118 parser.add_argument('-d', '--dir', action='append', nargs='+',
Jerome Forissier1d8c2a42018-09-07 17:05:21 +0200119 help='Search for ELF file in DIR. tee.elf is needed '
120 'to decode a TEE Core or pseudo-TA abort, while '
121 '<TA_uuid>.elf is required if a user-mode TA has '
122 'crashed. For convenience, ELF files may also be '
123 'given.')
Jerome Forissier5f7df502018-02-15 16:57:55 +0100124 parser.add_argument('-s', '--strip_path', nargs='?',
Jerome Forissier1d8c2a42018-09-07 17:05:21 +0200125 help='Strip STRIP_PATH from file paths (default: '
126 'current directory, use -s with no argument to show '
127 'full paths)', default=os.getcwd())
Jerome Forissier733a15f2017-05-19 17:40:17 +0200128
129 return parser.parse_args()
130
Jerome Forissierae252462018-05-25 15:07:28 +0200131
Jerome Forissier733a15f2017-05-19 17:40:17 +0200132class Symbolizer(object):
133 def __init__(self, out, dirs, strip_path):
134 self._out = out
135 self._dirs = dirs
136 self._strip_path = strip_path
137 self._addr2line = None
Jerome Forissier733a15f2017-05-19 17:40:17 +0200138 self.reset()
139
Jerome Forissier1cbf7772018-09-07 17:08:23 +0200140 def my_Popen(self, cmd):
141 try:
142 return subprocess.Popen(cmd, stdin=subprocess.PIPE,
Jerome Forissier17be2232020-01-29 14:21:06 +0100143 stdout=subprocess.PIPE,
144 universal_newlines=True,
Rouven Czerwinskibbaeed42019-08-07 20:07:00 +0200145 bufsize=1)
Jerome Forissier1cbf7772018-09-07 17:08:23 +0200146 except OSError as e:
Rouven Czerwinskibbaeed42019-08-07 20:07:00 +0200147 if e.errno == errno.ENOENT:
148 print("*** Error:{}: command not found".format(cmd[0]),
149 file=sys.stderr)
Jerome Forissier1cbf7772018-09-07 17:08:23 +0200150 sys.exit(1)
151
Jerome Forissier733a15f2017-05-19 17:40:17 +0200152 def get_elf(self, elf_or_uuid):
153 if not elf_or_uuid.endswith('.elf'):
154 elf_or_uuid += '.elf'
155 for d in self._dirs:
Jerome Forissier157e6212017-08-24 15:49:16 +0200156 if d.endswith(elf_or_uuid) and os.path.isfile(d):
157 return d
Jerome Forissier733a15f2017-05-19 17:40:17 +0200158 elf = glob.glob(d + '/' + elf_or_uuid)
159 if elf:
160 return elf[0]
161
Jerome Forissier24778de2020-02-12 14:48:03 +0100162 def set_arch(self, elf):
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100163 self._arch = os.getenv('CROSS_COMPILE')
Etienne Carriere8a6d4a82018-10-01 09:58:31 +0200164 if self._arch:
165 return
Jerome Forissier9bb9f372020-02-18 18:12:31 +0100166 p = subprocess.Popen(['file', '-L', elf], stdout=subprocess.PIPE)
Jerome Forissierae252462018-05-25 15:07:28 +0200167 output = p.stdout.readlines()
168 p.terminate()
Rouven Czerwinskibbaeed42019-08-07 20:07:00 +0200169 if b'ARM aarch64,' in output[0]:
Jerome Forissierae252462018-05-25 15:07:28 +0200170 self._arch = 'aarch64-linux-gnu-'
Rouven Czerwinskibbaeed42019-08-07 20:07:00 +0200171 elif b'ARM,' in output[0]:
Jerome Forissierae252462018-05-25 15:07:28 +0200172 self._arch = 'arm-linux-gnueabihf-'
Jerome Forissierd7204312017-09-04 17:58:52 +0200173
Jerome Forissier24778de2020-02-12 14:48:03 +0100174 def arch_prefix(self, cmd, elf):
175 self.set_arch(elf)
Jerome Forissierae252462018-05-25 15:07:28 +0200176 if self._arch is None:
177 return ''
Jerome Forissierd7204312017-09-04 17:58:52 +0200178 return self._arch + cmd
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200179
Jerome Forissierae252462018-05-25 15:07:28 +0200180 def spawn_addr2line(self, elf_name):
181 if elf_name is None:
182 return
183 if self._addr2line_elf_name is elf_name:
184 return
185 if self._addr2line:
186 self._addr2line.terminate
187 self._addr2line = None
188 elf = self.get_elf(elf_name)
189 if not elf:
190 return
Jerome Forissier24778de2020-02-12 14:48:03 +0100191 cmd = self.arch_prefix('addr2line', elf)
Jerome Forissierae252462018-05-25 15:07:28 +0200192 if not cmd:
193 return
Jerome Forissierc0c57c82020-01-08 14:57:32 +0100194 self._addr2line = self.my_Popen([cmd, '-f', '-p', '-e', elf])
Jerome Forissierba84a3f2020-02-12 14:44:03 +0100195 self._addr2line_elf_name = elf_name
Jerome Forissierae252462018-05-25 15:07:28 +0200196
197 # If addr falls into a region that maps a TA ELF file, return the load
198 # address of that file.
199 def elf_load_addr(self, addr):
200 if self._regions:
201 for r in self._regions:
202 r_addr = int(r[0], 16)
203 r_size = int(r[1], 16)
204 i_addr = int(addr, 16)
205 if (i_addr >= r_addr and i_addr < (r_addr + r_size)):
206 # Found region
207 elf_idx = r[2]
208 if elf_idx is not None:
209 return self._elfs[int(elf_idx)][1]
Sumit Garg099918f2019-09-05 13:23:01 +0530210 # In case address is not found in TA ELF file, fallback to tee.elf
211 # especially to symbolize mixed (user-space and kernel) addresses
212 # which is true when syscall ftrace is enabled along with TA
213 # ftrace.
Jerome Forissier91068f82019-11-26 10:51:45 +0100214 return self._tee_load_addr
Jerome Forissierae252462018-05-25 15:07:28 +0200215 else:
216 # tee.elf
Jerome Forissier105e09c2019-10-16 16:59:35 +0200217 return self._tee_load_addr
Jerome Forissierae252462018-05-25 15:07:28 +0200218
219 def elf_for_addr(self, addr):
220 l_addr = self.elf_load_addr(addr)
Jerome Forissier91068f82019-11-26 10:51:45 +0100221 if l_addr == self._tee_load_addr:
222 return 'tee.elf'
Jerome Forissierae252462018-05-25 15:07:28 +0200223 for k in self._elfs:
224 e = self._elfs[k]
225 if int(e[1], 16) == int(l_addr, 16):
226 return e[0]
227 return None
Jerome Forissier733a15f2017-05-19 17:40:17 +0200228
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200229 def subtract_load_addr(self, addr):
Jerome Forissierae252462018-05-25 15:07:28 +0200230 l_addr = self.elf_load_addr(addr)
231 if l_addr is None:
232 return None
233 if int(l_addr, 16) > int(addr, 16):
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200234 return ''
Jerome Forissierae252462018-05-25 15:07:28 +0200235 return '0x{:x}'.format(int(addr, 16) - int(l_addr, 16))
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200236
237 def resolve(self, addr):
238 reladdr = self.subtract_load_addr(addr)
Jerome Forissierae252462018-05-25 15:07:28 +0200239 self.spawn_addr2line(self.elf_for_addr(addr))
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200240 if not reladdr or not self._addr2line:
Jerome Forissier733a15f2017-05-19 17:40:17 +0200241 return '???'
Jerome Forissierc0c57c82020-01-08 14:57:32 +0100242 if self.elf_for_addr(addr) == 'tee.elf':
243 reladdr = '0x{:x}'.format(int(reladdr, 16) +
244 int(self.first_vma('tee.elf'), 16))
Jerome Forissier733a15f2017-05-19 17:40:17 +0200245 try:
Rouven Czerwinskibbaeed42019-08-07 20:07:00 +0200246 print(reladdr, file=self._addr2line.stdin)
Jerome Forissier733a15f2017-05-19 17:40:17 +0200247 ret = self._addr2line.stdout.readline().rstrip('\n')
248 except IOError:
249 ret = '!!!'
250 return ret
251
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200252 def symbol_plus_offset(self, addr):
253 ret = ''
254 prevsize = 0
255 reladdr = self.subtract_load_addr(addr)
Jerome Forissierae252462018-05-25 15:07:28 +0200256 elf_name = self.elf_for_addr(addr)
257 if elf_name is None:
258 return ''
259 elf = self.get_elf(elf_name)
Jerome Forissier24778de2020-02-12 14:48:03 +0100260 cmd = self.arch_prefix('nm', elf)
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200261 if not reladdr or not elf or not cmd:
262 return ''
Jerome Forissier30999122017-08-25 18:42:58 +0200263 ireladdr = int(reladdr, 16)
Jerome Forissier1cbf7772018-09-07 17:08:23 +0200264 nm = self.my_Popen([cmd, '--numeric-sort', '--print-size', elf])
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200265 for line in iter(nm.stdout.readline, ''):
266 try:
267 addr, size, _, name = line.split()
Jerome Forissier1d8c2a42018-09-07 17:05:21 +0200268 except ValueError:
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200269 # Size is missing
Jerome Forissierb4815422018-06-20 09:43:33 +0200270 try:
271 addr, _, name = line.split()
272 size = '0'
Jerome Forissier1d8c2a42018-09-07 17:05:21 +0200273 except ValueError:
Jerome Forissierb4815422018-06-20 09:43:33 +0200274 # E.g., undefined (external) symbols (line = "U symbol")
275 continue
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200276 iaddr = int(addr, 16)
277 isize = int(size, 16)
278 if iaddr == ireladdr:
279 ret = name
280 break
281 if iaddr < ireladdr and iaddr + isize >= ireladdr:
282 offs = ireladdr - iaddr
283 ret = name + '+' + str(offs)
284 break
285 if iaddr > ireladdr and prevsize == 0:
286 offs = iaddr + ireladdr
287 ret = prevname + '+' + str(offs)
288 break
289 prevsize = size
290 prevname = name
291 nm.terminate()
292 return ret
293
294 def section_plus_offset(self, addr):
295 ret = ''
296 reladdr = self.subtract_load_addr(addr)
Jerome Forissierae252462018-05-25 15:07:28 +0200297 elf_name = self.elf_for_addr(addr)
298 if elf_name is None:
299 return ''
300 elf = self.get_elf(elf_name)
Jerome Forissier24778de2020-02-12 14:48:03 +0100301 cmd = self.arch_prefix('objdump', elf)
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200302 if not reladdr or not elf or not cmd:
303 return ''
Jerome Forissier30999122017-08-25 18:42:58 +0200304 iaddr = int(reladdr, 16)
Jerome Forissier1cbf7772018-09-07 17:08:23 +0200305 objdump = self.my_Popen([cmd, '--section-headers', elf])
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200306 for line in iter(objdump.stdout.readline, ''):
307 try:
308 idx, name, size, vma, lma, offs, algn = line.split()
Jerome Forissier1d8c2a42018-09-07 17:05:21 +0200309 except ValueError:
Jerome Forissierae252462018-05-25 15:07:28 +0200310 continue
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200311 ivma = int(vma, 16)
312 isize = int(size, 16)
313 if ivma == iaddr:
314 ret = name
315 break
316 if ivma < iaddr and ivma + isize >= iaddr:
317 offs = iaddr - ivma
318 ret = name + '+' + str(offs)
319 break
320 objdump.terminate()
321 return ret
322
323 def process_abort(self, line):
324 ret = ''
325 match = re.search(ABORT_ADDR_RE, line)
326 addr = match.group('addr')
327 pre = match.start('addr')
328 post = match.end('addr')
329 sym = self.symbol_plus_offset(addr)
330 sec = self.section_plus_offset(addr)
331 if sym or sec:
332 ret += line[:pre]
333 ret += addr
334 if sym:
335 ret += ' ' + sym
336 if sec:
337 ret += ' ' + sec
338 ret += line[post:]
339 return ret
340
Jerome Forissier30999122017-08-25 18:42:58 +0200341 # Return all ELF sections with the ALLOC flag
Jerome Forissierae252462018-05-25 15:07:28 +0200342 def read_sections(self, elf_name):
343 if elf_name is None:
Jerome Forissier30999122017-08-25 18:42:58 +0200344 return
Jerome Forissierae252462018-05-25 15:07:28 +0200345 if elf_name in self._sections:
346 return
347 elf = self.get_elf(elf_name)
Jerome Forissierd7c22ac2020-06-22 14:07:38 +0200348 if not elf:
349 return
Jerome Forissier24778de2020-02-12 14:48:03 +0100350 cmd = self.arch_prefix('objdump', elf)
Jerome Forissier30999122017-08-25 18:42:58 +0200351 if not elf or not cmd:
352 return
Jerome Forissierae252462018-05-25 15:07:28 +0200353 self._sections[elf_name] = []
Jerome Forissier1cbf7772018-09-07 17:08:23 +0200354 objdump = self.my_Popen([cmd, '--section-headers', elf])
Jerome Forissier30999122017-08-25 18:42:58 +0200355 for line in iter(objdump.stdout.readline, ''):
356 try:
357 _, name, size, vma, _, _, _ = line.split()
Jerome Forissier1d8c2a42018-09-07 17:05:21 +0200358 except ValueError:
Jerome Forissier30999122017-08-25 18:42:58 +0200359 if 'ALLOC' in line:
Jerome Forissierae252462018-05-25 15:07:28 +0200360 self._sections[elf_name].append([name, int(vma, 16),
361 int(size, 16)])
Jerome Forissier30999122017-08-25 18:42:58 +0200362
Jerome Forissierc0c57c82020-01-08 14:57:32 +0100363 def first_vma(self, elf_name):
364 self.read_sections(elf_name)
365 return '0x{:x}'.format(self._sections[elf_name][0][1])
366
Jerome Forissier30999122017-08-25 18:42:58 +0200367 def overlaps(self, section, addr, size):
368 sec_addr = section[1]
369 sec_size = section[2]
370 if not size or not sec_size:
371 return False
Jerome Forissierae252462018-05-25 15:07:28 +0200372 return ((addr <= (sec_addr + sec_size - 1)) and
373 ((addr + size - 1) >= sec_addr))
Jerome Forissier30999122017-08-25 18:42:58 +0200374
Jerome Forissierae252462018-05-25 15:07:28 +0200375 def sections_in_region(self, addr, size, elf_idx):
Jerome Forissier30999122017-08-25 18:42:58 +0200376 ret = ''
377 addr = self.subtract_load_addr(addr)
378 if not addr:
379 return ''
380 iaddr = int(addr, 16)
381 isize = int(size, 16)
Jerome Forissierae252462018-05-25 15:07:28 +0200382 elf = self._elfs[int(elf_idx)][0]
383 if elf is None:
384 return ''
385 self.read_sections(elf)
386 if elf not in self._sections:
387 return ''
388 for s in self._sections[elf]:
Jerome Forissier30999122017-08-25 18:42:58 +0200389 if self.overlaps(s, iaddr, isize):
390 ret += ' ' + s[0]
391 return ret
392
Jerome Forissier733a15f2017-05-19 17:40:17 +0200393 def reset(self):
394 self._call_stack_found = False
Jerome Forissier733a15f2017-05-19 17:40:17 +0200395 if self._addr2line:
396 self._addr2line.terminate()
397 self._addr2line = None
Jerome Forissierae252462018-05-25 15:07:28 +0200398 self._addr2line_elf_name = None
Jerome Forissierd7204312017-09-04 17:58:52 +0200399 self._arch = None
Jerome Forissier142c5cc2017-08-24 15:07:17 +0200400 self._saved_abort_line = ''
Jerome Forissierae252462018-05-25 15:07:28 +0200401 self._sections = {} # {elf_name: [[name, addr, size], ...], ...}
402 self._regions = [] # [[addr, size, elf_idx, saved line], ...]
403 self._elfs = {0: ["tee.elf", 0]} # {idx: [uuid, load_addr], ...}
Jerome Forissier91068f82019-11-26 10:51:45 +0100404 self._tee_load_addr = '0x0'
Sumit Gargc90b6662019-03-28 18:24:21 +0530405 self._func_graph_found = False
406 self._func_graph_skip_line = True
Jerome Forissier733a15f2017-05-19 17:40:17 +0200407
Jerome Forissier095567e2018-05-29 17:42:34 +0200408 def pretty_print_path(self, path):
409 if self._strip_path:
410 return re.sub(re.escape(self._strip_path) + '/*', '', path)
411 return path
412
Jerome Forissier733a15f2017-05-19 17:40:17 +0200413 def write(self, line):
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100414 if self._call_stack_found:
415 match = re.search(STACK_ADDR_RE, line)
Jerome Forissier30999122017-08-25 18:42:58 +0200416 if match:
417 addr = match.group('addr')
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100418 pre = match.start('addr')
419 post = match.end('addr')
420 self._out.write(line[:pre])
421 self._out.write(addr)
Jerome Forissier5500d702020-07-31 11:30:54 +0200422 # The call stack contains return addresses (LR/ELR values).
423 # Heuristic: subtract 2 to obtain the call site of the function
424 # or the location of the exception. This value works for A64,
425 # A32 as well as Thumb.
426 pc = 0
427 lr = int(addr, 16)
428 if lr:
429 pc = lr - 2
430 res = self.resolve('0x{:x}'.format(pc))
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100431 res = self.pretty_print_path(res)
432 self._out.write(' ' + res)
433 self._out.write(line[post:])
Jerome Forissierae252462018-05-25 15:07:28 +0200434 return
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100435 else:
Jerome Forissier27b83ad2017-10-06 13:37:35 +0200436 self.reset()
Sumit Gargc90b6662019-03-28 18:24:21 +0530437 if self._func_graph_found:
438 match = re.search(GRAPH_ADDR_RE, line)
439 match_re = re.search(GRAPH_RE, line)
440 if match:
441 addr = match.group('addr')
442 pre = match.start('addr')
443 post = match.end('addr')
444 self._out.write(line[:pre])
445 res = self.resolve(addr)
446 res_arr = re.split(' ', res)
447 self._out.write(res_arr[0])
448 self._out.write(line[post:])
449 self._func_graph_skip_line = False
450 return
451 elif match_re:
452 self._out.write(line)
453 return
454 elif self._func_graph_skip_line:
455 return
456 else:
457 self.reset()
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100458 match = re.search(REGION_RE, line)
459 if match:
460 # Region table: save info for later processing once
461 # we know which UUID corresponds to which ELF index
462 addr = match.group('addr')
463 size = match.group('size')
464 elf_idx = match.group('elf_idx')
465 self._regions.append([addr, size, elf_idx, line])
466 return
467 match = re.search(ELF_LIST_RE, line)
468 if match:
469 # ELF list: save info for later. Region table and ELF list
470 # will be displayed when the call stack is reached
471 i = int(match.group('idx'))
472 self._elfs[i] = [match.group('uuid'), match.group('load_addr'),
473 line]
474 return
Jerome Forissier99e82b12022-05-05 10:19:22 +0200475 match = re.search(TA_PANIC_RE, line)
476 if match:
477 code = match.group('code')
478 if code in tee_result_names:
479 line = line.strip() + ' (' + tee_result_names[code] + ')\n'
480 self._out.write(line)
481 return
Jerome Forissier105e09c2019-10-16 16:59:35 +0200482 match = re.search(TEE_LOAD_ADDR_RE, line)
483 if match:
484 self._tee_load_addr = match.group('load_addr')
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100485 match = re.search(CALL_STACK_RE, line)
486 if match:
487 self._call_stack_found = True
488 if self._regions:
489 for r in self._regions:
490 r_addr = r[0]
491 r_size = r[1]
492 elf_idx = r[2]
493 saved_line = r[3]
494 if elf_idx is None:
495 self._out.write(saved_line)
496 else:
497 self._out.write(saved_line.strip() +
498 self.sections_in_region(r_addr,
499 r_size,
500 elf_idx) +
501 '\n')
502 if self._elfs:
503 for k in self._elfs:
504 e = self._elfs[k]
505 if (len(e) >= 3):
506 # TA executable or library
507 self._out.write(e[2].strip())
508 elf = self.get_elf(e[0])
509 if elf:
510 rpath = os.path.realpath(elf)
511 path = self.pretty_print_path(rpath)
512 self._out.write(' (' + path + ')')
513 self._out.write('\n')
514 # Here is a good place to resolve the abort address because we
515 # have all the information we need
516 if self._saved_abort_line:
517 self._out.write(self.process_abort(self._saved_abort_line))
Sumit Gargc90b6662019-03-28 18:24:21 +0530518 match = re.search(FUNC_GRAPH_RE, line)
519 if match:
520 self._func_graph_found = True
Jerome Forissier6e7c2e92018-11-14 11:02:49 +0100521 match = re.search(ABORT_ADDR_RE, line)
522 if match:
523 self.reset()
524 # At this point the arch and TA load address are unknown.
525 # Save the line so We can translate the abort address later.
526 self._saved_abort_line = line
527 self._out.write(line)
Jerome Forissier733a15f2017-05-19 17:40:17 +0200528
529 def flush(self):
530 self._out.flush()
531
Jerome Forissierae252462018-05-25 15:07:28 +0200532
Jerome Forissier733a15f2017-05-19 17:40:17 +0200533def main():
534 args = get_args()
535 if args.dir:
536 # Flatten list in case -d is used several times *and* with multiple
537 # arguments
538 args.dirs = [item for sublist in args.dir for item in sublist]
539 else:
540 args.dirs = []
541 symbolizer = Symbolizer(sys.stdout, args.dirs, args.strip_path)
542
Jerome Forissier6b4fc672019-09-23 09:49:32 +0200543 fd = sys.stdin.fileno()
Jerome Forissier20d152b2019-09-25 20:28:33 +0200544 isatty = os.isatty(fd)
545 if isatty:
546 old = termios.tcgetattr(fd)
547 new = termios.tcgetattr(fd)
548 new[3] = new[3] & ~termios.ECHO # lflags
Jerome Forissier6b4fc672019-09-23 09:49:32 +0200549 try:
Jerome Forissier20d152b2019-09-25 20:28:33 +0200550 if isatty:
551 termios.tcsetattr(fd, termios.TCSADRAIN, new)
Jerome Forissier6b4fc672019-09-23 09:49:32 +0200552 for line in sys.stdin:
553 symbolizer.write(line)
554 finally:
555 symbolizer.flush()
Jerome Forissier20d152b2019-09-25 20:28:33 +0200556 if isatty:
557 termios.tcsetattr(fd, termios.TCSADRAIN, old)
Jerome Forissier733a15f2017-05-19 17:40:17 +0200558
Jerome Forissier1d8c2a42018-09-07 17:05:21 +0200559
Jerome Forissier733a15f2017-05-19 17:40:17 +0200560if __name__ == "__main__":
561 main()