valgrind_tools.py revision 5821806d5e7f356e8fa4b058a389a808ea183019
1# Copyright (c) 2012 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5""" 6Classes in this file define additional actions that need to be taken to run a 7test under some kind of runtime error detection tool. 8 9The interface is intended to be used as follows. 10 111. For tests that simply run a native process (i.e. no activity is spawned): 12 13Call tool.CopyFiles(). 14Prepend test command line with tool.GetTestWrapper(). 15 162. For tests that spawn an activity: 17 18Call tool.CopyFiles(). 19Call tool.SetupEnvironment(). 20Run the test as usual. 21Call tool.CleanUpEnvironment(). 22""" 23 24import os.path 25import sys 26 27from constants import CHROME_DIR 28 29 30def SetChromeTimeoutScale(adb, scale): 31 """Sets the timeout scale in /data/local/tmp/chrome_timeout_scale to scale.""" 32 path = '/data/local/tmp/chrome_timeout_scale' 33 if not scale or scale == 1.0: 34 # Delete if scale is None/0.0/1.0 since the default timeout scale is 1.0 35 adb.RunShellCommand('rm %s' % path) 36 else: 37 adb.SetFileContents(path, '%f' % scale) 38 39 40class BaseTool(object): 41 """A tool that does nothing.""" 42 43 def GetTestWrapper(self): 44 """Returns a string that is to be prepended to the test command line.""" 45 return '' 46 47 def GetUtilWrapper(self): 48 """Returns the wrapper name for the utilities. 49 50 Returns: 51 A string that is to be prepended to the command line of utility 52 processes (forwarder, etc.). 53 """ 54 return '' 55 56 def CopyFiles(self): 57 """Copies tool-specific files to the device, create directories, etc.""" 58 pass 59 60 def SetupEnvironment(self): 61 """Sets up the system environment for a test. 62 63 This is a good place to set system properties. 64 """ 65 pass 66 67 def CleanUpEnvironment(self): 68 """Cleans up environment.""" 69 pass 70 71 def GetTimeoutScale(self): 72 """Returns a multiplier that should be applied to timeout values.""" 73 return 1.0 74 75 def NeedsDebugInfo(self): 76 """Whether this tool requires debug info. 77 78 Returns: 79 True if this tool can not work with stripped binaries. 80 """ 81 return False 82 83 84class AddressSanitizerTool(BaseTool): 85 """AddressSanitizer tool.""" 86 87 TMP_DIR = '/data/local/tmp/asan' 88 WRAPPER_NAME = 'asanwrapper.sh' 89 90 def __init__(self, adb): 91 self._adb = adb 92 self._wrap_properties = ['wrap.com.google.android.apps.ch', 93 'wrap.org.chromium.native_test'] 94 95 def CopyFiles(self): 96 """Copies ASan tools to the device.""" 97 files = ['tools/android/asan/asanwrapper.sh', 98 'third_party/llvm-build/Release+Asserts/lib/clang/3.2/lib/linux/' + 99 'libclang_rt.asan-arm-android.so'] 100 for f in files: 101 self._adb.PushIfNeeded(os.path.join(CHROME_DIR, f), 102 os.path.join(AddressSanitizerTool.TMP_DIR, 103 os.path.basename(f))) 104 105 def GetTestWrapper(self): 106 return os.path.join(AddressSanitizerTool.TMP_DIR, 107 AddressSanitizerTool.WRAPPER_NAME) 108 109 def GetUtilWrapper(self): 110 """Returns the wrapper for utilities, such as forwarder. 111 112 AddressSanitizer wrapper must be added to all instrumented binaries, 113 including forwarder and the like. This can be removed if such binaries 114 were built without instrumentation. """ 115 return self.GetTestWrapper() 116 117 def SetupEnvironment(self): 118 self._adb.EnableAdbRoot() 119 for prop in self._wrap_properties: 120 self._adb.RunShellCommand('setprop %s "logwrapper %s"' % ( 121 prop, self.GetTestWrapper())) 122 SetChromeTimeoutScale(self._adb, self.GetTimeoutScale()) 123 124 def CleanUpEnvironment(self): 125 for prop in self._wrap_properties: 126 self._adb.RunShellCommand('setprop %s ""' % (prop,)) 127 SetChromeTimeoutScale(self._adb, None) 128 129 def GetTimeoutScale(self): 130 # Very slow startup. 131 return 20.0 132 133 134class ValgrindTool(BaseTool): 135 """Base abstract class for Valgrind tools.""" 136 137 VG_DIR = '/data/local/tmp/valgrind' 138 VGLOGS_DIR = '/data/local/tmp/vglogs' 139 140 def __init__(self, adb): 141 self._adb = adb 142 # exactly 31 chars, SystemProperties::PROP_NAME_MAX 143 self._wrap_properties = ['wrap.com.google.android.apps.ch', 144 'wrap.org.chromium.native_test'] 145 146 def CopyFiles(self): 147 """Copies Valgrind tools to the device.""" 148 self._adb.RunShellCommand('rm -r %s; mkdir %s' % 149 (ValgrindTool.VG_DIR, ValgrindTool.VG_DIR)) 150 self._adb.RunShellCommand('rm -r %s; mkdir %s' % 151 (ValgrindTool.VGLOGS_DIR, 152 ValgrindTool.VGLOGS_DIR)) 153 files = self.GetFilesForTool() 154 for f in files: 155 self._adb.PushIfNeeded(os.path.join(CHROME_DIR, f), 156 os.path.join(ValgrindTool.VG_DIR, 157 os.path.basename(f))) 158 159 def SetupEnvironment(self): 160 """Sets up device environment.""" 161 self._adb.RunShellCommand('chmod 777 /data/local/tmp') 162 for prop in self._wrap_properties: 163 self._adb.RunShellCommand('setprop %s "logwrapper %s"' % ( 164 prop, self.GetTestWrapper())) 165 SetChromeTimeoutScale(self._adb, self.GetTimeoutScale()) 166 167 def CleanUpEnvironment(self): 168 """Cleans up device environment.""" 169 for prop in self._wrap_properties: 170 self._adb.RunShellCommand('setprop %s ""' % (prop,)) 171 SetChromeTimeoutScale(self._adb, None) 172 173 def GetFilesForTool(self): 174 """Returns a list of file names for the tool.""" 175 raise NotImplementedError() 176 177 def NeedsDebugInfo(self): 178 """Whether this tool requires debug info. 179 180 Returns: 181 True if this tool can not work with stripped binaries. 182 """ 183 return True 184 185 186class MemcheckTool(ValgrindTool): 187 """Memcheck tool.""" 188 189 def __init__(self, adb): 190 super(MemcheckTool, self).__init__(adb) 191 192 def GetFilesForTool(self): 193 """Returns a list of file names for the tool.""" 194 return ['tools/valgrind/android/vg-chrome-wrapper.sh', 195 'tools/valgrind/memcheck/suppressions.txt', 196 'tools/valgrind/memcheck/suppressions_android.txt'] 197 198 def GetTestWrapper(self): 199 """Returns a string that is to be prepended to the test command line.""" 200 return ValgrindTool.VG_DIR + '/' + 'vg-chrome-wrapper.sh' 201 202 def GetTimeoutScale(self): 203 """Returns a multiplier that should be applied to timeout values.""" 204 return 30 205 206 207class TSanTool(ValgrindTool): 208 """ThreadSanitizer tool. See http://code.google.com/p/data-race-test .""" 209 210 def __init__(self, adb): 211 super(TSanTool, self).__init__(adb) 212 213 def GetFilesForTool(self): 214 """Returns a list of file names for the tool.""" 215 return ['tools/valgrind/android/vg-chrome-wrapper-tsan.sh', 216 'tools/valgrind/tsan/suppressions.txt', 217 'tools/valgrind/tsan/suppressions_android.txt', 218 'tools/valgrind/tsan/ignores.txt'] 219 220 def GetTestWrapper(self): 221 """Returns a string that is to be prepended to the test command line.""" 222 return ValgrindTool.VG_DIR + '/' + 'vg-chrome-wrapper-tsan.sh' 223 224 def GetTimeoutScale(self): 225 """Returns a multiplier that should be applied to timeout values.""" 226 return 30.0 227 228 229TOOL_REGISTRY = { 230 'memcheck': lambda x: MemcheckTool(x), 231 'memcheck-renderer': lambda x: MemcheckTool(x), 232 'tsan': lambda x: TSanTool(x), 233 'tsan-renderer': lambda x: TSanTool(x), 234 'asan': lambda x: AddressSanitizerTool(x), 235} 236 237 238def CreateTool(tool_name, adb): 239 """Creates a tool with the specified tool name. 240 241 Args: 242 tool_name: Name of the tool to create. 243 adb: ADB interface the tool will use. 244 Returns: 245 A tool for the specified tool_name. 246 """ 247 if not tool_name: 248 return BaseTool() 249 250 ctor = TOOL_REGISTRY.get(tool_name) 251 if ctor: 252 return ctor(adb) 253 else: 254 print 'Unknown tool %s, available tools: %s' % ( 255 tool_name, ', '.join(sorted(TOOL_REGISTRY.keys()))) 256 sys.exit(1) 257