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