summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authordkegel@google.com <dkegel@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-27 17:53:14 +0000
committerdkegel@google.com <dkegel@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-27 17:53:14 +0000
commit44e780297e2c5ba8705c3c6c8d9ca5ea392c3a4c (patch)
tree180b368bdfc737458fb1d94ed7beb101413f5ff0 /tools
parent18305dec20e5e99a7e36aaf0d624edc3cbccdab8 (diff)
downloadchromium_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-xtools/valgrind/chrome_tests.py5
-rwxr-xr-xtools/valgrind/valgrind_analyze.py126
-rwxr-xr-xtools/valgrind/valgrind_test.py8
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"];