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

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 = [
Timur Iskhodzhanov 2011/08/16 13:48:02 this wasn't matching anything
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.*",
Lei Zhang 2011/08/16 18:49:04 Indeed, stuff below this is quite boring and can p
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(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 for boring_caller in _BORING_CALLERS:
Lei Zhang 2011/08/16 18:49:04 I think this double for-loop can exit a bit earlie
Timur Iskhodzhanov 2011/08/17 09:09:19 Absolutely! I've started from this one (not the ga
277 for boring_caller in [" fun:_ZN11MessageLoop3RunEv", 298 for frame in range(len(supplines)):
278 " fun:_ZN7testing4Test3RunEv"]: 299 if re.search(boring_caller, supplines[frame]):
279 try: 300 newlen = min(newlen, frame)
280 newlen = min(newlen, supplines.index(boring_caller)) 301 break
281 except ValueError:
282 pass
283 if (len(supplines) > newlen): 302 if (len(supplines) > newlen):
284 supplines = supplines[0:newlen] 303 supplines = supplines[0:newlen]
285 supplines.append("}") 304 supplines.append("}")
286 305
306 for frame in range(len(supplines)):
307 # Replace the always-changing anonymous namespace prefix with "*".
308 m = re.match("( +fun:)_ZN.*_GLOBAL__N_.*\.cc_" +
309 "[0-9a-fA-F]{8}_[0-9a-fA-F]{8}(.*)",
310 supplines[frame])
311 if m:
312 supplines[frame] = "*".join(m.groups())
313
287 output += "\n".join(supplines) + "\n" 314 output += "\n".join(supplines) + "\n"
288 315
289 return output 316 return output
290 317
291 def UniqueString(self): 318 def UniqueString(self):
292 ''' String to use for object identity. Don't print this, use str(obj) 319 ''' String to use for object identity. Don't print this, use str(obj)
293 instead.''' 320 instead.'''
294 rep = self._kind + " " 321 rep = self._kind + " "
295 for backtrace in self._backtraces: 322 for backtrace in self._backtraces:
296 for frame in backtrace[1]: 323 for frame in backtrace[1]:
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after
581 parser.error("no filename specified") 608 parser.error("no filename specified")
582 filenames = args 609 filenames = args
583 610
584 analyzer = MemcheckAnalyzer(options.source_dir, use_gdb=True) 611 analyzer = MemcheckAnalyzer(options.source_dir, use_gdb=True)
585 retcode = analyzer.Report(filenames) 612 retcode = analyzer.Report(filenames)
586 613
587 sys.exit(retcode) 614 sys.exit(retcode)
588 615
589 if __name__ == "__main__": 616 if __name__ == "__main__":
590 _main() 617 _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