Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(337)

Unified Diff: tools/valgrind/valgrind_analyze.py

Issue 16583: Make a valgrind tool in the same vein as the purify one. (Closed)
Patch Set: STOP! Grammar time! Created 11 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « tools/valgrind/suppressions.txt ('k') | tools/valgrind/valgrind_test.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/valgrind/valgrind_analyze.py
diff --git a/tools/valgrind/valgrind_analyze.py b/tools/valgrind/valgrind_analyze.py
new file mode 100755
index 0000000000000000000000000000000000000000..c73f6bf05309969cca80275a9ae4b8856c70c79d
--- /dev/null
+++ b/tools/valgrind/valgrind_analyze.py
@@ -0,0 +1,176 @@
+#!/usr/bin/python
+# Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# valgrind_analyze.py
+
+''' Given a valgrind XML file, parses errors and uniques them.'''
+
+import logging
+import optparse
+import os
+import sys
+from xml.dom.minidom import parse
+
+# These are functions (using C++ mangled names) that we look for in stack
+# traces. We don't show stack frames while pretty printing when they are below
+# any of the following:
+_TOP_OF_STACK_POINTS = [
+ # Don't show our testing framework.
+ "testing::Test::Run()",
+ # Also don't show the internals of libc/pthread.
+ "start_thread"
+]
+
+def getTextOf(top_node, name):
+ ''' Returns all text in all DOM nodes with a certain |name| that are children
+ of |top_node|.
+ '''
+
+ text = ""
+ for nodes_named in top_node.getElementsByTagName(name):
+ text += "".join([node.data for node in nodes_named.childNodes
+ if node.nodeType == node.TEXT_NODE])
+ return text
+
+def removeCommonRoot(source_dir, directory):
+ '''Returns a string with the string prefix |source_dir| removed from
+ |directory|.'''
+ if source_dir:
+ # Do this for safety, just in case directory is an absolute path outside of
+ # source_dir.
+ prefix = os.path.commonprefix([source_dir, directory])
+ return directory[len(prefix) + 1:]
+
+ return directory
+
+# Constants that give real names to the abbreviations in valgrind XML output.
+INSTRUCTION_POINTER = "ip"
+OBJECT_FILE = "obj"
+FUNCTION_NAME = "fn"
+SRC_FILE_DIR = "dir"
+SRC_FILE_NAME = "file"
+SRC_LINE = "line"
+
+class ValgrindError:
+ ''' Takes a <DOM Element: error> node and reads all the data from it. A
+ ValgrindError is immutable and is hashed on its pretty printed output.
+ '''
+
+ def __init__(self, source_dir, error_node):
+ ''' Copies all the relevant information out of the DOM and into object
+ properties.
+
+ Args:
+ error_node: The <error></error> DOM node we're extracting from.
+ source_dir: Prefix that should be stripped from the <dir> node.
+ '''
+
+ self._kind = getTextOf(error_node, "kind")
+ self._what = getTextOf(error_node, "what")
+
+ self._frames = []
+ stack_node = error_node.getElementsByTagName("stack")[0]
+
+ for frame in stack_node.getElementsByTagName("frame"):
+ frame_dict = {
+ INSTRUCTION_POINTER : getTextOf(frame, INSTRUCTION_POINTER),
+ OBJECT_FILE : getTextOf(frame, OBJECT_FILE),
+ FUNCTION_NAME : getTextOf(frame, FUNCTION_NAME),
+ SRC_FILE_DIR : removeCommonRoot(
+ source_dir, getTextOf(frame, SRC_FILE_DIR)),
+ SRC_FILE_NAME : getTextOf(frame, SRC_FILE_NAME),
+ SRC_LINE : getTextOf(frame, SRC_LINE)
+ }
+
+ self._frames += [frame_dict]
+
+ if frame_dict[FUNCTION_NAME] in _TOP_OF_STACK_POINTS:
+ break
+
+ def __str__(self):
+ ''' Pretty print the type and stack frame of this specific error.'''
+ output = self._kind + "\n"
+ for frame in self._frames:
+ output += (" " + (frame[FUNCTION_NAME] or frame[INSTRUCTION_POINTER]) +
+ " (")
+
+ if frame[SRC_FILE_DIR] != "":
+ output += (frame[SRC_FILE_DIR] + "/" + frame[SRC_FILE_DIR] + ":" +
+ frame[SRC_LINE])
+ else:
+ output += frame[OBJECT_FILE]
+ output += ")\n"
+
+ return output
+
+ def UniqueString(self):
+ ''' String to use for object identity. Don't print this, use str(obj)
+ instead.'''
+ rep = self._kind + " "
+ for frame in self._frames:
+ rep += frame[FUNCTION_NAME]
+
+ if frame[SRC_FILE_DIR] != "":
+ rep += frame[SRC_FILE_DIR] + "/" + frame[SRC_FILE_NAME]
+ else:
+ rep += frame[OBJECT_FILE]
+
+ return rep
+
+ def __hash__(self):
+ return hash(self.UniqueString())
+ def __eq__(self, rhs):
+ return self.UniqueString() == rhs
+
+class ValgrindAnalyze:
+ ''' Given a set of Valgrind XML files, parse all the errors out of them,
+ unique them and output the results.'''
+
+ def __init__(self, source_dir, files):
+ '''Reads in a set of files.
+
+ Args:
+ source_dir: Path to top of source tree for this build
+ files: A list of filenames.
+ '''
+
+ self._errors = set()
+ for file in files:
+ raw_errors = parse(file).getElementsByTagName("error")
+ for raw_error in raw_errors:
+ self._errors.add(ValgrindError(source_dir, raw_error))
+
+ def Report(self):
+ if self._errors:
+ logging.error("FAIL! There were %s errors: " % len(self._errors))
+
+ for error in self._errors:
+ logging.error(error)
+
+ return -1
+
+ logging.info("PASS! No errors found!")
+ return 0
+
+def _main():
+ '''For testing only. The ValgrindAnalyze class should be imported instead.'''
+ retcode = 0
+ parser = optparse.OptionParser("usage: %prog [options] <files to analyze>")
+ parser.add_option("", "--source_dir",
+ help="path to top of source tree for this build"
+ "(used to normalize source paths in baseline)")
+
+ (options, args) = parser.parse_args()
+ if not len(args) >= 1:
+ parser.error("no filename specified")
+ filenames = args
+
+ analyzer = ValgrindAnalyze(options.source_dir, filenames)
+ retcode = analyzer.Report()
+
+ sys.exit(retcode)
+
+if __name__ == "__main__":
+ _main()
« no previous file with comments | « tools/valgrind/suppressions.txt ('k') | tools/valgrind/valgrind_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698