2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
7 from collections
import defaultdict
16 def ReadReportsFromFile(filename
):
17 """ Returns a list of (report_hash, report) and the URL of the report on the
20 input_file
= file(filename
, 'r')
21 # reports is a list of (error hash, report) pairs.
23 in_suppression
= False
25 # This stores the last error hash found while reading the file.
27 for line
in input_file
:
29 line
= line
.replace("</span><span class=\"stdout\">", "")
30 line
= line
.replace("</span><span class=\"stderr\">", "")
31 line
= line
.replace("<", "<")
32 line
= line
.replace(">", ">")
36 reports
+= [[last_hash
, "\n".join(cur_supp
)]]
37 in_suppression
= False
41 cur_supp
+= [" "*3 + line
]
45 elif line
.find("Suppression (error hash=#") == 0:
46 last_hash
= line
[25:41]
47 # The line at the end of the file is assumed to store the URL of the report.
51 """ Demangle a list of C++ symbols, return a list of human-readable symbols.
53 args
= ['c++filt', '-n']
55 pipe
= subprocess
.Popen(args
, stdin
=subprocess
.PIPE
, stdout
=subprocess
.PIPE
)
56 stdout
, _
= pipe
.communicate()
57 demangled
= stdout
.split("\n")
59 # Each line ends with a newline, so the final entry of the split output
61 assert len(demangled
) == len(names
) + 1
64 def GetSymbolsFromReport(report
):
65 """Extract all symbols from a suppression report."""
68 prefix_len
= len(prefix
)
69 for line
in report
.splitlines():
70 index
= line
.find(prefix
)
72 symbols
.append(line
[index
+ prefix_len
:])
75 def PrintTopSymbols(symbol_reports
, top_count
):
76 """Print the |top_count| symbols with the most occurrences."""
77 boring_symbols
=['malloc', '_Znw*', 'TestBody']
78 sorted_reports
= sorted(filter(lambda x
:x
[0] not in boring_symbols
,
79 symbol_reports
.iteritems()),
80 key
=lambda x
:len(x
[1]), reverse
=True)
81 symbols
= symbol_reports
.keys()
82 demangled
= Demangle(symbols
)
83 assert len(demangled
) == len(symbols
)
84 symboltable
= dict(zip(symbols
, demangled
))
87 print "Top %d symbols" % top_count
88 for (symbol
, suppressions
) in sorted_reports
[:top_count
]:
89 print "%4d occurrences : %s" % (len(suppressions
), symboltable
[symbol
])
92 supp
= suppressions
.GetSuppressions()
94 # all_reports is a map {report: list of urls containing this report}
95 all_reports
= defaultdict(list)
97 symbol_reports
= defaultdict(list)
99 # Create argument parser.
100 parser
= argparse
.ArgumentParser()
101 parser
.add_argument('--top-symbols', type=int, default
=0,
102 help='Print a list of the top <n> symbols')
103 parser
.add_argument('--symbol-filter', action
='append',
104 help='Filter out all suppressions not containing the specified symbol(s). '
105 'Matches against the mangled names')
107 parser
.add_argument('reports', metavar
='report file', nargs
='+',
108 help='List of report files')
109 args
= parser
.parse_args(argv
)
111 for f
in args
.reports
:
112 f_reports
, url
= ReadReportsFromFile(f
)
113 for (hash, report
) in f_reports
:
114 all_reports
[report
] += [url
]
115 report_hashes
[report
] = hash
118 for r
in all_reports
:
119 cur_supp
= supp
['common_suppressions']
120 if all([re
.search("%20Mac%20|mac_valgrind", url
)
121 for url
in all_reports
[r
]]):
122 # Include mac suppressions if the report is only present on Mac
123 cur_supp
+= supp
['mac_suppressions']
124 elif all([re
.search("Windows%20", url
) for url
in all_reports
[r
]]):
125 # Include win32 suppressions if the report is only present on Windows
126 cur_supp
+= supp
['win_suppressions']
127 elif all([re
.search("Linux%20", url
) for url
in all_reports
[r
]]):
128 cur_supp
+= supp
['linux_suppressions']
129 elif all([re
.search("%20Heapcheck", url
)
130 for url
in all_reports
[r
]]):
131 cur_supp
+= supp
['heapcheck_suppressions']
132 if all(["DrMemory" in url
for url
in all_reports
[r
]]):
133 cur_supp
+= supp
['drmem_suppressions']
134 if all(["DrMemory%20full" in url
for url
in all_reports
[r
]]):
135 cur_supp
+= supp
['drmem_full_suppressions']
137 # Test if this report is already suppressed
140 if s
.Match(r
.split("\n")):
144 # Skip reports if none of the symbols are in the report.
145 if args
.symbol_filter
and all(not s
in r
for s
in args
.symbol_filter
):
150 print "==================================="
151 print "This report observed at"
152 for url
in all_reports
[r
]:
154 print "didn't match any suppressions:"
155 print "Suppression (error hash=#%s#):" % (report_hashes
[r
])
157 print "==================================="
159 if args
.top_symbols
> 0:
160 symbols
= GetSymbolsFromReport(r
)
161 for symbol
in symbols
:
162 symbol_reports
[symbol
].append(report_hashes
[r
])
164 if reports_count
> 0:
165 print ("%d unique reports don't match any of the suppressions" %
167 if args
.top_symbols
> 0:
168 PrintTopSymbols(symbol_reports
, args
.top_symbols
)
171 print "Congratulations! All reports are suppressed!"
172 # TODO(timurrrr): also make sure none of the old suppressions
173 # were narrowed too much.
176 if __name__
== "__main__":