#! @PYTHON@ # # Copyright (c) 2012 Nicira, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at: # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import optparse import os import re import subprocess import sys addr2line_cache = {} # None if addr2line is missing or broken. def addr2line(binary, addr): global addr2line_cache if addr2line_cache is None: return "" if addr in addr2line_cache: return addr2line_cache[addr] cmd = ["addr2line", "-f", "-s", "-e", binary, addr] try: proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) lines = proc.stdout.readlines() failed = proc.returncode except OSError: failed = True if failed: addr2line_cache = None return "" lines = [l.strip() for l in lines] return " ".join(lines) def main(): parser = optparse.OptionParser(version='@VERSION@', usage="usage: %prog [binary]", description="""\ Parses the output of ovs-appctl backtrace producing a more human readable result. Expected usage is for ovs-appctl backtrace to be piped in.""") options, args = parser.parse_args() if len(args) > 1: parser.print_help() sys.exit(1) if len(args) == 1: binary = args[0] else: binary = "@sbindir@/ovs-vswitchd" debug = "/usr/lib/debug%s.debug" % binary if os.path.exists(debug): binary = debug print "Binary: %s\n" % binary stdin = sys.stdin.read() trace_list = stdin.strip().split("\n\n") try: #Remove the first line from each trace. trace_list = [trace[(trace.index("\n") + 1):] for trace in trace_list] except ValueError: sys.stdout.write(stdin) sys.exit(1) trace_map = {} for trace in trace_list: trace_map[trace] = trace_map.get(trace, 0) + 1 sorted_traces = sorted(trace_map.items(), key=(lambda x: x[1]), reverse=True) for trace, count in sorted_traces: lines = trace.splitlines() longest = max(len(l) for l in lines) print "Backtrace Count: %d" % count for line in lines: match = re.search(r'\[(0x.*)]', line) if match: print "%s %s" % (line.ljust(longest), addr2line(binary, match.group(1))) else: print line print if __name__ == "__main__": main()