0

this question comes from reading the kernel, more specifically the trace macros. I got to them when I was studying how the kernel modules executes binary, elf and scripts files (fs/exec.c).

For some reason, I don't remember which got to the tracepoint.h file, where the macro TRACE_EVENT, among others, is defined. I'm using trace_event as an example because the trace example in the kernel uses this macro. The example has this use of the macro

    TRACE_EVENT(foo_bar,

    TP_PROTO(const char *foo, int bar, const int *lst,
         const char *string, const struct cpumask *mask),

    TP_ARGS(foo, bar, lst, string, mask),

    TP_STRUCT__entry(
        __array(    char,   foo,    10      )
        __field(    int,    bar         )
        __dynamic_array(int,    list,   __length_of(lst))
        __string(   str,    string          )
        __bitmask(  cpus,   num_possible_cpus() )
    ),

    TP_fast_assign(
        strlcpy(__entry->foo, foo, 10);
        __entry->bar    = bar;
        memcpy(__get_dynamic_array(list), lst,
               __length_of(lst) * sizeof(int));
        __assign_str(str, string);
        __assign_bitmask(cpus, cpumask_bits(mask), num_possible_cpus());
    ),

    TP_printk("foo %s %d %s %s %s %s (%s)", __entry->foo, __entry->bar,
/*
 * Notice here the use of some helper functions. This includes:
 *
 *  __print_symbolic( variable, { value, "string" }, ... ),
 *
 *    The variable is tested against each value of the { } pair. If
 *    the variable matches one of the values, then it will print the
 *    string in that pair. If non are matched, it returns a string
 *    version of the number (if __entry->bar == 7 then "7" is returned).
 */
          __print_symbolic(__entry->bar,
                   { 0, "zero" },
                   { TRACE_SAMPLE_FOO, "TWO" },
                   { TRACE_SAMPLE_BAR, "FOUR" },
                   { TRACE_SAMPLE_ZOO, "EIGHT" },
                   { 10, "TEN" }
              ),

/*
 *  __print_flags( variable, "delim", { value, "flag" }, ... ),
 *
 *    This is similar to __print_symbolic, except that it tests the bits
 *    of the value. If ((FLAG & variable) == FLAG) then the string is
 *    printed. If more than one flag matches, then each one that does is
 *    also printed with delim in between them.
 *    If not all bits are accounted for, then the not found bits will be
 *    added in hex format: 0x506 will show BIT2|BIT4|0x500
 */
          __print_flags(__entry->bar, "|",
                { 1, "BIT1" },
                { 2, "BIT2" },
                { 4, "BIT3" },
                { 8, "BIT4" }
              ),
/*
 *  __print_array( array, len, element_size )
 *
 *    This prints out the array that is defined by __array in a nice format.
 */
          __print_array(__get_dynamic_array(list),
                __get_dynamic_array_len(list) / sizeof(int),
                sizeof(int)),
          __get_str(str), __get_bitmask(cpus))
);

So, naturally, after this I wentto the definition of TRACE_EVENT and found this

#define TRACE_EVENT(name, proto, args, struct, assign, print) \ DECLARE_TRACE(name, PARAMS(proto), PARAMS(args))

As you can see, the trace_event macro does not use the print parameter (or argument?), as well as the struct and assign parameters.

It is very clearly stated that the macro needs them, but underneath it all it is simply calling the declare_trace macro which doesn't need them.

As for the rest of the continuation of the macro expansion I'm ok with it, nothing unexpected, but this particular usage of the macro bugs me. Do all the other fields serve some purpose or are they just ... there with no reason whatsoever for existing?

morcillo
  • 1,091
  • 5
  • 19
  • 51
  • Nothing happens to unused arguments; they're ignored. Typically, there are (or sometimes once were) alternative implementations of the macro that do use the extra arguments. If the extra arguments are definitively never needed, you can use `0` or `(void)0` or some such placeholder value for the unused arguments when you invoke the macro. – Jonathan Leffler May 01 '17 at 19:26
  • I thought so. I was certain I was going crazy, why have 3 unused parameters? I believed I forgot something. They take really good care in those parameters so they must be used somewhere, or so I thought – morcillo May 01 '17 at 19:32
  • The trace system is some sort of dark cpp magic, take a look at http://lxr.free-electrons.com/ident?i=TRACE_EVENT and notice it gets redefined. You'll probably have to dig deeper into the docs to understand how it works. – pvg May 01 '17 at 19:38
  • @pvg well sh*t ... but again, I know it's using the one I displayed because it's a direct example of the tracepoint, also it includes only linux/tracepoint.h, which is where I got everything .. you can check the file trace-event-sample.c and trace-event-sample.h – morcillo May 01 '17 at 19:53
  • @morcillo I don't really know much about it, I'm afraid. Those sample files I think ended up getting removed. – pvg May 01 '17 at 20:16

1 Answers1

1

As correctly @pvg points, linux/tracepoint.h is just the tip of the iceberg of the tracepoints. This header only declares appropriate functions and types. That is why it doesn't handle some args for TRACE_EVENT.

But the header with trace definitions is processed twice (or even more times), and next time all arguments to TRACE_EVENT are handled.

More about tracepoints in Linux kernel see Documentation/trace/tracepoints.txt.

Tsyvarev
  • 60,011
  • 17
  • 110
  • 153