15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/usr/bin/env python
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2011 The Chromium Authors. All rights reserved.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file.
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# memcheck_analyze.py
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)''' Given a valgrind XML file, parses errors and uniques them.'''
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import gdb_helper
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from collections import defaultdict
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import hashlib
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import logging
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import optparse
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import re
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import subprocess
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import sys
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import time
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from xml.dom.minidom import parse
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from xml.parsers.expat import ExpatError
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import common
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Global symbol table (yuck)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TheAddressTable = None
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# These are regexps that define functions (using C++ mangled names)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# we don't want to see in stack traces while pretty printing
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# or generating suppressions.
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Just stop printing the stack/suppression frames when the current one
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# matches any of these.
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_BORING_CALLERS = common.BoringCallers(mangled=True, use_re_wildcards=True)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def getTextOf(top_node, name):
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ''' Returns all text in all DOM nodes with a certain |name| that are children
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  of |top_node|.
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  '''
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  text = ""
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for nodes_named in top_node.getElementsByTagName(name):
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    text += "".join([node.data for node in nodes_named.childNodes
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     if node.nodeType == node.TEXT_NODE])
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return text
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def getCDATAOf(top_node, name):
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ''' Returns all CDATA in all DOM nodes with a certain |name| that are children
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  of |top_node|.
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  '''
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  text = ""
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for nodes_named in top_node.getElementsByTagName(name):
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    text += "".join([node.data for node in nodes_named.childNodes
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     if node.nodeType == node.CDATA_SECTION_NODE])
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (text == ""):
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return None
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return text
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def shortenFilePath(source_dir, directory):
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  '''Returns a string with the string prefix |source_dir| removed from
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  |directory|.'''
637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  prefixes_to_cut = ["build/src/", "valgrind/coregrind/", "out/Release/../../"]
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if source_dir:
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    prefixes_to_cut.append(source_dir)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for p in prefixes_to_cut:
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    index = directory.rfind(p)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if index != -1:
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      directory = directory[index + len(p):]
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return directory
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Constants that give real names to the abbreviations in valgrind XML output.
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)INSTRUCTION_POINTER = "ip"
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OBJECT_FILE = "obj"
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FUNCTION_NAME = "fn"
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SRC_FILE_DIR = "dir"
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SRC_FILE_NAME = "file"
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SRC_LINE = "line"
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def gatherFrames(node, source_dir):
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  frames = []
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for frame in node.getElementsByTagName("frame"):
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    frame_dict = {
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      INSTRUCTION_POINTER : getTextOf(frame, INSTRUCTION_POINTER),
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      OBJECT_FILE         : getTextOf(frame, OBJECT_FILE),
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FUNCTION_NAME       : getTextOf(frame, FUNCTION_NAME),
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SRC_FILE_DIR        : shortenFilePath(
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          source_dir, getTextOf(frame, SRC_FILE_DIR)),
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SRC_FILE_NAME       : getTextOf(frame, SRC_FILE_NAME),
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SRC_LINE            : getTextOf(frame, SRC_LINE)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Ignore this frame and all the following if it's a "boring" function.
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    enough_frames = False
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for regexp in _BORING_CALLERS:
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if re.match("^%s$" % regexp, frame_dict[FUNCTION_NAME]):
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        enough_frames = True
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if enough_frames:
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    frames += [frame_dict]
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    global TheAddressTable
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if TheAddressTable != None and frame_dict[SRC_LINE] == "":
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Try using gdb
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      TheAddressTable.Add(frame_dict[OBJECT_FILE],
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          frame_dict[INSTRUCTION_POINTER])
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return frames
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ValgrindError:
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ''' Takes a <DOM Element: error> node and reads all the data from it. A
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ValgrindError is immutable and is hashed on its pretty printed output.
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  '''
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, source_dir, error_node, commandline, testcase):
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ''' Copies all the relevant information out of the DOM and into object
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    properties.
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      error_node: The <error></error> DOM node we're extracting from.
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      source_dir: Prefix that should be stripped from the <dir> node.
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      commandline: The command that was run under valgrind
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      testcase: The test case name, if known.
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    '''
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Valgrind errors contain one <what><stack> pair, plus an optional
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # <auxwhat><stack> pair, plus an optional <origin><what><stack></origin>,
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # plus (since 3.5.0) a <suppression></suppression> pair.
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # (Origin is nicely enclosed; too bad the other two aren't.)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # The most common way to see all three in one report is
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # a syscall with a parameter that points to uninitialized memory, e.g.
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Format:
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # <error>
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #   <unique>0x6d</unique>
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #   <tid>1</tid>
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #   <kind>SyscallParam</kind>
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #   <what>Syscall param write(buf) points to uninitialised byte(s)</what>
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #   <stack>
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #     <frame>
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #     ...
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #     </frame>
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #   </stack>
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #   <auxwhat>Address 0x5c9af4f is 7 bytes inside a block of ...</auxwhat>
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #   <stack>
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #     <frame>
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #     ...
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #     </frame>
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #   </stack>
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #   <origin>
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #   <what>Uninitialised value was created by a heap allocation</what>
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #   <stack>
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #     <frame>
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #     ...
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #     </frame>
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #   </stack>
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #   </origin>
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #   <suppression>
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #     <sname>insert_a_suppression_name_here</sname>
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #     <skind>Memcheck:Param</skind>
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #     <skaux>write(buf)</skaux>
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #     <sframe> <fun>__write_nocancel</fun> </sframe>
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #     ...
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #     <sframe> <fun>main</fun> </sframe>
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #     <rawtext>
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # <![CDATA[
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # {
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #    <insert_a_suppression_name_here>
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #    Memcheck:Param
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #    write(buf)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #    fun:__write_nocancel
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #    ...
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #    fun:main
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # }
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # ]]>
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #     </rawtext>
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #   </suppression>
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # </error>
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Each frame looks like this:
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #  <frame>
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #    <ip>0x83751BC</ip>
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #    <obj>/data/dkegel/chrome-build/src/out/Release/base_unittests</obj>
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #    <fn>_ZN7testing8internal12TestInfoImpl7RunTestEPNS_8TestInfoE</fn>
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #    <dir>/data/dkegel/chrome-build/src/testing/gtest/src</dir>
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #    <file>gtest-internal-inl.h</file>
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #    <line>655</line>
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #  </frame>
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # although the dir, file, and line elements are missing if there is
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # no debug info.
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._kind = getTextOf(error_node, "kind")
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._backtraces = []
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._suppression = None
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._commandline = commandline
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._testcase = testcase
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._additional = []
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Iterate through the nodes, parsing <what|auxwhat><stack> pairs.
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    description = None
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for node in error_node.childNodes:
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if node.localName == "what" or node.localName == "auxwhat":
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        description = "".join([n.data for n in node.childNodes
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              if n.nodeType == n.TEXT_NODE])
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      elif node.localName == "xwhat":
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        description = getTextOf(node, "text")
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      elif node.localName == "stack":
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        assert description
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._backtraces.append([description, gatherFrames(node, source_dir)])
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        description = None
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      elif node.localName == "origin":
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        description = getTextOf(node, "what")
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        stack = node.getElementsByTagName("stack")[0]
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        frames = gatherFrames(stack, source_dir)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._backtraces.append([description, frames])
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        description = None
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        stack = None
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        frames = None
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      elif description and node.localName != None:
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # The lastest description has no stack, e.g. "Address 0x28 is unknown"
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._additional.append(description)
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        description = None
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if node.localName == "suppression":
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._suppression = getCDATAOf(node, "rawtext");
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __str__(self):
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ''' Pretty print the type and backtrace(s) of this specific error,
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        including suppression (which is just a mangled backtrace).'''
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    output = ""
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (self._commandline):
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      output += self._commandline + "\n"
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    output += self._kind + "\n"
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for backtrace in self._backtraces:
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      output += backtrace[0] + "\n"
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      filter = subprocess.Popen("c++filt -n", stdin=subprocess.PIPE,
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                stdout=subprocess.PIPE,
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                stderr=subprocess.STDOUT,
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                shell=True,
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                close_fds=True)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buf = ""
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for frame in backtrace[1]:
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        buf +=  (frame[FUNCTION_NAME] or frame[INSTRUCTION_POINTER]) + "\n"
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (stdoutbuf, stderrbuf) = filter.communicate(buf.encode('latin-1'))
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      demangled_names = stdoutbuf.split("\n")
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      i = 0
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for frame in backtrace[1]:
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        output += ("  " + demangled_names[i])
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        i = i + 1
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        global TheAddressTable
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if TheAddressTable != None and frame[SRC_FILE_DIR] == "":
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           # Try using gdb
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           foo = TheAddressTable.GetFileLine(frame[OBJECT_FILE],
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             frame[INSTRUCTION_POINTER])
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           if foo[0] != None:
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             output += (" (" + foo[0] + ":" + foo[1] + ")")
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        elif frame[SRC_FILE_DIR] != "":
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          output += (" (" + frame[SRC_FILE_DIR] + "/" + frame[SRC_FILE_NAME] +
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     ":" + frame[SRC_LINE] + ")")
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        else:
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          output += " (" + frame[OBJECT_FILE] + ")"
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        output += "\n"
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for additional in self._additional:
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      output += additional + "\n"
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert self._suppression != None, "Your Valgrind doesn't generate " \
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      "suppressions - is it too old?"
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._testcase:
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      output += "The report came from the `%s` test.\n" % self._testcase
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    output += "Suppression (error hash=#%016X#):\n" % self.ErrorHash()
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    output += ("  For more info on using suppressions see "
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               "http://dev.chromium.org/developers/tree-sheriffs/sheriff-details-chromium/memory-sheriff#TOC-Suppressing-memory-reports")
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Widen suppression slightly to make portable between mac and linux
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # TODO(timurrrr): Oops, these transformations should happen
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # BEFORE calculating the hash!
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    supp = self._suppression;
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    supp = supp.replace("fun:_Znwj", "fun:_Znw*")
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    supp = supp.replace("fun:_Znwm", "fun:_Znw*")
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    supp = supp.replace("fun:_Znaj", "fun:_Zna*")
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    supp = supp.replace("fun:_Znam", "fun:_Zna*")
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Make suppressions even less platform-dependent.
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for sz in [1, 2, 4, 8]:
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      supp = supp.replace("Memcheck:Addr%d" % sz, "Memcheck:Unaddressable")
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      supp = supp.replace("Memcheck:Value%d" % sz, "Memcheck:Uninitialized")
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    supp = supp.replace("Memcheck:Cond", "Memcheck:Uninitialized")
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Split into lines so we can enforce length limits
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    supplines = supp.split("\n")
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    supp = None  # to avoid re-use
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Truncate at line 26 (VG_MAX_SUPP_CALLERS plus 2 for name and type)
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # or at the first 'boring' caller.
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # (https://bugs.kde.org/show_bug.cgi?id=199468 proposes raising
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # VG_MAX_SUPP_CALLERS, but we're probably fine with it as is.)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    newlen = min(26, len(supplines));
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Drop boring frames and all the following.
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    enough_frames = False
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for frameno in range(newlen):
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for boring_caller in _BORING_CALLERS:
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if re.match("^ +fun:%s$" % boring_caller, supplines[frameno]):
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          newlen = frameno
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          enough_frames = True
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if enough_frames:
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (len(supplines) > newlen):
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      supplines = supplines[0:newlen]
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      supplines.append("}")
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for frame in range(len(supplines)):
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Replace the always-changing anonymous namespace prefix with "*".
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      m = re.match("( +fun:)_ZN.*_GLOBAL__N_.*\.cc_" +
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   "[0-9a-fA-F]{8}_[0-9a-fA-F]{8}(.*)",
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   supplines[frame])
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if m:
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        supplines[frame] = "*".join(m.groups())
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    output += "\n".join(supplines) + "\n"
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return output
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def UniqueString(self):
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ''' String to use for object identity. Don't print this, use str(obj)
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    instead.'''
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rep = self._kind + " "
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for backtrace in self._backtraces:
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for frame in backtrace[1]:
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        rep += frame[FUNCTION_NAME]
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if frame[SRC_FILE_DIR] != "":
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          rep += frame[SRC_FILE_DIR] + "/" + frame[SRC_FILE_NAME]
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        else:
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          rep += frame[OBJECT_FILE]
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return rep
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # This is a device-independent hash identifying the suppression.
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # By printing out this hash we can find duplicate reports between tests and
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # different shards running on multiple buildbots
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ErrorHash(self):
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return int(hashlib.md5(self.UniqueString()).hexdigest()[:16], 16)
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __hash__(self):
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hash(self.UniqueString())
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __eq__(self, rhs):
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.UniqueString() == rhs
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def log_is_finished(f, force_finish):
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  f.seek(0)
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  prev_line = ""
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while True:
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    line = f.readline()
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if line == "":
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not force_finish:
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return False
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Okay, the log is not finished but we can make it up to be parseable:
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if prev_line.strip() in ["</error>", "</errorcounts>", "</status>"]:
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        f.write("</valgrindoutput>\n")
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return True
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return False
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if '</valgrindoutput>' in line:
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Valgrind often has garbage after </valgrindoutput> upon crash.
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      f.truncate()
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return True
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    prev_line = line
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MemcheckAnalyzer:
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ''' Given a set of Valgrind XML files, parse all the errors out of them,
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unique them and output the results.'''
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SANITY_TEST_SUPPRESSIONS = {
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "Memcheck sanity test 01 (memory leak).": 1,
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "Memcheck sanity test 02 (malloc/read left).": 1,
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "Memcheck sanity test 03 (malloc/read right).": 1,
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "Memcheck sanity test 04 (malloc/write left).": 1,
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "Memcheck sanity test 05 (malloc/write right).": 1,
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "Memcheck sanity test 06 (new/read left).": 1,
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "Memcheck sanity test 07 (new/read right).": 1,
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "Memcheck sanity test 08 (new/write left).": 1,
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "Memcheck sanity test 09 (new/write right).": 1,
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "Memcheck sanity test 10 (write after free).": 1,
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "Memcheck sanity test 11 (write after delete).": 1,
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "Memcheck sanity test 12 (array deleted without []).": 1,
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "Memcheck sanity test 13 (single element deleted with []).": 1,
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "Memcheck sanity test 14 (malloc/read uninit).": 1,
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "Memcheck sanity test 15 (new/read uninit).": 1,
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Max time to wait for memcheck logs to complete.
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LOG_COMPLETION_TIMEOUT = 180.0
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, source_dir, show_all_leaks=False, use_gdb=False):
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    '''Create a parser for Memcheck logs.
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      source_dir: Path to top of source tree for this build
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      show_all_leaks: Whether to show even less important leaks
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      use_gdb: Whether to use gdb to resolve source filenames and line numbers
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               in the report stacktraces
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    '''
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._source_dir = source_dir
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._show_all_leaks = show_all_leaks
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._use_gdb = use_gdb
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Contains the set of unique errors
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._errors = set()
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Contains the time when the we started analyzing the first log file.
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # This variable is used to skip incomplete logs after some timeout.
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._analyze_start_time = None
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Report(self, files, testcase, check_sanity=False):
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    '''Reads in a set of files and prints Memcheck report.
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      files: A list of filenames.
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      check_sanity: if true, search for SANITY_TEST_SUPPRESSIONS
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    '''
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Beyond the detailed errors parsed by ValgrindError above,
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # the xml file contain records describing suppressions that were used:
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # <suppcounts>
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #  <pair>
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #    <count>28</count>
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #    <name>pango_font_leak_todo</name>
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #  </pair>
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #  <pair>
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #    <count>378</count>
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #    <name>bug_13243</name>
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #  </pair>
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # </suppcounts
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Collect these and print them at the end.
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # With our patch for https://bugs.kde.org/show_bug.cgi?id=205000 in,
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # the file also includes records of the form
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # <load_obj><obj>/usr/lib/libgcc_s.1.dylib</obj><ip>0x27000</ip></load_obj>
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # giving the filename and load address of each binary that was mapped
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # into the process.
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    global TheAddressTable
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._use_gdb:
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      TheAddressTable = gdb_helper.AddressTable()
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      TheAddressTable = None
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cur_report_errors = set()
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    suppcounts = defaultdict(int)
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    badfiles = set()
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._analyze_start_time == None:
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._analyze_start_time = time.time()
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    start_time = self._analyze_start_time
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parse_failed = False
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for file in files:
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Wait up to three minutes for valgrind to finish writing all files,
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # but after that, just skip incomplete files and warn.
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      f = open(file, "r+")
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pid = re.match(".*\.([0-9]+)$", file)
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if pid:
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pid = pid.groups()[0]
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      found = False
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      running = True
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      firstrun = True
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      skip = False
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      origsize = os.path.getsize(file)
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      while (running and not found and not skip and
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             (firstrun or
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              ((time.time() - start_time) < self.LOG_COMPLETION_TIMEOUT))):
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        firstrun = False
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        f.seek(0)
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if pid:
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          # Make sure the process is still running so we don't wait for
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          # 3 minutes if it was killed. See http://crbug.com/17453
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ps_out = subprocess.Popen("ps p %s" % pid, shell=True,
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    stdout=subprocess.PIPE).stdout
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if len(ps_out.readlines()) < 2:
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            running = False
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        else:
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          skip = True
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          running = False
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        found = log_is_finished(f, False)
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if not running and not found:
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          logging.warn("Valgrind process PID = %s is not running but its "
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       "XML log has not been finished correctly.\n"
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       "Make it up by adding some closing tags manually." % pid)
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          found = log_is_finished(f, not running)
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if running and not found:
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          time.sleep(1)
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      f.close()
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not found:
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        badfiles.add(file)
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        newsize = os.path.getsize(file)
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if origsize > newsize+1:
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          logging.warn(str(origsize - newsize) +
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       " bytes of junk were after </valgrindoutput> in %s!" %
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       file)
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        try:
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          parsed_file = parse(file);
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        except ExpatError, e:
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          parse_failed = True
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          logging.warn("could not parse %s: %s" % (file, e))
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          lineno = e.lineno - 1
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          context_lines = 5
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          context_start = max(0, lineno - context_lines)
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          context_end = lineno + context_lines + 1
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          context_file = open(file, "r")
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          for i in range(0, context_start):
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            context_file.readline()
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          for i in range(context_start, context_end):
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            context_data = context_file.readline().rstrip()
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if i != lineno:
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              logging.warn("  %s" % context_data)
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            else:
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              logging.warn("> %s" % context_data)
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          context_file.close()
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          continue
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if TheAddressTable != None:
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          load_objs = parsed_file.getElementsByTagName("load_obj")
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          for load_obj in load_objs:
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            obj = getTextOf(load_obj, "obj")
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            ip = getTextOf(load_obj, "ip")
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            TheAddressTable.AddBinaryAt(obj, ip)
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        commandline = None
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        preamble = parsed_file.getElementsByTagName("preamble")[0];
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for node in preamble.getElementsByTagName("line"):
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if node.localName == "line":
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            for x in node.childNodes:
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              if x.nodeType == node.TEXT_NODE and "Command" in x.data:
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                commandline = x.data
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        raw_errors = parsed_file.getElementsByTagName("error")
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for raw_error in raw_errors:
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          # Ignore "possible" leaks for now by default.
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (self._show_all_leaks or
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              getTextOf(raw_error, "kind") != "Leak_PossiblyLost"):
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            error = ValgrindError(self._source_dir,
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  raw_error, commandline, testcase)
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if error not in cur_report_errors:
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              # We haven't seen such errors doing this report yet...
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              if error in self._errors:
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                # ... but we saw it in earlier reports, e.g. previous UI test
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                cur_report_errors.add("This error was already printed in "
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      "some other test, see 'hash=#%016X#'" % \
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      error.ErrorHash())
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              else:
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                # ... and we haven't seen it in other tests as well
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                self._errors.add(error)
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                cur_report_errors.add(error)
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        suppcountlist = parsed_file.getElementsByTagName("suppcounts")
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if len(suppcountlist) > 0:
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          suppcountlist = suppcountlist[0]
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          for node in suppcountlist.getElementsByTagName("pair"):
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            count = getTextOf(node, "count");
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            name = getTextOf(node, "name");
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            suppcounts[name] += int(count)
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if len(badfiles) > 0:
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.warn("valgrind didn't finish writing %d files?!" % len(badfiles))
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for file in badfiles:
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        logging.warn("Last 20 lines of %s :" % file)
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        os.system("tail -n 20 '%s' 1>&2" % file)
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if parse_failed:
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.error("FAIL! Couldn't parse Valgrind output file")
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return -2
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    common.PrintUsedSuppressionsList(suppcounts)
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    retcode = 0
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if cur_report_errors:
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      logging.error("FAIL! There were %s errors: " % len(cur_report_errors))
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if TheAddressTable != None:
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        TheAddressTable.ResolveAll()
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for error in cur_report_errors:
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        logging.error(error)
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      retcode = -1
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Report tool's insanity even if there were errors.
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if check_sanity:
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      remaining_sanity_supp = MemcheckAnalyzer.SANITY_TEST_SUPPRESSIONS
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (name, count) in suppcounts.iteritems():
6005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        # Workaround for http://crbug.com/334074
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (name in remaining_sanity_supp and
6025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            remaining_sanity_supp[name] <= count):
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          del remaining_sanity_supp[name]
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if remaining_sanity_supp:
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        logging.error("FAIL! Sanity check failed!")
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        logging.info("The following test errors were not handled: ")
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for (name, count) in remaining_sanity_supp.iteritems():
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          logging.info("  * %dx %s" % (count, name))
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        retcode = -3
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if retcode != 0:
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return retcode
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    logging.info("PASS! No errors found!")
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _main():
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  '''For testing only. The MemcheckAnalyzer class should be imported instead.'''
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parser = optparse.OptionParser("usage: %prog [options] <files to analyze>")
6214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  parser.add_option("", "--source-dir",
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    help="path to top of source tree for this build"
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    "(used to normalize source paths in baseline)")
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  (options, args) = parser.parse_args()
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if len(args) == 0:
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parser.error("no filename specified")
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  filenames = args
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  analyzer = MemcheckAnalyzer(options.source_dir, use_gdb=True)
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return analyzer.Report(filenames, None)
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if __name__ == "__main__":
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sys.exit(_main())
636