Home | History | Annotate | Download | only in traceevent
      1 /*
      2  * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt (at) redhat.com>
      3  *
      4  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      5  * This program is free software; you can redistribute it and/or
      6  * modify it under the terms of the GNU Lesser General Public
      7  * License as published by the Free Software Foundation;
      8  * version 2.1 of the License (not later!)
      9  *
     10  * This program is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  * GNU Lesser General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU Lesser General Public
     16  * License along with this program; if not,  see <http://www.gnu.org/licenses>
     17  *
     18  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     19  */
     20 #include <stdio.h>
     21 #include <stdlib.h>
     22 #include <string.h>
     23 #include <stdarg.h>
     24 
     25 #include "event-parse.h"
     26 #include "event-utils.h"
     27 
     28 /*
     29  * The TRACE_SEQ_POISON is to catch the use of using
     30  * a trace_seq structure after it was destroyed.
     31  */
     32 #define TRACE_SEQ_POISON	((void *)0xdeadbeef)
     33 #define TRACE_SEQ_CHECK(s)						\
     34 do {									\
     35 	if ((s)->buffer == TRACE_SEQ_POISON)			\
     36 		die("Usage of trace_seq after it was destroyed");	\
     37 } while (0)
     38 
     39 /**
     40  * trace_seq_init - initialize the trace_seq structure
     41  * @s: a pointer to the trace_seq structure to initialize
     42  */
     43 void trace_seq_init(struct trace_seq *s)
     44 {
     45 	s->len = 0;
     46 	s->readpos = 0;
     47 	s->buffer_size = TRACE_SEQ_BUF_SIZE;
     48 	s->buffer = malloc_or_die(s->buffer_size);
     49 }
     50 
     51 /**
     52  * trace_seq_reset - re-initialize the trace_seq structure
     53  * @s: a pointer to the trace_seq structure to reset
     54  */
     55 void trace_seq_reset(struct trace_seq *s)
     56 {
     57 	if (!s)
     58 		return;
     59 	TRACE_SEQ_CHECK(s);
     60 	s->len = 0;
     61 	s->readpos = 0;
     62 }
     63 
     64 /**
     65  * trace_seq_destroy - free up memory of a trace_seq
     66  * @s: a pointer to the trace_seq to free the buffer
     67  *
     68  * Only frees the buffer, not the trace_seq struct itself.
     69  */
     70 void trace_seq_destroy(struct trace_seq *s)
     71 {
     72 	if (!s)
     73 		return;
     74 	TRACE_SEQ_CHECK(s);
     75 	free(s->buffer);
     76 	s->buffer = TRACE_SEQ_POISON;
     77 }
     78 
     79 static void expand_buffer(struct trace_seq *s)
     80 {
     81 	s->buffer_size += TRACE_SEQ_BUF_SIZE;
     82 	s->buffer = realloc(s->buffer, s->buffer_size);
     83 	if (!s->buffer)
     84 		die("Can't allocate trace_seq buffer memory");
     85 }
     86 
     87 /**
     88  * trace_seq_printf - sequence printing of trace information
     89  * @s: trace sequence descriptor
     90  * @fmt: printf format string
     91  *
     92  * It returns 0 if the trace oversizes the buffer's free
     93  * space, 1 otherwise.
     94  *
     95  * The tracer may use either sequence operations or its own
     96  * copy to user routines. To simplify formating of a trace
     97  * trace_seq_printf is used to store strings into a special
     98  * buffer (@s). Then the output may be either used by
     99  * the sequencer or pulled into another buffer.
    100  */
    101 int
    102 trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
    103 {
    104 	va_list ap;
    105 	int len;
    106 	int ret;
    107 
    108 	TRACE_SEQ_CHECK(s);
    109 
    110  try_again:
    111 	len = (s->buffer_size - 1) - s->len;
    112 
    113 	va_start(ap, fmt);
    114 	ret = vsnprintf(s->buffer + s->len, len, fmt, ap);
    115 	va_end(ap);
    116 
    117 	if (ret >= len) {
    118 		expand_buffer(s);
    119 		goto try_again;
    120 	}
    121 
    122 	s->len += ret;
    123 
    124 	return 1;
    125 }
    126 
    127 /**
    128  * trace_seq_vprintf - sequence printing of trace information
    129  * @s: trace sequence descriptor
    130  * @fmt: printf format string
    131  *
    132  * The tracer may use either sequence operations or its own
    133  * copy to user routines. To simplify formating of a trace
    134  * trace_seq_printf is used to store strings into a special
    135  * buffer (@s). Then the output may be either used by
    136  * the sequencer or pulled into another buffer.
    137  */
    138 int
    139 trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args)
    140 {
    141 	int len;
    142 	int ret;
    143 
    144 	TRACE_SEQ_CHECK(s);
    145 
    146  try_again:
    147 	len = (s->buffer_size - 1) - s->len;
    148 
    149 	ret = vsnprintf(s->buffer + s->len, len, fmt, args);
    150 
    151 	if (ret >= len) {
    152 		expand_buffer(s);
    153 		goto try_again;
    154 	}
    155 
    156 	s->len += ret;
    157 
    158 	return len;
    159 }
    160 
    161 /**
    162  * trace_seq_puts - trace sequence printing of simple string
    163  * @s: trace sequence descriptor
    164  * @str: simple string to record
    165  *
    166  * The tracer may use either the sequence operations or its own
    167  * copy to user routines. This function records a simple string
    168  * into a special buffer (@s) for later retrieval by a sequencer
    169  * or other mechanism.
    170  */
    171 int trace_seq_puts(struct trace_seq *s, const char *str)
    172 {
    173 	int len;
    174 
    175 	TRACE_SEQ_CHECK(s);
    176 
    177 	len = strlen(str);
    178 
    179 	while (len > ((s->buffer_size - 1) - s->len))
    180 		expand_buffer(s);
    181 
    182 	memcpy(s->buffer + s->len, str, len);
    183 	s->len += len;
    184 
    185 	return len;
    186 }
    187 
    188 int trace_seq_putc(struct trace_seq *s, unsigned char c)
    189 {
    190 	TRACE_SEQ_CHECK(s);
    191 
    192 	while (s->len >= (s->buffer_size - 1))
    193 		expand_buffer(s);
    194 
    195 	s->buffer[s->len++] = c;
    196 
    197 	return 1;
    198 }
    199 
    200 void trace_seq_terminate(struct trace_seq *s)
    201 {
    202 	TRACE_SEQ_CHECK(s);
    203 
    204 	/* There's always one character left on the buffer */
    205 	s->buffer[s->len] = 0;
    206 }
    207 
    208 int trace_seq_do_printf(struct trace_seq *s)
    209 {
    210 	TRACE_SEQ_CHECK(s);
    211 	return printf("%.*s", s->len, s->buffer);
    212 }
    213