diff options
Diffstat (limited to 'tools/lib/traceevent/trace-seq.c')
-rw-r--r-- | tools/lib/traceevent/trace-seq.c | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/tools/lib/traceevent/trace-seq.c b/tools/lib/traceevent/trace-seq.c new file mode 100644 index 000000000000..d2f265b48cde --- /dev/null +++ b/tools/lib/traceevent/trace-seq.c | |||
@@ -0,0 +1,199 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@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, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | * | ||
19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
20 | */ | ||
21 | #include <stdio.h> | ||
22 | #include <stdlib.h> | ||
23 | #include <string.h> | ||
24 | #include <stdarg.h> | ||
25 | |||
26 | #include "event-parse.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_destroy - free up memory of a trace_seq | ||
53 | * @s: a pointer to the trace_seq to free the buffer | ||
54 | * | ||
55 | * Only frees the buffer, not the trace_seq struct itself. | ||
56 | */ | ||
57 | void trace_seq_destroy(struct trace_seq *s) | ||
58 | { | ||
59 | if (!s) | ||
60 | return; | ||
61 | TRACE_SEQ_CHECK(s); | ||
62 | free(s->buffer); | ||
63 | s->buffer = TRACE_SEQ_POISON; | ||
64 | } | ||
65 | |||
66 | static void expand_buffer(struct trace_seq *s) | ||
67 | { | ||
68 | s->buffer_size += TRACE_SEQ_BUF_SIZE; | ||
69 | s->buffer = realloc(s->buffer, s->buffer_size); | ||
70 | if (!s->buffer) | ||
71 | die("Can't allocate trace_seq buffer memory"); | ||
72 | } | ||
73 | |||
74 | /** | ||
75 | * trace_seq_printf - sequence printing of trace information | ||
76 | * @s: trace sequence descriptor | ||
77 | * @fmt: printf format string | ||
78 | * | ||
79 | * It returns 0 if the trace oversizes the buffer's free | ||
80 | * space, 1 otherwise. | ||
81 | * | ||
82 | * The tracer may use either sequence operations or its own | ||
83 | * copy to user routines. To simplify formating of a trace | ||
84 | * trace_seq_printf is used to store strings into a special | ||
85 | * buffer (@s). Then the output may be either used by | ||
86 | * the sequencer or pulled into another buffer. | ||
87 | */ | ||
88 | int | ||
89 | trace_seq_printf(struct trace_seq *s, const char *fmt, ...) | ||
90 | { | ||
91 | va_list ap; | ||
92 | int len; | ||
93 | int ret; | ||
94 | |||
95 | TRACE_SEQ_CHECK(s); | ||
96 | |||
97 | try_again: | ||
98 | len = (s->buffer_size - 1) - s->len; | ||
99 | |||
100 | va_start(ap, fmt); | ||
101 | ret = vsnprintf(s->buffer + s->len, len, fmt, ap); | ||
102 | va_end(ap); | ||
103 | |||
104 | if (ret >= len) { | ||
105 | expand_buffer(s); | ||
106 | goto try_again; | ||
107 | } | ||
108 | |||
109 | s->len += ret; | ||
110 | |||
111 | return 1; | ||
112 | } | ||
113 | |||
114 | /** | ||
115 | * trace_seq_vprintf - sequence printing of trace information | ||
116 | * @s: trace sequence descriptor | ||
117 | * @fmt: printf format string | ||
118 | * | ||
119 | * The tracer may use either sequence operations or its own | ||
120 | * copy to user routines. To simplify formating of a trace | ||
121 | * trace_seq_printf is used to store strings into a special | ||
122 | * buffer (@s). Then the output may be either used by | ||
123 | * the sequencer or pulled into another buffer. | ||
124 | */ | ||
125 | int | ||
126 | trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args) | ||
127 | { | ||
128 | int len; | ||
129 | int ret; | ||
130 | |||
131 | TRACE_SEQ_CHECK(s); | ||
132 | |||
133 | try_again: | ||
134 | len = (s->buffer_size - 1) - s->len; | ||
135 | |||
136 | ret = vsnprintf(s->buffer + s->len, len, fmt, args); | ||
137 | |||
138 | if (ret >= len) { | ||
139 | expand_buffer(s); | ||
140 | goto try_again; | ||
141 | } | ||
142 | |||
143 | s->len += ret; | ||
144 | |||
145 | return len; | ||
146 | } | ||
147 | |||
148 | /** | ||
149 | * trace_seq_puts - trace sequence printing of simple string | ||
150 | * @s: trace sequence descriptor | ||
151 | * @str: simple string to record | ||
152 | * | ||
153 | * The tracer may use either the sequence operations or its own | ||
154 | * copy to user routines. This function records a simple string | ||
155 | * into a special buffer (@s) for later retrieval by a sequencer | ||
156 | * or other mechanism. | ||
157 | */ | ||
158 | int trace_seq_puts(struct trace_seq *s, const char *str) | ||
159 | { | ||
160 | int len; | ||
161 | |||
162 | TRACE_SEQ_CHECK(s); | ||
163 | |||
164 | len = strlen(str); | ||
165 | |||
166 | while (len > ((s->buffer_size - 1) - s->len)) | ||
167 | expand_buffer(s); | ||
168 | |||
169 | memcpy(s->buffer + s->len, str, len); | ||
170 | s->len += len; | ||
171 | |||
172 | return len; | ||
173 | } | ||
174 | |||
175 | int trace_seq_putc(struct trace_seq *s, unsigned char c) | ||
176 | { | ||
177 | TRACE_SEQ_CHECK(s); | ||
178 | |||
179 | while (s->len >= (s->buffer_size - 1)) | ||
180 | expand_buffer(s); | ||
181 | |||
182 | s->buffer[s->len++] = c; | ||
183 | |||
184 | return 1; | ||
185 | } | ||
186 | |||
187 | void trace_seq_terminate(struct trace_seq *s) | ||
188 | { | ||
189 | TRACE_SEQ_CHECK(s); | ||
190 | |||
191 | /* There's always one character left on the buffer */ | ||
192 | s->buffer[s->len] = 0; | ||
193 | } | ||
194 | |||
195 | int trace_seq_do_printf(struct trace_seq *s) | ||
196 | { | ||
197 | TRACE_SEQ_CHECK(s); | ||
198 | return printf("%.*s", s->len, s->buffer); | ||
199 | } | ||