1 /* 2 * trace_seq.c 3 * 4 * Copyright (C) 2008-2014 Red Hat Inc, Steven Rostedt <[email protected]> 5 * 6 */ 7 #include <linux/uaccess.h> 8 #include <linux/seq_file.h> 9 #include <linux/trace_seq.h> 10 11 int trace_print_seq(struct seq_file *m, struct trace_seq *s) 12 { 13 int len = s->len >= PAGE_SIZE ? PAGE_SIZE - 1 : s->len; 14 int ret; 15 16 ret = seq_write(m, s->buffer, len); 17 18 /* 19 * Only reset this buffer if we successfully wrote to the 20 * seq_file buffer. 21 */ 22 if (!ret) 23 trace_seq_init(s); 24 25 return ret; 26 } 27 28 /** 29 * trace_seq_printf - sequence printing of trace information 30 * @s: trace sequence descriptor 31 * @fmt: printf format string 32 * 33 * It returns 0 if the trace oversizes the buffer's free 34 * space, 1 otherwise. 35 * 36 * The tracer may use either sequence operations or its own 37 * copy to user routines. To simplify formating of a trace 38 * trace_seq_printf is used to store strings into a special 39 * buffer (@s). Then the output may be either used by 40 * the sequencer or pulled into another buffer. 41 */ 42 int 43 trace_seq_printf(struct trace_seq *s, const char *fmt, ...) 44 { 45 int len = (PAGE_SIZE - 1) - s->len; 46 va_list ap; 47 int ret; 48 49 if (s->full || !len) 50 return 0; 51 52 va_start(ap, fmt); 53 ret = vsnprintf(s->buffer + s->len, len, fmt, ap); 54 va_end(ap); 55 56 /* If we can't write it all, don't bother writing anything */ 57 if (ret >= len) { 58 s->full = 1; 59 return 0; 60 } 61 62 s->len += ret; 63 64 return 1; 65 } 66 EXPORT_SYMBOL_GPL(trace_seq_printf); 67 68 /** 69 * trace_seq_bitmask - put a list of longs as a bitmask print output 70 * @s: trace sequence descriptor 71 * @maskp: points to an array of unsigned longs that represent a bitmask 72 * @nmaskbits: The number of bits that are valid in @maskp 73 * 74 * It returns 0 if the trace oversizes the buffer's free 75 * space, 1 otherwise. 76 * 77 * Writes a ASCII representation of a bitmask string into @s. 78 */ 79 int 80 trace_seq_bitmask(struct trace_seq *s, const unsigned long *maskp, 81 int nmaskbits) 82 { 83 int len = (PAGE_SIZE - 1) - s->len; 84 int ret; 85 86 if (s->full || !len) 87 return 0; 88 89 ret = bitmap_scnprintf(s->buffer, len, maskp, nmaskbits); 90 s->len += ret; 91 92 return 1; 93 } 94 EXPORT_SYMBOL_GPL(trace_seq_bitmask); 95 96 /** 97 * trace_seq_vprintf - sequence printing of trace information 98 * @s: trace sequence descriptor 99 * @fmt: printf format string 100 * 101 * The tracer may use either sequence operations or its own 102 * copy to user routines. To simplify formating of a trace 103 * trace_seq_printf is used to store strings into a special 104 * buffer (@s). Then the output may be either used by 105 * the sequencer or pulled into another buffer. 106 */ 107 int 108 trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args) 109 { 110 int len = (PAGE_SIZE - 1) - s->len; 111 int ret; 112 113 if (s->full || !len) 114 return 0; 115 116 ret = vsnprintf(s->buffer + s->len, len, fmt, args); 117 118 /* If we can't write it all, don't bother writing anything */ 119 if (ret >= len) { 120 s->full = 1; 121 return 0; 122 } 123 124 s->len += ret; 125 126 return len; 127 } 128 EXPORT_SYMBOL_GPL(trace_seq_vprintf); 129 130 int trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary) 131 { 132 int len = (PAGE_SIZE - 1) - s->len; 133 int ret; 134 135 if (s->full || !len) 136 return 0; 137 138 ret = bstr_printf(s->buffer + s->len, len, fmt, binary); 139 140 /* If we can't write it all, don't bother writing anything */ 141 if (ret >= len) { 142 s->full = 1; 143 return 0; 144 } 145 146 s->len += ret; 147 148 return len; 149 } 150 151 /** 152 * trace_seq_puts - trace sequence printing of simple string 153 * @s: trace sequence descriptor 154 * @str: simple string to record 155 * 156 * The tracer may use either the sequence operations or its own 157 * copy to user routines. This function records a simple string 158 * into a special buffer (@s) for later retrieval by a sequencer 159 * or other mechanism. 160 */ 161 int trace_seq_puts(struct trace_seq *s, const char *str) 162 { 163 int len = strlen(str); 164 165 if (s->full) 166 return 0; 167 168 if (len > ((PAGE_SIZE - 1) - s->len)) { 169 s->full = 1; 170 return 0; 171 } 172 173 memcpy(s->buffer + s->len, str, len); 174 s->len += len; 175 176 return len; 177 } 178 179 int trace_seq_putc(struct trace_seq *s, unsigned char c) 180 { 181 if (s->full) 182 return 0; 183 184 if (s->len >= (PAGE_SIZE - 1)) { 185 s->full = 1; 186 return 0; 187 } 188 189 s->buffer[s->len++] = c; 190 191 return 1; 192 } 193 EXPORT_SYMBOL(trace_seq_putc); 194 195 int trace_seq_putmem(struct trace_seq *s, const void *mem, size_t len) 196 { 197 if (s->full) 198 return 0; 199 200 if (len > ((PAGE_SIZE - 1) - s->len)) { 201 s->full = 1; 202 return 0; 203 } 204 205 memcpy(s->buffer + s->len, mem, len); 206 s->len += len; 207 208 return len; 209 } 210 211 #define HEX_CHARS (MAX_MEMHEX_BYTES*2 + 1) 212 213 int trace_seq_putmem_hex(struct trace_seq *s, const void *mem, size_t len) 214 { 215 unsigned char hex[HEX_CHARS]; 216 const unsigned char *data = mem; 217 int i, j; 218 219 if (s->full) 220 return 0; 221 222 #ifdef __BIG_ENDIAN 223 for (i = 0, j = 0; i < len; i++) { 224 #else 225 for (i = len-1, j = 0; i >= 0; i--) { 226 #endif 227 hex[j++] = hex_asc_hi(data[i]); 228 hex[j++] = hex_asc_lo(data[i]); 229 } 230 hex[j++] = ' '; 231 232 return trace_seq_putmem(s, hex, j); 233 } 234 235 void *trace_seq_reserve(struct trace_seq *s, size_t len) 236 { 237 void *ret; 238 239 if (s->full) 240 return NULL; 241 242 if (len > ((PAGE_SIZE - 1) - s->len)) { 243 s->full = 1; 244 return NULL; 245 } 246 247 ret = s->buffer + s->len; 248 s->len += len; 249 250 return ret; 251 } 252 253 int trace_seq_path(struct trace_seq *s, const struct path *path) 254 { 255 unsigned char *p; 256 257 if (s->full) 258 return 0; 259 260 if (s->len >= (PAGE_SIZE - 1)) { 261 s->full = 1; 262 return 0; 263 } 264 265 p = d_path(path, s->buffer + s->len, PAGE_SIZE - s->len); 266 if (!IS_ERR(p)) { 267 p = mangle_path(s->buffer + s->len, p, "\n"); 268 if (p) { 269 s->len = p - s->buffer; 270 return 1; 271 } 272 } else { 273 s->buffer[s->len++] = '?'; 274 return 1; 275 } 276 277 s->full = 1; 278 return 0; 279 } 280 281 ssize_t trace_seq_to_user(struct trace_seq *s, char __user *ubuf, size_t cnt) 282 { 283 int len; 284 int ret; 285 286 if (!cnt) 287 return 0; 288 289 if (s->len <= s->readpos) 290 return -EBUSY; 291 292 len = s->len - s->readpos; 293 if (cnt > len) 294 cnt = len; 295 ret = copy_to_user(ubuf, s->buffer + s->readpos, cnt); 296 if (ret == cnt) 297 return -EFAULT; 298 299 cnt -= ret; 300 301 s->readpos += cnt; 302 return cnt; 303 } 304