diff options
Diffstat (limited to 'tools/lib/traceevent/trace-seq.c')
-rw-r--r-- | tools/lib/traceevent/trace-seq.c | 200 |
1 files changed, 200 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..b1ccc923e8a5 --- /dev/null +++ b/tools/lib/traceevent/trace-seq.c | |||
@@ -0,0 +1,200 @@ | |||
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 | #include "event-utils.h" | ||
28 | |||
29 | /* | ||
30 | * The TRACE_SEQ_POISON is to catch the use of using | ||
31 | * a trace_seq structure after it was destroyed. | ||
32 | */ | ||
33 | #define TRACE_SEQ_POISON ((void *)0xdeadbeef) | ||
34 | #define TRACE_SEQ_CHECK(s) \ | ||
35 | do { \ | ||
36 | if ((s)->buffer == TRACE_SEQ_POISON) \ | ||
37 | die("Usage of trace_seq after it was destroyed"); \ | ||
38 | } while (0) | ||
39 | |||
40 | /** | ||
41 | * trace_seq_init - initialize the trace_seq structure | ||
42 | * @s: a pointer to the trace_seq structure to initialize | ||
43 | */ | ||
44 | void trace_seq_init(struct trace_seq *s) | ||
45 | { | ||
46 | s->len = 0; | ||
47 | s->readpos = 0; | ||
48 | s->buffer_size = TRACE_SEQ_BUF_SIZE; | ||
49 | s->buffer = malloc_or_die(s->buffer_size); | ||
50 | } | ||
51 | |||
52 | /** | ||
53 | * trace_seq_destroy - free up memory of a trace_seq | ||
54 | * @s: a pointer to the trace_seq to free the buffer | ||
55 | * | ||
56 | * Only frees the buffer, not the trace_seq struct itself. | ||
57 | */ | ||
58 | void trace_seq_destroy(struct trace_seq *s) | ||
59 | { | ||
60 | if (!s) | ||
61 | return; | ||
62 | TRACE_SEQ_CHECK(s); | ||
63 | free(s->buffer); | ||
64 | s->buffer = TRACE_SEQ_POISON; | ||
65 | } | ||
66 | |||
67 | static void expand_buffer(struct trace_seq *s) | ||
68 | { | ||
69 | s->buffer_size += TRACE_SEQ_BUF_SIZE; | ||
70 | s->buffer = realloc(s->buffer, s->buffer_size); | ||
71 | if (!s->buffer) | ||
72 | die("Can't allocate trace_seq buffer memory"); | ||
73 | } | ||
74 | |||
75 | /** | ||
76 | * trace_seq_printf - sequence printing of trace information | ||
77 | * @s: trace sequence descriptor | ||
78 | * @fmt: printf format string | ||
79 | * | ||
80 | * It returns 0 if the trace oversizes the buffer's free | ||
81 | * space, 1 otherwise. | ||
82 | * | ||
83 | * The tracer may use either sequence operations or its own | ||
84 | * copy to user routines. To simplify formating of a trace | ||
85 | * trace_seq_printf is used to store strings into a special | ||
86 | * buffer (@s). Then the output may be either used by | ||
87 | * the sequencer or pulled into another buffer. | ||
88 | */ | ||
89 | int | ||
90 | trace_seq_printf(struct trace_seq *s, const char *fmt, ...) | ||
91 | { | ||
92 | va_list ap; | ||
93 | int len; | ||
94 | int ret; | ||
95 | |||
96 | TRACE_SEQ_CHECK(s); | ||
97 | |||
98 | try_again: | ||
99 | len = (s->buffer_size - 1) - s->len; | ||
100 | |||
101 | va_start(ap, fmt); | ||
102 | ret = vsnprintf(s->buffer + s->len, len, fmt, ap); | ||
103 | va_end(ap); | ||
104 | |||
105 | if (ret >= len) { | ||
106 | expand_buffer(s); | ||
107 | goto try_again; | ||
108 | } | ||
109 | |||
110 | s->len += ret; | ||
111 | |||
112 | return 1; | ||
113 | } | ||
114 | |||
115 | /** | ||
116 | * trace_seq_vprintf - sequence printing of trace information | ||
117 | * @s: trace sequence descriptor | ||
118 | * @fmt: printf format string | ||
119 | * | ||
120 | * The tracer may use either sequence operations or its own | ||
121 | * copy to user routines. To simplify formating of a trace | ||
122 | * trace_seq_printf is used to store strings into a special | ||
123 | * buffer (@s). Then the output may be either used by | ||
124 | * the sequencer or pulled into another buffer. | ||
125 | */ | ||
126 | int | ||
127 | trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args) | ||
128 | { | ||
129 | int len; | ||
130 | int ret; | ||
131 | |||
132 | TRACE_SEQ_CHECK(s); | ||
133 | |||
134 | try_again: | ||
135 | len = (s->buffer_size - 1) - s->len; | ||
136 | |||
137 | ret = vsnprintf(s->buffer + s->len, len, fmt, args); | ||
138 | |||
139 | if (ret >= len) { | ||
140 | expand_buffer(s); | ||
141 | goto try_again; | ||
142 | } | ||
143 | |||
144 | s->len += ret; | ||
145 | |||
146 | return len; | ||
147 | } | ||
148 | |||
149 | /** | ||
150 | * trace_seq_puts - trace sequence printing of simple string | ||
151 | * @s: trace sequence descriptor | ||
152 | * @str: simple string to record | ||
153 | * | ||
154 | * The tracer may use either the sequence operations or its own | ||
155 | * copy to user routines. This function records a simple string | ||
156 | * into a special buffer (@s) for later retrieval by a sequencer | ||
157 | * or other mechanism. | ||
158 | */ | ||
159 | int trace_seq_puts(struct trace_seq *s, const char *str) | ||
160 | { | ||
161 | int len; | ||
162 | |||
163 | TRACE_SEQ_CHECK(s); | ||
164 | |||
165 | len = strlen(str); | ||
166 | |||
167 | while (len > ((s->buffer_size - 1) - s->len)) | ||
168 | expand_buffer(s); | ||
169 | |||
170 | memcpy(s->buffer + s->len, str, len); | ||
171 | s->len += len; | ||
172 | |||
173 | return len; | ||
174 | } | ||
175 | |||
176 | int trace_seq_putc(struct trace_seq *s, unsigned char c) | ||
177 | { | ||
178 | TRACE_SEQ_CHECK(s); | ||
179 | |||
180 | while (s->len >= (s->buffer_size - 1)) | ||
181 | expand_buffer(s); | ||
182 | |||
183 | s->buffer[s->len++] = c; | ||
184 | |||
185 | return 1; | ||
186 | } | ||
187 | |||
188 | void trace_seq_terminate(struct trace_seq *s) | ||
189 | { | ||
190 | TRACE_SEQ_CHECK(s); | ||
191 | |||
192 | /* There's always one character left on the buffer */ | ||
193 | s->buffer[s->len] = 0; | ||
194 | } | ||
195 | |||
196 | int trace_seq_do_printf(struct trace_seq *s) | ||
197 | { | ||
198 | TRACE_SEQ_CHECK(s); | ||
199 | return printf("%.*s", s->len, s->buffer); | ||
200 | } | ||