xref: /aosp_15_r20/development/scripts/symbol.py (revision 90c8c64db3049935a07c6143d7fd006e26f8ecca)
1*90c8c64dSAndroid Build Coastguard Worker#!/usr/bin/env python3
2*90c8c64dSAndroid Build Coastguard Worker#
3*90c8c64dSAndroid Build Coastguard Worker# Copyright (C) 2013 The Android Open Source Project
4*90c8c64dSAndroid Build Coastguard Worker#
5*90c8c64dSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
6*90c8c64dSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
7*90c8c64dSAndroid Build Coastguard Worker# You may obtain a copy of the License at
8*90c8c64dSAndroid Build Coastguard Worker#
9*90c8c64dSAndroid Build Coastguard Worker#      http://www.apache.org/licenses/LICENSE-2.0
10*90c8c64dSAndroid Build Coastguard Worker#
11*90c8c64dSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
12*90c8c64dSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
13*90c8c64dSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*90c8c64dSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
15*90c8c64dSAndroid Build Coastguard Worker# limitations under the License.
16*90c8c64dSAndroid Build Coastguard Worker
17*90c8c64dSAndroid Build Coastguard Worker"""Module for looking up symbolic debugging information.
18*90c8c64dSAndroid Build Coastguard Worker
19*90c8c64dSAndroid Build Coastguard WorkerThe information can include symbol names, offsets, and source locations.
20*90c8c64dSAndroid Build Coastguard Worker"""
21*90c8c64dSAndroid Build Coastguard Worker
22*90c8c64dSAndroid Build Coastguard Workerimport atexit
23*90c8c64dSAndroid Build Coastguard Workerimport json
24*90c8c64dSAndroid Build Coastguard Workerimport glob
25*90c8c64dSAndroid Build Coastguard Workerimport os
26*90c8c64dSAndroid Build Coastguard Workerimport platform
27*90c8c64dSAndroid Build Coastguard Workerimport re
28*90c8c64dSAndroid Build Coastguard Workerimport shutil
29*90c8c64dSAndroid Build Coastguard Workerimport signal
30*90c8c64dSAndroid Build Coastguard Workerimport subprocess
31*90c8c64dSAndroid Build Coastguard Workerimport unittest
32*90c8c64dSAndroid Build Coastguard Worker
33*90c8c64dSAndroid Build Coastguard WorkerANDROID_BUILD_TOP = os.environ.get("ANDROID_BUILD_TOP", ".")
34*90c8c64dSAndroid Build Coastguard Worker
35*90c8c64dSAndroid Build Coastguard Worker
36*90c8c64dSAndroid Build Coastguard Workerdef FindClangDir():
37*90c8c64dSAndroid Build Coastguard Worker  get_clang_version = ANDROID_BUILD_TOP + "/build/soong/scripts/get_clang_version.py"
38*90c8c64dSAndroid Build Coastguard Worker  if os.path.exists(get_clang_version):
39*90c8c64dSAndroid Build Coastguard Worker    # We want the script to fail if get_clang_version.py exists but is unable
40*90c8c64dSAndroid Build Coastguard Worker    # to find the clang version.
41*90c8c64dSAndroid Build Coastguard Worker    version_output = subprocess.check_output(get_clang_version, text=True)
42*90c8c64dSAndroid Build Coastguard Worker    return ANDROID_BUILD_TOP + "/prebuilts/clang/host/linux-x86/" + version_output.strip()
43*90c8c64dSAndroid Build Coastguard Worker  else:
44*90c8c64dSAndroid Build Coastguard Worker    return None
45*90c8c64dSAndroid Build Coastguard Worker
46*90c8c64dSAndroid Build Coastguard Worker
47*90c8c64dSAndroid Build Coastguard Workerdef FindSymbolsDir():
48*90c8c64dSAndroid Build Coastguard Worker  saveddir = os.getcwd()
49*90c8c64dSAndroid Build Coastguard Worker  os.chdir(ANDROID_BUILD_TOP)
50*90c8c64dSAndroid Build Coastguard Worker  stream = None
51*90c8c64dSAndroid Build Coastguard Worker  try:
52*90c8c64dSAndroid Build Coastguard Worker    cmd = "build/soong/soong_ui.bash --dumpvar-mode --abs TARGET_OUT_UNSTRIPPED"
53*90c8c64dSAndroid Build Coastguard Worker    stream = subprocess.Popen(cmd, stdout=subprocess.PIPE, universal_newlines=True, shell=True).stdout
54*90c8c64dSAndroid Build Coastguard Worker    return str(stream.read().strip())
55*90c8c64dSAndroid Build Coastguard Worker  finally:
56*90c8c64dSAndroid Build Coastguard Worker    if stream is not None:
57*90c8c64dSAndroid Build Coastguard Worker        stream.close()
58*90c8c64dSAndroid Build Coastguard Worker    os.chdir(saveddir)
59*90c8c64dSAndroid Build Coastguard Worker
60*90c8c64dSAndroid Build Coastguard WorkerSYMBOLS_DIR = FindSymbolsDir()
61*90c8c64dSAndroid Build Coastguard Worker
62*90c8c64dSAndroid Build Coastguard WorkerARCH_IS_32BIT = None
63*90c8c64dSAndroid Build Coastguard Worker
64*90c8c64dSAndroid Build Coastguard WorkerVERBOSE = False
65*90c8c64dSAndroid Build Coastguard Worker
66*90c8c64dSAndroid Build Coastguard Worker# These are private. Do not access them from other modules.
67*90c8c64dSAndroid Build Coastguard Worker_CACHED_TOOLCHAIN = None
68*90c8c64dSAndroid Build Coastguard Worker_CACHED_CXX_FILT = None
69*90c8c64dSAndroid Build Coastguard Worker
70*90c8c64dSAndroid Build Coastguard Worker# Caches for symbolized information.
71*90c8c64dSAndroid Build Coastguard Worker_SYMBOL_INFORMATION_ADDR2LINE_CACHE = {}
72*90c8c64dSAndroid Build Coastguard Worker_SYMBOL_INFORMATION_OBJDUMP_CACHE = {}
73*90c8c64dSAndroid Build Coastguard Worker_SYMBOL_DEMANGLING_CACHE = {}
74*90c8c64dSAndroid Build Coastguard Worker
75*90c8c64dSAndroid Build Coastguard Worker# Caches for pipes to subprocesses.
76*90c8c64dSAndroid Build Coastguard Worker
77*90c8c64dSAndroid Build Coastguard Workerclass ProcessCache:
78*90c8c64dSAndroid Build Coastguard Worker  _cmd2pipe = {}
79*90c8c64dSAndroid Build Coastguard Worker  _lru = []
80*90c8c64dSAndroid Build Coastguard Worker
81*90c8c64dSAndroid Build Coastguard Worker  # Max number of open pipes.
82*90c8c64dSAndroid Build Coastguard Worker  _PIPE_MAX_OPEN = 10
83*90c8c64dSAndroid Build Coastguard Worker
84*90c8c64dSAndroid Build Coastguard Worker  def GetProcess(self, cmd):
85*90c8c64dSAndroid Build Coastguard Worker    cmd_tuple = tuple(cmd)  # Need to use a tuple as lists can't be dict keys.
86*90c8c64dSAndroid Build Coastguard Worker    # Pipe already available?
87*90c8c64dSAndroid Build Coastguard Worker    if cmd_tuple in self._cmd2pipe:
88*90c8c64dSAndroid Build Coastguard Worker      pipe = self._cmd2pipe[cmd_tuple]
89*90c8c64dSAndroid Build Coastguard Worker      # Update LRU.
90*90c8c64dSAndroid Build Coastguard Worker      self._lru = [(cmd_tuple, pipe)] + [i for i in self._lru if i[0] != cmd_tuple]
91*90c8c64dSAndroid Build Coastguard Worker      return pipe
92*90c8c64dSAndroid Build Coastguard Worker
93*90c8c64dSAndroid Build Coastguard Worker    # Not cached, yet. Open a new one.
94*90c8c64dSAndroid Build Coastguard Worker
95*90c8c64dSAndroid Build Coastguard Worker    # Check if too many are open, close the old ones.
96*90c8c64dSAndroid Build Coastguard Worker    while len(self._lru) >= self._PIPE_MAX_OPEN:
97*90c8c64dSAndroid Build Coastguard Worker      open_cmd, open_pipe = self._lru.pop()
98*90c8c64dSAndroid Build Coastguard Worker      del self._cmd2pipe[open_cmd]
99*90c8c64dSAndroid Build Coastguard Worker      self.TerminateProcess(open_pipe)
100*90c8c64dSAndroid Build Coastguard Worker
101*90c8c64dSAndroid Build Coastguard Worker    # Create and put into cache.
102*90c8c64dSAndroid Build Coastguard Worker    pipe = self.SpawnProcess(cmd)
103*90c8c64dSAndroid Build Coastguard Worker    self._cmd2pipe[cmd_tuple] = pipe
104*90c8c64dSAndroid Build Coastguard Worker    self._lru = [(cmd_tuple, pipe)] + self._lru
105*90c8c64dSAndroid Build Coastguard Worker    return pipe
106*90c8c64dSAndroid Build Coastguard Worker
107*90c8c64dSAndroid Build Coastguard Worker  def SpawnProcess(self, cmd):
108*90c8c64dSAndroid Build Coastguard Worker     return subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, universal_newlines=True)
109*90c8c64dSAndroid Build Coastguard Worker
110*90c8c64dSAndroid Build Coastguard Worker  def TerminateProcess(self, pipe):
111*90c8c64dSAndroid Build Coastguard Worker    pipe.stdin.close()
112*90c8c64dSAndroid Build Coastguard Worker    pipe.stdout.close()
113*90c8c64dSAndroid Build Coastguard Worker    pipe.terminate()
114*90c8c64dSAndroid Build Coastguard Worker    pipe.wait()
115*90c8c64dSAndroid Build Coastguard Worker
116*90c8c64dSAndroid Build Coastguard Worker  def KillAllProcesses(self):
117*90c8c64dSAndroid Build Coastguard Worker    for _, open_pipe in self._lru:
118*90c8c64dSAndroid Build Coastguard Worker      self.TerminateProcess(open_pipe)
119*90c8c64dSAndroid Build Coastguard Worker    _cmd2pipe = {}
120*90c8c64dSAndroid Build Coastguard Worker    _lru = []
121*90c8c64dSAndroid Build Coastguard Worker
122*90c8c64dSAndroid Build Coastguard Worker
123*90c8c64dSAndroid Build Coastguard Worker_PIPE_ADDR2LINE_CACHE = ProcessCache()
124*90c8c64dSAndroid Build Coastguard Worker_PIPE_CPPFILT_CACHE = ProcessCache()
125*90c8c64dSAndroid Build Coastguard Worker
126*90c8c64dSAndroid Build Coastguard Worker
127*90c8c64dSAndroid Build Coastguard Worker# Process cache cleanup on shutdown.
128*90c8c64dSAndroid Build Coastguard Worker
129*90c8c64dSAndroid Build Coastguard Workerdef CloseAllPipes():
130*90c8c64dSAndroid Build Coastguard Worker  _PIPE_ADDR2LINE_CACHE.KillAllProcesses()
131*90c8c64dSAndroid Build Coastguard Worker  _PIPE_CPPFILT_CACHE.KillAllProcesses()
132*90c8c64dSAndroid Build Coastguard Worker
133*90c8c64dSAndroid Build Coastguard Worker
134*90c8c64dSAndroid Build Coastguard Workeratexit.register(CloseAllPipes)
135*90c8c64dSAndroid Build Coastguard Worker
136*90c8c64dSAndroid Build Coastguard Worker
137*90c8c64dSAndroid Build Coastguard Workerdef PipeTermHandler(signum, frame):
138*90c8c64dSAndroid Build Coastguard Worker  CloseAllPipes()
139*90c8c64dSAndroid Build Coastguard Worker  os._exit(0)
140*90c8c64dSAndroid Build Coastguard Worker
141*90c8c64dSAndroid Build Coastguard Worker
142*90c8c64dSAndroid Build Coastguard Workerfor sig in (signal.SIGABRT, signal.SIGINT, signal.SIGTERM):
143*90c8c64dSAndroid Build Coastguard Worker  signal.signal(sig, PipeTermHandler)
144*90c8c64dSAndroid Build Coastguard Worker
145*90c8c64dSAndroid Build Coastguard Worker
146*90c8c64dSAndroid Build Coastguard Worker
147*90c8c64dSAndroid Build Coastguard Worker
148*90c8c64dSAndroid Build Coastguard Workerdef ToolPath(tool, toolchain=None):
149*90c8c64dSAndroid Build Coastguard Worker  """Return a fully-qualified path to the specified tool, or just the tool if it's on PATH """
150*90c8c64dSAndroid Build Coastguard Worker  if shutil.which(tool):
151*90c8c64dSAndroid Build Coastguard Worker    return tool
152*90c8c64dSAndroid Build Coastguard Worker  if not toolchain:
153*90c8c64dSAndroid Build Coastguard Worker    toolchain = FindToolchain()
154*90c8c64dSAndroid Build Coastguard Worker  return os.path.join(toolchain, tool)
155*90c8c64dSAndroid Build Coastguard Worker
156*90c8c64dSAndroid Build Coastguard Worker
157*90c8c64dSAndroid Build Coastguard Workerdef FindToolchain():
158*90c8c64dSAndroid Build Coastguard Worker  """Returns the toolchain."""
159*90c8c64dSAndroid Build Coastguard Worker
160*90c8c64dSAndroid Build Coastguard Worker  global _CACHED_TOOLCHAIN
161*90c8c64dSAndroid Build Coastguard Worker  if _CACHED_TOOLCHAIN:
162*90c8c64dSAndroid Build Coastguard Worker    return _CACHED_TOOLCHAIN
163*90c8c64dSAndroid Build Coastguard Worker
164*90c8c64dSAndroid Build Coastguard Worker  llvm_binutils_dir = ANDROID_BUILD_TOP + "/prebuilts/clang/host/linux-x86/llvm-binutils-stable/";
165*90c8c64dSAndroid Build Coastguard Worker  if not os.path.exists(llvm_binutils_dir):
166*90c8c64dSAndroid Build Coastguard Worker    raise Exception("Could not find llvm tool chain directory %s" % (llvm_binutils_dir))
167*90c8c64dSAndroid Build Coastguard Worker
168*90c8c64dSAndroid Build Coastguard Worker  _CACHED_TOOLCHAIN = llvm_binutils_dir
169*90c8c64dSAndroid Build Coastguard Worker  print("Using toolchain from:", _CACHED_TOOLCHAIN)
170*90c8c64dSAndroid Build Coastguard Worker  return _CACHED_TOOLCHAIN
171*90c8c64dSAndroid Build Coastguard Worker
172*90c8c64dSAndroid Build Coastguard Worker
173*90c8c64dSAndroid Build Coastguard Workerdef SymbolInformation(lib, addr):
174*90c8c64dSAndroid Build Coastguard Worker  """Look up symbol information about an address.
175*90c8c64dSAndroid Build Coastguard Worker
176*90c8c64dSAndroid Build Coastguard Worker  Args:
177*90c8c64dSAndroid Build Coastguard Worker    lib: library (or executable) pathname containing symbols
178*90c8c64dSAndroid Build Coastguard Worker    addr: string hexidecimal address
179*90c8c64dSAndroid Build Coastguard Worker
180*90c8c64dSAndroid Build Coastguard Worker  Returns:
181*90c8c64dSAndroid Build Coastguard Worker    A list of the form [(source_symbol, source_location,
182*90c8c64dSAndroid Build Coastguard Worker    object_symbol_with_offset)].
183*90c8c64dSAndroid Build Coastguard Worker
184*90c8c64dSAndroid Build Coastguard Worker    If the function has been inlined then the list may contain
185*90c8c64dSAndroid Build Coastguard Worker    more than one element with the symbols for the most deeply
186*90c8c64dSAndroid Build Coastguard Worker    nested inlined location appearing first.  The list is
187*90c8c64dSAndroid Build Coastguard Worker    always non-empty, even if no information is available.
188*90c8c64dSAndroid Build Coastguard Worker
189*90c8c64dSAndroid Build Coastguard Worker    Usually you want to display the source_location and
190*90c8c64dSAndroid Build Coastguard Worker    object_symbol_with_offset from the last element in the list.
191*90c8c64dSAndroid Build Coastguard Worker  """
192*90c8c64dSAndroid Build Coastguard Worker  info = SymbolInformationForSet(lib, set([addr]))
193*90c8c64dSAndroid Build Coastguard Worker  return (info and info.get(addr)) or [(None, None, None)]
194*90c8c64dSAndroid Build Coastguard Worker
195*90c8c64dSAndroid Build Coastguard Worker
196*90c8c64dSAndroid Build Coastguard Workerdef SymbolInformationForSet(lib, unique_addrs):
197*90c8c64dSAndroid Build Coastguard Worker  """Look up symbol information for a set of addresses from the given library.
198*90c8c64dSAndroid Build Coastguard Worker
199*90c8c64dSAndroid Build Coastguard Worker  Args:
200*90c8c64dSAndroid Build Coastguard Worker    lib: library (or executable) pathname containing symbols
201*90c8c64dSAndroid Build Coastguard Worker    unique_addrs: set of hexidecimal addresses
202*90c8c64dSAndroid Build Coastguard Worker
203*90c8c64dSAndroid Build Coastguard Worker  Returns:
204*90c8c64dSAndroid Build Coastguard Worker    A dictionary of the form {addr: [(source_symbol, source_location,
205*90c8c64dSAndroid Build Coastguard Worker    object_symbol_with_offset)]} where each address has a list of
206*90c8c64dSAndroid Build Coastguard Worker    associated symbols and locations.  The list is always non-empty.
207*90c8c64dSAndroid Build Coastguard Worker
208*90c8c64dSAndroid Build Coastguard Worker    If the function has been inlined then the list may contain
209*90c8c64dSAndroid Build Coastguard Worker    more than one element with the symbols for the most deeply
210*90c8c64dSAndroid Build Coastguard Worker    nested inlined location appearing first.  The list is
211*90c8c64dSAndroid Build Coastguard Worker    always non-empty, even if no information is available.
212*90c8c64dSAndroid Build Coastguard Worker
213*90c8c64dSAndroid Build Coastguard Worker    Usually you want to display the source_location and
214*90c8c64dSAndroid Build Coastguard Worker    object_symbol_with_offset from the last element in the list.
215*90c8c64dSAndroid Build Coastguard Worker  """
216*90c8c64dSAndroid Build Coastguard Worker  if not lib:
217*90c8c64dSAndroid Build Coastguard Worker    return None
218*90c8c64dSAndroid Build Coastguard Worker
219*90c8c64dSAndroid Build Coastguard Worker  addr_to_line = CallLlvmSymbolizerForSet(lib, unique_addrs)
220*90c8c64dSAndroid Build Coastguard Worker  if not addr_to_line:
221*90c8c64dSAndroid Build Coastguard Worker    return None
222*90c8c64dSAndroid Build Coastguard Worker
223*90c8c64dSAndroid Build Coastguard Worker  addr_to_objdump = CallObjdumpForSet(lib, unique_addrs)
224*90c8c64dSAndroid Build Coastguard Worker  if not addr_to_objdump:
225*90c8c64dSAndroid Build Coastguard Worker    return None
226*90c8c64dSAndroid Build Coastguard Worker
227*90c8c64dSAndroid Build Coastguard Worker  result = {}
228*90c8c64dSAndroid Build Coastguard Worker  for addr in unique_addrs:
229*90c8c64dSAndroid Build Coastguard Worker    source_info = addr_to_line.get(addr)
230*90c8c64dSAndroid Build Coastguard Worker    if not source_info:
231*90c8c64dSAndroid Build Coastguard Worker      source_info = [(None, None)]
232*90c8c64dSAndroid Build Coastguard Worker    if addr in addr_to_objdump:
233*90c8c64dSAndroid Build Coastguard Worker      (object_symbol, object_offset) = addr_to_objdump.get(addr)
234*90c8c64dSAndroid Build Coastguard Worker      object_symbol_with_offset = FormatSymbolWithOffset(object_symbol,
235*90c8c64dSAndroid Build Coastguard Worker                                                         object_offset)
236*90c8c64dSAndroid Build Coastguard Worker    else:
237*90c8c64dSAndroid Build Coastguard Worker      object_symbol_with_offset = None
238*90c8c64dSAndroid Build Coastguard Worker    result[addr] = [(source_symbol, source_location, object_symbol_with_offset)
239*90c8c64dSAndroid Build Coastguard Worker        for (source_symbol, source_location) in source_info]
240*90c8c64dSAndroid Build Coastguard Worker
241*90c8c64dSAndroid Build Coastguard Worker  return result
242*90c8c64dSAndroid Build Coastguard Worker
243*90c8c64dSAndroid Build Coastguard Worker
244*90c8c64dSAndroid Build Coastguard Workerdef _OptionalStackRecordField(json_result, field):
245*90c8c64dSAndroid Build Coastguard Worker  """Fix up bizarre formatting of llvm-symbolizer output
246*90c8c64dSAndroid Build Coastguard Worker
247*90c8c64dSAndroid Build Coastguard Worker  Some parts of the FRAME output are output as a string containing a hex
248*90c8c64dSAndroid Build Coastguard Worker  integer, or the empty string when it's missing.
249*90c8c64dSAndroid Build Coastguard Worker
250*90c8c64dSAndroid Build Coastguard Worker  Args:
251*90c8c64dSAndroid Build Coastguard Worker    json_result: dictionary containing the Frame response
252*90c8c64dSAndroid Build Coastguard Worker    field: name of the field we want to read
253*90c8c64dSAndroid Build Coastguard Worker
254*90c8c64dSAndroid Build Coastguard Worker  Returns:
255*90c8c64dSAndroid Build Coastguard Worker    integer of field value, or None if missing
256*90c8c64dSAndroid Build Coastguard Worker  """
257*90c8c64dSAndroid Build Coastguard Worker  value = json_result.get(field, "")
258*90c8c64dSAndroid Build Coastguard Worker  if isinstance(value, int):
259*90c8c64dSAndroid Build Coastguard Worker    # Leaving this here in case someone decides to fix the types of the
260*90c8c64dSAndroid Build Coastguard Worker    # symbolizer output, so it's easier to roll out.
261*90c8c64dSAndroid Build Coastguard Worker    return value
262*90c8c64dSAndroid Build Coastguard Worker  if value != "":
263*90c8c64dSAndroid Build Coastguard Worker    return int(value, 16)
264*90c8c64dSAndroid Build Coastguard Worker  return None
265*90c8c64dSAndroid Build Coastguard Worker
266*90c8c64dSAndroid Build Coastguard Worker
267*90c8c64dSAndroid Build Coastguard Workerdef _GetJSONSymbolizerForLib(lib, args=None):
268*90c8c64dSAndroid Build Coastguard Worker  """ Find symbol file for lib, and return a llvm-symbolizer instance for it.
269*90c8c64dSAndroid Build Coastguard Worker
270*90c8c64dSAndroid Build Coastguard Worker  Args:
271*90c8c64dSAndroid Build Coastguard Worker    lib: library (or executable) pathname containing symbols
272*90c8c64dSAndroid Build Coastguard Worker    args: (optional) list of arguments to pass to llvm-symbolizer
273*90c8c64dSAndroid Build Coastguard Worker
274*90c8c64dSAndroid Build Coastguard Worker  Returns:
275*90c8c64dSAndroid Build Coastguard Worker    child process, or None if lib not found
276*90c8c64dSAndroid Build Coastguard Worker  """
277*90c8c64dSAndroid Build Coastguard Worker  if args is None:
278*90c8c64dSAndroid Build Coastguard Worker    args = []
279*90c8c64dSAndroid Build Coastguard Worker  symbols = SYMBOLS_DIR + lib
280*90c8c64dSAndroid Build Coastguard Worker  if not os.path.exists(symbols):
281*90c8c64dSAndroid Build Coastguard Worker    symbols = lib
282*90c8c64dSAndroid Build Coastguard Worker    if not os.path.exists(symbols):
283*90c8c64dSAndroid Build Coastguard Worker      return None
284*90c8c64dSAndroid Build Coastguard Worker
285*90c8c64dSAndroid Build Coastguard Worker  # Make sure the symbols path is not a directory.
286*90c8c64dSAndroid Build Coastguard Worker  if os.path.isdir(symbols):
287*90c8c64dSAndroid Build Coastguard Worker    return None
288*90c8c64dSAndroid Build Coastguard Worker
289*90c8c64dSAndroid Build Coastguard Worker  cmd = [ToolPath("llvm-symbolizer"), "--output-style=JSON"] + args + ["--obj=" + symbols]
290*90c8c64dSAndroid Build Coastguard Worker  return _PIPE_ADDR2LINE_CACHE.GetProcess(cmd)
291*90c8c64dSAndroid Build Coastguard Worker
292*90c8c64dSAndroid Build Coastguard Worker
293*90c8c64dSAndroid Build Coastguard Workerdef GetStackRecordsForSet(lib, unique_addrs):
294*90c8c64dSAndroid Build Coastguard Worker  """Look up stack record information for a set of addresses
295*90c8c64dSAndroid Build Coastguard Worker
296*90c8c64dSAndroid Build Coastguard Worker  Args:
297*90c8c64dSAndroid Build Coastguard Worker    lib: library (or executable) pathname containing symbols
298*90c8c64dSAndroid Build Coastguard Worker    unique_addrs: set of integer addresses look up.
299*90c8c64dSAndroid Build Coastguard Worker
300*90c8c64dSAndroid Build Coastguard Worker  Returns:
301*90c8c64dSAndroid Build Coastguard Worker    A list of tuples
302*90c8c64dSAndroid Build Coastguard Worker    (addr, function_name, local_name, file_line, frame_offset, size, tag_offset)
303*90c8c64dSAndroid Build Coastguard Worker    describing the local variables of the stack frame.
304*90c8c64dSAndroid Build Coastguard Worker    frame_offset, size, tag_offset may be None.
305*90c8c64dSAndroid Build Coastguard Worker  """
306*90c8c64dSAndroid Build Coastguard Worker  child = _GetJSONSymbolizerForLib(lib)
307*90c8c64dSAndroid Build Coastguard Worker  if child is None:
308*90c8c64dSAndroid Build Coastguard Worker    return None
309*90c8c64dSAndroid Build Coastguard Worker  records = []
310*90c8c64dSAndroid Build Coastguard Worker  for addr in unique_addrs:
311*90c8c64dSAndroid Build Coastguard Worker    child.stdin.write("FRAME 0x%x\n" % addr)
312*90c8c64dSAndroid Build Coastguard Worker    child.stdin.flush()
313*90c8c64dSAndroid Build Coastguard Worker    json_result = json.loads(child.stdout.readline().strip())
314*90c8c64dSAndroid Build Coastguard Worker    for frame in json_result["Frame"]:
315*90c8c64dSAndroid Build Coastguard Worker      records.append(
316*90c8c64dSAndroid Build Coastguard Worker        (addr,
317*90c8c64dSAndroid Build Coastguard Worker        frame["FunctionName"],
318*90c8c64dSAndroid Build Coastguard Worker        frame["Name"],
319*90c8c64dSAndroid Build Coastguard Worker        frame["DeclFile"] + ":" + str(frame["DeclLine"]),
320*90c8c64dSAndroid Build Coastguard Worker        frame.get("FrameOffset"),
321*90c8c64dSAndroid Build Coastguard Worker        _OptionalStackRecordField(frame, "Size"),
322*90c8c64dSAndroid Build Coastguard Worker        _OptionalStackRecordField(frame, "TagOffset")))
323*90c8c64dSAndroid Build Coastguard Worker  return records
324*90c8c64dSAndroid Build Coastguard Worker
325*90c8c64dSAndroid Build Coastguard Worker
326*90c8c64dSAndroid Build Coastguard Workerdef CallLlvmSymbolizerForSet(lib, unique_addrs):
327*90c8c64dSAndroid Build Coastguard Worker  """Look up line and symbol information for a set of addresses.
328*90c8c64dSAndroid Build Coastguard Worker
329*90c8c64dSAndroid Build Coastguard Worker  Args:
330*90c8c64dSAndroid Build Coastguard Worker    lib: library (or executable) pathname containing symbols
331*90c8c64dSAndroid Build Coastguard Worker    unique_addrs: set of string hexidecimal addresses look up.
332*90c8c64dSAndroid Build Coastguard Worker
333*90c8c64dSAndroid Build Coastguard Worker  Returns:
334*90c8c64dSAndroid Build Coastguard Worker    A dictionary of the form {addr: [(symbol, file:line)]} where
335*90c8c64dSAndroid Build Coastguard Worker    each address has a list of associated symbols and locations
336*90c8c64dSAndroid Build Coastguard Worker    or an empty list if no symbol information was found.
337*90c8c64dSAndroid Build Coastguard Worker
338*90c8c64dSAndroid Build Coastguard Worker    If the function has been inlined then the list may contain
339*90c8c64dSAndroid Build Coastguard Worker    more than one element with the symbols for the most deeply
340*90c8c64dSAndroid Build Coastguard Worker    nested inlined location appearing first.
341*90c8c64dSAndroid Build Coastguard Worker  """
342*90c8c64dSAndroid Build Coastguard Worker  if not lib:
343*90c8c64dSAndroid Build Coastguard Worker    return None
344*90c8c64dSAndroid Build Coastguard Worker
345*90c8c64dSAndroid Build Coastguard Worker  result = {}
346*90c8c64dSAndroid Build Coastguard Worker  addrs = sorted(unique_addrs)
347*90c8c64dSAndroid Build Coastguard Worker
348*90c8c64dSAndroid Build Coastguard Worker  if lib in _SYMBOL_INFORMATION_ADDR2LINE_CACHE:
349*90c8c64dSAndroid Build Coastguard Worker    addr_cache = _SYMBOL_INFORMATION_ADDR2LINE_CACHE[lib]
350*90c8c64dSAndroid Build Coastguard Worker
351*90c8c64dSAndroid Build Coastguard Worker    # Go through and handle all known addresses.
352*90c8c64dSAndroid Build Coastguard Worker    for x in range(len(addrs)):
353*90c8c64dSAndroid Build Coastguard Worker      next_addr = addrs.pop(0)
354*90c8c64dSAndroid Build Coastguard Worker      if next_addr in addr_cache:
355*90c8c64dSAndroid Build Coastguard Worker        result[next_addr] = addr_cache[next_addr]
356*90c8c64dSAndroid Build Coastguard Worker      else:
357*90c8c64dSAndroid Build Coastguard Worker        # Re-add, needs to be symbolized.
358*90c8c64dSAndroid Build Coastguard Worker        addrs.append(next_addr)
359*90c8c64dSAndroid Build Coastguard Worker
360*90c8c64dSAndroid Build Coastguard Worker    if not addrs:
361*90c8c64dSAndroid Build Coastguard Worker      # Everything was cached, we're done.
362*90c8c64dSAndroid Build Coastguard Worker      return result
363*90c8c64dSAndroid Build Coastguard Worker  else:
364*90c8c64dSAndroid Build Coastguard Worker    addr_cache = {}
365*90c8c64dSAndroid Build Coastguard Worker    _SYMBOL_INFORMATION_ADDR2LINE_CACHE[lib] = addr_cache
366*90c8c64dSAndroid Build Coastguard Worker
367*90c8c64dSAndroid Build Coastguard Worker  child = _GetJSONSymbolizerForLib(
368*90c8c64dSAndroid Build Coastguard Worker    lib, ["--functions", "--inlines", "--demangle"])
369*90c8c64dSAndroid Build Coastguard Worker  if child is None:
370*90c8c64dSAndroid Build Coastguard Worker    return None
371*90c8c64dSAndroid Build Coastguard Worker  for addr in addrs:
372*90c8c64dSAndroid Build Coastguard Worker    try:
373*90c8c64dSAndroid Build Coastguard Worker      child.stdin.write("0x%s\n" % addr)
374*90c8c64dSAndroid Build Coastguard Worker      child.stdin.flush()
375*90c8c64dSAndroid Build Coastguard Worker      records = []
376*90c8c64dSAndroid Build Coastguard Worker      json_result = json.loads(child.stdout.readline().strip())
377*90c8c64dSAndroid Build Coastguard Worker      for symbol in json_result["Symbol"]:
378*90c8c64dSAndroid Build Coastguard Worker        function_name = symbol["FunctionName"]
379*90c8c64dSAndroid Build Coastguard Worker        # GNU style location: file_name:line_num
380*90c8c64dSAndroid Build Coastguard Worker        location = ("%s:%s" % (symbol["FileName"], symbol["Line"]))
381*90c8c64dSAndroid Build Coastguard Worker        records.append((function_name, location))
382*90c8c64dSAndroid Build Coastguard Worker    except IOError as e:
383*90c8c64dSAndroid Build Coastguard Worker      # Remove the / in front of the library name to match other output.
384*90c8c64dSAndroid Build Coastguard Worker      records = [(None, lib[1:] + "  ***Error: " + str(e))]
385*90c8c64dSAndroid Build Coastguard Worker    result[addr] = records
386*90c8c64dSAndroid Build Coastguard Worker    addr_cache[addr] = records
387*90c8c64dSAndroid Build Coastguard Worker  return result
388*90c8c64dSAndroid Build Coastguard Worker
389*90c8c64dSAndroid Build Coastguard Worker
390*90c8c64dSAndroid Build Coastguard Workerdef CallObjdumpForSet(lib, unique_addrs):
391*90c8c64dSAndroid Build Coastguard Worker  """Use objdump to find out the names of the containing functions.
392*90c8c64dSAndroid Build Coastguard Worker
393*90c8c64dSAndroid Build Coastguard Worker  Args:
394*90c8c64dSAndroid Build Coastguard Worker    lib: library (or executable) pathname containing symbols
395*90c8c64dSAndroid Build Coastguard Worker    unique_addrs: set of string hexidecimal addresses to find the functions for.
396*90c8c64dSAndroid Build Coastguard Worker
397*90c8c64dSAndroid Build Coastguard Worker  Returns:
398*90c8c64dSAndroid Build Coastguard Worker    A dictionary of the form {addr: (string symbol, offset)}.
399*90c8c64dSAndroid Build Coastguard Worker  """
400*90c8c64dSAndroid Build Coastguard Worker  if not lib:
401*90c8c64dSAndroid Build Coastguard Worker    return None
402*90c8c64dSAndroid Build Coastguard Worker
403*90c8c64dSAndroid Build Coastguard Worker  result = {}
404*90c8c64dSAndroid Build Coastguard Worker  addrs = sorted(unique_addrs)
405*90c8c64dSAndroid Build Coastguard Worker
406*90c8c64dSAndroid Build Coastguard Worker  addr_cache = None
407*90c8c64dSAndroid Build Coastguard Worker  if lib in _SYMBOL_INFORMATION_OBJDUMP_CACHE:
408*90c8c64dSAndroid Build Coastguard Worker    addr_cache = _SYMBOL_INFORMATION_OBJDUMP_CACHE[lib]
409*90c8c64dSAndroid Build Coastguard Worker
410*90c8c64dSAndroid Build Coastguard Worker    # Go through and handle all known addresses.
411*90c8c64dSAndroid Build Coastguard Worker    for x in range(len(addrs)):
412*90c8c64dSAndroid Build Coastguard Worker      next_addr = addrs.pop(0)
413*90c8c64dSAndroid Build Coastguard Worker      if next_addr in addr_cache:
414*90c8c64dSAndroid Build Coastguard Worker        result[next_addr] = addr_cache[next_addr]
415*90c8c64dSAndroid Build Coastguard Worker      else:
416*90c8c64dSAndroid Build Coastguard Worker        # Re-add, needs to be symbolized.
417*90c8c64dSAndroid Build Coastguard Worker        addrs.append(next_addr)
418*90c8c64dSAndroid Build Coastguard Worker
419*90c8c64dSAndroid Build Coastguard Worker    if not addrs:
420*90c8c64dSAndroid Build Coastguard Worker      # Everything was cached, we're done.
421*90c8c64dSAndroid Build Coastguard Worker      return result
422*90c8c64dSAndroid Build Coastguard Worker  else:
423*90c8c64dSAndroid Build Coastguard Worker    addr_cache = {}
424*90c8c64dSAndroid Build Coastguard Worker    _SYMBOL_INFORMATION_OBJDUMP_CACHE[lib] = addr_cache
425*90c8c64dSAndroid Build Coastguard Worker
426*90c8c64dSAndroid Build Coastguard Worker  symbols = SYMBOLS_DIR + lib
427*90c8c64dSAndroid Build Coastguard Worker  if not os.path.exists(symbols):
428*90c8c64dSAndroid Build Coastguard Worker    symbols = lib
429*90c8c64dSAndroid Build Coastguard Worker    if not os.path.exists(symbols):
430*90c8c64dSAndroid Build Coastguard Worker      return None
431*90c8c64dSAndroid Build Coastguard Worker
432*90c8c64dSAndroid Build Coastguard Worker  start_addr_dec = str(int(addrs[0], 16))
433*90c8c64dSAndroid Build Coastguard Worker  stop_addr_dec = str(int(addrs[-1], 16) + 8)
434*90c8c64dSAndroid Build Coastguard Worker  cmd = [ToolPath("llvm-objdump"),
435*90c8c64dSAndroid Build Coastguard Worker         "--section=.text",
436*90c8c64dSAndroid Build Coastguard Worker         "--demangle",
437*90c8c64dSAndroid Build Coastguard Worker         "--disassemble",
438*90c8c64dSAndroid Build Coastguard Worker         "--start-address=" + start_addr_dec,
439*90c8c64dSAndroid Build Coastguard Worker         "--stop-address=" + stop_addr_dec,
440*90c8c64dSAndroid Build Coastguard Worker         symbols]
441*90c8c64dSAndroid Build Coastguard Worker
442*90c8c64dSAndroid Build Coastguard Worker  # Function lines look like:
443*90c8c64dSAndroid Build Coastguard Worker  #   000177b0 <android::IBinder::~IBinder()+0x2c>:
444*90c8c64dSAndroid Build Coastguard Worker  # We pull out the address and function first. Then we check for an optional
445*90c8c64dSAndroid Build Coastguard Worker  # offset. This is tricky due to functions that look like "operator+(..)+0x2c"
446*90c8c64dSAndroid Build Coastguard Worker  func_regexp = re.compile("(^[a-f0-9]*) \<(.*)\>:$")
447*90c8c64dSAndroid Build Coastguard Worker  offset_regexp = re.compile("(.*)\+0x([a-f0-9]*)")
448*90c8c64dSAndroid Build Coastguard Worker
449*90c8c64dSAndroid Build Coastguard Worker  # A disassembly line looks like:
450*90c8c64dSAndroid Build Coastguard Worker  #   177b2:	b510      	push	{r4, lr}
451*90c8c64dSAndroid Build Coastguard Worker  asm_regexp = re.compile("(^[ a-f0-9]*):[ a-f0-0]*.*$")
452*90c8c64dSAndroid Build Coastguard Worker
453*90c8c64dSAndroid Build Coastguard Worker  current_symbol = None    # The current function symbol in the disassembly.
454*90c8c64dSAndroid Build Coastguard Worker  current_symbol_addr = 0  # The address of the current function.
455*90c8c64dSAndroid Build Coastguard Worker  addr_index = 0  # The address that we are currently looking for.
456*90c8c64dSAndroid Build Coastguard Worker
457*90c8c64dSAndroid Build Coastguard Worker  stream = subprocess.Popen(cmd, stdout=subprocess.PIPE, universal_newlines=True).stdout
458*90c8c64dSAndroid Build Coastguard Worker  for line in stream:
459*90c8c64dSAndroid Build Coastguard Worker    # Is it a function line like:
460*90c8c64dSAndroid Build Coastguard Worker    #   000177b0 <android::IBinder::~IBinder()>:
461*90c8c64dSAndroid Build Coastguard Worker    components = func_regexp.match(line)
462*90c8c64dSAndroid Build Coastguard Worker    if components:
463*90c8c64dSAndroid Build Coastguard Worker      # This is a new function, so record the current function and its address.
464*90c8c64dSAndroid Build Coastguard Worker      current_symbol_addr = int(components.group(1), 16)
465*90c8c64dSAndroid Build Coastguard Worker      current_symbol = components.group(2)
466*90c8c64dSAndroid Build Coastguard Worker
467*90c8c64dSAndroid Build Coastguard Worker      # Does it have an optional offset like: "foo(..)+0x2c"?
468*90c8c64dSAndroid Build Coastguard Worker      components = offset_regexp.match(current_symbol)
469*90c8c64dSAndroid Build Coastguard Worker      if components:
470*90c8c64dSAndroid Build Coastguard Worker        current_symbol = components.group(1)
471*90c8c64dSAndroid Build Coastguard Worker        offset = components.group(2)
472*90c8c64dSAndroid Build Coastguard Worker        if offset:
473*90c8c64dSAndroid Build Coastguard Worker          current_symbol_addr -= int(offset, 16)
474*90c8c64dSAndroid Build Coastguard Worker
475*90c8c64dSAndroid Build Coastguard Worker    # Is it an disassembly line like:
476*90c8c64dSAndroid Build Coastguard Worker    #   177b2:	b510      	push	{r4, lr}
477*90c8c64dSAndroid Build Coastguard Worker    components = asm_regexp.match(line)
478*90c8c64dSAndroid Build Coastguard Worker    if components:
479*90c8c64dSAndroid Build Coastguard Worker      addr = components.group(1)
480*90c8c64dSAndroid Build Coastguard Worker      target_addr = addrs[addr_index]
481*90c8c64dSAndroid Build Coastguard Worker      i_addr = int(addr, 16)
482*90c8c64dSAndroid Build Coastguard Worker      i_target = int(target_addr, 16)
483*90c8c64dSAndroid Build Coastguard Worker      if i_addr == i_target:
484*90c8c64dSAndroid Build Coastguard Worker        result[target_addr] = (current_symbol, i_target - current_symbol_addr)
485*90c8c64dSAndroid Build Coastguard Worker        addr_cache[target_addr] = result[target_addr]
486*90c8c64dSAndroid Build Coastguard Worker        addr_index += 1
487*90c8c64dSAndroid Build Coastguard Worker        if addr_index >= len(addrs):
488*90c8c64dSAndroid Build Coastguard Worker          break
489*90c8c64dSAndroid Build Coastguard Worker  stream.close()
490*90c8c64dSAndroid Build Coastguard Worker
491*90c8c64dSAndroid Build Coastguard Worker  return result
492*90c8c64dSAndroid Build Coastguard Worker
493*90c8c64dSAndroid Build Coastguard Worker
494*90c8c64dSAndroid Build Coastguard Workerdef CallCppFilt(mangled_symbol):
495*90c8c64dSAndroid Build Coastguard Worker  if mangled_symbol in _SYMBOL_DEMANGLING_CACHE:
496*90c8c64dSAndroid Build Coastguard Worker    return _SYMBOL_DEMANGLING_CACHE[mangled_symbol]
497*90c8c64dSAndroid Build Coastguard Worker
498*90c8c64dSAndroid Build Coastguard Worker  global _CACHED_CXX_FILT
499*90c8c64dSAndroid Build Coastguard Worker  if not _CACHED_CXX_FILT:
500*90c8c64dSAndroid Build Coastguard Worker    toolchains = None
501*90c8c64dSAndroid Build Coastguard Worker    clang_dir = FindClangDir()
502*90c8c64dSAndroid Build Coastguard Worker    if clang_dir:
503*90c8c64dSAndroid Build Coastguard Worker      if os.path.exists(clang_dir + "/bin/llvm-cxxfilt"):
504*90c8c64dSAndroid Build Coastguard Worker        toolchains = [clang_dir + "/bin/llvm-cxxfilt"]
505*90c8c64dSAndroid Build Coastguard Worker      else:
506*90c8c64dSAndroid Build Coastguard Worker        raise Exception("bin/llvm-cxxfilt missing from " + clang_dir)
507*90c8c64dSAndroid Build Coastguard Worker    else:
508*90c8c64dSAndroid Build Coastguard Worker      # When run in CI, we don't have a way to find the clang version.  But
509*90c8c64dSAndroid Build Coastguard Worker      # llvm-cxxfilt should be available in the following relative path.
510*90c8c64dSAndroid Build Coastguard Worker      toolchains = glob.glob("./clang-r*/bin/llvm-cxxfilt")
511*90c8c64dSAndroid Build Coastguard Worker      if toolchains and len(toolchains) != 1:
512*90c8c64dSAndroid Build Coastguard Worker        raise Exception("Expected one llvm-cxxfilt but found many: " + \
513*90c8c64dSAndroid Build Coastguard Worker                        ", ".join(toolchains))
514*90c8c64dSAndroid Build Coastguard Worker    if not toolchains:
515*90c8c64dSAndroid Build Coastguard Worker      raise Exception("Could not find llvm-cxxfilt tool")
516*90c8c64dSAndroid Build Coastguard Worker    _CACHED_CXX_FILT = sorted(toolchains)[-1]
517*90c8c64dSAndroid Build Coastguard Worker
518*90c8c64dSAndroid Build Coastguard Worker  cmd = [_CACHED_CXX_FILT]
519*90c8c64dSAndroid Build Coastguard Worker  process = _PIPE_CPPFILT_CACHE.GetProcess(cmd)
520*90c8c64dSAndroid Build Coastguard Worker  process.stdin.write(mangled_symbol)
521*90c8c64dSAndroid Build Coastguard Worker  process.stdin.write("\n")
522*90c8c64dSAndroid Build Coastguard Worker  process.stdin.flush()
523*90c8c64dSAndroid Build Coastguard Worker
524*90c8c64dSAndroid Build Coastguard Worker  demangled_symbol = process.stdout.readline().strip()
525*90c8c64dSAndroid Build Coastguard Worker
526*90c8c64dSAndroid Build Coastguard Worker  _SYMBOL_DEMANGLING_CACHE[mangled_symbol] = demangled_symbol
527*90c8c64dSAndroid Build Coastguard Worker
528*90c8c64dSAndroid Build Coastguard Worker  return demangled_symbol
529*90c8c64dSAndroid Build Coastguard Worker
530*90c8c64dSAndroid Build Coastguard Worker
531*90c8c64dSAndroid Build Coastguard Workerdef FormatSymbolWithOffset(symbol, offset):
532*90c8c64dSAndroid Build Coastguard Worker  if offset == 0:
533*90c8c64dSAndroid Build Coastguard Worker    return symbol
534*90c8c64dSAndroid Build Coastguard Worker  return "%s+%d" % (symbol, offset)
535*90c8c64dSAndroid Build Coastguard Worker
536*90c8c64dSAndroid Build Coastguard Workerdef FormatSymbolWithoutParameters(symbol):
537*90c8c64dSAndroid Build Coastguard Worker  """Remove parameters from function.
538*90c8c64dSAndroid Build Coastguard Worker
539*90c8c64dSAndroid Build Coastguard Worker  Rather than trying to parse the demangled C++ signature,
540*90c8c64dSAndroid Build Coastguard Worker  it just removes matching top level parenthesis.
541*90c8c64dSAndroid Build Coastguard Worker  """
542*90c8c64dSAndroid Build Coastguard Worker  if not symbol:
543*90c8c64dSAndroid Build Coastguard Worker    return symbol
544*90c8c64dSAndroid Build Coastguard Worker
545*90c8c64dSAndroid Build Coastguard Worker  result = symbol
546*90c8c64dSAndroid Build Coastguard Worker  result = result.replace(") const", ")")                  # Strip const keyword.
547*90c8c64dSAndroid Build Coastguard Worker  result = result.replace("operator<<", "operator\u00AB")  # Avoid unmatched '<'.
548*90c8c64dSAndroid Build Coastguard Worker  result = result.replace("operator>>", "operator\u00BB")  # Avoid unmatched '>'.
549*90c8c64dSAndroid Build Coastguard Worker  result = result.replace("operator->", "operator\u2192")  # Avoid unmatched '>'.
550*90c8c64dSAndroid Build Coastguard Worker
551*90c8c64dSAndroid Build Coastguard Worker  nested = []  # Keeps tract of current nesting level of parenthesis.
552*90c8c64dSAndroid Build Coastguard Worker  for i in reversed(range(len(result))):  # Iterate backward to make cutting easier.
553*90c8c64dSAndroid Build Coastguard Worker    c = result[i]
554*90c8c64dSAndroid Build Coastguard Worker    if c == ')' or c == '>':
555*90c8c64dSAndroid Build Coastguard Worker      if len(nested) == 0:
556*90c8c64dSAndroid Build Coastguard Worker        end = i + 1  # Mark the end of top-level pair.
557*90c8c64dSAndroid Build Coastguard Worker      nested.append(c)
558*90c8c64dSAndroid Build Coastguard Worker    if c == '(' or c == '<':
559*90c8c64dSAndroid Build Coastguard Worker      if len(nested) == 0 or {')':'(', '>':'<'}[nested.pop()] != c:
560*90c8c64dSAndroid Build Coastguard Worker        return symbol  # Malformed: character does not match its pair.
561*90c8c64dSAndroid Build Coastguard Worker      if len(nested) == 0 and c == '(' and (end - i) > 2:
562*90c8c64dSAndroid Build Coastguard Worker        result = result[:i] + result[end:]  # Remove substring (i, end).
563*90c8c64dSAndroid Build Coastguard Worker  if len(nested) > 0:
564*90c8c64dSAndroid Build Coastguard Worker    return symbol  # Malformed: missing pair.
565*90c8c64dSAndroid Build Coastguard Worker
566*90c8c64dSAndroid Build Coastguard Worker  return result.strip()
567*90c8c64dSAndroid Build Coastguard Worker
568*90c8c64dSAndroid Build Coastguard Workerdef SetBitness(lines):
569*90c8c64dSAndroid Build Coastguard Worker  global ARCH_IS_32BIT
570*90c8c64dSAndroid Build Coastguard Worker
571*90c8c64dSAndroid Build Coastguard Worker  trace_line = re.compile("\#[0-9]+[ \t]+..[ \t]+([0-9a-f]{8}|[0-9a-f]{16})([ \t]+|$)")
572*90c8c64dSAndroid Build Coastguard Worker  asan_trace_line = re.compile("\#[0-9]+[ \t]+0x([0-9a-f]+)[ \t]+")
573*90c8c64dSAndroid Build Coastguard Worker
574*90c8c64dSAndroid Build Coastguard Worker  ARCH_IS_32BIT = False
575*90c8c64dSAndroid Build Coastguard Worker  for line in lines:
576*90c8c64dSAndroid Build Coastguard Worker    trace_match = trace_line.search(line)
577*90c8c64dSAndroid Build Coastguard Worker    if trace_match:
578*90c8c64dSAndroid Build Coastguard Worker      # Try to guess the arch, we know the bitness.
579*90c8c64dSAndroid Build Coastguard Worker      if len(trace_match.group(1)) == 16:
580*90c8c64dSAndroid Build Coastguard Worker        ARCH_IS_32BIT = False
581*90c8c64dSAndroid Build Coastguard Worker      else:
582*90c8c64dSAndroid Build Coastguard Worker        ARCH_IS_32BIT = True
583*90c8c64dSAndroid Build Coastguard Worker      break
584*90c8c64dSAndroid Build Coastguard Worker    asan_trace_match = asan_trace_line.search(line)
585*90c8c64dSAndroid Build Coastguard Worker    if asan_trace_match:
586*90c8c64dSAndroid Build Coastguard Worker      # We might be able to guess the bitness by the length of the address.
587*90c8c64dSAndroid Build Coastguard Worker      if len(asan_trace_match.group(1)) > 8:
588*90c8c64dSAndroid Build Coastguard Worker        ARCH_IS_32BIT = False
589*90c8c64dSAndroid Build Coastguard Worker        # We know for a fact this is 64 bit, so we are done.
590*90c8c64dSAndroid Build Coastguard Worker        break
591*90c8c64dSAndroid Build Coastguard Worker      else:
592*90c8c64dSAndroid Build Coastguard Worker        # This might be 32 bit, or just a small address. Keep going in this
593*90c8c64dSAndroid Build Coastguard Worker        # case, but if we couldn't figure anything else out, go with 32 bit.
594*90c8c64dSAndroid Build Coastguard Worker        ARCH_IS_32BIT = True
595*90c8c64dSAndroid Build Coastguard Worker
596*90c8c64dSAndroid Build Coastguard Workerclass FindClangDirTests(unittest.TestCase):
597*90c8c64dSAndroid Build Coastguard Worker  @unittest.skipIf(ANDROID_BUILD_TOP == '.', 'Test only supported in an Android tree.')
598*90c8c64dSAndroid Build Coastguard Worker  def test_clang_dir_found(self):
599*90c8c64dSAndroid Build Coastguard Worker    self.assertIsNotNone(FindClangDir())
600*90c8c64dSAndroid Build Coastguard Worker
601*90c8c64dSAndroid Build Coastguard Workerclass SetBitnessTests(unittest.TestCase):
602*90c8c64dSAndroid Build Coastguard Worker  def test_32bit_check(self):
603*90c8c64dSAndroid Build Coastguard Worker    global ARCH_IS_32BIT
604*90c8c64dSAndroid Build Coastguard Worker
605*90c8c64dSAndroid Build Coastguard Worker    SetBitness(["#00 pc 000374e0"])
606*90c8c64dSAndroid Build Coastguard Worker    self.assertTrue(ARCH_IS_32BIT)
607*90c8c64dSAndroid Build Coastguard Worker
608*90c8c64dSAndroid Build Coastguard Worker  def test_64bit_check(self):
609*90c8c64dSAndroid Build Coastguard Worker    global ARCH_IS_32BIT
610*90c8c64dSAndroid Build Coastguard Worker
611*90c8c64dSAndroid Build Coastguard Worker    SetBitness(["#00 pc 00000000000374e0"])
612*90c8c64dSAndroid Build Coastguard Worker    self.assertFalse(ARCH_IS_32BIT)
613*90c8c64dSAndroid Build Coastguard Worker
614*90c8c64dSAndroid Build Coastguard Worker  def test_32bit_asan_trace_line_toolchain(self):
615*90c8c64dSAndroid Build Coastguard Worker    global ARCH_IS_32BIT
616*90c8c64dSAndroid Build Coastguard Worker
617*90c8c64dSAndroid Build Coastguard Worker    SetBitness(["#10 0xb5eeba5d  (/system/vendor/lib/egl/libGLESv1_CM_adreno.so+0xfa5d)"])
618*90c8c64dSAndroid Build Coastguard Worker    self.assertTrue(ARCH_IS_32BIT)
619*90c8c64dSAndroid Build Coastguard Worker
620*90c8c64dSAndroid Build Coastguard Worker  def test_64bit_asan_trace_line_toolchain(self):
621*90c8c64dSAndroid Build Coastguard Worker    global ARCH_IS_32BIT
622*90c8c64dSAndroid Build Coastguard Worker
623*90c8c64dSAndroid Build Coastguard Worker    SetBitness(["#12 0x5d33bf  (/system/lib/libclang_rt.asan-arm-android.so+0x823bf)",
624*90c8c64dSAndroid Build Coastguard Worker                "#12 0x11b35d33bf  (/system/lib/libclang_rt.asan-arm-android.so+0x823bf)"])
625*90c8c64dSAndroid Build Coastguard Worker    self.assertFalse(ARCH_IS_32BIT)
626*90c8c64dSAndroid Build Coastguard Worker
627*90c8c64dSAndroid Build Coastguard Workerclass FormatSymbolWithoutParametersTests(unittest.TestCase):
628*90c8c64dSAndroid Build Coastguard Worker  def test_c(self):
629*90c8c64dSAndroid Build Coastguard Worker    self.assertEqual(FormatSymbolWithoutParameters("foo"), "foo")
630*90c8c64dSAndroid Build Coastguard Worker    self.assertEqual(FormatSymbolWithoutParameters("foo+42"), "foo+42")
631*90c8c64dSAndroid Build Coastguard Worker
632*90c8c64dSAndroid Build Coastguard Worker  def test_simple(self):
633*90c8c64dSAndroid Build Coastguard Worker    self.assertEqual(FormatSymbolWithoutParameters("foo(int i)"), "foo")
634*90c8c64dSAndroid Build Coastguard Worker    self.assertEqual(FormatSymbolWithoutParameters("foo(int i)+42"), "foo+42")
635*90c8c64dSAndroid Build Coastguard Worker    self.assertEqual(FormatSymbolWithoutParameters("bar::foo(int i)+42"), "bar::foo+42")
636*90c8c64dSAndroid Build Coastguard Worker    self.assertEqual(FormatSymbolWithoutParameters("operator()"), "operator()")
637*90c8c64dSAndroid Build Coastguard Worker
638*90c8c64dSAndroid Build Coastguard Worker  def test_templates(self):
639*90c8c64dSAndroid Build Coastguard Worker    self.assertEqual(FormatSymbolWithoutParameters("bar::foo<T>(vector<T>& v)"), "bar::foo<T>")
640*90c8c64dSAndroid Build Coastguard Worker    self.assertEqual(FormatSymbolWithoutParameters("bar<T>::foo(vector<T>& v)"), "bar<T>::foo")
641*90c8c64dSAndroid Build Coastguard Worker    self.assertEqual(FormatSymbolWithoutParameters("bar::foo<T>(vector<T<U>>& v)"), "bar::foo<T>")
642*90c8c64dSAndroid Build Coastguard Worker    self.assertEqual(FormatSymbolWithoutParameters("bar::foo<(EnumType)0>(vector<(EnumType)0>& v)"),
643*90c8c64dSAndroid Build Coastguard Worker                                                   "bar::foo<(EnumType)0>")
644*90c8c64dSAndroid Build Coastguard Worker
645*90c8c64dSAndroid Build Coastguard Worker  def test_nested(self):
646*90c8c64dSAndroid Build Coastguard Worker    self.assertEqual(FormatSymbolWithoutParameters("foo(int i)::bar(int j)"), "foo::bar")
647*90c8c64dSAndroid Build Coastguard Worker
648*90c8c64dSAndroid Build Coastguard Worker  def test_unbalanced(self):
649*90c8c64dSAndroid Build Coastguard Worker    self.assertEqual(FormatSymbolWithoutParameters("foo(bar(int i)"), "foo(bar(int i)")
650*90c8c64dSAndroid Build Coastguard Worker    self.assertEqual(FormatSymbolWithoutParameters("foo)bar(int i)"), "foo)bar(int i)")
651*90c8c64dSAndroid Build Coastguard Worker    self.assertEqual(FormatSymbolWithoutParameters("foo<bar(int i)"), "foo<bar(int i)")
652*90c8c64dSAndroid Build Coastguard Worker    self.assertEqual(FormatSymbolWithoutParameters("foo>bar(int i)"), "foo>bar(int i)")
653*90c8c64dSAndroid Build Coastguard Worker
654*90c8c64dSAndroid Build Coastguard Workerif __name__ == '__main__':
655*90c8c64dSAndroid Build Coastguard Worker    unittest.main(verbosity=2)
656