#include <stdarg.h>
+/* Maximum number of callbacks per marker */
+#define LTT_NR_CALLBACKS 10
+
/* LTT flags
*
* LTT_FLAG_TRACE : first arg contains trace to write into.
#define LTT_FLAG_FORCE (1 << _LTT_FLAG_FORCE)
-char *(*ltt_serialize_cb)(char *buffer, const char *fmt, va_list args);
+char *(*ltt_serialize_cb)(char *buffer, int *cb_args,
+ const char *fmt, va_list args);
static int skip_atoi(const char **s)
/* Inspired from vsnprintf */
/* New types :
- * %r : serialized pointer.
+ * %r : serialized fixed length struct, union, array.
+ * %v : serialized sequence
+ * %k : callback
*/
static inline __attribute__((no_instrument_function))
-char *ltt_serialize_data(char *buffer, const char *fmt, va_list args)
+char *ltt_serialize_data(char *buffer, int *cb_args,
+ const char *fmt, va_list args)
{
int len;
const char *s;
/* 't' added for ptrdiff_t */
char *str; /* Pointer to write to */
ltt_serialize_cb cb;
+ int cb_arg_nr = 0;
str = buf;
if (buffer)
strcpy(str, s);
str += strlen(s);
+ /* Following alignment for genevent
+ * compatibility */
+ str += ltt_align(str, sizeof(void*));
continue;
case 'p':
memcpy(str, src, elem_size);
str += elem_size;
}
+ /* Following alignment for genevent
+ * compatibility */
+ str += ltt_align(str, sizeof(void*));
continue;
case 'k':
/* The callback will take as many arguments
* as it needs from args. They won't be
* type verified. */
- str = cb(str, fmt, args);
+ if (cb_arg_nr < LTT_NR_CALLBACKS)
+ str = cb(str, &cb_args[cb_arg_nr++],
+ fmt, args);
continue;
case 'n':
/* FIXME:
- * What does C99 say about the overflow case here? */
+ * What does C99 say about the overflow case
+ * here? */
if (qualifier == 'l') {
long * ip = va_arg(args, long *);
*ip = (str - buf);
- } else if (qualifier == 'Z' || qualifier == 'z') {
+ } else if (qualifier == 'Z'
+ || qualifier == 'z') {
size_t * ip = va_arg(args, size_t *);
*ip = (str - buf);
} else {
if (buffer)
switch (elem_size) {
case 1:
- *(int8_t*)str = (int8_t)va_arg(args, int);
+ *(int8_t*)str =
+ (int8_t)va_arg(args, int);
break;
case 2:
- *(int16_t*)str = (int16_t)va_arg(args, int);
+ *(int16_t*)str =
+ (int16_t)va_arg(args, int);
break;
case 4:
*(int32_t*)str = va_arg(args, int32_t);
* sizeof(void *) address. */
static inline __attribute__((no_instrument_function))
size_t ltt_get_data_size(ltt_facility_t fID, uint8_t eID,
+ int *cb_args,
const char *fmt, va_list args)
{
return (size_t)ltt_serialize_data(NULL, fmt, args);
static inline __attribute__((no_instrument_function))
void ltt_write_event_data(char *buffer,
ltt_facility_t fID, uint8_t eID,
+ int *cb_args,
const char *fmt, va_list args)
{
ltt_serialize_data(buffer, fmt, args);
uint64_t tsc;
char *buffer;
va_list args_copy;
+ int cb_args[LTT_NR_CALLBACKS];
/* This test is useful for quickly exiting static tracing when no
* trace is active. */
- if (likely(ltt_traces.num_active_traces == 0 && !(flags & LTT_FLAG_FORCE)))
+ if (likely(ltt_traces.num_active_traces == 0
+ && !(flags & LTT_FLAG_FORCE)))
return;
preempt_disable();
channel_index = ltt_get_channel_index(fID, eID);
va_copy(args_copy, args); /* Check : skip 2 st args if trace/ch */
- data_size = ltt_get_data_size(fID, eID, fmt, args_copy);
+ data_size = ltt_get_data_size(fID, eID, cb_args, fmt, args_copy);
va_end(args_copy);
/* Iterate on each traces */
buffer = ltt_write_event_header(trace, channel, buffer,
fID, eID, data_size, tsc);
va_copy(args_copy, args);
- ltt_write_event_data(buffer, fID, eID, fmt, args_copy);
+ ltt_write_event_data(buffer, fID, eID, cb_args, fmt, args_copy);
va_end(args_copy);
/* Out-of-order commit */
ltt_commit_slot(channel, &transport_data, buffer, slot_size);