Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/cddl/dev/dtrace/dtrace_debug.c
48254 views
1
/*-
2
* Copyright (C) 2008 John Birrell <[email protected]>.
3
* All rights reserved.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
8
* 1. Redistributions of source code must retain the above copyright
9
* notice(s), this list of conditions and the following disclaimer as
10
* the first lines of this file unmodified other than the possible
11
* addition of one or more copyright notices.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice(s), this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
*
16
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
17
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
20
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
26
* DAMAGE.
27
*
28
*/
29
30
#ifdef DEBUG
31
32
#include <machine/atomic.h>
33
34
#define DTRACE_DEBUG_BUFR_SIZE (32 * 1024)
35
36
struct dtrace_debug_data {
37
uintptr_t lock __aligned(CACHE_LINE_SIZE);
38
char bufr[DTRACE_DEBUG_BUFR_SIZE];
39
char *first;
40
char *last;
41
char *next;
42
} dtrace_debug_data[MAXCPU];
43
44
static char dtrace_debug_bufr[DTRACE_DEBUG_BUFR_SIZE];
45
46
static void
47
dtrace_debug_lock(int cpu)
48
{
49
uintptr_t tid;
50
51
tid = (uintptr_t)curthread;
52
spinlock_enter();
53
while (atomic_cmpset_acq_ptr(&dtrace_debug_data[cpu].lock, 0, tid) == 0) /* Loop until the lock is obtained. */
54
;
55
}
56
57
static void
58
dtrace_debug_unlock(int cpu)
59
{
60
atomic_store_rel_ptr(&dtrace_debug_data[cpu].lock, 0);
61
spinlock_exit();
62
}
63
64
static void
65
dtrace_debug_init(void *dummy)
66
{
67
int i;
68
struct dtrace_debug_data *d;
69
70
CPU_FOREACH(i) {
71
d = &dtrace_debug_data[i];
72
73
if (d->first == NULL) {
74
d->first = d->bufr;
75
d->next = d->bufr;
76
d->last = d->bufr + DTRACE_DEBUG_BUFR_SIZE - 1;
77
*(d->last) = '\0';
78
}
79
}
80
}
81
82
SYSINIT(dtrace_debug_init, SI_SUB_KDTRACE, SI_ORDER_ANY, dtrace_debug_init, NULL);
83
SYSINIT(dtrace_debug_smpinit, SI_SUB_SMP, SI_ORDER_ANY, dtrace_debug_init, NULL);
84
85
static void
86
dtrace_debug_output(void)
87
{
88
char *p;
89
int i;
90
struct dtrace_debug_data *d;
91
uintptr_t count;
92
93
CPU_FOREACH(i) {
94
dtrace_debug_lock(i);
95
96
d = &dtrace_debug_data[i];
97
98
count = 0;
99
100
if (d->first < d->next) {
101
char *p1 = dtrace_debug_bufr;
102
103
count = (uintptr_t) d->next - (uintptr_t) d->first;
104
105
for (p = d->first; p < d->next; p++)
106
*p1++ = *p;
107
} else if (d->first > d->next) {
108
char *p1 = dtrace_debug_bufr;
109
110
count = (uintptr_t) d->last - (uintptr_t) d->first;
111
112
for (p = d->first; p < d->last; p++)
113
*p1++ = *p;
114
115
count += (uintptr_t) d->next - (uintptr_t) d->bufr;
116
117
for (p = d->bufr; p < d->next; p++)
118
*p1++ = *p;
119
}
120
121
d->first = d->bufr;
122
d->next = d->bufr;
123
124
dtrace_debug_unlock(i);
125
126
if (count > 0) {
127
char *last = dtrace_debug_bufr + count;
128
129
p = dtrace_debug_bufr;
130
131
while (p < last) {
132
if (*p == '\0') {
133
p++;
134
continue;
135
}
136
137
printf("%s", p);
138
139
p += strlen(p);
140
}
141
}
142
}
143
}
144
145
/*
146
* Functions below here are called from the probe context, so they can't call
147
* _any_ functions outside the dtrace module without running foul of the function
148
* boundary trace provider (fbt). The purpose of these functions is limited to
149
* buffering debug strings for output when the probe completes on the current CPU.
150
*/
151
152
static __inline void
153
dtrace_debug__putc(int cpu, char c)
154
{
155
struct dtrace_debug_data *d;
156
157
d = &dtrace_debug_data[cpu];
158
*d->next++ = c;
159
160
if (d->next == d->last)
161
d->next = d->bufr;
162
163
*(d->next) = '\0';
164
165
if (d->next == d->first)
166
d->first++;
167
168
if (d->first == d->last)
169
d->first = d->bufr;
170
}
171
172
static void __used
173
dtrace_debug_putc(char c)
174
{
175
int cpu;
176
177
cpu = curcpu;
178
dtrace_debug_lock(cpu);
179
180
dtrace_debug__putc(cpu, c);
181
182
dtrace_debug_unlock(cpu);
183
}
184
185
static void __used
186
dtrace_debug_puts(const char *s)
187
{
188
int cpu;
189
190
cpu = curcpu;
191
dtrace_debug_lock(cpu);
192
193
while (*s != '\0')
194
dtrace_debug__putc(cpu, *s++);
195
196
dtrace_debug__putc(cpu, '\0');
197
198
dtrace_debug_unlock(cpu);
199
}
200
201
/*
202
* Snaffled from sys/kern/subr_prf.c
203
*
204
* Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
205
* order; return an optional length and a pointer to the last character
206
* written in the buffer (i.e., the first character of the string).
207
* The buffer pointed to by `nbuf' must have length >= MAXNBUF.
208
*/
209
static char *
210
dtrace_debug_ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
211
{
212
char *p, c;
213
214
p = nbuf;
215
*p = '\0';
216
do {
217
c = hex2ascii(num % base);
218
*++p = upper ? toupper(c) : c;
219
} while (num /= base);
220
if (lenp)
221
*lenp = p - nbuf;
222
return (p);
223
}
224
225
#define MAXNBUF (sizeof(intmax_t) * NBBY + 1)
226
227
static void
228
dtrace_debug_vprintf(int cpu, const char *fmt, va_list ap)
229
{
230
char nbuf[MAXNBUF];
231
const char *p, *percent, *q;
232
u_char *up;
233
int ch, n;
234
uintmax_t num;
235
int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
236
int cflag, hflag, jflag, tflag, zflag;
237
int dwidth, upper;
238
int radix = 10;
239
char padc;
240
int stop = 0, retval = 0;
241
242
num = 0;
243
244
if (fmt == NULL)
245
fmt = "(fmt null)\n";
246
247
for (;;) {
248
padc = ' ';
249
width = 0;
250
while ((ch = (u_char)*fmt++) != '%' || stop) {
251
if (ch == '\0') {
252
dtrace_debug__putc(cpu, '\0');
253
return;
254
}
255
dtrace_debug__putc(cpu, ch);
256
}
257
percent = fmt - 1;
258
qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
259
sign = 0; dot = 0; dwidth = 0; upper = 0;
260
cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
261
reswitch: switch (ch = (u_char)*fmt++) {
262
case '.':
263
dot = 1;
264
goto reswitch;
265
case '#':
266
sharpflag = 1;
267
goto reswitch;
268
case '+':
269
sign = 1;
270
goto reswitch;
271
case '-':
272
ladjust = 1;
273
goto reswitch;
274
case '%':
275
dtrace_debug__putc(cpu, ch);
276
break;
277
case '*':
278
if (!dot) {
279
width = va_arg(ap, int);
280
if (width < 0) {
281
ladjust = !ladjust;
282
width = -width;
283
}
284
} else {
285
dwidth = va_arg(ap, int);
286
}
287
goto reswitch;
288
case '0':
289
if (!dot) {
290
padc = '0';
291
goto reswitch;
292
}
293
case '1': case '2': case '3': case '4':
294
case '5': case '6': case '7': case '8': case '9':
295
for (n = 0;; ++fmt) {
296
n = n * 10 + ch - '0';
297
ch = *fmt;
298
if (ch < '0' || ch > '9')
299
break;
300
}
301
if (dot)
302
dwidth = n;
303
else
304
width = n;
305
goto reswitch;
306
case 'b':
307
num = (u_int)va_arg(ap, int);
308
p = va_arg(ap, char *);
309
for (q = dtrace_debug_ksprintn(nbuf, num, *p++, NULL, 0); *q;)
310
dtrace_debug__putc(cpu, *q--);
311
312
if (num == 0)
313
break;
314
315
for (tmp = 0; *p;) {
316
n = *p++;
317
if (num & (1 << (n - 1))) {
318
dtrace_debug__putc(cpu, tmp ? ',' : '<');
319
for (; (n = *p) > ' '; ++p)
320
dtrace_debug__putc(cpu, n);
321
tmp = 1;
322
} else
323
for (; *p > ' '; ++p)
324
continue;
325
}
326
if (tmp)
327
dtrace_debug__putc(cpu, '>');
328
break;
329
case 'c':
330
dtrace_debug__putc(cpu, va_arg(ap, int));
331
break;
332
case 'D':
333
up = va_arg(ap, u_char *);
334
p = va_arg(ap, char *);
335
if (!width)
336
width = 16;
337
while(width--) {
338
dtrace_debug__putc(cpu, hex2ascii(*up >> 4));
339
dtrace_debug__putc(cpu, hex2ascii(*up & 0x0f));
340
up++;
341
if (width)
342
for (q=p;*q;q++)
343
dtrace_debug__putc(cpu, *q);
344
}
345
break;
346
case 'd':
347
case 'i':
348
base = 10;
349
sign = 1;
350
goto handle_sign;
351
case 'h':
352
if (hflag) {
353
hflag = 0;
354
cflag = 1;
355
} else
356
hflag = 1;
357
goto reswitch;
358
case 'j':
359
jflag = 1;
360
goto reswitch;
361
case 'l':
362
if (lflag) {
363
lflag = 0;
364
qflag = 1;
365
} else
366
lflag = 1;
367
goto reswitch;
368
case 'n':
369
if (jflag)
370
*(va_arg(ap, intmax_t *)) = retval;
371
else if (qflag)
372
*(va_arg(ap, quad_t *)) = retval;
373
else if (lflag)
374
*(va_arg(ap, long *)) = retval;
375
else if (zflag)
376
*(va_arg(ap, size_t *)) = retval;
377
else if (hflag)
378
*(va_arg(ap, short *)) = retval;
379
else if (cflag)
380
*(va_arg(ap, char *)) = retval;
381
else
382
*(va_arg(ap, int *)) = retval;
383
break;
384
case 'o':
385
base = 8;
386
goto handle_nosign;
387
case 'p':
388
base = 16;
389
sharpflag = (width == 0);
390
sign = 0;
391
num = (uintptr_t)va_arg(ap, void *);
392
goto number;
393
case 'q':
394
qflag = 1;
395
goto reswitch;
396
case 'r':
397
base = radix;
398
if (sign)
399
goto handle_sign;
400
goto handle_nosign;
401
case 's':
402
p = va_arg(ap, char *);
403
if (p == NULL)
404
p = "(null)";
405
if (!dot)
406
n = strlen (p);
407
else
408
for (n = 0; n < dwidth && p[n]; n++)
409
continue;
410
411
width -= n;
412
413
if (!ladjust && width > 0)
414
while (width--)
415
dtrace_debug__putc(cpu, padc);
416
while (n--)
417
dtrace_debug__putc(cpu, *p++);
418
if (ladjust && width > 0)
419
while (width--)
420
dtrace_debug__putc(cpu, padc);
421
break;
422
case 't':
423
tflag = 1;
424
goto reswitch;
425
case 'u':
426
base = 10;
427
goto handle_nosign;
428
case 'X':
429
upper = 1;
430
case 'x':
431
base = 16;
432
goto handle_nosign;
433
case 'y':
434
base = 16;
435
sign = 1;
436
goto handle_sign;
437
case 'z':
438
zflag = 1;
439
goto reswitch;
440
handle_nosign:
441
sign = 0;
442
if (jflag)
443
num = va_arg(ap, uintmax_t);
444
else if (qflag)
445
num = va_arg(ap, u_quad_t);
446
else if (tflag)
447
num = va_arg(ap, ptrdiff_t);
448
else if (lflag)
449
num = va_arg(ap, u_long);
450
else if (zflag)
451
num = va_arg(ap, size_t);
452
else if (hflag)
453
num = (u_short)va_arg(ap, int);
454
else if (cflag)
455
num = (u_char)va_arg(ap, int);
456
else
457
num = va_arg(ap, u_int);
458
goto number;
459
handle_sign:
460
if (jflag)
461
num = va_arg(ap, intmax_t);
462
else if (qflag)
463
num = va_arg(ap, quad_t);
464
else if (tflag)
465
num = va_arg(ap, ptrdiff_t);
466
else if (lflag)
467
num = va_arg(ap, long);
468
else if (zflag)
469
num = va_arg(ap, size_t);
470
else if (hflag)
471
num = (short)va_arg(ap, int);
472
else if (cflag)
473
num = (char)va_arg(ap, int);
474
else
475
num = va_arg(ap, int);
476
number:
477
if (sign && (intmax_t)num < 0) {
478
neg = 1;
479
num = -(intmax_t)num;
480
}
481
p = dtrace_debug_ksprintn(nbuf, num, base, &tmp, upper);
482
if (sharpflag && num != 0) {
483
if (base == 8)
484
tmp++;
485
else if (base == 16)
486
tmp += 2;
487
}
488
if (neg)
489
tmp++;
490
491
if (!ladjust && padc != '0' && width
492
&& (width -= tmp) > 0)
493
while (width--)
494
dtrace_debug__putc(cpu, padc);
495
if (neg)
496
dtrace_debug__putc(cpu, '-');
497
if (sharpflag && num != 0) {
498
if (base == 8) {
499
dtrace_debug__putc(cpu, '0');
500
} else if (base == 16) {
501
dtrace_debug__putc(cpu, '0');
502
dtrace_debug__putc(cpu, 'x');
503
}
504
}
505
if (!ladjust && width && (width -= tmp) > 0)
506
while (width--)
507
dtrace_debug__putc(cpu, padc);
508
509
while (*p)
510
dtrace_debug__putc(cpu, *p--);
511
512
if (ladjust && width && (width -= tmp) > 0)
513
while (width--)
514
dtrace_debug__putc(cpu, padc);
515
516
break;
517
default:
518
while (percent < fmt)
519
dtrace_debug__putc(cpu, *percent++);
520
/*
521
* Since we ignore an formatting argument it is no
522
* longer safe to obey the remaining formatting
523
* arguments as the arguments will no longer match
524
* the format specs.
525
*/
526
stop = 1;
527
break;
528
}
529
}
530
531
dtrace_debug__putc(cpu, '\0');
532
}
533
534
void
535
dtrace_debug_printf(const char *fmt, ...)
536
{
537
va_list ap;
538
int cpu;
539
540
cpu = curcpu;
541
dtrace_debug_lock(cpu);
542
543
va_start(ap, fmt);
544
545
dtrace_debug_vprintf(cpu, fmt, ap);
546
547
va_end(ap);
548
549
dtrace_debug_unlock(cpu);
550
}
551
552
#else
553
554
#define dtrace_debug_output()
555
#define dtrace_debug_puts(_s)
556
#define dtrace_debug_printf(fmt, ...)
557
558
#endif
559
560