OSSL_TRACE_ENABLED(3ossl)

πŸ“¦ version 15.1, in freebsd 15.1

✨ OSSL_TRACE_ENABLED(3ossl) ✨

okay bestie, so like… the OpenSSL Tracing API is a thing, and it's part of the OpenSSL man crew (you know, the 3ossl section, iykyk). This whole page is literally about OSSL_trace_enabled, OSSL_trace_begin, OSSL_trace_end, OSSL_TRACE_BEGIN, OSSL_TRACE_END, OSSL_TRACE_CANCEL, OSSL_TRACE, OSSL_TRACE1, OSSL_TRACE2, OSSL_TRACE3, OSSL_TRACE4, OSSL_TRACE5, OSSL_TRACE6, OSSL_TRACE7, OSSL_TRACE8, OSSL_TRACE9, OSSL_TRACEV, OSSL_TRACE_STRING, OSSL_TRACE_STRING_MAX, OSSL_trace_string, and OSSL_TRACE_ENABLED. That's a LOT of names, but don't panic πŸ’…


🌸 SYNOPSIS 🌸

like, here's the whole vibe in code form:

#include <openssl/trace.h>

int OSSL_trace_enabled(int category);

BIO *OSSL_trace_begin(int category);
void OSSL_trace_end(int category, BIO *channel);

/* trace group macros */
OSSL_TRACE_BEGIN(category) {
    ...
    if (some_error) {
        /* Leave trace group prematurely in case of an error */
        OSSL_TRACE_CANCEL(category);
        goto err;
    }
    ...
} OSSL_TRACE_END(category);

/* one-shot trace macros */
OSSL_TRACE(category, text)
OSSL_TRACE1(category, format, arg1)
OSSL_TRACE2(category, format, arg1, arg2)
...
OSSL_TRACE9(category, format, arg1, ..., arg9)
OSSL_TRACE_STRING(category, text, full, data, len)

#define OSSL_TRACE_STRING_MAX 80
int OSSL_trace_string(BIO *out, int text, int full,
                      const unsigned char *data, size_t size);

/* check whether a trace category is enabled */
if (OSSL_TRACE_ENABLED(category)) {
    ...
}

πŸ¦‹ DESCRIPTION πŸ¦‹

So these functions are mainly for the girlies (and bros) who actually provide OpenSSL functionality β€” like, inside OpenSSL itself, or in engine modules or whatever similar thing you're building. Main character energy, honestly πŸ‘‘

If the tracing facility is enabled (peep "Configure Tracing" below πŸ‘‡), these functions are how you generate free-text tracing output. It's giving debug-lore.

The tracing output is split into types, and your app enables each one individually. The deets on these types live in "Trace types" over in OSSL_trace_set_callback(3). Oh, and heads up: the fallback type OSSL_TRACE_CATEGORY_ALL should not be used with the functions on this page. Not the vibe. πŸ™…β€β™€οΈ

Tracing for a specific category gets enabled at run-time if a so-called trace channel is attached to it. And what is a trace channel, you ask? It's literally just a BIO object that your app writes trace output to. Simple as that. πŸŽ€

Your app has two ways to register a trace channel:

That callback one gets wrapped internally by a dedicated BIO object, so from the tracing code's POV, both channel types are effectively indistinguishable. We call them a simple trace channel and a callback trace channel, respectively. Cute, right? 🫢

To actually produce trace output, you gotta:

  1. grab a pointer to the trace channel (the BIO object) using OSSL_trace_begin(),
  2. write to it using whatever BIO output routines you like, and
  3. release the channel using OSSL_trace_end().

The OSSL_trace_begin()/OSSL_trace_end() calls wrapping the output create a group, which acts as a critical section (guarded by a mutex) so that trace output from different threads doesn't get all mixed up. No messy group chat energy here, only clean threads. ✨

Normally the tracing code does not call OSSL_trace_{begin,end}() directly β€” it uses a set of convenience macros instead. Peep the "Macros" section below. πŸ’…

🌈 Functions 🌈

  • OSSL_trace_enabled() β€” use this to check if tracing for the given category is enabled, i.e. if the tracing facility was statically enabled (see "Configure Tracing" below) AND a trace channel was registered via OSSL_trace_set_channel(3) or OSSL_trace_set_callback(3).
  • OSSL_trace_begin() β€” starts a tracing section and hands you the channel for the given category as a BIO. This BIO can ONLY be used for output. The pointer it returns is NULL if the category is invalid or not enabled. Sorry bestie 😭
  • OSSL_trace_end() β€” ends a tracing section. That's it, that's the function.
  • OSSL_trace_string() β€” outputs data of length size as a string on BIO out. If text is 0, it masks any included control characters apart from newlines and makes sure that for nonempty input the output ends with a newline. Unless full is nonzero, the length is limited (with a suitable warning) to OSSL_TRACE_STRING_MAX characters β€” which currently is 80.
Using OSSL_trace_begin() and OSSL_trace_end() to wrap tracing sections is mandatory. Trying to produce tracing output outside of such sections is undefined behaviour. Like, don't. πŸ’€

πŸŽ€ Macros πŸŽ€

There's a whole set of convenience macros defined to make tracing easy and consistent. Obsessed.

OSSL_TRACE_BEGIN() and OSSL_TRACE_END() reserve the BIO "trc_out" and are used like this to wrap a trace section:

OSSL_TRACE_BEGIN(TLS) {

    BIO_printf(trc_out, ... );

} OSSL_TRACE_END(TLS);

Which normally expands to:

do {
    BIO *trc_out = OSSL_trace_begin(OSSL_TRACE_CATEGORY_TLS);
    if (trc_out != NULL) {
        ...
        BIO_printf(trc_out, ...);
    }
    OSSL_trace_end(OSSL_TRACE_CATEGORY_TLS, trc_out);
} while (0);

OSSL_TRACE_CANCEL() must be used before returning from or jumping out of a trace section:

OSSL_TRACE_BEGIN(TLS) {

    if (some_error) {
        OSSL_TRACE_CANCEL(TLS);
        goto err;
    }
    BIO_printf(trc_out, ... );

} OSSL_TRACE_END(TLS);

Which normally expands to:

do {
    BIO *trc_out = OSSL_trace_begin(OSSL_TRACE_CATEGORY_TLS);
    if (trc_out != NULL) {
        if (some_error) {
            OSSL_trace_end(OSSL_TRACE_CATEGORY_TLS, trc_out);
            goto err;
        }
        BIO_printf(trc_out, ... );
    }
    OSSL_trace_end(OSSL_TRACE_CATEGORY_TLS, trc_out);
} while (0);

OSSL_TRACE() and OSSL_TRACE1(), OSSL_TRACE2(), … OSSL_TRACE9() are the so-called one-shot macros:

  • The macro call OSSL_TRACE(category, text) produces literal text trace output.
  • The macro call OSSL_TRACEn(category, format, arg1, ..., argn) produces printf-style trace output with n format field arguments (n=1,…,9). It expands to:
OSSL_TRACE_BEGIN(category) {
    BIO_printf(trc_out, format, arg1, ..., argN);
} OSSL_TRACE_END(category)

Internally, ALL the one-shot macros are implemented using a generic OSSL_TRACEV() macro, because C90 does not support variadic macros. This helper macro has a rather weird synopsis and should not be used directly. Like, don't even try it, bestie. πŸ™ˆ

The macro call OSSL_TRACE_STRING(category, text, full, data, len) outputs data of length size as a string if tracing for the given category is enabled. It expands to:

OSSL_TRACE_BEGIN(category) {
    OSSL_trace_string(trc_out, text, full, data, len);
} OSSL_TRACE_END(category)

The OSSL_TRACE_ENABLED() macro can be used to conditionally execute some code ONLY if a specific trace category is enabled. In some situations this is simpler than entering a trace section using OSSL_TRACE_BEGIN() and OSSL_TRACE_END(). For example, the code:

if (OSSL_TRACE_ENABLED(TLS)) {
    ...
}

expands to:

if (OSSL_trace_enabled(OSSL_TRACE_CATEGORY_TLS) {
    ...
}

πŸ’œ NOTES πŸ’œ

It is not needed to guard trace output function calls like OSSL_TRACE(category, ...) by OSSL_TRACE_ENABLED(category). Like, they already handle that. Chill. 😌

If producing the trace output requires carrying out auxiliary calculations, that auxiliary code should be placed inside a conditional block which only executes if the trace category is enabled.

The most natural way to do this is to place the code inside the trace section itself, because it already introduces such a conditional block:

OSSL_TRACE_BEGIN(TLS) {
    int var = do_some_auxiliary_calculation();

    BIO_printf(trc_out, "var = %d\n", var);

} OSSL_TRACE_END(TLS);

In some cases it's more advantageous to use a simple conditional group instead of a trace section. This happens when calculations and tracing happen in different locations of the code, or if the calculations are so time-consuming that placing them inside a (critical) trace section would create too much contention:

if (OSSL_TRACE_ENABLED(TLS)) {
    int var = do_some_auxiliary_calculation();

    OSSL_TRACE1("var = %d\n", var);
}

But ngl, premature optimization of tracing code is in general futile and it's better to keep the tracing code as simple as possible. Because most often the limiting factor for the application's speed is the time it takes to print the trace output, not to calculate it. Periodt. πŸ”₯

πŸ‘‘ Configure Tracing πŸ‘‘

By default, the OpenSSL library is built with tracing disabled. So to use the tracing functionality documented here, you've gotta configure and build OpenSSL with the 'enable-trace' option. Slay that build config, bestie.

When the library is built with tracing disabled:

  • The macro OPENSSL_NO_TRACE is defined in <openssl/opensslconf.h>.
  • All functions are still present, but OSSL_trace_enabled() will always report the categories as disabled, and all other functions will do nothing.
  • The convenience macros are defined to produce dead code. For example, take this example from the "Macros" section above:
OSSL_TRACE_BEGIN(TLS) {

    if (condition) {
        OSSL_TRACE_CANCEL(TLS);
        goto err;
    }
    BIO_printf(trc_out, ... );

} OSSL_TRACE_END(TLS);

When the tracing API isn't operational, that expands to:

do {
    BIO *trc_out = NULL;
    if (0) {
        if (condition) {
            ((void)0);
            goto err;
        }
        BIO_printf(trc_out, ... );
    }
} while (0);

🌟 RETURN VALUES 🌟

  • OSSL_trace_enabled() returns 1 if tracing for the given type is operational and enabled, otherwise 0.
  • OSSL_trace_begin() returns a BIO pointer if the given type is enabled, otherwise NULL.
  • OSSL_trace_string() returns the number of characters emitted, or -1 on error.

πŸ’– SEE ALSO πŸ’–

OSSL_trace_set_channel(3), OSSL_trace_set_callback(3)


πŸ“ HISTORY πŸ“

The OpenSSL Tracing API was added in OpenSSL 3.0.

OSSL_TRACE_STRING(), OSSL_TRACE_STRING_MAX, and OSSL_trace_string were added in OpenSSL 3.2. Glow-up era. ✨


Copyright 2019-2023 The OpenSSL Project Authors. All Rights Reserved.

Licensed under the Apache License 2.0 (the "License"). You may not use this file except in compliance with the License. You can obtain a copy in the file LICENSE in the source distribution or at <https://www.openssl.org/source/license.html>.


ok that's literally the whole page, you ate that πŸ’… this was version 3.5.6 dated 2026-04-07, from the OSSL_TRACE_ENABLED(3ossl) manual. go forth and trace, bestie πŸ¦‹βœ¨
πŸ“¦ where this page comes from