/src/openvswitch/lib/backtrace.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2008, 2009, 2010, 2011, 2013 Nicira, Inc. |
3 | | * |
4 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | | * you may not use this file except in compliance with the License. |
6 | | * You may obtain a copy of the License at: |
7 | | * |
8 | | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | | * |
10 | | * Unless required by applicable law or agreed to in writing, software |
11 | | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | | * See the License for the specific language governing permissions and |
14 | | * limitations under the License. |
15 | | */ |
16 | | |
17 | | #include <config.h> |
18 | | #include <errno.h> |
19 | | #include <fcntl.h> |
20 | | #include <inttypes.h> |
21 | | #include <string.h> |
22 | | #include <unistd.h> |
23 | | |
24 | | #include "backtrace.h" |
25 | | #include "openvswitch/vlog.h" |
26 | | #include "util.h" |
27 | | |
28 | | VLOG_DEFINE_THIS_MODULE(backtrace); |
29 | | |
30 | | #ifdef HAVE_BACKTRACE |
31 | | #include <execinfo.h> |
32 | | void |
33 | | backtrace_capture(struct backtrace *b) |
34 | 0 | { |
35 | 0 | b->n_frames = backtrace(b->frames, BACKTRACE_MAX_FRAMES); |
36 | 0 | } |
37 | | |
38 | | void |
39 | | backtrace_format(struct ds *ds, const struct backtrace *bt, |
40 | | const char *delimiter) |
41 | 0 | { |
42 | 0 | if (bt->n_frames) { |
43 | 0 | char **symbols = backtrace_symbols(bt->frames, bt->n_frames); |
44 | |
|
45 | 0 | if (!symbols) { |
46 | 0 | return; |
47 | 0 | } |
48 | | |
49 | 0 | for (int i = 0; i < bt->n_frames - 1; i++) { |
50 | 0 | ds_put_format(ds, "%s%s", symbols[i], delimiter); |
51 | 0 | } |
52 | |
|
53 | 0 | ds_put_format(ds, "%s", symbols[bt->n_frames - 1]); |
54 | |
|
55 | 0 | free(symbols); |
56 | 0 | } |
57 | 0 | } |
58 | | |
59 | | #else |
60 | | void |
61 | | backtrace_capture(struct backtrace *backtrace) |
62 | | { |
63 | | backtrace->n_frames = 0; |
64 | | } |
65 | | |
66 | | void |
67 | | backtrace_format(struct ds *ds, const struct backtrace *bt OVS_UNUSED, |
68 | | const char *delimiter OVS_UNUSED) |
69 | | { |
70 | | ds_put_cstr(ds, "backtrace() is not supported!\n"); |
71 | | } |
72 | | #endif |
73 | | |
74 | | void |
75 | | log_backtrace_at(const char *msg, const char *where) |
76 | 0 | { |
77 | 0 | struct backtrace b; |
78 | 0 | struct ds ds = DS_EMPTY_INITIALIZER; |
79 | |
|
80 | 0 | backtrace_capture(&b); |
81 | 0 | if (msg) { |
82 | 0 | ds_put_format(&ds, "%s ", msg); |
83 | 0 | } |
84 | |
|
85 | 0 | ds_put_cstr(&ds, where); |
86 | 0 | ds_put_cstr(&ds, " backtrace:\n"); |
87 | 0 | backtrace_format(&ds, &b, "\n"); |
88 | 0 | VLOG_ERR("%s", ds_cstr_ro(&ds)); |
89 | |
|
90 | 0 | ds_destroy(&ds); |
91 | 0 | } |
92 | | |
93 | | #if defined(HAVE_UNWIND) || defined(HAVE_BACKTRACE) |
94 | | static bool |
95 | | read_received_backtrace(int fd, void *dest, size_t len) |
96 | 0 | { |
97 | 0 | VLOG_DBG("%s fd %d", __func__, fd); |
98 | 0 | fcntl(fd, F_SETFL, O_NONBLOCK); |
99 | 0 | memset(dest, 0, len); |
100 | |
|
101 | 0 | int byte_read = read(fd, dest, len); |
102 | 0 | if (byte_read < 0) { |
103 | 0 | VLOG_ERR("Read fd %d failed: %s", fd, ovs_strerror(errno)); |
104 | 0 | } |
105 | |
|
106 | 0 | return byte_read > 0;; |
107 | 0 | } |
108 | | #else |
109 | | static bool |
110 | | read_received_backtrace(int fd OVS_UNUSED, void *dest OVS_UNUSED, |
111 | | size_t len OVS_UNUSED) |
112 | | { |
113 | | return false; |
114 | | } |
115 | | #endif |
116 | | |
117 | | #ifdef HAVE_UNWIND |
118 | | void |
119 | | log_received_backtrace(int fd) |
120 | | { |
121 | | struct unw_backtrace backtrace[UNW_MAX_DEPTH]; |
122 | | |
123 | | if (read_received_backtrace(fd, backtrace, UNW_MAX_BUF)) { |
124 | | struct ds ds = DS_EMPTY_INITIALIZER; |
125 | | |
126 | | ds_put_cstr(&ds, BACKTRACE_DUMP_MSG); |
127 | | |
128 | | for (int i = 0; i < UNW_MAX_DEPTH; i++) { |
129 | | if (backtrace[i].func[0] == 0) { |
130 | | break; |
131 | | } |
132 | | ds_put_format(&ds, "0x%016"PRIxPTR" <%s+0x%"PRIxPTR">\n", |
133 | | backtrace[i].ip, |
134 | | backtrace[i].func, |
135 | | backtrace[i].offset); |
136 | | } |
137 | | |
138 | | VLOG_WARN("%s", ds_cstr_ro(&ds)); |
139 | | |
140 | | ds_destroy(&ds); |
141 | | } |
142 | | } |
143 | | #elif HAVE_BACKTRACE |
144 | | void |
145 | | log_received_backtrace(int fd) |
146 | 0 | { |
147 | 0 | struct backtrace bt; |
148 | |
|
149 | 0 | if (read_received_backtrace(fd, &bt, sizeof bt)) { |
150 | 0 | struct ds ds = DS_EMPTY_INITIALIZER; |
151 | |
|
152 | 0 | bt.n_frames = MIN(bt.n_frames, BACKTRACE_MAX_FRAMES); |
153 | |
|
154 | 0 | ds_put_cstr(&ds, BACKTRACE_DUMP_MSG); |
155 | 0 | backtrace_format(&ds, &bt, "\n"); |
156 | 0 | VLOG_WARN("%s", ds_cstr_ro(&ds)); |
157 | |
|
158 | 0 | ds_destroy(&ds); |
159 | 0 | } |
160 | 0 | } |
161 | | #else |
162 | | void |
163 | | log_received_backtrace(int daemonize_fd OVS_UNUSED) |
164 | | { |
165 | | VLOG_WARN("Backtrace using libunwind or backtrace() is not supported."); |
166 | | } |
167 | | #endif |