]>
Commit | Line | Data |
---|---|---|
013061cf EJ |
1 | #! @PYTHON@ |
2 | # | |
3 | # Copyright (c) 2012 Nicira, Inc. | |
4 | # | |
5 | # Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | # you may not use this file except in compliance with the License. | |
7 | # You may obtain a copy of the License at: | |
8 | # | |
9 | # http://www.apache.org/licenses/LICENSE-2.0 | |
10 | # | |
11 | # Unless required by applicable law or agreed to in writing, software | |
12 | # distributed under the License is distributed on an "AS IS" BASIS, | |
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | # See the License for the specific language governing permissions and | |
15 | # limitations under the License. | |
16 | ||
17 | import optparse | |
18 | import os | |
19 | import re | |
20 | import subprocess | |
21 | import sys | |
22 | ||
23 | ||
24 | addr2line_cache = {} # None if addr2line is missing or broken. | |
25 | ||
26 | ||
27 | def addr2line(binary, addr): | |
28 | global addr2line_cache | |
29 | ||
30 | if addr2line_cache is None: | |
31 | return "" | |
32 | ||
33 | if addr in addr2line_cache: | |
34 | return addr2line_cache[addr] | |
35 | ||
36 | cmd = ["addr2line", "-f", "-s", "-e", binary, addr] | |
37 | try: | |
38 | proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, | |
39 | stderr=subprocess.PIPE) | |
40 | lines = proc.stdout.readlines() | |
41 | failed = proc.returncode | |
42 | except OSError: | |
43 | failed = True | |
44 | ||
45 | if failed: | |
46 | addr2line_cache = None | |
47 | return "" | |
48 | ||
49 | lines = [l.strip() for l in lines] | |
50 | return " ".join(lines) | |
51 | ||
52 | ||
53 | def main(): | |
54 | parser = optparse.OptionParser(version='@VERSION@', | |
55 | usage="usage: %prog [binary]", | |
56 | description="""\ | |
57 | Parses the output of ovs-appctl backtrace producing a more human readable | |
58 | result. Expected usage is for ovs-appctl backtrace to be piped in.""") | |
59 | options, args = parser.parse_args() | |
60 | ||
61 | if len(args) > 1: | |
62 | parser.print_help() | |
63 | sys.exit(1) | |
64 | ||
65 | if len(args) == 1: | |
66 | binary = args[0] | |
67 | else: | |
68 | binary = "@sbindir@/ovs-vswitchd" | |
69 | debug = "/usr/lib/debug%s.debug" % binary | |
70 | if os.path.exists(debug): | |
71 | binary = debug | |
72 | ||
73 | print "Binary: %s\n" % binary | |
74 | ||
75 | stdin = sys.stdin.read() | |
013061cf | 76 | |
7d1563e9 EJ |
77 | traces = [] |
78 | for trace in stdin.strip().split("\n\n"): | |
013061cf | 79 | lines = trace.splitlines() |
7d1563e9 EJ |
80 | match = re.search(r'Count (\d+)', lines[0]) |
81 | if match: | |
82 | count = int(match.group(1)) | |
83 | else: | |
84 | count = 0 | |
85 | traces.append((lines[1:], count)) | |
86 | traces = sorted(traces, key=(lambda x: x[1]), reverse=True) | |
87 | ||
88 | for lines, count in traces: | |
013061cf EJ |
89 | longest = max(len(l) for l in lines) |
90 | ||
91 | print "Backtrace Count: %d" % count | |
92 | for line in lines: | |
93 | match = re.search(r'\[(0x.*)]', line) | |
94 | if match: | |
95 | print "%s %s" % (line.ljust(longest), | |
96 | addr2line(binary, match.group(1))) | |
97 | else: | |
98 | print line | |
99 | ||
100 | ||
101 | ||
102 | if __name__ == "__main__": | |
103 | main() |