Coverage Report

Created: 2026-08-30 07:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vulkan-loader/loader/log.c
Line
Count
Source
1
/*
2
 *
3
 * Copyright (c) 2014-2022 The Khronos Group Inc.
4
 * Copyright (c) 2014-2022 Valve Corporation
5
 * Copyright (c) 2014-2022 LunarG, Inc.
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 *
19
 * Author: Jon Ashburn <jon@lunarg.com>
20
 * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
21
 * Author: Chia-I Wu <olvaffe@gmail.com>
22
 * Author: Chia-I Wu <olv@lunarg.com>
23
 * Author: Mark Lobodzinski <mark@LunarG.com>
24
 * Author: Lenny Komow <lenny@lunarg.com>
25
 * Author: Charles Giessen <charles@lunarg.com>
26
 *
27
 */
28
29
#include "log.h"
30
31
#include <stdio.h>
32
#include <stdarg.h>
33
34
#include "debug_utils.h"
35
#include "loader_common.h"
36
#include "loader_environment.h"
37
#include "settings.h"
38
#include "vk_loader_platform.h"
39
40
uint32_t g_loader_debug = 0;
41
42
2
void loader_init_global_debug_level(void) {
43
2
    char *env;
44
2
    char *orig;
45
46
2
    if (g_loader_debug > 0) return;
47
48
2
    g_loader_debug = 0;
49
50
    // Parse comma-separated debug options
51
2
    orig = env = loader_getenv("VK_LOADER_DEBUG", NULL);
52
2
    while (env) {
53
0
        char *p = strchr(env, ',');
54
0
        size_t len;
55
56
0
        if (p) {
57
0
            len = p - env;
58
0
        } else {
59
0
            len = strlen(env);
60
0
        }
61
62
0
        if (len > 0) {
63
0
            if (strncmp(env, "all", len) == 0) {
64
0
                g_loader_debug = ~0u;
65
0
            } else if (strncmp(env, "warn", len) == 0) {
66
0
                g_loader_debug |= VULKAN_LOADER_WARN_BIT;
67
0
            } else if (strncmp(env, "info", len) == 0) {
68
0
                g_loader_debug |= VULKAN_LOADER_INFO_BIT;
69
0
            } else if (strncmp(env, "perf", len) == 0) {
70
0
                g_loader_debug |= VULKAN_LOADER_PERF_BIT;
71
0
            } else if (strncmp(env, "error", len) == 0) {
72
0
                g_loader_debug |= VULKAN_LOADER_ERROR_BIT;
73
0
            } else if (strncmp(env, "debug", len) == 0) {
74
0
                g_loader_debug |= VULKAN_LOADER_DEBUG_BIT;
75
0
            } else if (strncmp(env, "layer", len) == 0) {
76
0
                g_loader_debug |= VULKAN_LOADER_LAYER_BIT;
77
0
            } else if (strncmp(env, "driver", len) == 0 || strncmp(env, "implem", len) == 0 || strncmp(env, "icd", len) == 0) {
78
0
                g_loader_debug |= VULKAN_LOADER_DRIVER_BIT;
79
0
            }
80
0
        }
81
82
0
        if (!p) break;
83
84
0
        env = p + 1;
85
0
    }
86
87
2
    loader_free_getenv(orig, NULL);
88
2
}
89
90
125
void loader_set_global_debug_level(uint32_t new_loader_debug) { g_loader_debug = new_loader_debug; }
91
92
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters) - msg_type/cmd_line_size are convertible types, always passed in this order
93
1.06k
void generate_debug_flag_str(VkFlags msg_type, size_t cmd_line_size, char *cmd_line_msg) {
94
1.06k
    cmd_line_msg[0] = '\0';
95
96
1.06k
    if ((msg_type & VULKAN_LOADER_ERROR_BIT) != 0) {
97
31
        loader_strncat(cmd_line_msg, cmd_line_size, "ERROR", sizeof("ERROR"));
98
31
    }
99
1.06k
    if ((msg_type & VULKAN_LOADER_WARN_BIT) != 0) {
100
51
        if (strlen(cmd_line_msg) > 0) {
101
25
            loader_strncat(cmd_line_msg, cmd_line_size, " | ", sizeof(" | "));
102
25
        }
103
51
        loader_strncat(cmd_line_msg, cmd_line_size, "WARNING", sizeof("WARNING"));
104
51
    }
105
1.06k
    if ((msg_type & VULKAN_LOADER_INFO_BIT) != 0) {
106
38
        if (strlen(cmd_line_msg) > 0) {
107
26
            loader_strncat(cmd_line_msg, cmd_line_size, " | ", sizeof(" | "));
108
26
        }
109
38
        loader_strncat(cmd_line_msg, cmd_line_size, "INFO", sizeof("INFO"));
110
38
    }
111
1.06k
    if ((msg_type & VULKAN_LOADER_DEBUG_BIT) != 0) {
112
47
        if (strlen(cmd_line_msg) > 0) {
113
34
            loader_strncat(cmd_line_msg, cmd_line_size, " | ", sizeof(" | "));
114
34
        }
115
47
        loader_strncat(cmd_line_msg, cmd_line_size, "DEBUG", sizeof("DEBUG"));
116
47
    }
117
1.06k
    if ((msg_type & VULKAN_LOADER_PERF_BIT) != 0) {
118
43
        if (strlen(cmd_line_msg) > 0) {
119
33
            loader_strncat(cmd_line_msg, cmd_line_size, " | ", sizeof(" | "));
120
33
        }
121
43
        loader_strncat(cmd_line_msg, cmd_line_size, "PERF", sizeof("PERF"));
122
43
    }
123
1.06k
    if ((msg_type & VULKAN_LOADER_DRIVER_BIT) != 0) {
124
48
        if (strlen(cmd_line_msg) > 0) {
125
36
            loader_strncat(cmd_line_msg, cmd_line_size, " | ", sizeof(" | "));
126
36
        }
127
48
        loader_strncat(cmd_line_msg, cmd_line_size, "DRIVER", sizeof("DRIVER"));
128
48
    }
129
1.06k
    if ((msg_type & VULKAN_LOADER_LAYER_BIT) != 0) {
130
50
        if (strlen(cmd_line_msg) > 0) {
131
37
            loader_strncat(cmd_line_msg, cmd_line_size, " | ", sizeof(" | "));
132
37
        }
133
50
        loader_strncat(cmd_line_msg, cmd_line_size, "LAYER", sizeof("LAYER"));
134
50
    }
135
136
1.06k
#undef STRNCAT_TO_BUFFER
137
1.06k
}
138
139
void DECORATE_PRINTF(4, 5)
140
    // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) - msg_type/msg_code (unused) are convertible types; public API order
141
619k
    loader_log(const struct loader_instance *inst, VkFlags msg_type, int32_t msg_code, const char *format, ...) {
142
619k
    (void)msg_code;
143
619k
    char msg[512] = {0};
144
145
619k
    va_list ap;
146
619k
    va_start(ap, format);
147
619k
    int ret = vsnprintf(msg, sizeof(msg), format, ap);
148
619k
    if ((ret >= (int)sizeof(msg)) || ret < 0) {
149
482
        msg[sizeof(msg) - 1] = '\0';
150
482
    }
151
619k
    va_end(ap);
152
153
619k
    if (inst) {
154
        // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange) - external Vulkan enum, has no zero value we can add
155
0
        VkDebugUtilsMessageSeverityFlagBitsEXT severity = 0;
156
0
        VkDebugUtilsMessageTypeFlagsEXT type = 0;
157
0
        VkDebugUtilsMessengerCallbackDataEXT callback_data = {0};
158
0
        VkDebugUtilsObjectNameInfoEXT object_name = {0};
159
160
        // NOLINTNEXTLINE(bugprone-branch-clone) - duplicated so combined bit calls (e.g. WARN_BIT|LAYER_BIT) match first branch
161
0
        if ((msg_type & VULKAN_LOADER_INFO_BIT) != 0) {
162
0
            severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
163
0
        } else if ((msg_type & VULKAN_LOADER_WARN_BIT) != 0) {
164
0
            severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
165
0
        } else if ((msg_type & VULKAN_LOADER_ERROR_BIT) != 0) {
166
0
            severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
167
0
        } else if ((msg_type & VULKAN_LOADER_DEBUG_BIT) != 0) {
168
0
            severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
169
0
        } else if ((msg_type & VULKAN_LOADER_LAYER_BIT) != 0 || (msg_type & VULKAN_LOADER_DRIVER_BIT) != 0) {
170
            // Just driver or just layer bit should be treated as an info message in debug utils.
171
0
            severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
172
0
        }
173
174
0
        if ((msg_type & VULKAN_LOADER_PERF_BIT) != 0) {
175
0
            type = VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
176
0
        } else if ((msg_type & VULKAN_LOADER_VALIDATION_BIT) != 0) {
177
            // For loader logging, if it's a validation message, we still want to also keep the general flag as well
178
            // so messages of type validation can still be triggered for general message callbacks.
179
0
            type = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
180
0
        } else {
181
0
            type = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT;
182
0
        }
183
184
0
        callback_data.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT;
185
0
        callback_data.pMessageIdName = "Loader Message";
186
0
        callback_data.pMessage = msg;
187
0
        callback_data.objectCount = 1;
188
0
        callback_data.pObjects = &object_name;
189
0
        object_name.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
190
0
        object_name.objectType = VK_OBJECT_TYPE_INSTANCE;
191
0
        object_name.objectHandle = (uint64_t)(uintptr_t)inst;
192
193
0
        util_SubmitDebugUtilsMessageEXT(inst, severity, type, &callback_data);
194
0
    }
195
196
    // Always log to stderr if this is a fatal error
197
619k
    if (0 == (msg_type & VULKAN_LOADER_FATAL_ERROR_BIT)) {
198
619k
        if (inst && inst->settings.settings_active && inst->settings.debug_level > 0) {
199
            // Exit early if the current instance settings have some debugging options but do match the current msg_type
200
0
            if (0 == (msg_type & inst->settings.debug_level)) {
201
0
                return;
202
0
            }
203
            // Check the global settings and if that doesn't say to skip, check the environment variable
204
619k
        } else if (0 == (msg_type & g_loader_debug)) {
205
226k
            return;
206
226k
        }
207
619k
    }
208
209
#if defined(DEBUG)
210
    int debug_flag_mask =
211
        (int)(msg_type & (VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_DEBUG_BIT));
212
    assert((debug_flag_mask == 0 || debug_flag_mask == VULKAN_LOADER_ERROR_BIT || debug_flag_mask == VULKAN_LOADER_WARN_BIT ||
213
            debug_flag_mask == VULKAN_LOADER_INFO_BIT || debug_flag_mask == VULKAN_LOADER_DEBUG_BIT) &&
214
           "This log has more than one exclusive debug flags (error, warn, info, debug) set");
215
#endif
216
217
    // Only need enough space to create the filter description header for log messages
218
    // Also use the same header for all output
219
392k
    char cmd_line_msg[64] = {0};
220
392k
    size_t cmd_line_size = sizeof(cmd_line_msg);
221
222
392k
    loader_strncat(cmd_line_msg, cmd_line_size, "[Vulkan Loader] ", sizeof("[Vulkan Loader] "));
223
224
392k
    bool need_separator = false;
225
392k
    if ((msg_type & VULKAN_LOADER_ERROR_BIT) != 0) {
226
3.54k
        loader_strncat(cmd_line_msg, cmd_line_size, "ERROR", sizeof("ERROR"));
227
3.54k
        need_separator = true;
228
388k
    } else if ((msg_type & VULKAN_LOADER_WARN_BIT) != 0) {
229
132k
        loader_strncat(cmd_line_msg, cmd_line_size, "WARNING", sizeof("WARNING"));
230
132k
        need_separator = true;
231
256k
    } else if ((msg_type & VULKAN_LOADER_INFO_BIT) != 0) {
232
54.1k
        loader_strncat(cmd_line_msg, cmd_line_size, "INFO", sizeof("INFO"));
233
54.1k
        need_separator = true;
234
202k
    } else if ((msg_type & VULKAN_LOADER_DEBUG_BIT) != 0) {
235
130k
        loader_strncat(cmd_line_msg, cmd_line_size, "DEBUG", sizeof("DEBUG"));
236
130k
        need_separator = true;
237
130k
    }
238
239
392k
    if ((msg_type & VULKAN_LOADER_PERF_BIT) != 0) {
240
0
        if (need_separator) {
241
0
            loader_strncat(cmd_line_msg, cmd_line_size, " | ", sizeof(" | "));
242
0
        }
243
0
        loader_strncat(cmd_line_msg, cmd_line_size, "PERF", sizeof("PERF"));
244
392k
    } else if ((msg_type & VULKAN_LOADER_DRIVER_BIT) != 0) {
245
0
        if (need_separator) {
246
0
            loader_strncat(cmd_line_msg, cmd_line_size, " | ", sizeof(" | "));
247
0
        }
248
0
        loader_strncat(cmd_line_msg, cmd_line_size, "DRIVER", sizeof("DRIVER"));
249
392k
    } else if ((msg_type & VULKAN_LOADER_LAYER_BIT) != 0) {
250
140k
        if (need_separator) {
251
68.8k
            loader_strncat(cmd_line_msg, cmd_line_size, " | ", sizeof(" | "));
252
68.8k
        }
253
140k
        loader_strncat(cmd_line_msg, cmd_line_size, "LAYER", sizeof("LAYER"));
254
140k
    }
255
256
392k
    loader_strncat(cmd_line_msg, cmd_line_size, ": ", sizeof(": "));
257
392k
    size_t num_used = strlen(cmd_line_msg);
258
259
    // Justifies the output to at least 29 spaces
260
392k
    if (num_used < 32) {
261
374k
        const char space_buffer[] = "                                ";
262
        // Only write (32 - num_used) spaces
263
374k
        loader_strncat(cmd_line_msg, cmd_line_size, space_buffer, sizeof(space_buffer) - 1 - num_used);
264
374k
    }
265
    // Assert that we didn't write more than what is available in cmd_line_msg
266
392k
    assert(cmd_line_size > num_used);
267
268
    // NOLINTBEGIN(cert-err33-c) - this is the logger itself; no sane recovery from a failed stderr write
269
    //fputs(cmd_line_msg, stderr);
270
    //fputs(msg, stderr);
271
    //fputc('\n', stderr);
272
    // NOLINTEND(cert-err33-c)
273
#if defined(WIN32)
274
    OutputDebugString(cmd_line_msg);
275
    OutputDebugString(msg);
276
    OutputDebugString("\n");
277
#endif
278
392k
}
279
280
void loader_log_asm_function_not_supported(const struct loader_instance *inst, VkFlags msg_type, int32_t msg_code,
281
0
                                           const char *func_name) {
282
0
    loader_log(inst, msg_type, msg_code, "Function %s not supported for this physical device", func_name);
283
0
}
284
285
0
void loader_log_generate_uuid_string(const uint8_t uuid[16], char output[UUID_STR_LEN]) {
286
0
    assert(uuid && output);
287
    // NOLINTNEXTLINE(cert-err33-c) - fixed format string and fixed-size output buffer sized to fit exactly; cannot fail or truncate
288
0
    snprintf(output, UUID_STR_LEN, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", uuid[0], uuid[1],
289
0
             uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7], uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13],
290
0
             uuid[14], uuid[15]);
291
0
}