Coverage Report

Created: 2025-07-01 06:51

/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