at v4.20-rc6 242 lines 5.3 kB view raw
1// SPDX-License-Identifier: LGPL-2.1 2/* 3 * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> 4 * 5 */ 6#include "trace-seq.h" 7 8#include <stdio.h> 9#include <stdlib.h> 10#include <string.h> 11#include <stdarg.h> 12 13#include <asm/bug.h> 14#include "event-parse.h" 15#include "event-utils.h" 16 17/* 18 * The TRACE_SEQ_POISON is to catch the use of using 19 * a trace_seq structure after it was destroyed. 20 */ 21#define TRACE_SEQ_POISON ((void *)0xdeadbeef) 22#define TRACE_SEQ_CHECK(s) \ 23do { \ 24 if (WARN_ONCE((s)->buffer == TRACE_SEQ_POISON, \ 25 "Usage of trace_seq after it was destroyed")) \ 26 (s)->state = TRACE_SEQ__BUFFER_POISONED; \ 27} while (0) 28 29#define TRACE_SEQ_CHECK_RET_N(s, n) \ 30do { \ 31 TRACE_SEQ_CHECK(s); \ 32 if ((s)->state != TRACE_SEQ__GOOD) \ 33 return n; \ 34} while (0) 35 36#define TRACE_SEQ_CHECK_RET(s) TRACE_SEQ_CHECK_RET_N(s, ) 37#define TRACE_SEQ_CHECK_RET0(s) TRACE_SEQ_CHECK_RET_N(s, 0) 38 39/** 40 * trace_seq_init - initialize the trace_seq structure 41 * @s: a pointer to the trace_seq structure to initialize 42 */ 43void 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(s->buffer_size); 49 if (s->buffer != NULL) 50 s->state = TRACE_SEQ__GOOD; 51 else 52 s->state = TRACE_SEQ__MEM_ALLOC_FAILED; 53} 54 55/** 56 * trace_seq_reset - re-initialize the trace_seq structure 57 * @s: a pointer to the trace_seq structure to reset 58 */ 59void trace_seq_reset(struct trace_seq *s) 60{ 61 if (!s) 62 return; 63 TRACE_SEQ_CHECK(s); 64 s->len = 0; 65 s->readpos = 0; 66} 67 68/** 69 * trace_seq_destroy - free up memory of a trace_seq 70 * @s: a pointer to the trace_seq to free the buffer 71 * 72 * Only frees the buffer, not the trace_seq struct itself. 73 */ 74void trace_seq_destroy(struct trace_seq *s) 75{ 76 if (!s) 77 return; 78 TRACE_SEQ_CHECK_RET(s); 79 free(s->buffer); 80 s->buffer = TRACE_SEQ_POISON; 81} 82 83static void expand_buffer(struct trace_seq *s) 84{ 85 char *buf; 86 87 buf = realloc(s->buffer, s->buffer_size + TRACE_SEQ_BUF_SIZE); 88 if (WARN_ONCE(!buf, "Can't allocate trace_seq buffer memory")) { 89 s->state = TRACE_SEQ__MEM_ALLOC_FAILED; 90 return; 91 } 92 93 s->buffer = buf; 94 s->buffer_size += TRACE_SEQ_BUF_SIZE; 95} 96 97/** 98 * trace_seq_printf - sequence printing of trace information 99 * @s: trace sequence descriptor 100 * @fmt: printf format string 101 * 102 * It returns 0 if the trace oversizes the buffer's free 103 * space, 1 otherwise. 104 * 105 * The tracer may use either sequence operations or its own 106 * copy to user routines. To simplify formating of a trace 107 * trace_seq_printf is used to store strings into a special 108 * buffer (@s). Then the output may be either used by 109 * the sequencer or pulled into another buffer. 110 */ 111int 112trace_seq_printf(struct trace_seq *s, const char *fmt, ...) 113{ 114 va_list ap; 115 int len; 116 int ret; 117 118 try_again: 119 TRACE_SEQ_CHECK_RET0(s); 120 121 len = (s->buffer_size - 1) - s->len; 122 123 va_start(ap, fmt); 124 ret = vsnprintf(s->buffer + s->len, len, fmt, ap); 125 va_end(ap); 126 127 if (ret >= len) { 128 expand_buffer(s); 129 goto try_again; 130 } 131 132 s->len += ret; 133 134 return 1; 135} 136 137/** 138 * trace_seq_vprintf - sequence printing of trace information 139 * @s: trace sequence descriptor 140 * @fmt: printf format string 141 * 142 * The tracer may use either sequence operations or its own 143 * copy to user routines. To simplify formating of a trace 144 * trace_seq_printf is used to store strings into a special 145 * buffer (@s). Then the output may be either used by 146 * the sequencer or pulled into another buffer. 147 */ 148int 149trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args) 150{ 151 int len; 152 int ret; 153 154 try_again: 155 TRACE_SEQ_CHECK_RET0(s); 156 157 len = (s->buffer_size - 1) - s->len; 158 159 ret = vsnprintf(s->buffer + s->len, len, fmt, args); 160 161 if (ret >= len) { 162 expand_buffer(s); 163 goto try_again; 164 } 165 166 s->len += ret; 167 168 return len; 169} 170 171/** 172 * trace_seq_puts - trace sequence printing of simple string 173 * @s: trace sequence descriptor 174 * @str: simple string to record 175 * 176 * The tracer may use either the sequence operations or its own 177 * copy to user routines. This function records a simple string 178 * into a special buffer (@s) for later retrieval by a sequencer 179 * or other mechanism. 180 */ 181int trace_seq_puts(struct trace_seq *s, const char *str) 182{ 183 int len; 184 185 TRACE_SEQ_CHECK_RET0(s); 186 187 len = strlen(str); 188 189 while (len > ((s->buffer_size - 1) - s->len)) 190 expand_buffer(s); 191 192 TRACE_SEQ_CHECK_RET0(s); 193 194 memcpy(s->buffer + s->len, str, len); 195 s->len += len; 196 197 return len; 198} 199 200int trace_seq_putc(struct trace_seq *s, unsigned char c) 201{ 202 TRACE_SEQ_CHECK_RET0(s); 203 204 while (s->len >= (s->buffer_size - 1)) 205 expand_buffer(s); 206 207 TRACE_SEQ_CHECK_RET0(s); 208 209 s->buffer[s->len++] = c; 210 211 return 1; 212} 213 214void trace_seq_terminate(struct trace_seq *s) 215{ 216 TRACE_SEQ_CHECK_RET(s); 217 218 /* There's always one character left on the buffer */ 219 s->buffer[s->len] = 0; 220} 221 222int trace_seq_do_fprintf(struct trace_seq *s, FILE *fp) 223{ 224 TRACE_SEQ_CHECK(s); 225 226 switch (s->state) { 227 case TRACE_SEQ__GOOD: 228 return fprintf(fp, "%.*s", s->len, s->buffer); 229 case TRACE_SEQ__BUFFER_POISONED: 230 fprintf(fp, "%s\n", "Usage of trace_seq after it was destroyed"); 231 break; 232 case TRACE_SEQ__MEM_ALLOC_FAILED: 233 fprintf(fp, "%s\n", "Can't allocate trace_seq buffer memory"); 234 break; 235 } 236 return -1; 237} 238 239int trace_seq_do_printf(struct trace_seq *s) 240{ 241 return trace_seq_do_fprintf(s, stdout); 242}