]>
Commit | Line | Data |
---|---|---|
064af421 | 1 | /* |
482557e5 | 2 | * Copyright (c) 2008, 2009, 2010, 2011, 2013 Nicira, Inc. |
064af421 | 3 | * |
a14bc59f BP |
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: | |
064af421 | 7 | * |
a14bc59f BP |
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. | |
064af421 BP |
15 | */ |
16 | ||
17 | #include <config.h> | |
e2ed6fbe WT |
18 | #include <errno.h> |
19 | #include <fcntl.h> | |
d0b99d38 | 20 | #include <inttypes.h> |
e2ed6fbe WT |
21 | #include <string.h> |
22 | #include <unistd.h> | |
0e6644c3 | 23 | |
064af421 | 24 | #include "backtrace.h" |
e6211adc | 25 | #include "openvswitch/vlog.h" |
e2ed6fbe | 26 | #include "util.h" |
d0b99d38 AZ |
27 | |
28 | VLOG_DEFINE_THIS_MODULE(backtrace); | |
0e6644c3 | 29 | |
0e6644c3 BP |
30 | #ifdef HAVE_BACKTRACE |
31 | #include <execinfo.h> | |
32 | void | |
33 | backtrace_capture(struct backtrace *b) | |
34 | { | |
35 | void *frames[BACKTRACE_MAX_FRAMES]; | |
36 | int i; | |
37 | ||
38 | b->n_frames = backtrace(frames, BACKTRACE_MAX_FRAMES); | |
39 | for (i = 0; i < b->n_frames; i++) { | |
40 | b->frames[i] = (uintptr_t) frames[i]; | |
41 | } | |
42 | } | |
d0b99d38 | 43 | |
482557e5 | 44 | #else |
0e6644c3 BP |
45 | void |
46 | backtrace_capture(struct backtrace *backtrace) | |
47 | { | |
e4fd8d28 | 48 | backtrace->n_frames = 0; |
064af421 | 49 | } |
0e6644c3 | 50 | #endif |
d0b99d38 AZ |
51 | |
52 | static char * | |
53 | backtrace_format(const struct backtrace *b, struct ds *ds) | |
54 | { | |
55 | if (b->n_frames) { | |
56 | int i; | |
57 | ||
58 | ds_put_cstr(ds, " (backtrace:"); | |
59 | for (i = 0; i < b->n_frames; i++) { | |
60 | ds_put_format(ds, " 0x%08"PRIxPTR, b->frames[i]); | |
61 | } | |
62 | ds_put_cstr(ds, ")"); | |
63 | } | |
64 | ||
65 | return ds_cstr(ds); | |
66 | } | |
67 | ||
68 | void | |
69 | log_backtrace_at(const char *msg, const char *where) | |
70 | { | |
71 | struct backtrace b; | |
72 | struct ds ds = DS_EMPTY_INITIALIZER; | |
73 | ||
74 | backtrace_capture(&b); | |
75 | if (msg) { | |
76 | ds_put_format(&ds, "%s ", msg); | |
77 | } | |
78 | ||
79 | ds_put_cstr(&ds, where); | |
80 | VLOG_ERR("%s", backtrace_format(&b, &ds)); | |
81 | ||
82 | ds_destroy(&ds); | |
83 | } | |
e2ed6fbe WT |
84 | |
85 | #ifdef HAVE_UNWIND | |
86 | void | |
87 | log_received_backtrace(int fd) { | |
88 | int byte_read; | |
89 | struct unw_backtrace backtrace[UNW_MAX_DEPTH]; | |
90 | ||
91 | VLOG_WARN("%s fd %d", __func__, fd); | |
92 | fcntl(fd, F_SETFL, O_NONBLOCK); | |
93 | memset(backtrace, 0, UNW_MAX_BUF); | |
94 | ||
95 | byte_read = read(fd, backtrace, UNW_MAX_BUF); | |
96 | if (byte_read < 0) { | |
97 | VLOG_ERR("Read fd %d failed: %s", fd, | |
98 | ovs_strerror(errno)); | |
99 | } else if (byte_read > 0) { | |
100 | VLOG_WARN("SIGSEGV detected, backtrace:"); | |
101 | for (int i = 0; i < UNW_MAX_DEPTH; i++) { | |
102 | if (backtrace[i].func[0] == 0) { | |
103 | break; | |
104 | } | |
0b265306 | 105 | VLOG_WARN("0x%016"PRIxPTR" <%s+0x%"PRIxPTR">\n", |
e2ed6fbe WT |
106 | backtrace[i].ip, |
107 | backtrace[i].func, | |
108 | backtrace[i].offset); | |
109 | } | |
110 | } | |
111 | } | |
112 | #else /* !HAVE_UNWIND */ | |
113 | void | |
114 | log_received_backtrace(int daemonize_fd OVS_UNUSED) { | |
115 | VLOG_WARN("Backtrace using libunwind not supported."); | |
116 | } | |
117 | #endif /* HAVE_UNWIND */ |