Coverage Report

Created: 2026-08-26 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tpm2-tss/src/util/log.c
Line
Count
Source
1
/* SPDX-FileCopyrightText: 2018 - 2022, Intel */
2
/* SPDX-FileCopyrightText: 2018 - 2020, Fraunhofer SIT sponsored by Infineon */
3
/* SPDX-FileCopyrightText: 2019, Fabrice Funtaine */
4
/* SPDX-FileCopyrightText: 2019, Alon Bar-Lev */
5
/* SPDX-FileCopyrightText: 2019 - 2022, Infineon Technologies AG */
6
/* SPDX-FileCopyrightText: 2022, Juergen Repp */
7
/* SPDX-License-Identifier: BSD-2-Clause */
8
#ifdef HAVE_CONFIG_H
9
#include "config.h" // IWYU pragma: keep
10
#endif
11
12
#include <ctype.h>
13
#include <errno.h>
14
#include <stdarg.h>
15
#include <stdio.h>
16
#include <stdlib.h>
17
#include <string.h>
18
19
#define LOGMODULE log
20
#include "log.h"
21
22
#if !defined(_MSC_VER) || defined(__INTEL_COMPILER)
23
#define likely(x)   __builtin_expect(!!(x), 1)
24
438
#define unlikely(x) __builtin_expect(!!(x), 0)
25
#else
26
/* Microsoft Visual Studio gives internal error C1001 with _builtin_expect */
27
#define likely(x)   (x)
28
#define unlikely(x) (x)
29
#endif
30
31
#if MAXLOGLEVEL != LOGL_NONE
32
33
static const char *log_strings[]
34
    = { "none", "(unused)", "ERROR", "WARNING", "info", "debug", "trace" };
35
36
/**
37
 * Compares two strings byte by byte and ignores the
38
 * character's case. Stops at the n-th byte of both
39
 * strings.
40
 *
41
 * This is basically a replacement of the POSIX-function
42
 * _strncasecmp_. Since tpm2-tss is supposed to be compatible
43
 * with ISO C99 and not with POSIX, _strncasecmp_ had to be
44
 * replaced. This function creates lowercase representations
45
 * of the strings and compares them bytewise.
46
 *
47
 * @param string1 The first of the two strings to compare
48
 * @param string2 The second of the two strings to compare
49
 * @param n The maximum number of bytes to compare
50
 * @return 0 if both strings are equal (case insensitive),
51
 *  an integer greater than zero if string1 is greater than
52
 *  string 2 and an integer smaller than zero if string1 is
53
 *  smaller than string2
54
 *
55
 */
56
static int
57
0
case_insensitive_strncmp(const char *string1, const char *string2, size_t n) {
58
0
    if ((string1 == NULL) && (string2 == NULL)) {
59
0
        return 0;
60
0
    }
61
0
    if ((string1 == NULL) && (string2 != NULL)) {
62
0
        return -1;
63
0
    }
64
0
    if ((string1 != NULL) && (string2 == NULL)) {
65
0
        return 1;
66
0
    }
67
0
    if (n == 0) { // Zero bytes are always equal
68
0
        return 0;
69
0
    }
70
0
    if (string1 == string2) { // return equal if they point to same location
71
0
        return 0;
72
0
    }
73
74
0
    int result;
75
0
    do {
76
0
        result = tolower((unsigned char)*string1) - tolower((unsigned char)*string2);
77
0
        if (result != 0) {
78
0
            break;
79
0
        }
80
0
    } while (*string1++ != '\0' && *string2++ != '\0' && --n);
81
0
    return result;
82
0
}
83
84
static log_level getLogLevel(const char *module, log_level logdefault);
85
86
static FILE *
87
438
getLogFile(void) {
88
438
#ifdef LOG_FILE_ENABLED
89
438
    const char  *envpath;
90
438
    static FILE *file = NULL;
91
92
438
    if (file) {
93
219
        return file;
94
219
    }
95
96
219
    envpath = getenv("TSS2_LOGFILE");
97
219
    if (envpath == NULL || !case_insensitive_strncmp(envpath, "stderr", 7)) {
98
219
        file = stderr;
99
219
    } else if (!strcmp(envpath, "-") || !case_insensitive_strncmp(envpath, "stdout", 7)) {
100
0
        file = stdout;
101
0
    } else {
102
0
        file = fopen(envpath, "a+");
103
0
        if (file == NULL) {
104
0
            file = stderr;
105
0
            fprintf(file, "Failed to open logging file %s: %s\n", envpath, strerror(errno));
106
0
            fflush(file);
107
0
        }
108
0
    }
109
110
219
    return file;
111
#else
112
    return stderr;
113
#endif
114
438
}
115
116
void
117
doLogBlob(log_level      loglevel,
118
          const char    *module,
119
          log_level      logdefault,
120
          log_level     *status,
121
          const char    *file,
122
          const char    *func,
123
          int            line,
124
          const uint8_t *blob,
125
          size_t         size,
126
          const char    *fmt,
127
0
          ...) {
128
0
    FILE *logfile;
129
0
    if (unlikely(*status == LOGLEVEL_UNDEFINED))
130
0
        *status = getLogLevel(module, logdefault);
131
0
    if (loglevel > *status)
132
0
        return;
133
134
0
    va_list vaargs;
135
0
    va_start(vaargs, fmt);
136
    /* TODO: Unfortunately, vsnprintf(NULL, 0, ...) do not behave the same as
137
       snprintf(NULL, 0, ...). Until there is an alternative, messages on
138
       logblob are restricted to 255 characters
139
    int msg_len = vsnprintf(NULL, 0, fmt, vaargs); */
140
0
    int  msg_len = 255;
141
0
    char msg[msg_len + 1];
142
0
    vsnprintf(msg, sizeof(msg), fmt, vaargs);
143
0
    va_end(vaargs);
144
145
0
    if (!blob) {
146
0
        doLog(loglevel, module, logdefault, status, file, func, line, "%s (size=%zi): (null)", msg,
147
0
              size);
148
0
        return;
149
0
    }
150
151
0
    doLog(loglevel, module, logdefault, status, file, func, line, "%s (size=%zi):", msg, size);
152
153
0
    unsigned int i, y, x, off, off2;
154
0
    unsigned int width = 16;
155
0
#define LINE_LEN 64
156
0
    char buffer[LINE_LEN];
157
158
0
    for (i = 1, off = 0, off2 = 0; i <= size; i++) {
159
0
        if (i == 1) {
160
0
            sprintf(&buffer[off], "%04x: ", i - 1);
161
0
            off += 6;
162
0
        }
163
164
        /* data output */
165
0
        sprintf(&buffer[off], "%02x", blob[i - 1]);
166
0
        off += 2;
167
168
        /* ASCII output */
169
0
        if ((i % width == 0 && i > 1) || i == size) {
170
0
            sprintf(&buffer[off], "  ");
171
0
            off += 2;
172
            /* Align to the right */
173
0
            for (x = off; x < width * 2 + 8; x++) {
174
0
                sprintf(&buffer[off], " ");
175
0
                off++;
176
0
            }
177
178
            /* Account for a line that is not 'full' */
179
0
            unsigned int less = width - (i % width);
180
0
            if (less == width)
181
0
                less = 0;
182
183
0
            for (y = 0; y < width - less; y++) {
184
0
                if (isgraph(blob[off2 + y])) {
185
0
                    sprintf(&buffer[y + off], "%c", blob[off2 + y]);
186
0
                } else {
187
0
                    sprintf(&buffer[y + off], "%c", '.');
188
0
                }
189
0
            }
190
            /* print the line and restart */
191
0
            logfile = getLogFile();
192
0
            fprintf(logfile, "%s\n", buffer);
193
0
            fflush(logfile);
194
0
            off2 = i;
195
0
            off = 0;
196
0
            memset(buffer, '\0', LINE_LEN);
197
0
            sprintf(&buffer[off], "%04x: ", i);
198
0
            off += 6;
199
0
        }
200
0
    }
201
0
}
202
203
void
204
doLog(log_level   loglevel,
205
      const char *module,
206
      log_level   logdefault,
207
      log_level  *status,
208
      const char *file,
209
      const char *func,
210
      int         line,
211
      const char *msg,
212
438
      ...) {
213
438
    FILE *logfile;
214
438
    if (unlikely(*status == LOGLEVEL_UNDEFINED))
215
219
        *status = getLogLevel(module, logdefault);
216
217
438
    if (loglevel > *status)
218
0
        return;
219
220
438
    int  size = snprintf(NULL, 0, "%s:%s:%s:%d:%s() %s \n", log_strings[loglevel], module, file,
221
438
                         line, func, msg);
222
438
    char fmt[size + 1];
223
438
    snprintf(fmt, sizeof(fmt), "%s:%s:%s:%d:%s() %s \n", log_strings[loglevel], module, file, line,
224
438
             func, msg);
225
226
438
    va_list vaargs;
227
438
    va_start(vaargs, msg);
228
438
    logfile = getLogFile();
229
438
    vfprintf(logfile, fmt,
230
             /* log_strings[loglevel], module, file, func, line, */
231
438
             vaargs);
232
438
    fflush(logfile);
233
438
    va_end(vaargs);
234
438
}
235
236
static log_level
237
0
log_stringlevel(const char *n) {
238
0
    log_level i;
239
0
    for (i = 0; i < sizeof(log_strings) / sizeof(log_strings[0]); i++) {
240
0
        if (case_insensitive_strncmp(log_strings[i], n, strlen(log_strings[i])) == 0) {
241
0
            return i;
242
0
        }
243
0
    }
244
0
    return LOGLEVEL_UNDEFINED;
245
0
}
246
247
static log_level
248
219
getLogLevel(const char *module, log_level logdefault) {
249
219
    log_level   loglevel = logdefault;
250
219
    const char *envlevel = getenv("TSS2_LOG");
251
219
    const char *i = envlevel;
252
219
    if (envlevel == NULL)
253
219
        return loglevel;
254
0
    while ((i = strchr(i, '+')) != NULL) {
255
0
        if ((envlevel <= i - strlen("all") && case_insensitive_strncmp(i - 3, "all", 3) == 0)
256
0
            || (envlevel <= i - strlen(module)
257
0
                && case_insensitive_strncmp(i - strlen(module), module, strlen(module)) == 0)) {
258
0
            log_level tmp = log_stringlevel(i + 1);
259
0
            if (tmp != LOGLEVEL_UNDEFINED)
260
0
                loglevel = tmp;
261
0
        }
262
0
        i = i + 1;
263
0
    }
264
0
    return loglevel;
265
219
}
266
#endif