Coverage Report

Created: 2026-04-12 06:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openvswitch/lib/backtrace.c
Line
Count
Source
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
    if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
99
0
        VLOG_WARN("Failed to set fd %d non-blocking: %s",
100
0
                  fd, ovs_strerror(errno));
101
0
    }
102
0
    memset(dest, 0, len);
103
104
0
    int byte_read = read(fd, dest, len);
105
0
    if (byte_read < 0) {
106
0
        VLOG_ERR("Read fd %d failed: %s", fd, ovs_strerror(errno));
107
0
    }
108
109
0
    return byte_read > 0;;
110
0
}
111
#else
112
static bool
113
read_received_backtrace(int fd OVS_UNUSED, void *dest OVS_UNUSED,
114
                        size_t len OVS_UNUSED)
115
{
116
    return false;
117
}
118
#endif
119
120
#ifdef HAVE_UNWIND
121
void
122
log_received_backtrace(int fd)
123
{
124
    struct unw_backtrace backtrace[UNW_MAX_DEPTH];
125
126
    if (read_received_backtrace(fd, backtrace, UNW_MAX_BUF)) {
127
        struct ds ds = DS_EMPTY_INITIALIZER;
128
129
        ds_put_cstr(&ds, BACKTRACE_DUMP_MSG);
130
131
        for (int i = 0; i < UNW_MAX_DEPTH; i++) {
132
            if (backtrace[i].func[0] == 0) {
133
                break;
134
            }
135
            ds_put_format(&ds, "0x%016"PRIxPTR" <%s+0x%"PRIxPTR">\n",
136
                          backtrace[i].ip,
137
                          backtrace[i].func,
138
                          backtrace[i].offset);
139
        }
140
141
        VLOG_WARN("%s", ds_cstr_ro(&ds));
142
143
        ds_destroy(&ds);
144
    }
145
}
146
#elif HAVE_BACKTRACE
147
void
148
log_received_backtrace(int fd)
149
0
{
150
0
    struct backtrace bt;
151
152
0
    if (read_received_backtrace(fd, &bt, sizeof bt)) {
153
0
        struct ds ds = DS_EMPTY_INITIALIZER;
154
155
0
        bt.n_frames = MIN(MAX(bt.n_frames, 0), BACKTRACE_MAX_FRAMES);
156
157
0
        ds_put_cstr(&ds, BACKTRACE_DUMP_MSG);
158
0
        backtrace_format(&ds, &bt, "\n");
159
0
        VLOG_WARN("%s", ds_cstr_ro(&ds));
160
161
0
        ds_destroy(&ds);
162
0
    }
163
0
}
164
#else
165
void
166
log_received_backtrace(int daemonize_fd OVS_UNUSED)
167
{
168
    VLOG_WARN("Backtrace using libunwind or backtrace() is not supported.");
169
}
170
#endif