diff options
author | dkegel@google.com <dkegel@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-27 17:53:14 +0000 |
---|---|---|
committer | dkegel@google.com <dkegel@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-27 17:53:14 +0000 |
commit | 44e780297e2c5ba8705c3c6c8d9ca5ea392c3a4c (patch) | |
tree | 180b368bdfc737458fb1d94ed7beb101413f5ff0 /tools | |
parent | 18305dec20e5e99a7e36aaf0d624edc3cbccdab8 (diff) | |
download | chromium_src-44e780297e2c5ba8705c3c6c8d9ca5ea392c3a4c.zip chromium_src-44e780297e2c5ba8705c3c6c8d9ca5ea392c3a4c.tar.gz chromium_src-44e780297e2c5ba8705c3c6c8d9ca5ea392c3a4c.tar.bz2 |
Support --track_origins option.
Review URL: http://codereview.chromium.org/53119
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@12667 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'tools')
-rwxr-xr-x | tools/valgrind/chrome_tests.py | 5 | ||||
-rwxr-xr-x | tools/valgrind/valgrind_analyze.py | 126 | ||||
-rwxr-xr-x | tools/valgrind/valgrind_test.py | 8 |
3 files changed, 99 insertions, 40 deletions
diff --git a/tools/valgrind/chrome_tests.py b/tools/valgrind/chrome_tests.py index 0383cf45..42c90ba 100755 --- a/tools/valgrind/chrome_tests.py +++ b/tools/valgrind/chrome_tests.py @@ -134,6 +134,8 @@ class ChromeTests: cmd.append("--verbose") if self._options.show_all_leaks: cmd.append("--show_all_leaks") + if self._options.track_origins: + cmd.append("--track_origins") if self._options.generate_suppressions: cmd.append("--generate_suppressions") if exe == "ui_tests": @@ -360,6 +362,9 @@ def _main(_): parser.add_option("", "--show_all_leaks", action="store_true", default=False, help="also show even less blatant leaks") + parser.add_option("", "--track_origins", action="store_true", + default=False, + help="Show whence uninit bytes came. 30% slower.") parser.add_option("", "--no-reinstrument", action="store_true", default=False, help="Don't force a re-instrumentation for ui_tests") parser.add_option("", "--generate_suppressions", action="store_true", diff --git a/tools/valgrind/valgrind_analyze.py b/tools/valgrind/valgrind_analyze.py index 0a08306..4260fcd 100755 --- a/tools/valgrind/valgrind_analyze.py +++ b/tools/valgrind/valgrind_analyze.py @@ -53,6 +53,23 @@ SRC_FILE_DIR = "dir" SRC_FILE_NAME = "file" SRC_LINE = "line" +def gatherFrames(node, source_dir): + frames = [] + for frame in 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) + } + frames += [frame_dict] + if frame_dict[FUNCTION_NAME] in _TOP_OF_STACK_POINTS: + break + return frames + 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. @@ -67,41 +84,73 @@ class ValgrindError: 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) - } + # Valgrind errors contain one <what><stack> pair, plus an optional + # <auxwhat><stack> pair, plus an optional <origin><what><stack></origin>. + # (Origin is nicely enclosed; too bad the other two aren't.) + # The most common way to see all three in one report is + # a syscall with a parameter that points to uninitialized memory, e.g. + # Format: + # <error> + # <unique>0x6d</unique> + # <tid>1</tid> + # <kind>SyscallParam</kind> + # <what>Syscall param write(buf) points to uninitialised byte(s)</what> + # <stack> + # <frame> + # ... + # </frame> + # </stack> + # <auxwhat>Address 0x5c9af4f is 7 bytes inside a block of ...</auxwhat> + # <stack> + # <frame> + # ... + # </frame> + # </stack> + # <origin> + # <what>Uninitialised value was created by a heap allocation</what> + # <stack> + # <frame> + # ... + # </frame> + # </stack> + # </origin> - self._frames += [frame_dict] - - if frame_dict[FUNCTION_NAME] in _TOP_OF_STACK_POINTS: - break + self._kind = getTextOf(error_node, "kind") + self._backtraces = [] + + # Iterate through the nodes, parsing <what|auxwhat><stack> pairs. + description = None + for node in error_node.childNodes: + if node.localName == "what" or node.localName == "auxwhat": + description = "".join([n.data for n in node.childNodes + if n.nodeType == n.TEXT_NODE]) + elif node.localName == "stack": + self._backtraces.append([description, gatherFrames(node, source_dir)]) + description = None + elif node.localName == "origin": + description = getTextOf(node, "what") + stack = node.getElementsByTagName("stack")[0] + frames = gatherFrames(stack, source_dir) + self._backtraces.append([description, frames]) + description = None + stack = None + frames = None def __str__(self): - ''' Pretty print the type and stack frame of this specific error.''' + ''' Pretty print the type and backtrace(s) 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_NAME] + ":" + - frame[SRC_LINE]) - else: - output += frame[OBJECT_FILE] - output += ")\n" + for backtrace in self._backtraces: + output += backtrace[0] + "\n" + for frame in backtrace[1]: + output += (" " + (frame[FUNCTION_NAME] or frame[INSTRUCTION_POINTER]) + + " (") + + if frame[SRC_FILE_DIR] != "": + output += (frame[SRC_FILE_DIR] + "/" + frame[SRC_FILE_NAME] + ":" + + frame[SRC_LINE]) + else: + output += frame[OBJECT_FILE] + output += ")\n" return output @@ -109,13 +158,14 @@ class ValgrindError: ''' 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] + for backtrace in self._backtraces: + for frame in backtrace[1]: + 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 diff --git a/tools/valgrind/valgrind_test.py b/tools/valgrind/valgrind_test.py index 26f2be2..f13ad8e 100755 --- a/tools/valgrind/valgrind_test.py +++ b/tools/valgrind/valgrind_test.py @@ -69,6 +69,9 @@ class Valgrind(object): self._parser.add_option("", "--show_all_leaks", action="store_true", default=False, help="also show less blatant leaks") + self._parser.add_option("", "--track_origins", action="store_true", + default=False, + help="Show whence uninit bytes came. 30% slower.") self._parser.add_option("", "--generate_suppressions", action="store_true", default=False, help="Skip analysis and generate suppressions") @@ -177,14 +180,15 @@ class ValgrindLinux(Valgrind): def ValgrindCommand(self): """Get the valgrind command to run.""" # note that self._args begins with the exe to be run - # TODO(erg): We probably want to get a version of valgrind that supports - # the "--track-origins" option... proc = ["valgrind", "--smc-check=all", "--leak-check=full", "--num-callers=30"] if self._options.show_all_leaks: proc += ["--show-reachable=yes"]; + if self._options.track_origins: + proc += ["--track-origins=yes"]; + if self._options.trace_children: proc += ["--trace-children=yes"]; |