/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sys/types.h>
#ifndef DEBUG
#define DEBUG
#define _SYS_DEBUG_H
#include <sys/xc_impl.h>
#undef DEBUG
#else
#define _SYS_DEBUG_H
#include <sys/xc_impl.h>
#endif
#include <sys/traptrace.h>
#include <sys/machparam.h>
#include <sys/intreg.h>
#include <sys/ivintr.h>
#include <sys/mutex_impl.h>
#include <mdb/mdb_modapi.h>
#include <mdb/mdb_ctf.h>
#include <mdb/mdb_whatis.h>
#include "sfmmu.h"
#ifndef SYSTRAP_TT
#define SYSTRAP_TT 0x1300
#endif
typedef struct trap_trace_fullrec {
struct trap_trace_record ttf_rec;
int ttf_cpu;
} trap_trace_fullrec_t;
#ifdef sun4v
typedef struct htrap_trace_fullrec {
struct htrap_trace_record ttf_rec;
int ttf_cpu;
} htrap_trace_fullrec_t;
#endif
/*
* These strings and accompanying macros allow our string table to look
* just like the real table in trap_table.s.
*/
static const char NOT[] = "reserved"; /* common reserved string */
static const char BAD[] = "unused"; /* common unused string */
#define NOT4 NOT, NOT, NOT, NOT
#define BAD4 BAD, BAD, BAD, BAD
static const char *const ttdescr[] = {
NOT, /* 000 reserved */
"power-on", /* 001 power on reset */
"watchdog", /* 002 watchdog reset */
"xir", /* 003 externally initiated reset */
"sir", /* 004 software initiated reset */
"red", /* 005 red mode exception */
NOT, NOT, /* 006 - 007 reserved */
"immu-xcp", /* 008 instruction access exception */
"immu-miss", /* 009 instruction access MMU miss */
"immu-err", /* 00A instruction access error */
NOT, NOT4, /* 00B - 00F reserved */
"ill-inst", /* 010 illegal instruction */
"priv-inst", /* 011 privileged opcode */
"unimp-ldd", /* 012 unimplemented LDD */
"unimp-std", /* 013 unimplemented STD */
NOT4, NOT4, NOT4, /* 014 - 01F reserved */
"fp-disable", /* 020 fp disabled */
"fp-ieee754", /* 021 fp exception ieee 754 */
"fp-xcp-other", /* 022 fp exception other */
"tag-oflow", /* 023 tag overflow */
"cleanwin", /* 024 clean window */
"cleanwin", /* 025 clean window */
"cleanwin", /* 026 clean window */
"cleanwin", /* 027 clean window */
"div-zero", /* 028 division by zero */
"internal-err", /* 029 internal processor error */
NOT, NOT, NOT4, /* 02A - 02F reserved */
"dmmu-xcp", /* 030 data access exception */
"dmmu-miss", /* 031 data access MMU miss */
"dmmu-err", /* 032 data access error */
"dmmu-prot", /* 033 data access protection */
"unalign", /* 034 mem address not aligned */
"lddf-unalign", /* 035 LDDF mem address not aligned */
"stdf-unalign", /* 036 STDF mem address not aligned */
"priv-act", /* 037 privileged action */
"ldqf-unalign", /* 038 LDQF mem address not aligned */
"stqf-unalign", /* 039 STQF mem address not aligned */
NOT, NOT, NOT4, /* 03A - 03F reserved */
"async-d-err", /* 040 async data error */
"level-1", /* 041 interrupt level 1 */
"level-2", /* 042 interrupt level 2 */
"level-3", /* 043 interrupt level 3 */
"level-4", /* 044 interrupt level 4 */
"level-5", /* 045 interrupt level 5 */
"level-6", /* 046 interrupt level 6 */
"level-7", /* 047 interrupt level 7 */
"level-8", /* 048 interrupt level 8 */
"level-9", /* 049 interrupt level 9 */
"level-10", /* 04A interrupt level 10 */
"level-11", /* 04B interrupt level 11 */
"level-12", /* 04C interrupt level 12 */
"level-13", /* 04D interrupt level 13 */
"level-14", /* 04E interrupt level 14 */
"level-15", /* 04F interrupt level 15 */
NOT4, NOT4, NOT4, NOT4, /* 050 - 05F reserved */
"int-vec", /* 060 interrupt vector */
"pa-watch", /* 061 PA watchpoint */
"va-watch", /* 062 VA watchpoint */
"ecc-err", /* 063 corrected ECC error */
"itlb-miss", /* 064 instruction access MMU miss */
"itlb-miss", /* 065 instruction access MMU miss */
"itlb-miss", /* 066 instruction access MMU miss */
"itlb-miss", /* 067 instruction access MMU miss */
"dtlb-miss", /* 068 data access MMU miss */
"dtlb-miss", /* 069 data access MMU miss */
"dtlb-miss", /* 06A data access MMU miss */
"dtlb-miss", /* 06B data access MMU miss */
"dtlb-prot", /* 06C data access protection */
"dtlb-prot", /* 06D data access protection */
"dtlb-prot", /* 06E data access protection */
"dtlb-prot", /* 06F data access protection */
"fast-ecc-err", /* 070 fast ecache ECC error */
"dp-err", /* 071 data cache parity error */
"ip-err", /* 072 instr cache parity error */
NOT, NOT4, NOT4, /* 073 - 07B reserved */
#ifdef sun4v
"cpu-mondo", /* 07C CPU mondo */
"dev-mondo", /* 07D device mondo */
"res.-err", /* 07E resumable error */
"non-res.-err", /* 07F non-resumable error */
#else
NOT4, /* 07C - 07F reserved */
#endif
"spill-0-norm", /* 080 spill 0 normal */
"spill-0-norm", /* 081 spill 0 normal */
"spill-0-norm", /* 082 spill 0 normal */
"spill-0-norm", /* 083 spill 0 normal */
"spill-1-norm", /* 084 spill 1 normal */
"spill-1-norm", /* 085 spill 1 normal */
"spill-1-norm", /* 086 spill 1 normal */
"spill-1-norm", /* 087 spill 1 normal */
"spill-2-norm", /* 088 spill 2 normal */
"spill-2-norm", /* 089 spill 2 normal */
"spill-2-norm", /* 08A spill 2 normal */
"spill-2-norm", /* 08B spill 2 normal */
"spill-3-norm", /* 08C spill 3 normal */
"spill-3-norm", /* 08D spill 3 normal */
"spill-3-norm", /* 08E spill 3 normal */
"spill-3-norm", /* 08F spill 3 normal */
"spill-4-norm", /* 090 spill 4 normal */
"spill-4-norm", /* 091 spill 4 normal */
"spill-4-norm", /* 092 spill 4 normal */
"spill-4-norm", /* 093 spill 4 normal */
"spill-5-norm", /* 094 spill 5 normal */
"spill-5-norm", /* 095 spill 5 normal */
"spill-5-norm", /* 096 spill 5 normal */
"spill-5-norm", /* 097 spill 5 normal */
"spill-6-norm", /* 098 spill 6 normal */
"spill-6-norm", /* 099 spill 6 normal */
"spill-6-norm", /* 09A spill 6 normal */
"spill-6-norm", /* 09B spill 6 normal */
"spill-7-norm", /* 09C spill 7 normal */
"spill-7-norm", /* 09D spill 7 normal */
"spill-7-norm", /* 09E spill 7 normal */
"spill-7-norm", /* 09F spill 7 normal */
"spill-0-oth", /* 0A0 spill 0 other */
"spill-0-oth", /* 0A1 spill 0 other */
"spill-0-oth", /* 0A2 spill 0 other */
"spill-0-oth", /* 0A3 spill 0 other */
"spill-1-oth", /* 0A4 spill 1 other */
"spill-1-oth", /* 0A5 spill 1 other */
"spill-1-oth", /* 0A6 spill 1 other */
"spill-1-oth", /* 0A7 spill 1 other */
"spill-2-oth", /* 0A8 spill 2 other */
"spill-2-oth", /* 0A9 spill 2 other */
"spill-2-oth", /* 0AA spill 2 other */
"spill-2-oth", /* 0AB spill 2 other */
"spill-3-oth", /* 0AC spill 3 other */
"spill-3-oth", /* 0AD spill 3 other */
"spill-3-oth", /* 0AE spill 3 other */
"spill-3-oth", /* 0AF spill 3 other */
"spill-4-oth", /* 0B0 spill 4 other */
"spill-4-oth", /* 0B1 spill 4 other */
"spill-4-oth", /* 0B2 spill 4 other */
"spill-4-oth", /* 0B3 spill 4 other */
"spill-5-oth", /* 0B4 spill 5 other */
"spill-5-oth", /* 0B5 spill 5 other */
"spill-5-oth", /* 0B6 spill 5 other */
"spill-5-oth", /* 0B7 spill 5 other */
"spill-6-oth", /* 0B8 spill 6 other */
"spill-6-oth", /* 0B9 spill 6 other */
"spill-6-oth", /* 0BA spill 6 other */
"spill-6-oth", /* 0BB spill 6 other */
"spill-7-oth", /* 0BC spill 7 other */
"spill-7-oth", /* 0BD spill 7 other */
"spill-7-oth", /* 0BE spill 7 other */
"spill-7-oth", /* 0BF spill 7 other */
"fill-0-norm", /* 0C0 fill 0 normal */
"fill-0-norm", /* 0C1 fill 0 normal */
"fill-0-norm", /* 0C2 fill 0 normal */
"fill-0-norm", /* 0C3 fill 0 normal */
"fill-1-norm", /* 0C4 fill 1 normal */
"fill-1-norm", /* 0C5 fill 1 normal */
"fill-1-norm", /* 0C6 fill 1 normal */
"fill-1-norm", /* 0C7 fill 1 normal */
"fill-2-norm", /* 0C8 fill 2 normal */
"fill-2-norm", /* 0C9 fill 2 normal */
"fill-2-norm", /* 0CA fill 2 normal */
"fill-2-norm", /* 0CB fill 2 normal */
"fill-3-norm", /* 0CC fill 3 normal */
"fill-3-norm", /* 0CD fill 3 normal */
"fill-3-norm", /* 0CE fill 3 normal */
"fill-3-norm", /* 0CF fill 3 normal */
"fill-4-norm", /* 0D0 fill 4 normal */
"fill-4-norm", /* 0D1 fill 4 normal */
"fill-4-norm", /* 0D2 fill 4 normal */
"fill-4-norm", /* 0D3 fill 4 normal */
"fill-5-norm", /* 0D4 fill 5 normal */
"fill-5-norm", /* 0D5 fill 5 normal */
"fill-5-norm", /* 0D6 fill 5 normal */
"fill-5-norm", /* 0D7 fill 5 normal */
"fill-6-norm", /* 0D8 fill 6 normal */
"fill-6-norm", /* 0D9 fill 6 normal */
"fill-6-norm", /* 0DA fill 6 normal */
"fill-6-norm", /* 0DB fill 6 normal */
"fill-7-norm", /* 0DC fill 7 normal */
"fill-7-norm", /* 0DD fill 7 normal */
"fill-7-norm", /* 0DE fill 7 normal */
"fill-7-norm", /* 0DF fill 7 normal */
"fill-0-oth", /* 0E0 fill 0 other */
"fill-0-oth", /* 0E1 fill 0 other */
"fill-0-oth", /* 0E2 fill 0 other */
"fill-0-oth", /* 0E3 fill 0 other */
"fill-1-oth", /* 0E4 fill 1 other */
"fill-1-oth", /* 0E5 fill 1 other */
"fill-1-oth", /* 0E6 fill 1 other */
"fill-1-oth", /* 0E7 fill 1 other */
"fill-2-oth", /* 0E8 fill 2 other */
"fill-2-oth", /* 0E9 fill 2 other */
"fill-2-oth", /* 0EA fill 2 other */
"fill-2-oth", /* 0EB fill 2 other */
"fill-3-oth", /* 0EC fill 3 other */
"fill-3-oth", /* 0ED fill 3 other */
"fill-3-oth", /* 0EE fill 3 other */
"fill-3-oth", /* 0EF fill 3 other */
"fill-4-oth", /* 0F0 fill 4 other */
"fill-4-oth", /* 0F1 fill 4 other */
"fill-4-oth", /* 0F2 fill 4 other */
"fill-4-oth", /* 0F3 fill 4 other */
"fill-5-oth", /* 0F4 fill 5 other */
"fill-5-oth", /* 0F5 fill 5 other */
"fill-5-oth", /* 0F6 fill 5 other */
"fill-5-oth", /* 0F7 fill 5 other */
"fill-6-oth", /* 0F8 fill 6 other */
"fill-6-oth", /* 0F9 fill 6 other */
"fill-6-oth", /* 0FA fill 6 other */
"fill-6-oth", /* 0FB fill 6 other */
"fill-7-oth", /* 0FC fill 7 other */
"fill-7-oth", /* 0FD fill 7 other */
"fill-7-oth", /* 0FE fill 7 other */
"fill-7-oth", /* 0FF fill 7 other */
"syscall-4x", /* 100 old system call */
"usr-brkpt", /* 101 user breakpoint */
"usr-div-zero", /* 102 user divide by zero */
"flush-wins", /* 103 flush windows */
"clean-wins", /* 104 clean windows */
"range-chk", /* 105 range check ?? */
"fix-align", /* 106 do unaligned references */
BAD, /* 107 unused */
"syscall-32", /* 108 ILP32 system call on LP64 */
"set-t0-addr", /* 109 set trap0 address */
BAD, BAD, BAD4, /* 10A - 10F unused */
BAD4, BAD4, BAD4, BAD4, /* 110 - 11F unused (V9 user traps?) */
"get-cc", /* 120 get condition codes */
"set-cc", /* 121 set condition codes */
"get-psr", /* 122 get psr */
"set-psr", /* 123 set psr (some fields) */
"getts", /* 124 get timestamp */
"gethrvtime", /* 125 get lwp virtual time */
"self-xcall", /* 126 self xcall */
"gethrtime", /* 127 get hrestime */
BAD, /* 128 unused (ST_SETV9STACK) */
"getlgrp", /* 129 get lgrpid */
BAD, BAD, BAD4, /* 12A - 12F unused */
BAD4, BAD4, /* 130 - 137 unused */
"dtrace-pid", /* 138 DTrace pid provider */
BAD, /* 139 unused */
"dtrace-return", /* 13A DTrace pid provider */
BAD, BAD4, /* 13B - 13F unused */
"syscall-64", /* 140 LP64 system call */
BAD, /* 141 unused */
"tt-freeze", /* 142 freeze traptrace */
"tt-unfreeze", /* 143 unfreeze traptrace */
BAD4, BAD4, BAD4, /* 144 - 14F unused */
BAD4, BAD4, BAD4, BAD4, /* 150 - 15F unused */
BAD4, BAD4, BAD4, BAD4, /* 160 - 16F unused */
BAD4, BAD4, BAD4, /* 170 - 17B unused */
"ptl1-panic", /* 17C test ptl1_panic */
"kmdb-enter", /* 17D kmdb enter (L1-A) */
"kmdb-brkpt", /* 17E kmdb breakpoint */
"obp-brkpt", /* 17F obp breakpoint */
#ifdef sun4v
"fast_trap", /* 180 hypervisor fast trap */
"cpu_tick_npt", /* 181 cpu_tick_npt() hcall */
"cpu_stick_npt", /* 182 cpu_stick_npt() hcall */
"mmu_map_addr", /* 183 mmu_map_addr() hcall */
"mmu_unmap_addr", /* 184 mmu_unmap_addr() hcall */
"ttrace_addentry", /* 185 ttrace_addentry() hcall */
NOT, NOT, NOT4, NOT4, /* 186 - 18F reserved */
#else
NOT4, NOT4, NOT4, NOT4, /* 180 - 18F reserved */
#endif
NOT4, NOT4, NOT4, NOT4, /* 190 - 19F reserved */
NOT4, NOT4, NOT4, NOT4, /* 1A0 - 1AF reserved */
NOT4, NOT4, NOT4, NOT4, /* 1B0 - 1BF reserved */
NOT4, NOT4, NOT4, NOT4, /* 1C0 - 1CF reserved */
NOT4, NOT4, NOT4, NOT4, /* 1D0 - 1DF reserved */
NOT4, NOT4, NOT4, NOT4, /* 1E0 - 1EF reserved */
NOT4, NOT4, NOT4, NOT4 /* 1F0 - 1FF reserved */
};
static const size_t ttndescr = sizeof (ttdescr) / sizeof (ttdescr[0]);
static GElf_Sym iv_sym;
/*
* Persistent data (shouldn't change).
*/
static int ncpu; /* _ncpu */
static ssize_t mbox_size; /* size of xc_mbox */
static ulong_t mbox_stoff; /* offset of xc_mbox.xc_state */
static mdb_ctf_id_t mbox_states; /* xc_state enumeration */
static int
fetch_ncpu(void)
{
if (ncpu == 0)
if (mdb_readsym(&ncpu, sizeof (ncpu), "_ncpu") == -1) {
mdb_warn("symbol '_ncpu' not found");
return (1);
}
return (0);
}
static int
fetch_mbox(void)
{
if (mbox_size <= 0) {
mdb_ctf_id_t id;
if (mdb_ctf_lookup_by_name("struct xc_mbox", &id) == -1) {
mdb_warn("couldn't find type 'struct xc_mbox'");
return (1);
}
/*
* These two could be combined into a single call to
* mdb_ctf_member_info if xc_state was actually of type
* enum xc_states.
*/
if (mdb_ctf_lookup_by_name("enum xc_states",
&mbox_states) == -1) {
mdb_warn("couldn't find type 'enum xc_states'");
return (1);
}
if (mdb_ctf_offsetof(id, "xc_state", &mbox_stoff) == -1) {
mdb_warn("couldn't find 'xc_mbox.xc_state'");
return (1);
}
mbox_stoff /= NBBY;
if ((mbox_size = mdb_ctf_type_size(id)) == -1) {
mdb_warn("couldn't size 'struct xc_mbox'");
return (1);
}
}
return (0);
}
static int
print_range(int start, int end, int separator)
{
int count;
char tmp;
char *format;
if (start == end) {
/* Unfortunately, mdb_printf returns void */
format = separator ? ", %d" : "%d";
mdb_printf(format, start);
count = mdb_snprintf(&tmp, 1, format, start);
} else {
format = separator ? ", %d-%d" : "%d-%d";
mdb_printf(format, start, end);
count = mdb_snprintf(&tmp, 1, format, start, end);
}
return (count);
}
static void
print_cpuset_range(ulong_t *cs, int words, int width)
{
int i, j;
ulong_t m;
int in = 0;
int start;
int end;
int count = 0;
int sep = 0;
for (i = 0; i < words; i++)
for (j = 0, m = 1; j < BT_NBIPUL; j++, m <<= 1)
if (cs[i] & m) {
if (in == 0) {
start = i * BT_NBIPUL + j;
in = 1;
}
} else {
if (in == 1) {
end = i * BT_NBIPUL + j - 1;
count += print_range(start, end, sep);
sep = 1;
in = 0;
}
}
if (in == 1) {
end = i * BT_NBIPUL - 1;
count += print_range(start, end, sep);
}
while (count++ < width)
mdb_printf(" ");
}
/*ARGSUSED*/
static int
cmd_cpuset(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
uint_t rflag = 0, lflag = 0;
int words;
ulong_t *setp, set = 0;
if (mdb_getopts(argc, argv,
'l', MDB_OPT_SETBITS, TRUE, &lflag,
'r', MDB_OPT_SETBITS, TRUE, &rflag, NULL) != argc)
return (DCMD_USAGE);
if (lflag && rflag)
return (DCMD_USAGE);
if (fetch_ncpu())
return (DCMD_ERR);
if ((words = BT_BITOUL(ncpu)) == 1) {
setp = &set;
mdb_vread(setp, sizeof (ulong_t), addr);
} else {
setp = mdb_alloc(words * sizeof (ulong_t), UM_SLEEP | UM_GC);
mdb_vread(setp, words * sizeof (ulong_t), addr);
}
if (lflag) {
int i, j;
ulong_t m;
for (i = 0; i < words; i++)
for (j = 0, m = 1; j < BT_NBIPUL; j++, m <<= 1)
if (setp[i] & m)
mdb_printf("%r\n", i * BT_NBIPUL + j);
} else if (rflag) {
int i;
int sep = 0;
for (i = 0; i < words; i++) {
mdb_printf(sep ? " %?0lx" : "%?0lx", setp[i]);
sep = 1;
}
} else {
print_cpuset_range(setp, words, 0);
}
return (DCMD_OK);
}
/*ARGSUSED*/
int
ttctl(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
TRAP_TRACE_CTL *ctls, *ctl;
int i, traptrace_buf_inuse = 0;
if (argc != 0)
return (DCMD_USAGE);
if (fetch_ncpu())
return (DCMD_ERR);
ctls = mdb_alloc(sizeof (TRAP_TRACE_CTL) * ncpu, UM_SLEEP | UM_GC);
if (mdb_readsym(ctls, sizeof (TRAP_TRACE_CTL) * ncpu,
"trap_trace_ctl") == -1) {
mdb_warn("symbol 'trap_trace_ctl' not found");
return (DCMD_ERR);
}
for (ctl = &ctls[0], i = 0; i < ncpu; i++, ctl++) {
if (ctl->d.vaddr_base == 0)
continue;
traptrace_buf_inuse = 1;
mdb_printf("trap_trace_ctl[%d] = {\n", i);
mdb_printf(" vaddr_base = 0x%lx\n", (long)ctl->d.vaddr_base);
mdb_printf(" last_offset = 0x%x\n", ctl->d.last_offset);
mdb_printf(" offset = 0x%x\n", ctl->d.offset);
mdb_printf(" limit = 0x%x\n", ctl->d.limit);
mdb_printf(" paddr_base = 0x%llx\n", ctl->d.paddr_base);
mdb_printf(" asi = 0x%02x\n}\n", ctl->d.asi);
}
if (!traptrace_buf_inuse) {
mdb_warn("traptrace not configured");
return (DCMD_ERR);
}
return (DCMD_OK);
}
/*ARGSUSED*/
static int
ttprint_short(uintptr_t addr, const trap_trace_fullrec_t *full, int *cpu)
{
const char *ttstr;
const struct trap_trace_record *ttp = &full->ttf_rec;
if (*cpu == -1)
mdb_printf("%3d ", full->ttf_cpu);
else
if (*cpu != full->ttf_cpu)
return (0);
/*
* Decoding the traptype field is a bit messy. First we check for
* several well-defined 16-bit values defined in <sys/traptrace.h>.
*/
switch (ttp->tt_tt) {
case TT_SC_ENTR:
ttstr = "sys-enter";
break;
case TT_SC_RET:
ttstr = "sys-exit";
break;
case TT_SYS_RTT_PROM:
ttstr = "prom_rtt";
break;
case TT_SYS_RTT_PRIV:
ttstr = "priv_rtt";
break;
case TT_SYS_RTT_USER:
ttstr = "user_rtt";
break;
case TT_INTR_EXIT:
ttstr = "int-thr-exit";
break;
default:
/*
* Next we consider several prefixes (which are
* typically OR'd with other information such as the
* %pil or %tt value at the time of the trace).
*/
switch (ttp->tt_tt & 0xff00) {
case TT_SERVE_INTR:
ttstr = "serve-intr";
break;
case TT_XCALL:
ttstr = "xcall";
break;
case TT_XCALL_CONT:
ttstr = "xcall-cont";
break;
case SYSTRAP_TT:
ttstr = "sys_trap";
break;
default:
/*
* Otherwise we try to convert the
* tt value to a string using our
* giant lookup table.
*/
ttstr = ttp->tt_tt < ttndescr ?
ttdescr[ttp->tt_tt] : "?";
}
}
#ifdef sun4v
mdb_printf("%016llx %04hx %-12s %02x %02x %0?p %A\n", ttp->tt_tick,
ttp->tt_tt, ttstr, ttp->tt_tl, ttp->tt_gl,
ttp->tt_tpc, ttp->tt_tpc);
#else
mdb_printf("%016llx %04hx %-12s %04hx %0?p %A\n", ttp->tt_tick,
ttp->tt_tt, ttstr, ttp->tt_tl, ttp->tt_tpc, ttp->tt_tpc);
#endif
return (WALK_NEXT);
}
/*ARGSUSED*/
static int
ttprint_long(uintptr_t addr, const trap_trace_fullrec_t *full, int *cpu)
{
const struct trap_trace_record *ttp = &full->ttf_rec;
if (*cpu == -1)
mdb_printf("%3d ", full->ttf_cpu);
else if (*cpu != full->ttf_cpu)
return (WALK_NEXT);
#ifdef sun4v
mdb_printf("%016llx %016llx %04hx %02x %02x %0?p %0?p %0?p "
"[%p,%p,%p,%p]\n",
ttp->tt_tick, ttp->tt_tstate, ttp->tt_tt, ttp->tt_tl, ttp->tt_gl,
ttp->tt_tpc, ttp->tt_sp, ttp->tt_tr,
ttp->tt_f1, ttp->tt_f2, ttp->tt_f3, ttp->tt_f4);
#else
mdb_printf("%016llx %016llx %04hx %04hx %0?p %0?p %0?p [%p,%p,%p,%p]\n",
ttp->tt_tick, ttp->tt_tstate, ttp->tt_tt, ttp->tt_tl,
ttp->tt_tpc, ttp->tt_sp, ttp->tt_tr,
ttp->tt_f1, ttp->tt_f2, ttp->tt_f3, ttp->tt_f4);
#endif
return (WALK_NEXT);
}
typedef struct ttrace_cpu_data {
struct trap_trace_record *tc_buf;
struct trap_trace_record *tc_rec;
struct trap_trace_record *tc_stop;
size_t tc_bufsiz;
uintptr_t tc_base;
} ttrace_cpu_data_t;
typedef struct ttrace_walk_data {
int tw_ncpu;
ttrace_cpu_data_t *tw_cpus;
} ttrace_walk_data_t;
int
ttrace_walk_init(mdb_walk_state_t *wsp)
{
TRAP_TRACE_CTL *ctls, *ctl;
int i, traptrace_buf_inuse = 0;
ttrace_walk_data_t *tw;
ttrace_cpu_data_t *tc;
struct trap_trace_record *buf;
if (wsp->walk_addr != NULL) {
mdb_warn("ttrace only supports global walks\n");
return (WALK_ERR);
}
if (fetch_ncpu())
return (WALK_ERR);
ctls = mdb_alloc(sizeof (TRAP_TRACE_CTL) * ncpu, UM_SLEEP);
if (mdb_readsym(ctls, sizeof (TRAP_TRACE_CTL) * ncpu,
"trap_trace_ctl") == -1) {
mdb_warn("symbol 'trap_trace_ctl' not found");
mdb_free(ctls, sizeof (TRAP_TRACE_CTL) * ncpu);
return (WALK_ERR);
}
tw = mdb_zalloc(sizeof (ttrace_walk_data_t), UM_SLEEP);
tw->tw_ncpu = ncpu;
tw->tw_cpus = mdb_zalloc(sizeof (ttrace_cpu_data_t) * ncpu, UM_SLEEP);
for (i = 0; i < ncpu; i++) {
ctl = &ctls[i];
if (ctl->d.vaddr_base == 0)
continue;
traptrace_buf_inuse = 1;
tc = &(tw->tw_cpus[i]);
tc->tc_bufsiz = ctl->d.limit -
sizeof (struct trap_trace_record);
tc->tc_buf = buf = mdb_alloc(tc->tc_bufsiz, UM_SLEEP);
tc->tc_base = (uintptr_t)ctl->d.vaddr_base;
if (mdb_vread(buf, tc->tc_bufsiz, tc->tc_base) == -1) {
mdb_warn("failed to read trap trace buffer at %p",
ctl->d.vaddr_base);
mdb_free(buf, tc->tc_bufsiz);
tc->tc_buf = NULL;
} else {
tc->tc_rec = (struct trap_trace_record *)
((uintptr_t)buf + (uintptr_t)ctl->d.last_offset);
tc->tc_stop = (struct trap_trace_record *)
((uintptr_t)buf + (uintptr_t)ctl->d.offset);
}
}
if (!traptrace_buf_inuse) {
mdb_warn("traptrace not configured");
mdb_free(ctls, sizeof (TRAP_TRACE_CTL) * ncpu);
return (DCMD_ERR);
}
mdb_free(ctls, sizeof (TRAP_TRACE_CTL) * ncpu);
wsp->walk_data = tw;
return (WALK_NEXT);
}
int
ttrace_walk_step(mdb_walk_state_t *wsp)
{
ttrace_walk_data_t *tw = wsp->walk_data;
ttrace_cpu_data_t *tc;
struct trap_trace_record *rec;
int oldest, i, status;
uint64_t oldest_tick = 0;
int done = 1;
trap_trace_fullrec_t fullrec;
for (i = 0; i < tw->tw_ncpu; i++) {
tc = &(tw->tw_cpus[i]);
if (tc->tc_rec == NULL)
continue;
done = 0;
if (tc->tc_rec->tt_tick == 0)
mdb_warn("Warning: tt_tick == 0\n");
if (tc->tc_rec->tt_tick > oldest_tick) {
oldest_tick = tc->tc_rec->tt_tick;
oldest = i;
}
}
if (done)
return (-1);
tc = &(tw->tw_cpus[oldest]);
rec = tc->tc_rec;
fullrec.ttf_rec = *rec;
fullrec.ttf_cpu = oldest;
if (oldest_tick != 0)
status = wsp->walk_callback((uintptr_t)rec -
(uintptr_t)tc->tc_buf + tc->tc_base, &fullrec,
wsp->walk_cbdata);
tc->tc_rec--;
if (tc->tc_rec < tc->tc_buf)
tc->tc_rec = (struct trap_trace_record *)((uintptr_t)
tc->tc_buf + (uintptr_t)tc->tc_bufsiz -
sizeof (struct trap_trace_record));
if (tc->tc_rec == tc->tc_stop) {
tc->tc_rec = NULL;
mdb_free(tc->tc_buf, tc->tc_bufsiz);
}
return (status);
}
void
ttrace_walk_fini(mdb_walk_state_t *wsp)
{
ttrace_walk_data_t *tw = wsp->walk_data;
mdb_free(tw->tw_cpus, sizeof (ttrace_cpu_data_t) * tw->tw_ncpu);
mdb_free(tw, sizeof (ttrace_walk_data_t));
}
int
ttrace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
uint_t opt_x = FALSE;
int cpu = -1;
mdb_walk_cb_t ttprint;
if (mdb_getopts(argc, argv,
'x', MDB_OPT_SETBITS, TRUE, &opt_x, NULL) != argc)
return (DCMD_USAGE);
if (flags & DCMD_ADDRSPEC) {
if (fetch_ncpu())
return (DCMD_ERR);
if (addr >= ncpu) {
mdb_warn("expected cpu between 0 and %d\n", ncpu - 1);
return (DCMD_ERR);
}
cpu = (int)addr;
}
if (cpu == -1)
mdb_printf("CPU ");
if (opt_x) {
#ifdef sun4v
mdb_printf("%-16s %-16s %-4s %-3s %-3s %-?s %-?s %-?s "
"F1-4\n", "%tick", "%tstate", "%tt", "%tl", "%gl",
"%tpc", "%sp", "TR");
#else
mdb_printf("%-16s %-16s %-4s %-4s %-?s %-?s %-?s "
"F1-4\n", "%tick", "%tstate", "%tt", "%tl",
"%tpc", "%sp", "TR");
#endif
ttprint = (mdb_walk_cb_t)ttprint_long;
} else {
#ifdef sun4v
mdb_printf("%-16s %-4s %-12s %-3s %-3s %s\n",
"%tick", "%tt", "", "%tl", "%gl", "%tpc");
#else
mdb_printf("%-16s %-4s %-12s %-4s %s\n",
"%tick", "%tt", "", "%tl", "%tpc");
#endif
ttprint = (mdb_walk_cb_t)ttprint_short;
}
if (mdb_walk("ttrace", ttprint, &cpu) == -1) {
mdb_warn("couldn't walk ttrace");
return (DCMD_ERR);
}
return (DCMD_OK);
}
#ifdef sun4v
/*ARGSUSED*/
int
httctl(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
TRAP_TRACE_CTL *ctls, *ctl;
int i, htraptrace_buf_inuse = 0;
htrap_trace_hdr_t hdr;
if (argc != 0)
return (DCMD_USAGE);
if (fetch_ncpu())
return (DCMD_ERR);
ctls = mdb_alloc(sizeof (TRAP_TRACE_CTL) * ncpu, UM_SLEEP | UM_GC);
if (mdb_readsym(ctls, sizeof (TRAP_TRACE_CTL) * ncpu,
"trap_trace_ctl") == -1) {
mdb_warn("symbol 'trap_trace_ctl' not found");
return (DCMD_ERR);
}
for (ctl = &ctls[0], i = 0; i < ncpu; i++, ctl++) {
if (ctl->d.hvaddr_base == 0)
continue;
htraptrace_buf_inuse = 1;
mdb_vread(&hdr, sizeof (htrap_trace_hdr_t),
(uintptr_t)ctl->d.hvaddr_base);
mdb_printf("htrap_trace_ctl[%d] = {\n", i);
mdb_printf(" vaddr_base = 0x%lx\n", (long)ctl->d.hvaddr_base);
mdb_printf(" last_offset = 0x%lx\n", hdr.last_offset);
mdb_printf(" offset = 0x%lx\n", hdr.offset);
mdb_printf(" limit = 0x%x\n", ctl->d.hlimit);
mdb_printf(" paddr_base = 0x%llx\n}\n", ctl->d.hpaddr_base);
}
if (!htraptrace_buf_inuse) {
mdb_warn("hv traptrace not configured");
return (DCMD_ERR);
}
return (DCMD_OK);
}
/*ARGSUSED*/
static int
httprint_short(uintptr_t addr, const htrap_trace_fullrec_t *full, int *cpu)
{
const char *ttstr;
const struct htrap_trace_record *ttp = &full->ttf_rec;
if (*cpu == -1)
mdb_printf("%3d ", full->ttf_cpu);
else
if (*cpu != full->ttf_cpu)
return (0);
/*
* Convert the tt value to a string using our gaint lookuo table
*/
ttstr = ttp->tt_tt < ttndescr ? ttdescr[ttp->tt_tt] : "?";
mdb_printf("%016llx %02x %04hx %04hx %-16s %02x %02x %0?p %A\n",
ttp->tt_tick, ttp->tt_ty, ttp->tt_tag, ttp->tt_tt, ttstr,
ttp->tt_tl, ttp->tt_gl, ttp->tt_tpc, ttp->tt_tpc);
return (WALK_NEXT);
}
/*ARGSUSED*/
static int
httprint_long(uintptr_t addr, const htrap_trace_fullrec_t *full, int *cpu)
{
const struct htrap_trace_record *ttp = &full->ttf_rec;
if (*cpu == -1)
mdb_printf("%3d ", full->ttf_cpu);
else if (*cpu != full->ttf_cpu)
return (WALK_NEXT);
mdb_printf("%016llx %016llx %02x %02x %04hx %04hx %02x %02x %0?p "
"[%p,%p,%p,%p]\n",
ttp->tt_tick, ttp->tt_tstate, ttp->tt_hpstate, ttp->tt_ty,
ttp->tt_tag, ttp->tt_tt, ttp->tt_tl, ttp->tt_gl, ttp->tt_tpc,
ttp->tt_f1, ttp->tt_f2, ttp->tt_f3, ttp->tt_f4);
return (WALK_NEXT);
}
typedef struct httrace_cpu_data {
struct htrap_trace_record *tc_buf;
struct htrap_trace_record *tc_rec;
struct htrap_trace_record *tc_stop;
size_t tc_bufsiz;
uintptr_t tc_base;
} httrace_cpu_data_t;
typedef struct httrace_walk_data {
int tw_ncpu;
httrace_cpu_data_t *tw_cpus;
} httrace_walk_data_t;
int
httrace_walk_init(mdb_walk_state_t *wsp)
{
TRAP_TRACE_CTL *ctls, *ctl;
int i, htraptrace_buf_inuse = 0;
httrace_walk_data_t *tw;
httrace_cpu_data_t *tc;
struct htrap_trace_record *buf;
htrap_trace_hdr_t *hdr;
if (wsp->walk_addr != NULL) {
mdb_warn("httrace only supports global walks\n");
return (WALK_ERR);
}
if (fetch_ncpu())
return (WALK_ERR);
ctls = mdb_alloc(sizeof (TRAP_TRACE_CTL) * ncpu, UM_SLEEP);
if (mdb_readsym(ctls, sizeof (TRAP_TRACE_CTL) * ncpu,
"trap_trace_ctl") == -1) {
mdb_warn("symbol 'trap_trace_ctl' not found");
mdb_free(ctls, sizeof (TRAP_TRACE_CTL) * ncpu);
return (WALK_ERR);
}
tw = mdb_zalloc(sizeof (httrace_walk_data_t), UM_SLEEP);
tw->tw_ncpu = ncpu;
tw->tw_cpus = mdb_zalloc(sizeof (httrace_cpu_data_t) * ncpu, UM_SLEEP);
for (i = 0; i < ncpu; i++) {
ctl = &ctls[i];
if (ctl->d.hvaddr_base == 0)
continue;
htraptrace_buf_inuse = 1;
tc = &(tw->tw_cpus[i]);
tc->tc_bufsiz = ctl->d.hlimit;
tc->tc_buf = buf = mdb_alloc(tc->tc_bufsiz, UM_SLEEP);
tc->tc_base = (uintptr_t)ctl->d.hvaddr_base;
if (mdb_vread(buf, tc->tc_bufsiz, tc->tc_base) == -1) {
mdb_warn("failed to read hv trap trace buffer at %p",
ctl->d.hvaddr_base);
mdb_free(buf, tc->tc_bufsiz);
tc->tc_buf = NULL;
} else {
hdr = (htrap_trace_hdr_t *)buf;
tc->tc_rec = (struct htrap_trace_record *)
((uintptr_t)buf + (uintptr_t)hdr->last_offset);
tc->tc_stop = (struct htrap_trace_record *)
((uintptr_t)buf + (uintptr_t)hdr->offset);
}
}
if (!htraptrace_buf_inuse) {
mdb_warn("hv traptrace not configured");
mdb_free(ctls, sizeof (TRAP_TRACE_CTL) * ncpu);
return (DCMD_ERR);
}
mdb_free(ctls, sizeof (TRAP_TRACE_CTL) * ncpu);
wsp->walk_data = tw;
return (WALK_NEXT);
}
int
httrace_walk_step(mdb_walk_state_t *wsp)
{
httrace_walk_data_t *tw = wsp->walk_data;
httrace_cpu_data_t *tc;
struct htrap_trace_record *rec;
int oldest, i, status;
uint64_t oldest_tick = 0;
int done = 1;
htrap_trace_fullrec_t fullrec;
for (i = 0; i < tw->tw_ncpu; i++) {
tc = &(tw->tw_cpus[i]);
if (tc->tc_rec == NULL)
continue;
done = 0;
if (tc->tc_rec->tt_tick == 0)
mdb_warn("Warning: tt_tick == 0\n");
if (tc->tc_rec->tt_tick >= oldest_tick) {
oldest_tick = tc->tc_rec->tt_tick;
oldest = i;
}
}
if (done)
return (-1);
tc = &(tw->tw_cpus[oldest]);
rec = tc->tc_rec;
fullrec.ttf_rec = *rec;
fullrec.ttf_cpu = oldest;
if (oldest_tick != 0)
status = wsp->walk_callback((uintptr_t)rec -
(uintptr_t)tc->tc_buf + tc->tc_base, &fullrec,
wsp->walk_cbdata);
tc->tc_rec--;
/* first record of the trap trace buffer is trap trace header */
if (tc->tc_rec == tc->tc_buf)
tc->tc_rec = (struct htrap_trace_record *)((uintptr_t)
tc->tc_buf + (uintptr_t)tc->tc_bufsiz -
sizeof (struct htrap_trace_record));
if (tc->tc_rec == tc->tc_stop) {
tc->tc_rec = NULL;
mdb_free(tc->tc_buf, tc->tc_bufsiz);
}
return (status);
}
void
httrace_walk_fini(mdb_walk_state_t *wsp)
{
httrace_walk_data_t *tw = wsp->walk_data;
mdb_free(tw->tw_cpus, sizeof (httrace_cpu_data_t) * tw->tw_ncpu);
mdb_free(tw, sizeof (httrace_walk_data_t));
}
int
httrace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
uint_t opt_x = FALSE;
int cpu = -1;
mdb_walk_cb_t ttprint;
if (mdb_getopts(argc, argv,
'x', MDB_OPT_SETBITS, TRUE, &opt_x, NULL) != argc)
return (DCMD_USAGE);
if (flags & DCMD_ADDRSPEC) {
if (fetch_ncpu())
return (DCMD_ERR);
if (addr >= ncpu) {
mdb_warn("expected cpu between 0 and %d\n", ncpu - 1);
return (DCMD_ERR);
}
cpu = (int)addr;
}
if (cpu == -1)
mdb_printf("CPU ");
if (opt_x) {
mdb_printf("%-16s %-16s %-3s %-3s %-4s %-4s %-3s %-3s %-?s "
"F1-4\n", "%tick", "%tstate", "%hp", "%ty", "%tag",
"%tt", "%tl", "%gl", "%tpc");
ttprint = (mdb_walk_cb_t)httprint_long;
} else {
mdb_printf("%-16s %-3s %-4s %-4s %-16s %-3s %-3s %s\n",
"%tick", "%ty", "%tag", "%tt", "", "%tl", "%gl",
"%tpc");
ttprint = (mdb_walk_cb_t)httprint_short;
}
if (mdb_walk("httrace", ttprint, &cpu) == -1) {
mdb_warn("couldn't walk httrace");
return (DCMD_ERR);
}
return (DCMD_OK);
}
#endif
struct {
int xc_type;
const char *xc_str;
} xc_data[] = {
{ XT_ONE_SELF, "xt-one-self" },
{ XT_ONE_OTHER, "xt-one-other" },
{ XT_SOME_SELF, "xt-some-self" },
{ XT_SOME_OTHER, "xt-some-other" },
{ XT_ALL_SELF, "xt-all-self" },
{ XT_ALL_OTHER, "xt-all-other" },
{ XC_ONE_SELF, "xc-one-self" },
{ XC_ONE_OTHER, "xc-one-other" },
{ XC_ONE_OTHER_H, "xc-one-other-h" },
{ XC_SOME_SELF, "xc-some-self" },
{ XC_SOME_OTHER, "xc-some-other" },
{ XC_SOME_OTHER_H, "xc-some-other-h" },
{ XC_ALL_SELF, "xc-all-self" },
{ XC_ALL_OTHER, "xc-all-other" },
{ XC_ALL_OTHER_H, "xc-all-other-h" },
{ XC_ATTENTION, "xc-attention" },
{ XC_DISMISSED, "xc-dismissed" },
{ XC_LOOP_ENTER, "xc-loop-enter" },
{ XC_LOOP_DOIT, "xc-loop-doit" },
{ XC_LOOP_EXIT, "xc-loop-exit" },
{ 0, NULL }
};
/*ARGSUSED*/
int
xctrace_walk(uintptr_t addr, const trap_trace_fullrec_t *full, int *cpu)
{
const struct trap_trace_record *ttp = &full->ttf_rec;
int i, type = ttp->tt_tt & 0xff;
const char *str = "???";
if ((ttp->tt_tt & 0xff00) == TT_XCALL) {
for (i = 0; xc_data[i].xc_str != NULL; i++) {
if (xc_data[i].xc_type == type) {
str = xc_data[i].xc_str;
break;
}
}
} else if ((ttp->tt_tt & 0xff00) == TT_XCALL_CONT) {
str = "xcall-cont";
mdb_printf("%3d %016llx %-16s %08x %08x %08x %08x\n",
full->ttf_cpu, ttp->tt_tick, str, ttp->tt_f1, ttp->tt_f2,
ttp->tt_f3, ttp->tt_f4);
return (WALK_NEXT);
} else if (ttp->tt_tt == 0x60) {
str = "int-vec";
} else {
return (WALK_NEXT);
}
mdb_printf("%3d %016llx %-16s %08x %a\n", full->ttf_cpu,
ttp->tt_tick, str, ttp->tt_sp, ttp->tt_tr);
return (WALK_NEXT);
}
/*ARGSUSED*/
int
xctrace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
if ((flags & DCMD_ADDRSPEC) || argc != 0)
return (DCMD_USAGE);
if (mdb_walk("ttrace", (mdb_walk_cb_t)xctrace_walk, NULL) == -1) {
mdb_warn("couldn't walk ttrace");
return (DCMD_ERR);
}
return (DCMD_OK);
}
/*
* Grrr... xc_mbox isn't in an _impl header file; we define it here.
*/
typedef struct xc_mbox {
xcfunc_t *xc_func;
uint64_t xc_arg1;
uint64_t xc_arg2;
cpuset_t xc_cpuset;
volatile uint_t xc_state;
} xc_mbox_t;
typedef struct xc_mbox_walk {
int xw_ndx;
uintptr_t xw_addr;
xc_mbox_t *xw_mbox;
} xc_mbox_walk_t;
static int
xc_mbox_walk_init(mdb_walk_state_t *wsp)
{
GElf_Sym sym;
xc_mbox_walk_t *xw;
if (mdb_lookup_by_name("xc_mbox", &sym) == -1) {
mdb_warn("couldn't find 'xc_mbox'");
return (WALK_ERR);
}
if (fetch_ncpu() || fetch_mbox())
return (WALK_ERR);
xw = mdb_zalloc(sizeof (xc_mbox_walk_t), UM_SLEEP);
xw->xw_mbox = mdb_zalloc(mbox_size * ncpu, UM_SLEEP);
if (mdb_readsym(xw->xw_mbox, mbox_size * ncpu, "xc_mbox") == -1) {
mdb_warn("couldn't read 'xc_mbox'");
mdb_free(xw->xw_mbox, mbox_size * ncpu);
mdb_free(xw, sizeof (xc_mbox_walk_t));
return (WALK_ERR);
}
xw->xw_addr = sym.st_value;
wsp->walk_data = xw;
return (WALK_NEXT);
}
static int
xc_mbox_walk_step(mdb_walk_state_t *wsp)
{
xc_mbox_walk_t *xw = wsp->walk_data;
int status;
if (xw->xw_ndx == ncpu)
return (WALK_DONE);
status = wsp->walk_callback(xw->xw_addr,
&xw->xw_mbox[xw->xw_ndx++], wsp->walk_cbdata);
xw->xw_addr += mbox_size;
return (status);
}
static void
xc_mbox_walk_fini(mdb_walk_state_t *wsp)
{
xc_mbox_walk_t *xw = wsp->walk_data;
mdb_free(xw->xw_mbox, mbox_size * ncpu);
mdb_free(xw, sizeof (xc_mbox_walk_t));
}
static int
xc_mbox(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
xc_mbox_t *mbox;
GElf_Sym sym;
const char *state;
if (argc != 0)
return (DCMD_USAGE);
if (!(flags & DCMD_ADDRSPEC)) {
if (mdb_walk_dcmd("xc_mbox", "xc_mbox", argc, argv) == -1) {
mdb_warn("can't walk 'xc_mbox'");
return (DCMD_ERR);
}
return (DCMD_OK);
}
if (fetch_ncpu() || fetch_mbox())
return (DCMD_ERR);
if (DCMD_HDRSPEC(flags)) {
mdb_printf("%3s %-8s %-8s %-9s %-16s %-16s %s\n",
"CPU", "ADDR", "STATE", "CPUSET", "ARG1", "ARG2", "HNDLR");
}
mbox = mdb_alloc(mbox_size, UM_SLEEP | UM_GC);
if (mdb_vread(mbox, mbox_size, addr) == -1) {
mdb_warn("couldn't read xc_mbox at %p", addr);
return (DCMD_ERR);
}
if (mbox->xc_func == NULL)
return (DCMD_OK);
if (mdb_lookup_by_name("xc_mbox", &sym) == -1) {
mdb_warn("couldn't read 'xc_mbox'");
return (DCMD_ERR);
}
state = mdb_ctf_enum_name(mbox_states,
/* LINTED - alignment */
*(int *)((char *)mbox + mbox_stoff));
mdb_printf("%3d %08x %-8s [ ",
(int)((addr - sym.st_value) / mbox_size), addr,
state ? state : "XC_???");
print_cpuset_range((ulong_t *)&mbox->xc_cpuset, BT_BITOUL(ncpu), 5);
mdb_printf(" ] %-16a %-16a %a\n",
mbox->xc_arg1, mbox->xc_arg2, mbox->xc_func);
return (DCMD_OK);
}
typedef struct vecint_walk_data {
intr_vec_t **vec_table;
uintptr_t vec_base;
size_t vec_idx;
size_t vec_size;
} vecint_walk_data_t;
int
vecint_walk_init(mdb_walk_state_t *wsp)
{
vecint_walk_data_t *vecint;
if (wsp->walk_addr != NULL) {
mdb_warn("vecint walk only supports global walks\n");
return (WALK_ERR);
}
vecint = mdb_zalloc(sizeof (vecint_walk_data_t), UM_SLEEP);
vecint->vec_size = MAXIVNUM * sizeof (intr_vec_t *);
vecint->vec_base = (uintptr_t)iv_sym.st_value;
vecint->vec_table = mdb_zalloc(vecint->vec_size, UM_SLEEP);
if (mdb_vread(vecint->vec_table, vecint->vec_size,
vecint->vec_base) == -1) {
mdb_warn("couldn't read intr_vec_table");
mdb_free(vecint->vec_table, vecint->vec_size);
mdb_free(vecint, sizeof (vecint_walk_data_t));
return (WALK_ERR);
}
wsp->walk_data = vecint;
return (WALK_NEXT);
}
int
vecint_walk_step(mdb_walk_state_t *wsp)
{
vecint_walk_data_t *vecint = (vecint_walk_data_t *)wsp->walk_data;
size_t max = vecint->vec_size / sizeof (intr_vec_t *);
intr_vec_t iv;
int status;
if (wsp->walk_addr == NULL) {
while ((vecint->vec_idx < max) && ((wsp->walk_addr =
(uintptr_t)vecint->vec_table[vecint->vec_idx++]) == NULL))
continue;
}
if (wsp->walk_addr == NULL)
return (WALK_DONE);
status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
wsp->walk_cbdata);
if (mdb_vread(&iv, sizeof (intr_vec_t),
(uintptr_t)wsp->walk_addr) == -1) {
mdb_warn("failed to read iv_p %p\n", wsp->walk_addr);
return (WALK_ERR);
}
wsp->walk_addr = (uintptr_t)iv.iv_vec_next;
return (status);
}
void
vecint_walk_fini(mdb_walk_state_t *wsp)
{
vecint_walk_data_t *vecint = wsp->walk_data;
mdb_free(vecint->vec_table, vecint->vec_size);
mdb_free(vecint, sizeof (vecint_walk_data_t));
}
int
vecint_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
intr_vec_t iv;
if (!(flags & DCMD_ADDRSPEC)) {
if (mdb_walk_dcmd("vecint", "vecint", argc, argv) == -1) {
mdb_warn("can't walk vecint");
return (DCMD_ERR);
}
return (DCMD_OK);
}
if (DCMD_HDRSPEC(flags)) {
mdb_printf("%4s %?s %4s %?s %?s %s\n", "INUM", "ADDR",
"PIL", "ARG1", "ARG2", "HANDLER");
}
if (mdb_vread(&iv, sizeof (iv), addr) == -1) {
mdb_warn("couldn't read intr_vec_table at %p", addr);
return (DCMD_ERR);
}
mdb_printf("%4x %?p %4d %?p %?p %a\n", iv.iv_inum, addr,
iv.iv_pil, iv.iv_arg1, iv.iv_arg2, iv.iv_handler);
return (DCMD_OK);
}
int
softint_walk_init(mdb_walk_state_t *wsp)
{
intr_vec_t *list;
if (wsp->walk_addr != NULL) {
mdb_warn("softint walk only supports global walks\n");
return (WALK_ERR);
}
/* Read global softint linked list pointer */
if (mdb_readvar(&list, "softint_list") == -1) {
mdb_warn("failed to read the global softint_list pointer\n");
return (WALK_ERR);
}
wsp->walk_addr = (uintptr_t)list;
return (WALK_NEXT);
}
/*ARGSUSED*/
void
softint_walk_fini(mdb_walk_state_t *wsp)
{
/* Nothing to do here */
}
int
softint_walk_step(mdb_walk_state_t *wsp)
{
intr_vec_t iv;
int status;
if (wsp->walk_addr == NULL)
return (WALK_DONE);
status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
wsp->walk_cbdata);
if (mdb_vread(&iv, sizeof (intr_vec_t),
(uintptr_t)wsp->walk_addr) == -1) {
mdb_warn("failed to read iv_p %p\n", wsp->walk_addr);
return (WALK_ERR);
}
wsp->walk_addr = (uintptr_t)iv.iv_vec_next;
return (status);
}
int
softint_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
intr_vec_t iv;
if (!(flags & DCMD_ADDRSPEC)) {
if (mdb_walk_dcmd("softint", "softint", argc, argv) == -1) {
mdb_warn("can't walk softint");
return (DCMD_ERR);
}
return (DCMD_OK);
}
if (DCMD_HDRSPEC(flags)) {
mdb_printf("%?s %4s %4s %4s %?s %?s %s\n", "ADDR", "TYPE",
"PEND", "PIL", "ARG1", "ARG2", "HANDLER");
}
if (mdb_vread(&iv, sizeof (iv), addr) == -1) {
mdb_warn("couldn't read softint at %p", addr);
return (DCMD_ERR);
}
mdb_printf("%?p %4s %4d %4d %?p %?p %a\n", addr,
(iv.iv_flags & IV_SOFTINT_MT) ? "M" : "S",
iv.iv_flags & IV_SOFTINT_PEND, iv.iv_pil,
iv.iv_arg1, iv.iv_arg2, iv.iv_handler);
return (DCMD_OK);
}
static int
whatis_walk_tt(uintptr_t taddr, const trap_trace_fullrec_t *ttf,
mdb_whatis_t *w)
{
uintptr_t cur = 0;
while (mdb_whatis_match(w, taddr, sizeof (struct trap_trace_record),
&cur))
mdb_whatis_report_object(w, cur, taddr,
"trap trace record for cpu %d\n", ttf->ttf_cpu);
return (WHATIS_WALKRET(w));
}
/*ARGSUSED*/
static int
whatis_run_traptrace(mdb_whatis_t *w, void *ignored)
{
GElf_Sym sym;
if (mdb_lookup_by_name("trap_trace_ctl", &sym) == -1)
return (0);
if (mdb_walk("ttrace", (mdb_walk_cb_t)whatis_walk_tt, w) == -1)
mdb_warn("failed to walk 'ttrace'");
return (0);
}
/*ARGSUSED*/
int
mutex_owner_init(mdb_walk_state_t *wsp)
{
return (WALK_NEXT);
}
int
mutex_owner_step(mdb_walk_state_t *wsp)
{
uintptr_t addr = wsp->walk_addr;
mutex_impl_t mtx;
uintptr_t owner;
kthread_t thr;
if (mdb_vread(&mtx, sizeof (mtx), addr) == -1)
return (WALK_ERR);
if (!MUTEX_TYPE_ADAPTIVE(&mtx))
return (WALK_DONE);
if ((owner = (uintptr_t)MUTEX_OWNER(&mtx)) == NULL)
return (WALK_DONE);
if (mdb_vread(&thr, sizeof (thr), owner) != -1)
(void) wsp->walk_callback(owner, &thr, wsp->walk_cbdata);
return (WALK_DONE);
}
static const mdb_dcmd_t dcmds[] = {
{ "cpuset", ":[-l|-r]", "dump a cpuset_t", cmd_cpuset },
{ "ttctl", NULL, "dump trap trace ctl records", ttctl },
{ "ttrace", "[-x]", "dump trap trace buffer for a cpu", ttrace },
#ifdef sun4v
{ "httctl", NULL, "dump hv trap trace ctl records", httctl },
{ "httrace", "[-x]", "dump hv trap trace buffer for a cpu", httrace },
#endif
{ "xc_mbox", "?", "dump xcall mboxes", xc_mbox },
{ "xctrace", NULL, "dump xcall trace buffer", xctrace },
{ "vecint", NULL, "display a registered hardware interrupt",
vecint_dcmd },
{ "softint", NULL, "display a registered software interrupt",
softint_dcmd },
{ "sfmmu_vtop", ":[[-v] -a as]", "print virtual to physical mapping",
sfmmu_vtop },
{ "memseg_list", ":", "show memseg list", memseg_list },
{ "tsbinfo", ":[-l [-a]]", "show tsbinfo", tsbinfo_list,
tsbinfo_help },
{ NULL }
};
static const mdb_walker_t walkers[] = {
{ "mutex_owner", "walks the owner of a mutex",
mutex_owner_init, mutex_owner_step },
{ "ttrace", "walks the trap trace buffer for a CPU",
ttrace_walk_init, ttrace_walk_step, ttrace_walk_fini },
#ifdef sun4v
{ "httrace", "walks the hv trap trace buffer for a CPU",
httrace_walk_init, httrace_walk_step, httrace_walk_fini },
#endif
{ "xc_mbox", "walks the cross call mail boxes",
xc_mbox_walk_init, xc_mbox_walk_step, xc_mbox_walk_fini },
{ "vecint", "walk the list of registered hardware interrupts",
vecint_walk_init, vecint_walk_step, vecint_walk_fini },
{ "softint", "walk the list of registered software interrupts",
softint_walk_init, softint_walk_step, softint_walk_fini },
{ "memseg", "walk the memseg structures",
memseg_walk_init, memseg_walk_step, memseg_walk_fini },
{ NULL }
};
static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers };
const mdb_modinfo_t *
_mdb_init(void)
{
if (mdb_lookup_by_name("intr_vec_table", &iv_sym) == -1) {
mdb_warn("couldn't find intr_vec_table");
return (NULL);
}
mdb_whatis_register("traptrace", whatis_run_traptrace, NULL,
WHATIS_PRIO_EARLY, WHATIS_REG_NO_ID);
return (&modinfo);
}