15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""Runs an exe through Valgrind and puts the intermediate files in a
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)directory.
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import datetime
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import glob
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import logging
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import optparse
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import re
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import shutil
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import stat
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import subprocess
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import sys
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import tempfile
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import common
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import drmemory_analyze
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import memcheck_analyze
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import tsan_analyze
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class BaseTool(object):
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Abstract class for running Valgrind-, PIN-based and other dynamic
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  error detector tools.
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Always subclass this and implement ToolCommand with framework- and
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tool-specific stuff.
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self):
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    temp_parent_dir = None
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.log_parent_dir = ""
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if common.IsWindows():
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # gpu process on Windows Vista+ runs at Low Integrity and can only
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # write to certain directories (http://crbug.com/119131)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      #
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # TODO(bruening): if scripts die in middle and don't clean up temp
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # dir, we'll accumulate files in profile dir.  should remove
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # really old files automatically.
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      profile = os.getenv("USERPROFILE")
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if profile:
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.log_parent_dir = profile + "\\AppData\\LocalLow\\"
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if os.path.exists(self.log_parent_dir):
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          self.log_parent_dir = common.NormalizeWindowsPath(self.log_parent_dir)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          temp_parent_dir = self.log_parent_dir
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Generated every time (even when overridden)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.temp_dir = tempfile.mkdtemp(prefix="vg_logs_", dir=temp_parent_dir)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.log_dir = self.temp_dir # overridable by --keep_logs
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.option_parser_hooks = []
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # TODO(glider): we may not need some of the env vars on some of the
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # platforms.
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._env = {
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "G_SLICE" : "always-malloc",
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "NSS_DISABLE_UNLOAD" : "1",
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "NSS_DISABLE_ARENA_FREE_LIST" : "1",
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "GTEST_DEATH_TEST_USE_FORK": "1",
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ToolName(self):
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    raise NotImplementedError, "This method should be implemented " \
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               "in the tool-specific subclass"
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Analyze(self, check_sanity=False):
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    raise NotImplementedError, "This method should be implemented " \
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               "in the tool-specific subclass"
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def RegisterOptionParserHook(self, hook):
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Frameworks and tools can add their own flags to the parser.
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.option_parser_hooks.append(hook)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def CreateOptionParser(self):
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Defines Chromium-specific flags.
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._parser = optparse.OptionParser("usage: %prog [options] <program to "
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         "test>")
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._parser.disable_interspersed_args()
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._parser.add_option("-t", "--timeout",
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      dest="timeout", metavar="TIMEOUT", default=10000,
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      help="timeout in seconds for the run (default 10000)")
844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    self._parser.add_option("", "--build-dir",
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            help="the location of the compiler output")
864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    self._parser.add_option("", "--source-dir",
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            help="path to top of source tree for this build"
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 "(used to normalize source paths in baseline)")
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._parser.add_option("", "--gtest_filter", default="",
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            help="which test case to run")
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._parser.add_option("", "--gtest_repeat",
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            help="how many times to run each test")
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._parser.add_option("", "--gtest_print_time", action="store_true",
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            default=False,
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            help="show how long each test takes")
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._parser.add_option("", "--ignore_exit_code", action="store_true",
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            default=False,
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            help="ignore exit code of the test "
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 "(e.g. test failures)")
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._parser.add_option("", "--keep_logs", action="store_true",
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            default=False,
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            help="store memory tool logs in the <tool>.logs "
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 "directory instead of /tmp.\nThis can be "
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 "useful for tool developers/maintainers.\n"
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 "Please note that the <tool>.logs directory "
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 "will be clobbered on tool startup.")
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # To add framework- or tool-specific flags, please add a hook using
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # RegisterOptionParserHook in the corresponding subclass.
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # See ValgrindTool and ThreadSanitizerBase for examples.
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for hook in self.option_parser_hooks:
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      hook(self, self._parser)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ParseArgv(self, args):
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.CreateOptionParser()
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # self._tool_flags will store those tool flags which we don't parse
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # manually in this script.
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._tool_flags = []
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    known_args = []
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """ We assume that the first argument not starting with "-" is a program
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    name and all the following flags should be passed to the program.
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TODO(timurrrr): customize optparse instead
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while len(args) > 0 and args[0][:1] == "-":
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      arg = args[0]
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (arg == "--"):
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if self._parser.has_option(arg.split("=")[0]):
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        known_args += [arg]
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._tool_flags += [arg]
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      args = args[1:]
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if len(args) > 0:
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      known_args += args
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._options, self._args = self._parser.parse_args(known_args)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._timeout = int(self._options.timeout)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._source_dir = self._options.source_dir
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._options.keep_logs:
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # log_parent_dir has trailing slash if non-empty
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.log_dir = self.log_parent_dir + "%s.logs" % self.ToolName()
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if os.path.exists(self.log_dir):
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        shutil.rmtree(self.log_dir)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      os.mkdir(self.log_dir)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.info("Logs are in " + self.log_dir)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._ignore_exit_code = self._options.ignore_exit_code
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._options.gtest_filter != "":
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._args.append("--gtest_filter=%s" % self._options.gtest_filter)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._options.gtest_repeat:
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._args.append("--gtest_repeat=%s" % self._options.gtest_repeat)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._options.gtest_print_time:
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._args.append("--gtest_print_time")
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return True
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Setup(self, args):
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.ParseArgv(args)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ToolCommand(self):
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    raise NotImplementedError, "This method should be implemented " \
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               "in the tool-specific subclass"
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Cleanup(self):
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # You may override it in the tool-specific subclass
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pass
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Execute(self):
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """ Execute the app to be tested after successful instrumentation.
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Full execution command-line provided by subclassers via proc."""
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    logging.info("starting execution...")
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc = self.ToolCommand()
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for var in self._env:
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      common.PutEnvAndLog(var, self._env[var])
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return common.RunSubprocess(proc, self._timeout)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def RunTestsAndAnalyze(self, check_sanity):
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    exec_retcode = self.Execute()
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    analyze_retcode = self.Analyze(check_sanity)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if analyze_retcode:
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.error("Analyze failed.")
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.info("Search the log for '[ERROR]' to see the error reports.")
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return analyze_retcode
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if exec_retcode:
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if self._ignore_exit_code:
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        logging.info("Test execution failed, but the exit code is ignored.")
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        logging.error("Test execution failed.")
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return exec_retcode
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.info("Test execution completed successfully.")
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not analyze_retcode:
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.info("Analysis completed successfully.")
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Main(self, args, check_sanity, min_runtime_in_seconds):
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Call this to run through the whole process: Setup, Execute, Analyze"""
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    start_time = datetime.datetime.now()
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    retcode = -1
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.Setup(args):
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      retcode = self.RunTestsAndAnalyze(check_sanity)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      shutil.rmtree(self.temp_dir, ignore_errors=True)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.Cleanup()
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.error("Setup failed")
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    end_time = datetime.datetime.now()
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    runtime_in_seconds = (end_time - start_time).seconds
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hours = runtime_in_seconds / 3600
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    seconds = runtime_in_seconds % 3600
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    minutes = seconds / 60
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    seconds = seconds % 60
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    logging.info("elapsed time: %02d:%02d:%02d" % (hours, minutes, seconds))
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (min_runtime_in_seconds > 0 and
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        runtime_in_seconds < min_runtime_in_seconds):
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.error("Layout tests finished too quickly. "
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    "It should have taken at least %d seconds. "
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    "Something went wrong?" % min_runtime_in_seconds)
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      retcode = -1
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return retcode
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Run(self, args, module, min_runtime_in_seconds=0):
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MODULES_TO_SANITY_CHECK = ["base"]
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # TODO(timurrrr): this is a temporary workaround for http://crbug.com/47844
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.ToolName() == "tsan" and common.IsMac():
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      MODULES_TO_SANITY_CHECK = []
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    check_sanity = module in MODULES_TO_SANITY_CHECK
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.Main(args, check_sanity, min_runtime_in_seconds)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ValgrindTool(BaseTool):
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Abstract class for running Valgrind tools.
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Always subclass this and implement ToolSpecificFlags() and
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExtendOptionParser() for tool-specific stuff.
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self):
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    super(ValgrindTool, self).__init__()
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.RegisterOptionParserHook(ValgrindTool.ExtendOptionParser)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def UseXML(self):
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Override if tool prefers nonxml output
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return True
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def SelfContained(self):
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Returns true iff the tool is distibuted as a self-contained
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # .sh script (e.g. ThreadSanitizer)
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return False
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ExtendOptionParser(self, parser):
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.add_option("", "--suppressions", default=[],
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            action="append",
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            help="path to a valgrind suppression file")
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.add_option("", "--indirect", action="store_true",
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            default=False,
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            help="set BROWSER_WRAPPER rather than "
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 "running valgrind directly")
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.add_option("", "--indirect_webkit_layout", action="store_true",
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            default=False,
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            help="set --wrapper rather than running Dr. Memory "
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 "directly.")
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.add_option("", "--trace_children", action="store_true",
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            default=False,
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            help="also trace child processes")
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.add_option("", "--num-callers",
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            dest="num_callers", default=30,
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            help="number of callers to show in stack traces")
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.add_option("", "--generate_dsym", action="store_true",
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          default=False,
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          help="Generate .dSYM file on Mac if needed. Slow!")
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Setup(self, args):
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not BaseTool.Setup(self, args):
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return False
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if common.IsMac():
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.PrepareForTestMac()
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return True
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def PrepareForTestMac(self):
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Runs dsymutil if needed.
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Valgrind for Mac OS X requires that debugging information be in a .dSYM
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bundle generated by dsymutil.  It is not currently able to chase DWARF
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data into .o files like gdb does, so executables without .dSYM bundles or
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    with the Chromium-specific "fake_dsym" bundles generated by
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    build/mac/strip_save_dsym won't give source file and line number
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    information in valgrind.
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    This function will run dsymutil if the .dSYM bundle is missing or if
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    it looks like a fake_dsym.  A non-fake dsym that already exists is assumed
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    to be up-to-date.
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    test_command = self._args[0]
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dsym_bundle = self._args[0] + '.dSYM'
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dsym_file = os.path.join(dsym_bundle, 'Contents', 'Resources', 'DWARF',
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             os.path.basename(test_command))
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dsym_info_plist = os.path.join(dsym_bundle, 'Contents', 'Info.plist')
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    needs_dsymutil = True
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    saved_test_command = None
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if os.path.exists(dsym_file) and os.path.exists(dsym_info_plist):
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Look for the special fake_dsym tag in dsym_info_plist.
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dsym_info_plist_contents = open(dsym_info_plist).read()
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not re.search('^\s*<key>fake_dsym</key>$', dsym_info_plist_contents,
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       re.MULTILINE):
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # fake_dsym is not set, this is a real .dSYM bundle produced by
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # dsymutil.  dsymutil does not need to be run again.
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        needs_dsymutil = False
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # fake_dsym is set.  dsym_file is a copy of the original test_command
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # before it was stripped.  Copy it back to test_command so that
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # dsymutil has unstripped input to work with.  Move the stripped
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # test_command out of the way, it will be restored when this is
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # done.
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        saved_test_command = test_command + '.stripped'
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        os.rename(test_command, saved_test_command)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        shutil.copyfile(dsym_file, test_command)
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        shutil.copymode(saved_test_command, test_command)
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if needs_dsymutil:
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if self._options.generate_dsym:
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # Remove the .dSYM bundle if it exists.
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        shutil.rmtree(dsym_bundle, True)
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        dsymutil_command = ['dsymutil', test_command]
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # dsymutil is crazy slow.  Ideally we'd have a timeout here,
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # but common.RunSubprocess' timeout is only checked
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # after each line of output; dsymutil is silent
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # until the end, and is then killed, which is silly.
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        common.RunSubprocess(dsymutil_command)
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if saved_test_command:
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          os.rename(saved_test_command, test_command)
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        logging.info("No real .dSYM for test_command.  Line numbers will "
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     "not be shown.  Either tell xcode to generate .dSYM "
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     "file, or use --generate_dsym option to this tool.")
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ToolCommand(self):
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Get the valgrind command to run."""
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Note that self._args begins with the exe to be run.
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tool_name = self.ToolName()
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Construct the valgrind command.
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.SelfContained():
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      proc = ["valgrind-%s.sh" % tool_name]
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
3603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if 'CHROME_VALGRIND' in os.environ:
3613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        path = os.path.join(os.environ['CHROME_VALGRIND'], "bin", "valgrind")
3623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      else:
3633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        path = "valgrind"
3643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      proc = [path, "--tool=%s" % tool_name]
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc += ["--num-callers=%i" % int(self._options.num_callers)]
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._options.trace_children:
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      proc += ["--trace-children=yes"]
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      proc += ["--trace-children-skip='*dbus-daemon*'"]
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      proc += ["--trace-children-skip='*dbus-launch*'"]
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      proc += ["--trace-children-skip='*perl*'"]
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      proc += ["--trace-children-skip='*python*'"]
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      # This is really Python, but for some reason Valgrind follows it.
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      proc += ["--trace-children-skip='*lsb_release*'"]
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc += self.ToolSpecificFlags()
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc += self._tool_flags
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    suppression_count = 0
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for suppression_file in self._options.suppressions:
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if os.path.exists(suppression_file):
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        suppression_count += 1
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        proc += ["--suppressions=%s" % suppression_file]
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not suppression_count:
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.warning("WARNING: NOT USING SUPPRESSIONS!")
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    logfilename = self.log_dir + ("/%s." % tool_name) + "%p"
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.UseXML():
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      proc += ["--xml=yes", "--xml-file=" + logfilename]
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      proc += ["--log-file=" + logfilename]
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # The Valgrind command is constructed.
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
39790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    # Valgrind doesn't play nice with the Chrome sandbox.  Empty this env var
39890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    # set by runtest.py to disable the sandbox.
39990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if os.environ.get("CHROME_DEVEL_SANDBOX", None):
400a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      logging.info("Removing CHROME_DEVEL_SANDBOX from environment")
40190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      os.environ["CHROME_DEVEL_SANDBOX"] = ''
40290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Handle --indirect_webkit_layout separately.
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._options.indirect_webkit_layout:
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Need to create the wrapper before modifying |proc|.
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      wrapper = self.CreateBrowserWrapper(proc, webkit=True)
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      proc = self._args
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      proc.append("--wrapper")
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      proc.append(wrapper)
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return proc
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._options.indirect:
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      wrapper = self.CreateBrowserWrapper(proc)
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      os.environ["BROWSER_WRAPPER"] = wrapper
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.info('export BROWSER_WRAPPER=' + wrapper)
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      proc = []
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc += self._args
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return proc
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ToolSpecificFlags(self):
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    raise NotImplementedError, "This method should be implemented " \
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               "in the tool-specific subclass"
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def CreateBrowserWrapper(self, proc, webkit=False):
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """The program being run invokes Python or something else that can't stand
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    to be valgrinded, and also invokes the Chrome browser. In this case, use a
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    magic wrapper to only valgrind the Chrome browser. Build the wrapper here.
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns the path to the wrapper. It's up to the caller to use the wrapper
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    appropriately.
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    command = " ".join(proc)
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Add the PID of the browser wrapper to the logfile names so we can
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # separate log files for different UI tests at the analyze stage.
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    command = command.replace("%p", "$$.%p")
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (fd, indirect_fname) = tempfile.mkstemp(dir=self.log_dir,
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            prefix="browser_wrapper.",
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            text=True)
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    f = os.fdopen(fd, "w")
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    f.write('#!/bin/bash\n'
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'echo "Started Valgrind wrapper for this test, PID=$$" >&2\n')
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    f.write('DIR=`dirname $0`\n'
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            'TESTNAME_FILE=$DIR/testcase.$$.name\n\n')
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if webkit:
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Webkit layout_tests pass the URL as the first line of stdin.
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      f.write('tee $TESTNAME_FILE | %s "$@"\n' % command)
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Try to get the test case name by looking at the program arguments.
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # i.e. Chromium ui_tests used --test-name arg.
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # TODO(timurrrr): This doesn't handle "--test-name Test.Name"
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # TODO(timurrrr): ui_tests are dead. Where do we use the non-webkit
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # wrapper now? browser_tests? What do they do?
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      f.write('for arg in $@\ndo\n'
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              '  if [[ "$arg" =~ --test-name=(.*) ]]\n  then\n'
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              '    echo ${BASH_REMATCH[1]} >$TESTNAME_FILE\n'
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              '  fi\n'
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              'done\n\n'
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              '%s "$@"\n' % command)
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    f.close()
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    os.chmod(indirect_fname, stat.S_IRUSR|stat.S_IXUSR)
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return indirect_fname
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def CreateAnalyzer(self):
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    raise NotImplementedError, "This method should be implemented " \
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               "in the tool-specific subclass"
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetAnalyzeResults(self, check_sanity=False):
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Glob all the files in the log directory
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    filenames = glob.glob(self.log_dir + "/" + self.ToolName() + ".*")
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # If we have browser wrapper, the logfiles are named as
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # "toolname.wrapper_PID.valgrind_PID".
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Let's extract the list of wrapper_PIDs and name it ppids
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ppids = set([int(f.split(".")[-2]) \
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                for f in filenames if re.search("\.[0-9]+\.[0-9]+$", f)])
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    analyzer = self.CreateAnalyzer()
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if len(ppids) == 0:
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Fast path - no browser wrapper was set.
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return analyzer.Report(filenames, None, check_sanity)
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = 0
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for ppid in ppids:
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      testcase_name = None
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      try:
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        f = open(self.log_dir + ("/testcase.%d.name" % ppid))
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        testcase_name = f.read().strip()
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        f.close()
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        wk_layout_prefix="third_party/WebKit/LayoutTests/"
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        wk_prefix_at = testcase_name.rfind(wk_layout_prefix)
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if wk_prefix_at != -1:
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          testcase_name = testcase_name[wk_prefix_at + len(wk_layout_prefix):]
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      except IOError:
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pass
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      print "====================================================="
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      print " Below is the report for valgrind wrapper PID=%d." % ppid
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if testcase_name:
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        print " It was used while running the `%s` test." % testcase_name
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        print " You can find the corresponding test"
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        print " by searching the above log for 'PID=%d'" % ppid
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sys.stdout.flush()
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ppid_filenames = [f for f in filenames \
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        if re.search("\.%d\.[0-9]+$" % ppid, f)]
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # check_sanity won't work with browser wrappers
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert check_sanity == False
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret |= analyzer.Report(ppid_filenames, testcase_name)
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      print "====================================================="
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sys.stdout.flush()
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ret != 0:
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      print ""
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      print "The Valgrind reports are grouped by test names."
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      print "Each test has its PID printed in the log when the test was run"
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      print "and at the beginning of its Valgrind report."
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      print "Hint: you can search for the reports by Ctrl+F -> `=#`"
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sys.stdout.flush()
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ret
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# TODO(timurrrr): Split into a separate file.
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Memcheck(ValgrindTool):
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Memcheck
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Dynamic memory error detector for Linux & Mac
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  http://valgrind.org/info/tools.html#memcheck
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self):
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    super(Memcheck, self).__init__()
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.RegisterOptionParserHook(Memcheck.ExtendOptionParser)
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ToolName(self):
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return "memcheck"
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ExtendOptionParser(self, parser):
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.add_option("--leak-check", "--leak_check", type="string",
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      default="yes",  # --leak-check=yes is equivalent of =full
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      help="perform leak checking at the end of the run")
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.add_option("", "--show_all_leaks", action="store_true",
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      default=False,
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      help="also show less blatant leaks")
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.add_option("", "--track_origins", action="store_true",
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      default=False,
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      help="Show whence uninitialized bytes came. 30% slower.")
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ToolSpecificFlags(self):
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = ["--gen-suppressions=all", "--demangle=no"]
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret += ["--leak-check=%s" % self._options.leak_check]
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._options.show_all_leaks:
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret += ["--show-reachable=yes"]
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret += ["--show-possibly-lost=no"]
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._options.track_origins:
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret += ["--track-origins=yes"]
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # TODO(glider): this is a temporary workaround for http://crbug.com/51716
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Let's see whether it helps.
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if common.IsMac():
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret += ["--smc-check=all"]
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ret
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def CreateAnalyzer(self):
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    use_gdb = common.IsMac()
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return memcheck_analyze.MemcheckAnalyzer(self._source_dir,
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            self._options.show_all_leaks,
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            use_gdb=use_gdb)
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Analyze(self, check_sanity=False):
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = self.GetAnalyzeResults(check_sanity)
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ret != 0:
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.info("Please see http://dev.chromium.org/developers/how-tos/"
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   "using-valgrind for the info on Memcheck/Valgrind")
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ret
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class PinTool(BaseTool):
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Abstract class for running PIN tools.
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Always subclass this and implement ToolSpecificFlags() and
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExtendOptionParser() for tool-specific stuff.
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def PrepareForTest(self):
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pass
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ToolSpecificFlags(self):
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    raise NotImplementedError, "This method should be implemented " \
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               "in the tool-specific subclass"
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ToolCommand(self):
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Get the PIN command to run."""
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Construct the PIN command.
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pin_cmd = os.getenv("PIN_COMMAND")
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not pin_cmd:
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise RuntimeError, "Please set PIN_COMMAND environment variable " \
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          "with the path to pin.exe"
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc = pin_cmd.split(" ")
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc += self.ToolSpecificFlags()
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # The PIN command is constructed.
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # PIN requires -- to separate PIN flags from the executable name.
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # self._args begins with the exe to be run.
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc += ["--"]
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc += self._args
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return proc
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ThreadSanitizerBase(object):
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """ThreadSanitizer
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Dynamic data race detector for Linux, Mac and Windows.
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  http://code.google.com/p/data-race-test/wiki/ThreadSanitizer
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Since TSan works on both Valgrind (Linux, Mac) and PIN (Windows), we need
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  to have multiple inheritance
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  INFO_MESSAGE="Please see http://dev.chromium.org/developers/how-tos/" \
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               "using-valgrind/threadsanitizer for the info on " \
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               "ThreadSanitizer"
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self):
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    super(ThreadSanitizerBase, self).__init__()
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.RegisterOptionParserHook(ThreadSanitizerBase.ExtendOptionParser)
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ToolName(self):
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return "tsan"
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def UseXML(self):
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return False
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def SelfContained(self):
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return True
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ExtendOptionParser(self, parser):
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.add_option("", "--hybrid", default="no",
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      dest="hybrid",
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      help="Finds more data races, may give false positive "
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      "reports unless the code is annotated")
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.add_option("", "--announce-threads", default="yes",
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      dest="announce_threads",
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      help="Show the the stack traces of thread creation")
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.add_option("", "--free-is-write", default="no",
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      dest="free_is_write",
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      help="Treat free()/operator delete as memory write. "
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      "This helps finding more data races, but (currently) "
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      "this may give false positive reports on std::string "
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      "internals, see http://code.google.com/p/data-race-test"
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      "/issues/detail?id=40")
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def EvalBoolFlag(self, flag_value):
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (flag_value in ["1", "true", "yes"]):
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return True
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif (flag_value in ["0", "false", "no"]):
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return False
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    raise RuntimeError, "Can't parse flag value (%s)" % flag_value
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ToolSpecificFlags(self):
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = []
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ignore_files = ["ignores.txt"]
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for platform_suffix in common.PlatformNames():
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ignore_files.append("ignores_%s.txt" % platform_suffix)
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for ignore_file in ignore_files:
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      fullname =  os.path.join(self._source_dir,
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "tools", "valgrind", "tsan", ignore_file)
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if os.path.exists(fullname):
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        fullname = common.NormalizeWindowsPath(fullname)
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ret += ["--ignore=%s" % fullname]
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # This should shorten filepaths for local builds.
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret += ["--file-prefix-to-cut=%s/" % self._source_dir]
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # This should shorten filepaths on bots.
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret += ["--file-prefix-to-cut=build/src/"]
6897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    ret += ["--file-prefix-to-cut=out/Release/../../"]
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # This should shorten filepaths for functions intercepted in TSan.
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret += ["--file-prefix-to-cut=scripts/tsan/tsan/"]
6937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    ret += ["--file-prefix-to-cut=src/tsan/tsan/"]
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret += ["--gen-suppressions=true"]
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.EvalBoolFlag(self._options.hybrid):
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret += ["--hybrid=yes"] # "no" is the default value for TSAN
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.EvalBoolFlag(self._options.announce_threads):
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret += ["--announce-threads"]
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.EvalBoolFlag(self._options.free_is_write):
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret += ["--free-is-write=yes"]
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret += ["--free-is-write=no"]
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # --show-pc flag is needed for parsing the error logs on Darwin.
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if platform_suffix == 'mac':
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret += ["--show-pc=yes"]
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret += ["--show-pid=no"]
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    boring_callers = common.BoringCallers(mangled=False, use_re_wildcards=False)
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # TODO(timurrrr): In fact, we want "starting from .." instead of "below .."
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for bc in boring_callers:
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret += ["--cut_stack_below=%s" % bc]
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ret
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ThreadSanitizerPosix(ThreadSanitizerBase, ValgrindTool):
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ToolSpecificFlags(self):
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc = ThreadSanitizerBase.ToolSpecificFlags(self)
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # The -v flag is needed for printing the list of used suppressions and
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # obtaining addresses for loaded shared libraries on Mac.
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc += ["-v"]
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return proc
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def CreateAnalyzer(self):
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    use_gdb = common.IsMac()
7324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return tsan_analyze.TsanAnalyzer(use_gdb)
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Analyze(self, check_sanity=False):
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = self.GetAnalyzeResults(check_sanity)
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ret != 0:
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.info(self.INFO_MESSAGE)
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ret
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ThreadSanitizerWindows(ThreadSanitizerBase, PinTool):
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self):
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    super(ThreadSanitizerWindows, self).__init__()
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.RegisterOptionParserHook(ThreadSanitizerWindows.ExtendOptionParser)
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ExtendOptionParser(self, parser):
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.add_option("", "--suppressions", default=[],
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      action="append",
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      help="path to TSan suppression file")
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ToolSpecificFlags(self):
7552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    add_env = {
7562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "CHROME_ALLOCATOR" : "WINHEAP",
7572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
7582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for k,v in add_env.iteritems():
7592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      logging.info("export %s=%s", k, v)
7602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      os.putenv(k, v)
7612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc = ThreadSanitizerBase.ToolSpecificFlags(self)
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # On PIN, ThreadSanitizer has its own suppression mechanism
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # and --log-file flag which work exactly on Valgrind.
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    suppression_count = 0
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for suppression_file in self._options.suppressions:
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if os.path.exists(suppression_file):
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        suppression_count += 1
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        suppression_file = common.NormalizeWindowsPath(suppression_file)
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        proc += ["--suppressions=%s" % suppression_file]
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not suppression_count:
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.warning("WARNING: NOT USING SUPPRESSIONS!")
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    logfilename = self.log_dir + "/tsan.%p"
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc += ["--log-file=" + common.NormalizeWindowsPath(logfilename)]
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # TODO(timurrrr): Add flags for Valgrind trace children analog when we
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # start running complex tests (e.g. UI) under TSan/Win.
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return proc
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Analyze(self, check_sanity=False):
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    filenames = glob.glob(self.log_dir + "/tsan.*")
7858bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    analyzer = tsan_analyze.TsanAnalyzer()
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = analyzer.Report(filenames, None, check_sanity)
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ret != 0:
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.info(self.INFO_MESSAGE)
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ret
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class DrMemory(BaseTool):
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Dr.Memory
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Dynamic memory error detector for Windows.
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  http://dev.chromium.org/developers/how-tos/using-drmemory
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  It is not very mature at the moment, some things might not work properly.
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, full_mode, pattern_mode):
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    super(DrMemory, self).__init__()
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.full_mode = full_mode
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.pattern_mode = pattern_mode
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.RegisterOptionParserHook(DrMemory.ExtendOptionParser)
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ToolName(self):
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return "drmemory"
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ExtendOptionParser(self, parser):
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.add_option("", "--suppressions", default=[],
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      action="append",
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      help="path to a drmemory suppression file")
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.add_option("", "--follow_python", action="store_true",
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      default=False, dest="follow_python",
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      help="Monitor python child processes.  If off, neither "
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      "python children nor any children of python children "
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      "will be monitored.")
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.add_option("", "--indirect", action="store_true",
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      default=False,
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      help="set BROWSER_WRAPPER rather than "
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           "running Dr. Memory directly on the harness")
8222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    parser.add_option("", "--indirect_webkit_layout", action="store_true",
8232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                      default=False,
8242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                      help="set --wrapper rather than running valgrind "
8252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                      "directly.")
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.add_option("", "--use_debug", action="store_true",
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      default=False, dest="use_debug",
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      help="Run Dr. Memory debug build")
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.add_option("", "--trace_children", action="store_true",
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            default=True,
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            help="TODO: default value differs from Valgrind")
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ToolCommand(self):
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Get the tool command to run."""
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # WINHEAP is what Dr. Memory supports as there are issues w/ both
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # jemalloc (http://code.google.com/p/drmemory/issues/detail?id=320) and
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # tcmalloc (http://code.google.com/p/drmemory/issues/detail?id=314)
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    add_env = {
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "CHROME_ALLOCATOR" : "WINHEAP",
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "JSIMD_FORCEMMX"   : "1",  # http://code.google.com/p/drmemory/issues/detail?id=540
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for k,v in add_env.iteritems():
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.info("export %s=%s", k, v)
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      os.putenv(k, v)
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    drmem_cmd = os.getenv("DRMEMORY_COMMAND")
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not drmem_cmd:
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise RuntimeError, "Please set DRMEMORY_COMMAND environment variable " \
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          "with the path to drmemory.exe"
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc = drmem_cmd.split(" ")
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # By default, don't run python (this will exclude python's children as well)
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # to reduce runtime.  We're not really interested in spending time finding
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # bugs in the python implementation.
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # With file-based config we must update the file every time, and
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # it will affect simultaneous drmem uses by this user.  While file-based
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # config has many advantages, here we may want this-instance-only
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # (http://code.google.com/p/drmemory/issues/detail?id=334).
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    drconfig_cmd = [ proc[0].replace("drmemory.exe", "drconfig.exe") ]
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    drconfig_cmd += ["-quiet"] # suppress errors about no 64-bit libs
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    run_drconfig = True
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._options.follow_python:
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.info("Following python children")
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # -unreg fails if not already registered so query for that first
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      query_cmd = drconfig_cmd + ["-isreg", "python.exe"]
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      query_proc = subprocess.Popen(query_cmd, stdout=subprocess.PIPE,
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    shell=True)
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (query_out, query_err) = query_proc.communicate()
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if re.search("exe not registered", query_out):
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        run_drconfig = False # all set
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        drconfig_cmd += ["-unreg", "python.exe"]
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.info("Excluding python children")
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      drconfig_cmd += ["-reg", "python.exe", "-norun"]
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if run_drconfig:
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      drconfig_retcode = common.RunSubprocess(drconfig_cmd, self._timeout)
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if drconfig_retcode:
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        logging.error("Configuring whether to follow python children failed " \
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      "with %d.", drconfig_retcode)
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        raise RuntimeError, "Configuring python children failed "
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    suppression_count = 0
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    supp_files = self._options.suppressions
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.full_mode:
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      supp_files += [s.replace(".txt", "_full.txt") for s in supp_files]
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for suppression_file in supp_files:
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if os.path.exists(suppression_file):
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        suppression_count += 1
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        proc += ["-suppress", common.NormalizeWindowsPath(suppression_file)]
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not suppression_count:
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.warning("WARNING: NOT USING SUPPRESSIONS!")
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Un-comment to dump Dr.Memory events on error
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #proc += ["-dr_ops", "-dumpcore_mask", "-dr_ops", "0x8bff"]
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Un-comment and comment next line to debug Dr.Memory
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #proc += ["-dr_ops", "-no_hide"]
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #proc += ["-dr_ops", "-msgbox_mask", "-dr_ops", "15"]
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #Proc += ["-dr_ops", "-stderr_mask", "-dr_ops", "15"]
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Ensure we see messages about Dr. Memory crashing!
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc += ["-dr_ops", "-stderr_mask", "-dr_ops", "12"]
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._options.use_debug:
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      proc += ["-debug"]
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc += ["-logdir", common.NormalizeWindowsPath(self.log_dir)]
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.log_parent_dir:
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # gpu process on Windows Vista+ runs at Low Integrity and can only
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # write to certain directories (http://crbug.com/119131)
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      symcache_dir = os.path.join(self.log_parent_dir, "drmemory.symcache")
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif self._options.build_dir:
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # The other case is only possible with -t cmdline.
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Anyways, if we omit -symcache_dir the -logdir's value is used which
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # should be fine.
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      symcache_dir = os.path.join(self._options.build_dir, "drmemory.symcache")
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if symcache_dir:
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not os.path.exists(symcache_dir):
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        try:
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          os.mkdir(symcache_dir)
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        except OSError:
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          logging.warning("Can't create symcache dir?")
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if os.path.exists(symcache_dir):
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        proc += ["-symcache_dir", common.NormalizeWindowsPath(symcache_dir)]
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Use -no_summary to suppress DrMemory's summary and init-time
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # notifications.  We generate our own with drmemory_analyze.py.
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc += ["-batch", "-no_summary"]
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Un-comment to disable interleaved output.  Will also suppress error
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # messages normally printed to stderr.
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #proc += ["-quiet", "-no_results_to_stderr"]
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc += ["-callstack_max_frames", "40"]
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
938d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    # disable leak scan for now
939d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    proc += ["-no_count_leaks", "-no_leak_scan"]
940d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
9411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    # crbug.com/413215, no heap mismatch check for Windows release build binary
9421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if common.IsWindows() and "Release" in self._options.build_dir:
9431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        proc += ["-no_check_delete_mismatch"]
9441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # make callstacks easier to read
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc += ["-callstack_srcfile_prefix",
9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             "build\\src,chromium\\src,crt_build\\self_x86"]
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc += ["-callstack_modname_hide",
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             "*drmemory*,chrome.dll"]
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    boring_callers = common.BoringCallers(mangled=False, use_re_wildcards=False)
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # TODO(timurrrr): In fact, we want "starting from .." instead of "below .."
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc += ["-callstack_truncate_below", ",".join(boring_callers)]
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.pattern_mode:
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      proc += ["-pattern", "0xf1fd", "-no_count_leaks", "-redzone_size", "0x20"]
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif not self.full_mode:
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      proc += ["-light"]
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc += self._tool_flags
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Dr.Memory requires -- to separate tool flags from the executable name.
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc += ["--"]
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if self._options.indirect or self._options.indirect_webkit_layout:
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # TODO(timurrrr): reuse for TSan on Windows
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      wrapper_path = os.path.join(self._source_dir,
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  "tools", "valgrind", "browser_wrapper_win.py")
9692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      wrapper = " ".join(["python", wrapper_path] + proc)
9702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      self.CreateBrowserWrapper(wrapper)
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.info("browser wrapper = " + " ".join(proc))
9722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if self._options.indirect_webkit_layout:
9732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        proc = self._args
9742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        # Layout tests want forward slashes.
9752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        wrapper = wrapper.replace('\\', '/')
9762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        proc += ["--wrapper", wrapper]
9772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return proc
9782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      else:
9792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        proc = []
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Note that self._args begins with the name of the exe to be run.
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._args[0] = common.NormalizeWindowsPath(self._args[0])
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc += self._args
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return proc
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def CreateBrowserWrapper(self, command):
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    os.putenv("BROWSER_WRAPPER", command)
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Analyze(self, check_sanity=False):
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Use one analyzer for all the log files to avoid printing duplicate reports
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # TODO(timurrrr): unify this with Valgrind and other tools when we have
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # http://code.google.com/p/drmemory/issues/detail?id=684
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    analyzer = drmemory_analyze.DrMemoryAnalyzer()
9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = 0
9972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if not self._options.indirect and not self._options.indirect_webkit_layout:
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      filenames = glob.glob(self.log_dir + "/*/results.txt")
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret = analyzer.Report(filenames, None, check_sanity)
10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      testcases = glob.glob(self.log_dir + "/testcase.*.logs")
10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # If we have browser wrapper, the per-test logdirs are named as
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # "testcase.wrapper_PID.name".
10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Let's extract the list of wrapper_PIDs and name it ppids.
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # NOTE: ppids may contain '_', i.e. they are not ints!
10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ppids = set([f.split(".")[-2] for f in testcases])
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for ppid in ppids:
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        testcase_name = None
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        try:
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          f = open("%s/testcase.%s.name" % (self.log_dir, ppid))
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          testcase_name = f.read().strip()
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          f.close()
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        except IOError:
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          pass
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        print "====================================================="
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        print " Below is the report for drmemory wrapper PID=%s." % ppid
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if testcase_name:
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          print " It was used while running the `%s` test." % testcase_name
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        else:
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          # TODO(timurrrr): hm, the PID line is suppressed on Windows...
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          print " You can find the corresponding test"
10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          print " by searching the above log for 'PID=%s'" % ppid
10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sys.stdout.flush()
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ppid_filenames = glob.glob("%s/testcase.%s.logs/*/results.txt" %
10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   (self.log_dir, ppid))
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ret |= analyzer.Report(ppid_filenames, testcase_name, False)
10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        print "====================================================="
10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sys.stdout.flush()
10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    logging.info("Please see http://dev.chromium.org/developers/how-tos/"
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 "using-drmemory for the info on Dr. Memory")
10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ret
10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# RaceVerifier support. See
10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# http://code.google.com/p/data-race-test/wiki/RaceVerifier for more details.
10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ThreadSanitizerRV1Analyzer(tsan_analyze.TsanAnalyzer):
10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """ TsanAnalyzer that saves race reports to a file. """
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TMP_FILE = "rvlog.tmp"
10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, source_dir, use_gdb):
10458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    super(ThreadSanitizerRV1Analyzer, self).__init__(use_gdb)
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.out = open(self.TMP_FILE, "w")
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Report(self, files, testcase, check_sanity=False):
10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    reports = self.GetReports(files)
10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for report in reports:
10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      print >>self.out, report
10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if len(reports) > 0:
10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.info("RaceVerifier pass 1 of 2, found %i reports" % len(reports))
10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return -1
10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0
10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def CloseOutputFile(self):
10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.out.close()
10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ThreadSanitizerRV1Mixin(object):
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """RaceVerifier first pass.
10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Runs ThreadSanitizer as usual, but hides race reports and collects them in a
10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  temporary file"""
10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self):
10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    super(ThreadSanitizerRV1Mixin, self).__init__()
10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.RegisterOptionParserHook(ThreadSanitizerRV1Mixin.ExtendOptionParser)
10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ExtendOptionParser(self, parser):
10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.set_defaults(hybrid="yes")
10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def CreateAnalyzer(self):
10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    use_gdb = common.IsMac()
10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.analyzer = ThreadSanitizerRV1Analyzer(self._source_dir, use_gdb)
10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.analyzer
10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Cleanup(self):
10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    super(ThreadSanitizerRV1Mixin, self).Cleanup()
10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.analyzer.CloseOutputFile()
10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ThreadSanitizerRV2Mixin(object):
10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """RaceVerifier second pass."""
10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self):
10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    super(ThreadSanitizerRV2Mixin, self).__init__()
10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.RegisterOptionParserHook(ThreadSanitizerRV2Mixin.ExtendOptionParser)
10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ExtendOptionParser(self, parser):
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.add_option("", "--race-verifier-sleep-ms",
10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            dest="race_verifier_sleep_ms", default=10,
10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            help="duration of RaceVerifier delays")
10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ToolSpecificFlags(self):
10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc = super(ThreadSanitizerRV2Mixin, self).ToolSpecificFlags()
10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proc += ['--race-verifier=%s' % ThreadSanitizerRV1Analyzer.TMP_FILE,
10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             '--race-verifier-sleep-ms=%d' %
11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             int(self._options.race_verifier_sleep_ms)]
11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return proc
11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Cleanup(self):
11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    super(ThreadSanitizerRV2Mixin, self).Cleanup()
11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    os.unlink(ThreadSanitizerRV1Analyzer.TMP_FILE)
11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ThreadSanitizerRV1Posix(ThreadSanitizerRV1Mixin, ThreadSanitizerPosix):
11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pass
11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ThreadSanitizerRV2Posix(ThreadSanitizerRV2Mixin, ThreadSanitizerPosix):
11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pass
11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ThreadSanitizerRV1Windows(ThreadSanitizerRV1Mixin,
11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                ThreadSanitizerWindows):
11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pass
11195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ThreadSanitizerRV2Windows(ThreadSanitizerRV2Mixin,
11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                ThreadSanitizerWindows):
11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pass
11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class RaceVerifier(object):
11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Runs tests under RaceVerifier/Valgrind."""
11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MORE_INFO_URL = "http://code.google.com/p/data-race-test/wiki/RaceVerifier"
11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def RV1Factory(self):
11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if common.IsWindows():
11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ThreadSanitizerRV1Windows()
11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ThreadSanitizerRV1Posix()
11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def RV2Factory(self):
11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if common.IsWindows():
11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ThreadSanitizerRV2Windows()
11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ThreadSanitizerRV2Posix()
11425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ToolName(self):
11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return "tsan"
11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Main(self, args, check_sanity, min_runtime_in_seconds):
11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    logging.info("Running a TSan + RaceVerifier test. For more information, " +
11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 "see " + self.MORE_INFO_URL)
11495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd1 = self.RV1Factory()
11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = cmd1.Main(args, check_sanity, min_runtime_in_seconds)
11515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Verify race reports, if there are any.
11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ret == -1:
11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.info("Starting pass 2 of 2. Running the same binary in " +
11545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   "RaceVerifier mode to confirm possible race reports.")
11555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.info("For more information, see " + self.MORE_INFO_URL)
11565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cmd2 = self.RV2Factory()
11575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret = cmd2.Main(args, check_sanity, min_runtime_in_seconds)
11585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
11595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.info("No reports, skipping RaceVerifier second pass")
11605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    logging.info("Please see " + self.MORE_INFO_URL + " for more information " +
11615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 "on RaceVerifier")
11625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ret
11635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Run(self, args, module, min_runtime_in_seconds=0):
11655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   return self.Main(args, False, min_runtime_in_seconds)
11665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class EmbeddedTool(BaseTool):
11695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Abstract class for tools embedded directly into the test binary.
11705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
11715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # TODO(glider): need to override Execute() and support process chaining here.
11725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ToolCommand(self):
11745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # In the simplest case just the args of the script.
11755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._args
11765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Asan(EmbeddedTool):
11795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """AddressSanitizer, a memory error detector.
11805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  More information at
11825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  http://dev.chromium.org/developers/testing/addresssanitizer
11835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
11845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self):
11855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    super(Asan, self).__init__()
11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._timeout = 1200
11875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if common.IsMac():
11885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._env["DYLD_NO_PIE"] = "1"
11895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ToolName(self):
11925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return "asan"
11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ToolCommand(self):
11955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # TODO(glider): use pipes instead of the ugly wrapper here once they
11965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # are supported.
11975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    procs = [os.path.join(self._source_dir, "tools", "valgrind",
11985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              "asan", "asan_wrapper.sh")]
11995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    procs.extend(self._args)
12005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return procs
12015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Analyze(sels, unused_check_sanity):
12035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0
12045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ToolFactory:
12075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Create(self, tool_name):
12085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if tool_name == "memcheck":
12095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return Memcheck()
12105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if tool_name == "tsan":
12115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if common.IsWindows():
12125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return ThreadSanitizerWindows()
12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return ThreadSanitizerPosix()
12155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if tool_name == "drmemory" or tool_name == "drmemory_light":
12165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # TODO(timurrrr): remove support for "drmemory" when buildbots are
12175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # switched to drmemory_light OR make drmemory==drmemory_full the default
12185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # mode when the tool is mature enough.
12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return DrMemory(False, False)
12205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if tool_name == "drmemory_full":
12215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return DrMemory(True, False)
12225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if tool_name == "drmemory_pattern":
12235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return DrMemory(False, True)
12245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if tool_name == "tsan_rv":
12255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return RaceVerifier()
12265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if tool_name == "asan":
12275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return Asan()
12285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    try:
12295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      platform_name = common.PlatformNames()[0]
12305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    except common.NotImplementedError:
12315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      platform_name = sys.platform + "(Unknown)"
12325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    raise RuntimeError, "Unknown tool (tool=%s, platform=%s)" % (tool_name,
12335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                                 platform_name)
12345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def CreateTool(tool):
12365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ToolFactory().Create(tool)
1237