1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 #include "cyclic.h"
29
30 #define CYCLIC_TRACE
31
32 #include <mdb/mdb_modapi.h>
33 #include <sys/timer.h>
34 #include <sys/cyclic_impl.h>
35 #include <sys/sysmacros.h>
36 #include <stdio.h>
37
38 int
cyccpu_vread(cyc_cpu_t * cpu,uintptr_t addr)39 cyccpu_vread(cyc_cpu_t *cpu, uintptr_t addr)
40 {
41 static int inited = 0;
42 static int cyc_trace_enabled = 0;
43 static size_t cyccpu_size;
44
45 if (!inited) {
46 inited = 1;
47 (void) mdb_readvar(&cyc_trace_enabled, "cyc_trace_enabled");
48 cyccpu_size = (cyc_trace_enabled) ? sizeof (*cpu) :
49 OFFSETOF(cyc_cpu_t, cyp_trace);
50 }
51
52 if (mdb_vread(cpu, cyccpu_size, addr) == -1)
53 return (-1);
54
55 if (!cyc_trace_enabled)
56 bzero(cpu->cyp_trace, sizeof (cpu->cyp_trace));
57
58 return (0);
59 }
60
61 int
cyccpu_walk_init(mdb_walk_state_t * wsp)62 cyccpu_walk_init(mdb_walk_state_t *wsp)
63 {
64 if (mdb_layered_walk("cpu", wsp) == -1) {
65 mdb_warn("couldn't walk 'cpu'");
66 return (WALK_ERR);
67 }
68
69 return (WALK_NEXT);
70 }
71
72 int
cyccpu_walk_step(mdb_walk_state_t * wsp)73 cyccpu_walk_step(mdb_walk_state_t *wsp)
74 {
75 uintptr_t addr = (uintptr_t)((cpu_t *)wsp->walk_layer)->cpu_cyclic;
76 cyc_cpu_t cpu;
77
78 if (cyccpu_vread(&cpu, addr) == -1) {
79 mdb_warn("couldn't read cyc_cpu at %p", addr);
80 return (WALK_ERR);
81 }
82
83 return (wsp->walk_callback(addr, &cpu, wsp->walk_cbdata));
84 }
85
86 int
cycomni_walk_init(mdb_walk_state_t * wsp)87 cycomni_walk_init(mdb_walk_state_t *wsp)
88 {
89 cyc_id_t id;
90
91 if (wsp->walk_addr == NULL) {
92 mdb_warn("must provide a cyclic id\n");
93 return (WALK_ERR);
94 }
95
96 if (mdb_vread(&id, sizeof (id), wsp->walk_addr) == -1) {
97 mdb_warn("couldn't read cyc_id_t at %p", wsp->walk_addr);
98 return (WALK_ERR);
99 }
100
101 if (id.cyi_cpu != NULL || id.cyi_omni_list == NULL ||
102 id.cyi_omni_hdlr.cyo_online == NULL) {
103 mdb_warn("%p is not an omnipresent cyclic.\n", wsp->walk_addr);
104 return (WALK_ERR);
105 }
106
107 wsp->walk_addr = (uintptr_t)id.cyi_omni_list;
108
109 return (WALK_NEXT);
110 }
111
112 int
cycomni_walk_step(mdb_walk_state_t * wsp)113 cycomni_walk_step(mdb_walk_state_t *wsp)
114 {
115 uintptr_t addr = wsp->walk_addr;
116 cyc_omni_cpu_t omni;
117
118 if (addr == NULL)
119 return (WALK_DONE);
120
121 if (mdb_vread(&omni, sizeof (omni), addr) == -1) {
122 mdb_warn("couldn't read cyc_omni_cpu at %p", addr);
123 return (WALK_ERR);
124 }
125
126 wsp->walk_addr = (uintptr_t)omni.cyo_next;
127
128 return (wsp->walk_callback(addr, &omni, wsp->walk_cbdata));
129 }
130
131 void
cyclic_dump_node(cyc_cpu_t * cpu,cyc_index_t * heap,char ** c,size_t w,int ndx,int l,int r,int depth)132 cyclic_dump_node(cyc_cpu_t *cpu, cyc_index_t *heap, char **c, size_t w,
133 int ndx, int l, int r, int depth)
134 {
135 int heap_left, heap_right;
136 int me;
137 int i, x = l + (r - l) / 2;
138 size_t n = w - (x - 1); /* n bytes left for snprintf after c[][x - 1] */
139
140 heap_left = CYC_HEAP_LEFT(ndx);
141 heap_right = CYC_HEAP_RIGHT(ndx);
142 me = heap[ndx];
143
144 if (ndx >= cpu->cyp_nelems)
145 return;
146
147 if (me < 10) {
148 (void) mdb_snprintf(&c[depth][x - 1], n, " %d", me);
149 } else if (me >= 100) {
150 (void) mdb_snprintf(&c[depth][x - 1], n, "%3d", me);
151 } else {
152 (void) mdb_snprintf(&c[depth][x - 1], n, "%s%2d%s",
153 CYC_HEAP_LEFT(CYC_HEAP_PARENT(ndx)) == ndx ? " " : "", me,
154 CYC_HEAP_LEFT(CYC_HEAP_PARENT(ndx)) == ndx ? "" : " ");
155 }
156
157 if (r - l > 5) {
158 c[++depth][x] = '|';
159 depth++;
160
161 for (i = l + (r - l) / 4; i < r - (r - l) / 4; i++)
162 c[depth][i] = '-';
163 c[depth][l + (r - l) / 4] = '+';
164 c[depth][r - (r - l) / 4 - 1] = '+';
165 c[depth][x] = '+';
166 } else {
167
168 if (heap_left >= cpu->cyp_nelems)
169 return;
170
171 (void) mdb_snprintf(&c[++depth][x - 1], n, "L%d",
172 heap[heap_left]);
173
174 if (heap_right >= cpu->cyp_nelems)
175 return;
176
177 (void) mdb_snprintf(&c[++depth][x - 1], n, "R%d",
178 heap[heap_right]);
179 return;
180 }
181
182 if (heap_left < cpu->cyp_nelems)
183 cyclic_dump_node(cpu, heap, c, w, heap_left, l, x, depth + 1);
184
185 if (heap_right < cpu->cyp_nelems)
186 cyclic_dump_node(cpu, heap, c, w, heap_right, x, r, depth + 1);
187 }
188
189 #define LINES_PER_LEVEL 3
190
191 void
cyclic_pretty_dump(cyc_cpu_t * cpu)192 cyclic_pretty_dump(cyc_cpu_t *cpu)
193 {
194 char **c;
195 int i, j;
196 int width = 80;
197 int depth;
198 cyc_index_t *heap;
199 size_t hsize = sizeof (cyc_index_t) * cpu->cyp_size;
200
201 heap = mdb_alloc(hsize, UM_SLEEP | UM_GC);
202
203 if (mdb_vread(heap, hsize, (uintptr_t)cpu->cyp_heap) == -1) {
204 mdb_warn("couldn't read heap at %p", (uintptr_t)cpu->cyp_heap);
205 return;
206 }
207
208 for (depth = 0; (1 << depth) < cpu->cyp_nelems; depth++)
209 continue;
210 depth++;
211 depth = (depth + 1) * LINES_PER_LEVEL;
212
213 c = mdb_zalloc(sizeof (char *) * depth, UM_SLEEP|UM_GC);
214
215 for (i = 0; i < depth; i++)
216 c[i] = mdb_zalloc(width, UM_SLEEP|UM_GC);
217
218 cyclic_dump_node(cpu, heap, c, width, 0, 1, width - 2, 0);
219
220 for (i = 0; i < depth; i++) {
221 int dump = 0;
222 for (j = 0; j < width - 1; j++) {
223 if (c[i][j] == '\0')
224 c[i][j] = ' ';
225 else
226 dump = 1;
227 }
228 c[i][width - 2] = '\n';
229
230 if (dump)
231 mdb_printf(c[i]);
232 }
233 }
234
235 /*
236 * Yes, this is very weak. Full 16-column-wide 64-bit addresses screw up
237 * ::cycinfo's very carefully planned 80-column layout. We set the column
238 * width for addresses to be 11 (instead of 16), knowing that the kernel
239 * heap (from which these data structures are allocated) starts at
240 * 0x0000030000000000, and isn't likely to extend to 0x0000100000000000.
241 */
242 #ifdef _LP64
243 #define CYC_ADDR_WIDTH 11
244 #else
245 #define CYC_ADDR_WIDTH 8
246 #endif
247
248 int
cycinfo(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)249 cycinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
250 {
251 cyc_cpu_t cpu;
252 cpu_t c;
253 cyc_index_t root, i, *heap;
254 size_t hsize;
255 cyclic_t *cyc;
256 uintptr_t caddr;
257 uint_t verbose = FALSE, Verbose = FALSE;
258 int header = 0;
259 cyc_level_t lev;
260
261 if (!(flags & DCMD_ADDRSPEC)) {
262 if (mdb_walk_dcmd("cyccpu", "cycinfo", argc, argv) == -1) {
263 mdb_warn("can't walk 'cyccpu'");
264 return (DCMD_ERR);
265 }
266 return (DCMD_OK);
267 }
268
269 if (mdb_getopts(argc, argv,
270 'v', MDB_OPT_SETBITS, TRUE, &verbose,
271 'V', MDB_OPT_SETBITS, TRUE, &Verbose, NULL) != argc)
272 return (DCMD_USAGE);
273
274 if (!DCMD_HDRSPEC(flags) && (verbose || Verbose))
275 mdb_printf("\n\n");
276
277 if (DCMD_HDRSPEC(flags) || verbose || Verbose)
278 mdb_printf("%3s %*s %7s %6s %*s %15s %s\n", "CPU",
279 CYC_ADDR_WIDTH, "CYC_CPU", "STATE", "NELEMS",
280 CYC_ADDR_WIDTH, "ROOT", "FIRE", "HANDLER");
281
282 if (cyccpu_vread(&cpu, addr) == -1) {
283 mdb_warn("couldn't read cyc_cpu at %p", addr);
284 return (DCMD_ERR);
285 }
286
287 if (mdb_vread(&c, sizeof (c), (uintptr_t)cpu.cyp_cpu) == -1) {
288 mdb_warn("couldn't read cpu at %p", cpu.cyp_cpu);
289 return (DCMD_ERR);
290 }
291
292 cyc = mdb_alloc(sizeof (cyclic_t) * cpu.cyp_size, UM_SLEEP | UM_GC);
293 caddr = (uintptr_t)cpu.cyp_cyclics;
294
295 if (mdb_vread(cyc, sizeof (cyclic_t) * cpu.cyp_size, caddr) == -1) {
296 mdb_warn("couldn't read cyclic at %p", caddr);
297 return (DCMD_ERR);
298 }
299
300 hsize = sizeof (cyc_index_t) * cpu.cyp_size;
301 heap = mdb_alloc(hsize, UM_SLEEP | UM_GC);
302
303 if (mdb_vread(heap, hsize, (uintptr_t)cpu.cyp_heap) == -1) {
304 mdb_warn("couldn't read heap at %p", cpu.cyp_heap);
305 return (DCMD_ERR);
306 }
307
308 root = heap[0];
309
310 mdb_printf("%3d %0*p %7s %6d ", c.cpu_id, CYC_ADDR_WIDTH, addr,
311 cpu.cyp_state == CYS_ONLINE ? "online" :
312 cpu.cyp_state == CYS_OFFLINE ? "offline" :
313 cpu.cyp_state == CYS_EXPANDING ? "expand" :
314 cpu.cyp_state == CYS_REMOVING ? "remove" :
315 cpu.cyp_state == CYS_SUSPENDED ? "suspend" : "????",
316 cpu.cyp_nelems);
317
318 if (cpu.cyp_nelems > 0)
319 mdb_printf("%0*p %15llx %a\n", CYC_ADDR_WIDTH,
320 caddr, cyc[root].cy_expire, cyc[root].cy_handler);
321 else
322 mdb_printf("%*s %15s %s\n", CYC_ADDR_WIDTH, "-", "-", "-");
323
324 if (!verbose && !Verbose)
325 return (DCMD_OK);
326
327 mdb_printf("\n");
328
329 cyclic_pretty_dump(&cpu);
330
331 mdb_inc_indent(2);
332
333 for (i = 0; i < cpu.cyp_size; i++) {
334 int j;
335
336 for (j = 0; j < cpu.cyp_size; j++) {
337 if (heap[j] == i)
338 break;
339 }
340
341 if (!Verbose && j >= cpu.cyp_nelems)
342 continue;
343
344 if (!header) {
345 header = 1;
346 mdb_printf("\n%*s %3s %4s %4s %5s %15s %7s %s\n",
347 CYC_ADDR_WIDTH, "ADDR", "NDX", "HEAP", "LEVL",
348 "PEND", "FIRE", "USECINT", "HANDLER");
349 }
350
351 mdb_printf("%0*p %3d ", CYC_ADDR_WIDTH,
352 caddr + i * sizeof (cyclic_t), i);
353
354 mdb_printf("%4d ", j);
355
356 if (j >= cpu.cyp_nelems) {
357 mdb_printf("%4s %5s %15s %7s %s\n", "-", "-",
358 "-", "-", "-");
359 continue;
360 }
361
362 mdb_printf("%4s %5d %15llx ",
363 cyc[i].cy_level == CY_HIGH_LEVEL ? "high" :
364 cyc[i].cy_level == CY_LOCK_LEVEL ? "lock" :
365 cyc[i].cy_level == CY_LOW_LEVEL ? "low" : "????",
366 cyc[i].cy_pend, cyc[i].cy_expire);
367
368 if (cyc[i].cy_interval + cyc[i].cy_expire != INT64_MAX)
369 mdb_printf("%7lld ", cyc[i].cy_interval /
370 (uint64_t)(NANOSEC / MICROSEC));
371 else
372 mdb_printf("%7s ", "-");
373
374 mdb_printf("%a\n", cyc[i].cy_handler);
375 }
376
377
378 if (!Verbose)
379 goto out;
380
381 for (lev = CY_LOW_LEVEL; lev < CY_LOW_LEVEL + CY_SOFT_LEVELS; lev++) {
382 cyc_softbuf_t *softbuf = &cpu.cyp_softbuf[lev];
383 char which = softbuf->cys_hard, shared = 1;
384 cyc_pcbuffer_t *pc;
385 size_t bufsiz;
386 cyc_index_t *buf;
387
388 if (softbuf->cys_hard != softbuf->cys_soft)
389 shared = 0;
390
391 again:
392 pc = &softbuf->cys_buf[which];
393 bufsiz = (pc->cypc_sizemask + 1) * sizeof (cyc_index_t);
394 buf = mdb_alloc(bufsiz, UM_SLEEP | UM_GC);
395
396 if (mdb_vread(buf, bufsiz, (uintptr_t)pc->cypc_buf) == -1) {
397 mdb_warn("couldn't read cypc_buf at %p", pc->cypc_buf);
398 continue;
399 }
400
401 mdb_printf("\n%3s %4s %4s %4s %*s %4s %*s\n", "CPU",
402 "LEVL", "USER", "NDX", CYC_ADDR_WIDTH, "ADDR", "CYC",
403 CYC_ADDR_WIDTH, "CYC_ADDR", "PEND");
404
405 for (i = 0; i <= pc->cypc_sizemask &&
406 i <= pc->cypc_prodndx; i++) {
407 uintptr_t cyc_addr = caddr + buf[i] * sizeof (cyclic_t);
408
409 mdb_printf("%3d %4s %4s ", c.cpu_id,
410 lev == CY_HIGH_LEVEL ? "high" :
411 lev == CY_LOCK_LEVEL ? "lock" :
412 lev == CY_LOW_LEVEL ? "low" : "????",
413 shared ? "shrd" : which == softbuf->cys_hard ?
414 "hard" : "soft");
415
416 mdb_printf("%4d %0*p ", i, CYC_ADDR_WIDTH,
417 (uintptr_t)&buf[i] - (uintptr_t)&buf[0] +
418 (uintptr_t)pc->cypc_buf, buf[i],
419 caddr + buf[i] * sizeof (cyclic_t));
420
421 if (i >= pc->cypc_prodndx)
422 mdb_printf("%4s %*s %5s ",
423 "-", CYC_ADDR_WIDTH, "-", "-");
424 else {
425 cyclic_t c;
426
427 if (mdb_vread(&c, sizeof (c), cyc_addr) == -1) {
428 mdb_warn("\ncouldn't read cyclic at "
429 "%p", cyc_addr);
430 continue;
431 }
432
433 mdb_printf("%4d %0*p %5d ", buf[i],
434 CYC_ADDR_WIDTH, cyc_addr, c.cy_pend);
435 }
436
437 if (i == (pc->cypc_consndx & pc->cypc_sizemask)) {
438 mdb_printf("<-- consndx");
439 if (i == (pc->cypc_prodndx & pc->cypc_sizemask))
440 mdb_printf(",prodndx");
441 mdb_printf("\n");
442 continue;
443 }
444
445 if (i == (pc->cypc_prodndx & pc->cypc_sizemask)) {
446 mdb_printf("<-- prodndx\n");
447 continue;
448 }
449 mdb_printf("\n");
450
451 if (i >= pc->cypc_prodndx)
452 break;
453 }
454
455 if (!shared && which == softbuf->cys_hard) {
456 which = softbuf->cys_soft;
457 goto again;
458 }
459 }
460
461 out:
462 mdb_dec_indent(2);
463 return (DCMD_OK);
464 }
465
466 int
cyctrace_walk_init(mdb_walk_state_t * wsp)467 cyctrace_walk_init(mdb_walk_state_t *wsp)
468 {
469 cyc_cpu_t *cpu;
470 int i;
471
472 cpu = mdb_zalloc(sizeof (cyc_cpu_t), UM_SLEEP);
473
474 if (wsp->walk_addr == NULL) {
475 /*
476 * If an address isn't provided, we'll use the passive buffer.
477 */
478 GElf_Sym sym;
479 cyc_tracebuf_t *tr = &cpu->cyp_trace[0];
480 uintptr_t addr;
481
482 if (mdb_lookup_by_name("cyc_ptrace", &sym) == -1) {
483 mdb_warn("couldn't find passive buffer");
484 return (-1);
485 }
486
487 addr = (uintptr_t)sym.st_value;
488
489 if (mdb_vread(tr, sizeof (cyc_tracebuf_t), addr) == -1) {
490 mdb_warn("couldn't read passive buffer");
491 return (-1);
492 }
493
494 wsp->walk_addr = addr - offsetof(cyc_cpu_t, cyp_trace[0]);
495 } else {
496 if (cyccpu_vread(cpu, wsp->walk_addr) == -1) {
497 mdb_warn("couldn't read cyc_cpu at %p", wsp->walk_addr);
498 mdb_free(cpu, sizeof (cyc_cpu_t));
499 return (-1);
500 }
501 }
502
503 for (i = 0; i < CY_LEVELS; i++) {
504 if (cpu->cyp_trace[i].cyt_ndx-- == 0)
505 cpu->cyp_trace[i].cyt_ndx = CY_NTRACEREC - 1;
506 }
507
508 wsp->walk_data = cpu;
509
510 return (0);
511 }
512
513 int
cyctrace_walk_step(mdb_walk_state_t * wsp)514 cyctrace_walk_step(mdb_walk_state_t *wsp)
515 {
516 cyc_cpu_t *cpu = wsp->walk_data;
517 cyc_tracebuf_t *buf = cpu->cyp_trace;
518 hrtime_t latest = 0;
519 int i, ndx, new_ndx, lev, rval;
520 uintptr_t addr;
521
522 for (i = 0; i < CY_LEVELS; i++) {
523 if ((ndx = buf[i].cyt_ndx) == -1)
524 continue;
525
526 /*
527 * Account for NPT.
528 */
529 buf[i].cyt_buf[ndx].cyt_tstamp <<= 1;
530 buf[i].cyt_buf[ndx].cyt_tstamp >>= 1;
531
532 if (buf[i].cyt_buf[ndx].cyt_tstamp > latest) {
533 latest = buf[i].cyt_buf[ndx].cyt_tstamp;
534 lev = i;
535 }
536 }
537
538 /*
539 * If we didn't find one, we're done.
540 */
541 if (latest == 0)
542 return (-1);
543
544 buf = &buf[lev];
545 ndx = buf->cyt_ndx;
546 addr = wsp->walk_addr +
547 (uintptr_t)&(buf->cyt_buf[ndx]) - (uintptr_t)cpu;
548
549 rval = wsp->walk_callback(addr, &buf->cyt_buf[ndx], wsp->walk_cbdata);
550
551 new_ndx = ndx == 0 ? CY_NTRACEREC - 1 : ndx - 1;
552
553 if (buf->cyt_buf[new_ndx].cyt_tstamp != 0 &&
554 buf->cyt_buf[new_ndx].cyt_tstamp > buf->cyt_buf[ndx].cyt_tstamp)
555 new_ndx = -1;
556
557 buf->cyt_ndx = new_ndx;
558
559 return (rval);
560 }
561
562 void
cyctrace_walk_fini(mdb_walk_state_t * wsp)563 cyctrace_walk_fini(mdb_walk_state_t *wsp)
564 {
565 cyc_cpu_t *cpu = wsp->walk_data;
566
567 mdb_free(cpu, sizeof (cyc_cpu_t));
568 }
569
570 #define WHYLEN 17
571
572 int
cyctrace_walk(uintptr_t addr,const cyc_tracerec_t * rec,cyc_cpu_t * cpu)573 cyctrace_walk(uintptr_t addr, const cyc_tracerec_t *rec, cyc_cpu_t *cpu)
574 {
575 int i;
576 char c[WHYLEN];
577
578 for (i = 0; cpu != NULL && i < CY_LEVELS; i++)
579 if (addr < (uintptr_t)&cpu->cyp_trace[i + 1].cyt_buf[0])
580 break;
581
582 (void) mdb_readstr(c, WHYLEN, (uintptr_t)rec->cyt_why);
583
584 mdb_printf("%08p %4s %15llx %-*s %15llx %15llx\n",
585 addr & UINT_MAX, cpu == NULL ? "pasv" :
586 i == CY_HIGH_LEVEL ? "high" : i == CY_LOCK_LEVEL ? "lock" :
587 i == CY_LOW_LEVEL ? "low" : "????", rec->cyt_tstamp, WHYLEN, c,
588 rec->cyt_arg0, rec->cyt_arg1);
589
590 return (0);
591 }
592
593 /*ARGSUSED*/
594 int
cyctrace(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)595 cyctrace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
596 {
597 if (!(flags & DCMD_ADDRSPEC) || argc != 0)
598 addr = NULL;
599
600 if (mdb_pwalk("cyctrace", (mdb_walk_cb_t)cyctrace_walk,
601 (void *)addr, addr) == -1) {
602 mdb_warn("couldn't walk cyctrace");
603 return (DCMD_ERR);
604 }
605
606 return (DCMD_OK);
607 }
608
609 int
cyccover_comp(const void * l,const void * r)610 cyccover_comp(const void *l, const void *r)
611 {
612 cyc_coverage_t *lhs = (cyc_coverage_t *)l;
613 cyc_coverage_t *rhs = (cyc_coverage_t *)r;
614
615 char ly[WHYLEN], ry[WHYLEN];
616
617 if (rhs->cyv_why == lhs->cyv_why)
618 return (0);
619
620 if (rhs->cyv_why == NULL)
621 return (-1);
622
623 if (lhs->cyv_why == NULL)
624 return (1);
625
626 (void) mdb_readstr(ly, WHYLEN, (uintptr_t)lhs->cyv_why);
627 (void) mdb_readstr(ry, WHYLEN, (uintptr_t)rhs->cyv_why);
628
629 return (strcmp(ly, ry));
630 }
631
632 /*ARGSUSED*/
633 int
cyccover(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)634 cyccover(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
635 {
636 cyc_coverage_t cv[CY_NCOVERAGE];
637 char c[WHYLEN];
638 GElf_Sym sym;
639 int i;
640
641 if ((flags & DCMD_ADDRSPEC) || argc != 0)
642 return (DCMD_USAGE);
643
644 if (mdb_lookup_by_name("cyc_coverage", &sym) == -1) {
645 mdb_warn("couldn't find coverage information");
646 return (DCMD_ABORT);
647 }
648
649 addr = (uintptr_t)sym.st_value;
650
651 if (mdb_vread(cv, sizeof (cyc_coverage_t) * CY_NCOVERAGE, addr) == -1) {
652 mdb_warn("couldn't read coverage array at %p", addr);
653 return (DCMD_ABORT);
654 }
655
656 mdb_printf("%-*s %8s %8s %8s %15s %15s\n",
657 WHYLEN, "POINT", "HIGH", "LOCK", "LOW/PASV", "ARG0", "ARG1");
658
659 qsort(cv, CY_NCOVERAGE, sizeof (cyc_coverage_t), cyccover_comp);
660
661 for (i = 0; i < CY_NCOVERAGE; i++) {
662 if (cv[i].cyv_why != NULL) {
663 (void) mdb_readstr(c, WHYLEN, (uintptr_t)cv[i].cyv_why);
664 mdb_printf("%-*s %8d %8d %8d %15llx %15llx\n",
665 WHYLEN, c,
666 cv[i].cyv_count[CY_HIGH_LEVEL],
667 cv[i].cyv_count[CY_LOCK_LEVEL],
668 cv[i].cyv_passive_count != 0 ?
669 cv[i].cyv_passive_count :
670 cv[i].cyv_count[CY_LOW_LEVEL],
671 cv[i].cyv_arg0, cv[i].cyv_arg1);
672 }
673 }
674
675 return (DCMD_OK);
676 }
677
678 /*ARGSUSED*/
679 int
cyclic(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)680 cyclic(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
681 {
682 cyclic_t cyc;
683
684 if (!(flags & DCMD_ADDRSPEC) || argc != 0)
685 return (DCMD_USAGE);
686
687 if (DCMD_HDRSPEC(flags))
688 mdb_printf("%?s %4s %5s %5s %15s %7s %s\n", "ADDR", "LEVL",
689 "PEND", "FLAGS", "FIRE", "USECINT", "HANDLER");
690
691 if (mdb_vread(&cyc, sizeof (cyclic_t), addr) == -1) {
692 mdb_warn("couldn't read cyclic at %p", addr);
693 return (DCMD_ERR);
694 }
695
696 mdb_printf("%0?p %4s %5d %04x %15llx %7lld %a\n", addr,
697 cyc.cy_level == CY_HIGH_LEVEL ? "high" :
698 cyc.cy_level == CY_LOCK_LEVEL ? "lock" :
699 cyc.cy_level == CY_LOW_LEVEL ? "low" : "????",
700 cyc.cy_pend, cyc.cy_flags, cyc.cy_expire,
701 cyc.cy_interval / (uint64_t)(NANOSEC / MICROSEC),
702 cyc.cy_handler);
703
704 return (DCMD_OK);
705 }
706
707 static int
cycid_cpu(cyc_cpu_t * addr,int ndx)708 cycid_cpu(cyc_cpu_t *addr, int ndx)
709 {
710 cyc_cpu_t cpu;
711 cpu_t c;
712 uintptr_t caddr;
713 cyclic_t cyc;
714
715 if (cyccpu_vread(&cpu, (uintptr_t)addr) == -1) {
716 mdb_warn("couldn't read cyc_cpu at %p", addr);
717 return (DCMD_ERR);
718 }
719
720 if (mdb_vread(&c, sizeof (c), (uintptr_t)cpu.cyp_cpu) == -1) {
721 mdb_warn("couldn't read cpu at %p", cpu.cyp_cpu);
722 return (DCMD_ERR);
723 }
724
725 caddr = (uintptr_t)cpu.cyp_cyclics + ndx * sizeof (cyclic_t);
726
727 if (mdb_vread(&cyc, sizeof (cyc), caddr) == -1) {
728 mdb_warn("couldn't read cyclic at %p", caddr);
729 return (DCMD_ERR);
730 }
731
732 mdb_printf("%4d %3d %?p %a\n", c.cpu_id, ndx, caddr, cyc.cy_handler);
733
734 return (DCMD_OK);
735 }
736
737 /*ARGSUSED*/
738 static int
cycid_walk_omni(uintptr_t addr,const cyc_omni_cpu_t * omni,int * ignored)739 cycid_walk_omni(uintptr_t addr, const cyc_omni_cpu_t *omni, int *ignored)
740 {
741 mdb_printf("%?s ");
742 cycid_cpu(omni->cyo_cpu, omni->cyo_ndx);
743
744 return (WALK_NEXT);
745 }
746
747 /*ARGSUSED*/
748 int
cycid(uintptr_t addr,uint_t flags,int ac,const mdb_arg_t * av)749 cycid(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av)
750 {
751 cyc_id_t id;
752
753 if (!(flags & DCMD_ADDRSPEC)) {
754 if (mdb_walk_dcmd("cyclic_id_cache", "cycid", ac, av) == -1) {
755 mdb_warn("can't walk cyclic_id_cache");
756 return (DCMD_ERR);
757 }
758
759 return (DCMD_OK);
760 }
761
762 if (DCMD_HDRSPEC(flags)) {
763 mdb_printf("%?s %4s %3s %?s %s\n", "ADDR", "CPU", "NDX",
764 "CYCLIC", "HANDLER");
765 }
766
767 if (mdb_vread(&id, sizeof (id), addr) == -1) {
768 mdb_warn("couldn't read cyc_id_t at %p", addr);
769 return (DCMD_ERR);
770 }
771
772 if (id.cyi_cpu == NULL) {
773 /*
774 * This is an omnipresent cyclic.
775 */
776 mdb_printf("%?p %4s %3s %?s %a\n", addr, "omni", "-", "-",
777 id.cyi_omni_hdlr.cyo_online);
778 mdb_printf("%?s |\n", "");
779 mdb_printf("%?s +-->%4s %3s %?s %s\n", "",
780 "CPU", "NDX", "CYCLIC", "HANDLER");
781
782 if (mdb_pwalk("cycomni",
783 (mdb_walk_cb_t)cycid_walk_omni, NULL, addr) == -1) {
784 mdb_warn("couldn't walk cycomni for %p", addr);
785 return (DCMD_ERR);
786 }
787
788 mdb_printf("\n");
789
790 return (DCMD_OK);
791 }
792
793 mdb_printf("%?p ", addr);
794
795 return (cycid_cpu(id.cyi_cpu, id.cyi_ndx));
796 }
797