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

Side by Side Diff: tools/valgrind/memcheck_analyze.py

Issue 7665001: Improve memcheck_analyze (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 4 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/python 1 #!/usr/bin/python
2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2011 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 # memcheck_analyze.py 6 # memcheck_analyze.py
7 7
8 ''' Given a valgrind XML file, parses errors and uniques them.''' 8 ''' Given a valgrind XML file, parses errors and uniques them.'''
9 9
10 import gdb_helper 10 import gdb_helper
11 11
12 import hashlib 12 import hashlib
13 import logging 13 import logging
14 import optparse 14 import optparse
15 import os 15 import os
16 import re 16 import re
17 import subprocess 17 import subprocess
18 import sys 18 import sys
19 import time 19 import time
20 from xml.dom.minidom import parse 20 from xml.dom.minidom import parse
21 from xml.parsers.expat import ExpatError 21 from xml.parsers.expat import ExpatError
22 22
23 import common 23 import common
24 24
25 # Global symbol table (yuck) 25 # Global symbol table (yuck)
26 TheAddressTable = None 26 TheAddressTable = None
27 27
28 # These are functions (using C++ mangled names) that we look for in stack 28 # These are regexps that define functions (using C++ mangled names)
29 # traces. We don't show stack frames while pretty printing when they are below 29 # we don't want to see in stack traces while pretty printing
30 # any of the following: 30 # or generating suppressions.
31 _TOP_OF_STACK_POINTS = [ 31 # Just stop printing the stack/suppression frames when the current one
32 # Don't show our testing framework. 32 # matches any of these.
33 "testing::Test::Run()", 33 _BORING_CALLERS = [
34 # TODO(timurrrr): add more boring callers when needed
35
36 # Don't show our testing framework:
34 "_ZN7testing4Test3RunEv", 37 "_ZN7testing4Test3RunEv",
38 "_ZN7testing8internal35HandleExceptionsInMethodIfSupported.*",
39 "_ZN7testing8internal38HandleSehExceptionsInMethodIfSupported.*",
40
41 # Depends on scheduling:
42 "_ZN11MessageLoop3RunEv",
43 "_ZN14RunnableMethod.*",
44
35 # Also don't show the internals of libc/pthread. 45 # Also don't show the internals of libc/pthread.
36 "start_thread" 46 "start_thread"
37 ] 47 ]
38 48
39 def getTextOf(top_node, name): 49 def getTextOf(top_node, name):
40 ''' Returns all text in all DOM nodes with a certain |name| that are children 50 ''' Returns all text in all DOM nodes with a certain |name| that are children
41 of |top_node|. 51 of |top_node|.
42 ''' 52 '''
43 53
44 text = "" 54 text = ""
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
88 for frame in node.getElementsByTagName("frame"): 98 for frame in node.getElementsByTagName("frame"):
89 frame_dict = { 99 frame_dict = {
90 INSTRUCTION_POINTER : getTextOf(frame, INSTRUCTION_POINTER), 100 INSTRUCTION_POINTER : getTextOf(frame, INSTRUCTION_POINTER),
91 OBJECT_FILE : getTextOf(frame, OBJECT_FILE), 101 OBJECT_FILE : getTextOf(frame, OBJECT_FILE),
92 FUNCTION_NAME : getTextOf(frame, FUNCTION_NAME), 102 FUNCTION_NAME : getTextOf(frame, FUNCTION_NAME),
93 SRC_FILE_DIR : shortenFilePath( 103 SRC_FILE_DIR : shortenFilePath(
94 source_dir, getTextOf(frame, SRC_FILE_DIR)), 104 source_dir, getTextOf(frame, SRC_FILE_DIR)),
95 SRC_FILE_NAME : getTextOf(frame, SRC_FILE_NAME), 105 SRC_FILE_NAME : getTextOf(frame, SRC_FILE_NAME),
96 SRC_LINE : getTextOf(frame, SRC_LINE) 106 SRC_LINE : getTextOf(frame, SRC_LINE)
97 } 107 }
108
109 # Ignore this frame and all the following if it's a "boring" function.
110 enough_frames = False
111 for regexp in _BORING_CALLERS:
112 if re.match("^%s$" % regexp, frame_dict[FUNCTION_NAME]):
113 enough_frames = True
114 break
115 if enough_frames:
116 break
117
98 frames += [frame_dict] 118 frames += [frame_dict]
99 if frame_dict[FUNCTION_NAME] in _TOP_OF_STACK_POINTS: 119
100 break
101 global TheAddressTable 120 global TheAddressTable
102 if TheAddressTable != None and frame_dict[SRC_LINE] == "": 121 if TheAddressTable != None and frame_dict[SRC_LINE] == "":
103 # Try using gdb 122 # Try using gdb
104 TheAddressTable.Add(frame_dict[OBJECT_FILE], 123 TheAddressTable.Add(frame_dict[OBJECT_FILE],
105 frame_dict[INSTRUCTION_POINTER]) 124 frame_dict[INSTRUCTION_POINTER])
106 return frames 125 return frames
107 126
108 class ValgrindError: 127 class ValgrindError:
109 ''' Takes a <DOM Element: error> node and reads all the data from it. A 128 ''' Takes a <DOM Element: error> node and reads all the data from it. A
110 ValgrindError is immutable and is hashed on its pretty printed output. 129 ValgrindError is immutable and is hashed on its pretty printed output.
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after
258 output += "Suppression (error hash=#%016X#):\n" % self.ErrorHash() 277 output += "Suppression (error hash=#%016X#):\n" % self.ErrorHash()
259 output += (" For more info on using suppressions see " 278 output += (" For more info on using suppressions see "
260 "http://dev.chromium.org/developers/how-tos/using-valgrind#TOC-Su ppressing-Errors") 279 "http://dev.chromium.org/developers/how-tos/using-valgrind#TOC-Su ppressing-Errors")
261 280
262 # Widen suppression slightly to make portable between mac and linux 281 # Widen suppression slightly to make portable between mac and linux
263 supp = self._suppression; 282 supp = self._suppression;
264 supp = supp.replace("fun:_Znwj", "fun:_Znw*") 283 supp = supp.replace("fun:_Znwj", "fun:_Znw*")
265 supp = supp.replace("fun:_Znwm", "fun:_Znw*") 284 supp = supp.replace("fun:_Znwm", "fun:_Znw*")
266 supp = supp.replace("fun:_Znaj", "fun:_Zna*") 285 supp = supp.replace("fun:_Znaj", "fun:_Zna*")
267 supp = supp.replace("fun:_Znam", "fun:_Zna*") 286 supp = supp.replace("fun:_Znam", "fun:_Zna*")
287
268 # Split into lines so we can enforce length limits 288 # Split into lines so we can enforce length limits
269 supplines = supp.split("\n") 289 supplines = supp.split("\n")
290 supp = None # to avoid re-use
270 291
271 # Truncate at line 26 (VG_MAX_SUPP_CALLERS plus 2 for name and type) 292 # Truncate at line 26 (VG_MAX_SUPP_CALLERS plus 2 for name and type)
272 # or at the first 'boring' caller. 293 # or at the first 'boring' caller.
273 # (https://bugs.kde.org/show_bug.cgi?id=199468 proposes raising 294 # (https://bugs.kde.org/show_bug.cgi?id=199468 proposes raising
274 # VG_MAX_SUPP_CALLERS, but we're probably fine with it as is.) 295 # VG_MAX_SUPP_CALLERS, but we're probably fine with it as is.)
275 # TODO(dkegel): add more boring callers 296 newlen = min(26, len(supplines));
276 newlen = 26; 297
277 for boring_caller in [" fun:_ZN11MessageLoop3RunEv", 298 # Drop boring frames and all the following.
278 " fun:_ZN7testing4Test3RunEv"]: 299 enough_frames = False
279 try: 300 for frameno in range(newlen):
280 newlen = min(newlen, supplines.index(boring_caller)) 301 for boring_caller in _BORING_CALLERS:
281 except ValueError: 302 if re.match("^ +fun:%s$" % boring_caller, supplines[frameno]):
282 pass 303 newlen = frameno
304 enough_frames = True
305 break
306 if enough_frames:
307 break
283 if (len(supplines) > newlen): 308 if (len(supplines) > newlen):
284 supplines = supplines[0:newlen] 309 supplines = supplines[0:newlen]
285 supplines.append("}") 310 supplines.append("}")
286 311
312 for frame in range(len(supplines)):
313 # Replace the always-changing anonymous namespace prefix with "*".
314 m = re.match("( +fun:)_ZN.*_GLOBAL__N_.*\.cc_" +
315 "[0-9a-fA-F]{8}_[0-9a-fA-F]{8}(.*)",
316 supplines[frame])
317 if m:
318 supplines[frame] = "*".join(m.groups())
319
287 output += "\n".join(supplines) + "\n" 320 output += "\n".join(supplines) + "\n"
288 321
289 return output 322 return output
290 323
291 def UniqueString(self): 324 def UniqueString(self):
292 ''' String to use for object identity. Don't print this, use str(obj) 325 ''' String to use for object identity. Don't print this, use str(obj)
293 instead.''' 326 instead.'''
294 rep = self._kind + " " 327 rep = self._kind + " "
295 for backtrace in self._backtraces: 328 for backtrace in self._backtraces:
296 for frame in backtrace[1]: 329 for frame in backtrace[1]:
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after
581 parser.error("no filename specified") 614 parser.error("no filename specified")
582 filenames = args 615 filenames = args
583 616
584 analyzer = MemcheckAnalyzer(options.source_dir, use_gdb=True) 617 analyzer = MemcheckAnalyzer(options.source_dir, use_gdb=True)
585 retcode = analyzer.Report(filenames) 618 retcode = analyzer.Report(filenames)
586 619
587 sys.exit(retcode) 620 sys.exit(retcode)
588 621
589 if __name__ == "__main__": 622 if __name__ == "__main__":
590 _main() 623 _main()
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698