diff options
Diffstat (limited to 'usr/src/cmd/mdb/common/modules')
-rw-r--r-- | usr/src/cmd/mdb/common/modules/genunix/Makefile.files | 1 | ||||
-rw-r--r-- | usr/src/cmd/mdb/common/modules/genunix/ctxop.c | 3 | ||||
-rw-r--r-- | usr/src/cmd/mdb/common/modules/genunix/genunix.c | 105 | ||||
-rw-r--r-- | usr/src/cmd/mdb/common/modules/genunix/refhash.c | 61 | ||||
-rw-r--r-- | usr/src/cmd/mdb/common/modules/genunix/refhash.h | 35 | ||||
-rw-r--r-- | usr/src/cmd/mdb/common/modules/genunix/zone.c | 46 | ||||
-rw-r--r-- | usr/src/cmd/mdb/common/modules/genunix/zone.h | 1 | ||||
-rw-r--r-- | usr/src/cmd/mdb/common/modules/ipc/ipc.c | 5 | ||||
-rw-r--r-- | usr/src/cmd/mdb/common/modules/libc/libc.c | 28 | ||||
-rw-r--r-- | usr/src/cmd/mdb/common/modules/mdb_ks/mdb_ks.c | 67 | ||||
-rw-r--r-- | usr/src/cmd/mdb/common/modules/random/random.c | 16 | ||||
-rw-r--r-- | usr/src/cmd/mdb/common/modules/xhci/xhci.c | 893 |
12 files changed, 1165 insertions, 96 deletions
diff --git a/usr/src/cmd/mdb/common/modules/genunix/Makefile.files b/usr/src/cmd/mdb/common/modules/genunix/Makefile.files index 315a3df138..4e1900c44b 100644 --- a/usr/src/cmd/mdb/common/modules/genunix/Makefile.files +++ b/usr/src/cmd/mdb/common/modules/genunix/Makefile.files @@ -72,6 +72,7 @@ GENUNIX_SRCS = \ pci.c \ pg.c \ rctl.c \ + refhash.c \ refstr.c \ sobj.c \ streams.c \ diff --git a/usr/src/cmd/mdb/common/modules/genunix/ctxop.c b/usr/src/cmd/mdb/common/modules/genunix/ctxop.c index d78432b743..c8a59ce9ac 100644 --- a/usr/src/cmd/mdb/common/modules/genunix/ctxop.c +++ b/usr/src/cmd/mdb/common/modules/genunix/ctxop.c @@ -27,8 +27,9 @@ * Copyright 2018 Joyent, Inc. */ -#include <mdb/mdb_modapi.h> +#include <sys/mdb_modapi.h> #include <mdb/mdb_ctf.h> +#include <sys/thread.h> #include "ctxop.h" struct ctxop_walk_state { diff --git a/usr/src/cmd/mdb/common/modules/genunix/genunix.c b/usr/src/cmd/mdb/common/modules/genunix/genunix.c index 4a48514d81..30449f0631 100644 --- a/usr/src/cmd/mdb/common/modules/genunix/genunix.c +++ b/usr/src/cmd/mdb/common/modules/genunix/genunix.c @@ -99,6 +99,7 @@ #include "pci.h" #include "pg.h" #include "rctl.h" +#include "refhash.h" #include "sobj.h" #include "streams.h" #include "sysevent.h" @@ -116,10 +117,6 @@ */ #define NINTR 16 -#define KILOS 10 -#define MEGS 20 -#define GIGS 30 - #ifndef STACK_BIAS #define STACK_BIAS 0 #endif @@ -2136,24 +2133,24 @@ typedef struct datafmt { } datafmt_t; static datafmt_t kmemfmt[] = { - { "cache ", "name ", - "-------------------------", "%-25s " }, - { " buf", " size", "------", "%6u " }, - { " buf", "in use", "------", "%6u " }, - { " buf", " total", "------", "%6u " }, - { " memory", " in use", "----------", "%10lu%c " }, - { " alloc", " succeed", "---------", "%9u " }, - { "alloc", " fail", "-----", "%5u " }, + { "cache ", "name ", + "------------------------------", "%-30s " }, + { " buf", " size", "-----", "%5H " }, + { " buf", " in use", "---------", "%9u " }, + { " buf", " total", "---------", "%9u " }, + { "memory", "in use", "------", "%6lH " }, + { " alloc", " succeed", "----------", "%10u " }, + { "alloc", " fail", "-----", "%5u" }, { NULL, NULL, NULL, NULL } }; static datafmt_t vmemfmt[] = { - { "vmem ", "name ", - "-------------------------", "%-*s " }, - { " memory", " in use", "----------", "%9llu%c " }, - { " memory", " total", "-----------", "%10llu%c " }, - { " memory", " import", "----------", "%9llu%c " }, - { " alloc", " succeed", "---------", "%9llu " }, + { "vmem ", "name ", + "------------------------------", "%-*s " }, + { " memory", " in use", "---------", "%9llH " }, + { " memory", " total", "----------", "%10llH " }, + { " memory", " import", "---------", "%9llH " }, + { " alloc", " succeed", "----------", "%10llu " }, { "alloc", " fail", "-----", "%5llu " }, { NULL, NULL, NULL, NULL } }; @@ -2205,15 +2202,9 @@ typedef struct kmastat_vmem { int kv_fail; } kmastat_vmem_t; -typedef struct kmastat_args { - kmastat_vmem_t **ka_kvpp; - uint_t ka_shift; -} kmastat_args_t; - static int -kmastat_cache(uintptr_t addr, const kmem_cache_t *cp, kmastat_args_t *kap) +kmastat_cache(uintptr_t addr, const kmem_cache_t *cp, kmastat_vmem_t **kvpp) { - kmastat_vmem_t **kvpp = kap->ka_kvpp; kmastat_vmem_t *kv; datafmt_t *dfp = kmemfmt; int magsize; @@ -2254,9 +2245,7 @@ out: mdb_printf((dfp++)->fmt, cp->cache_bufsize); mdb_printf((dfp++)->fmt, total - avail); mdb_printf((dfp++)->fmt, total); - mdb_printf((dfp++)->fmt, meminuse >> kap->ka_shift, - kap->ka_shift == GIGS ? 'G' : kap->ka_shift == MEGS ? 'M' : - kap->ka_shift == KILOS ? 'K' : 'B'); + mdb_printf((dfp++)->fmt, meminuse); mdb_printf((dfp++)->fmt, alloc); mdb_printf((dfp++)->fmt, cp->cache_alloc_fail); mdb_printf("\n"); @@ -2265,9 +2254,8 @@ out: } static int -kmastat_vmem_totals(uintptr_t addr, const vmem_t *v, kmastat_args_t *kap) +kmastat_vmem_totals(uintptr_t addr, const vmem_t *v, kmastat_vmem_t *kv) { - kmastat_vmem_t *kv = *kap->ka_kvpp; size_t len; while (kv != NULL && kv->kv_addr != addr) @@ -2276,20 +2264,18 @@ kmastat_vmem_totals(uintptr_t addr, const vmem_t *v, kmastat_args_t *kap) if (kv == NULL || kv->kv_alloc == 0) return (WALK_NEXT); - len = MIN(17, strlen(v->vm_name)); + len = MIN(22, strlen(v->vm_name)); - mdb_printf("Total [%s]%*s %6s %6s %6s %10lu%c %9u %5u\n", v->vm_name, - 17 - len, "", "", "", "", - kv->kv_meminuse >> kap->ka_shift, - kap->ka_shift == GIGS ? 'G' : kap->ka_shift == MEGS ? 'M' : - kap->ka_shift == KILOS ? 'K' : 'B', kv->kv_alloc, kv->kv_fail); + mdb_printf("Total [%s]%*s %5s %9s %9s %6lH %10u %5u\n", v->vm_name, + 22 - len, "", "", "", "", + kv->kv_meminuse, kv->kv_alloc, kv->kv_fail); return (WALK_NEXT); } /*ARGSUSED*/ static int -kmastat_vmem(uintptr_t addr, const vmem_t *v, const uint_t *shiftp) +kmastat_vmem(uintptr_t addr, const vmem_t *v, const void *ignored) { datafmt_t *dfp = vmemfmt; const vmem_kstat_t *vkp = &v->vm_kstat; @@ -2307,16 +2293,10 @@ kmastat_vmem(uintptr_t addr, const vmem_t *v, const uint_t *shiftp) } mdb_printf("%*s", ident, ""); - mdb_printf((dfp++)->fmt, 25 - ident, v->vm_name); - mdb_printf((dfp++)->fmt, vkp->vk_mem_inuse.value.ui64 >> *shiftp, - *shiftp == GIGS ? 'G' : *shiftp == MEGS ? 'M' : - *shiftp == KILOS ? 'K' : 'B'); - mdb_printf((dfp++)->fmt, vkp->vk_mem_total.value.ui64 >> *shiftp, - *shiftp == GIGS ? 'G' : *shiftp == MEGS ? 'M' : - *shiftp == KILOS ? 'K' : 'B'); - mdb_printf((dfp++)->fmt, vkp->vk_mem_import.value.ui64 >> *shiftp, - *shiftp == GIGS ? 'G' : *shiftp == MEGS ? 'M' : - *shiftp == KILOS ? 'K' : 'B'); + mdb_printf((dfp++)->fmt, 30 - ident, v->vm_name); + mdb_printf((dfp++)->fmt, vkp->vk_mem_inuse.value.ui64); + mdb_printf((dfp++)->fmt, vkp->vk_mem_total.value.ui64); + mdb_printf((dfp++)->fmt, vkp->vk_mem_import.value.ui64); mdb_printf((dfp++)->fmt, vkp->vk_alloc.value.ui64); mdb_printf((dfp++)->fmt, vkp->vk_fail.value.ui64); @@ -2331,44 +2311,35 @@ kmastat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { kmastat_vmem_t *kv = NULL; datafmt_t *dfp; - kmastat_args_t ka; - - ka.ka_shift = 0; - if (mdb_getopts(argc, argv, - 'k', MDB_OPT_SETBITS, KILOS, &ka.ka_shift, - 'm', MDB_OPT_SETBITS, MEGS, &ka.ka_shift, - 'g', MDB_OPT_SETBITS, GIGS, &ka.ka_shift, NULL) != argc) - return (DCMD_USAGE); for (dfp = kmemfmt; dfp->hdr1 != NULL; dfp++) - mdb_printf("%s ", dfp->hdr1); + mdb_printf("%s%s", dfp == kmemfmt ? "" : " ", dfp->hdr1); mdb_printf("\n"); for (dfp = kmemfmt; dfp->hdr1 != NULL; dfp++) - mdb_printf("%s ", dfp->hdr2); + mdb_printf("%s%s", dfp == kmemfmt ? "" : " ", dfp->hdr2); mdb_printf("\n"); for (dfp = kmemfmt; dfp->hdr1 != NULL; dfp++) - mdb_printf("%s ", dfp->dashes); + mdb_printf("%s%s", dfp == kmemfmt ? "" : " ", dfp->dashes); mdb_printf("\n"); - ka.ka_kvpp = &kv; - if (mdb_walk("kmem_cache", (mdb_walk_cb_t)kmastat_cache, &ka) == -1) { + if (mdb_walk("kmem_cache", (mdb_walk_cb_t)kmastat_cache, &kv) == -1) { mdb_warn("can't walk 'kmem_cache'"); return (DCMD_ERR); } for (dfp = kmemfmt; dfp->hdr1 != NULL; dfp++) - mdb_printf("%s ", dfp->dashes); + mdb_printf("%s%s", dfp == kmemfmt ? "" : " ", dfp->dashes); mdb_printf("\n"); - if (mdb_walk("vmem", (mdb_walk_cb_t)kmastat_vmem_totals, &ka) == -1) { + if (mdb_walk("vmem", (mdb_walk_cb_t)kmastat_vmem_totals, kv) == -1) { mdb_warn("can't walk 'vmem'"); return (DCMD_ERR); } for (dfp = kmemfmt; dfp->hdr1 != NULL; dfp++) - mdb_printf("%s ", dfp->dashes); + mdb_printf("%s%s", dfp == kmemfmt ? "" : " ", dfp->dashes); mdb_printf("\n"); mdb_printf("\n"); @@ -2385,7 +2356,7 @@ kmastat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) mdb_printf("%s ", dfp->dashes); mdb_printf("\n"); - if (mdb_walk("vmem", (mdb_walk_cb_t)kmastat_vmem, &ka.ka_shift) == -1) { + if (mdb_walk("vmem", (mdb_walk_cb_t)kmastat_vmem, NULL) == -1) { mdb_warn("can't walk 'vmem'"); return (DCMD_ERR); } @@ -4481,6 +4452,8 @@ static const mdb_dcmd_t dcmds[] = { /* from zone.c */ { "zid2zone", ":", "find the zone_t with the given zone id", zid2zone }, + { "zdid2zone", ":", "find the zone_t with the given zone debug id", + zdid2zone }, { "zone", "?[-r [-v]]", "display kernel zone(s)", zoneprt }, { "zsd", ":[-v] [zsd_key]", "display zone-specific-data entries for " "selected zones", zsd }, @@ -4802,6 +4775,10 @@ static const mdb_walker_t walkers[] = { { "rctl_val", "given a rctl_t, walk all rctl_val entries associated", rctl_val_walk_init, rctl_val_walk_step }, + /* from refhash.c */ + { REFHASH_WALK_NAME, REFHASH_WALK_DESC, + refhash_walk_init, refhash_walk_step, NULL }, + /* from sobj.c */ { "blocked", "walk threads blocked on a given sobj", blocked_walk_init, blocked_walk_step, NULL }, diff --git a/usr/src/cmd/mdb/common/modules/genunix/refhash.c b/usr/src/cmd/mdb/common/modules/genunix/refhash.c new file mode 100644 index 0000000000..4b4c92dc14 --- /dev/null +++ b/usr/src/cmd/mdb/common/modules/genunix/refhash.c @@ -0,0 +1,61 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2018, Joyent, Inc. + */ + +#include <mdb/mdb_modapi.h> +#include <mdb/mdb_ctf.h> + +#include <inttypes.h> +#include <sys/refhash.h> + +typedef struct refhash_walk_data { + size_t rwd_offset; +} refhash_walk_data_t; + +int +refhash_walk_init(mdb_walk_state_t *wsp) +{ + refhash_t refh = { 0 }; + refhash_walk_data_t *rwd; + int offset; + + /* mdb_ctf_offsetof_by_name() will print any errors */ + if ((offset = mdb_ctf_offsetof_by_name("refhash_t", "rh_objs")) == -1) + return (WALK_ERR); + + if (mdb_vread(&refh, sizeof (refhash_t), wsp->walk_addr) == -1) { + mdb_warn("failed to read refhash_t at %#lx", wsp->walk_addr); + return (WALK_ERR); + } + + rwd = wsp->walk_data = mdb_zalloc(sizeof (*rwd), UM_SLEEP | UM_GC); + rwd->rwd_offset = refh.rh_link_off; + + wsp->walk_addr += offset; + if (mdb_layered_walk("list", wsp) == -1) { + mdb_warn("can't walk refhash_t"); + return (WALK_ERR); + } + + return (WALK_NEXT); +} + +int +refhash_walk_step(mdb_walk_state_t *wsp) +{ + refhash_walk_data_t *rwd = wsp->walk_data; + uintptr_t addr = wsp->walk_addr - rwd->rwd_offset; + + return (wsp->walk_callback(addr, wsp->walk_layer, wsp->walk_cbdata)); +} diff --git a/usr/src/cmd/mdb/common/modules/genunix/refhash.h b/usr/src/cmd/mdb/common/modules/genunix/refhash.h new file mode 100644 index 0000000000..1e91ced8d5 --- /dev/null +++ b/usr/src/cmd/mdb/common/modules/genunix/refhash.h @@ -0,0 +1,35 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2018, Joyent, Inc. + */ + +#ifndef _REFHASH_H +#define _REFHASH_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define REFHASH_WALK_NAME "refhash" +#define REFHASH_WALK_DESC "walk a refhash" + +struct mdb_walk_state; + +extern int refhash_walk_init(struct mdb_walk_state *); +extern int refhash_walk_step(struct mdb_walk_state *); + +#ifdef __cplusplus +} +#endif + +#endif /* _REFHASH_H */ diff --git a/usr/src/cmd/mdb/common/modules/genunix/zone.c b/usr/src/cmd/mdb/common/modules/genunix/zone.c index 49cd3e7b6e..57545d94a3 100644 --- a/usr/src/cmd/mdb/common/modules/genunix/zone.c +++ b/usr/src/cmd/mdb/common/modules/genunix/zone.c @@ -20,7 +20,7 @@ */ /* * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, Joyent, Inc. All rights reserved. + * Copyright (c) 2018, Joyent, Inc. All rights reserved. */ #include <mdb/mdb_param.h> @@ -34,9 +34,9 @@ #define ZONE_NAMELEN 20 #ifdef _LP64 -#define ZONE_PATHLEN 32 +#define ZONE_PATHLEN 25 #else -#define ZONE_PATHLEN 40 +#define ZONE_PATHLEN 33 #endif /* @@ -52,7 +52,8 @@ char *zone_status_names[] = { "empty", /* ZONE_IS_EMPTY */ "down", /* ZONE_IS_DOWN */ "dying", /* ZONE_IS_DYING */ - "dead" /* ZONE_IS_DEAD */ + "dead", /* ZONE_IS_DEAD */ + "free" /* ZONE_IS_FREE */ }; static int @@ -80,6 +81,31 @@ zid2zone(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) return (DCMD_OK); } +static int +zdid_lookup_cb(uintptr_t addr, const zone_t *zone, void *arg) +{ + zoneid_t zdid = *(uintptr_t *)arg; + if (zone->zone_did == zdid) + mdb_printf("%p\n", addr); + + return (WALK_NEXT); +} + +/*ARGSUSED*/ +int +zdid2zone(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("zone", (mdb_walk_cb_t)zdid_lookup_cb, &addr) == -1) { + mdb_warn("failed to walk zone"); + return (DCMD_ERR); + } + + return (DCMD_OK); +} + int zoneprt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { @@ -122,10 +148,10 @@ zoneprt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) */ if (DCMD_HDRSPEC(flags)) { if (ropt_given == FALSE) - mdb_printf("%<u>%?s %6s %-13s %-20s %-s%</u>\n", + mdb_printf("%<u>%?s %4s %-13s %-19s %-s%</u>\n", "ADDR", "ID", "STATUS", "NAME", "PATH"); else - mdb_printf("%<u>%?s %6s %10s %10s %-20s%</u>\n", + mdb_printf("%<u>%?s %6s %10s %10s %-19s%</u>\n", "ADDR", "ID", "REFS", "CREFS", "NAME"); } @@ -164,7 +190,7 @@ zoneprt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) statusp = zone_status_names[zn.zone_status]; else statusp = "???"; - mdb_printf("%0?p %6d %-13s %-20s %s\n", addr, zn.zone_id, + mdb_printf("%0?p %4d %-13s %-19s %s\n", addr, zn.zone_id, statusp, name, path); } else { /* @@ -172,7 +198,7 @@ zoneprt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) * Display the zone's subsystem-specific reference counts if * the user specified the '-v' option. */ - mdb_printf("%0?p %6d %10u %10u %-20s\n", addr, zn.zone_id, + mdb_printf("%0?p %6d %10u %10u %-19s\n", addr, zn.zone_id, zn.zone_ref, zn.zone_cred_ref, name); if (vopt_given == TRUE) { GElf_Sym subsys_names_sym; @@ -410,7 +436,7 @@ zsd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) * Prepare to output the specified zone's ZSD information. */ if (DCMD_HDRSPEC(flags)) - mdb_printf("%<u>%-20s %?s %?s %8s%</u>\n", "ZONE", "KEY", + mdb_printf("%<u>%-19s %?s %?s %8s%</u>\n", "ZONE", "KEY", "VALUE", "FLAGS"); len = mdb_readstr(name, ZONE_NAMELEN, (uintptr_t)zone.zone_name); if (len > 0) { @@ -419,7 +445,7 @@ zsd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) } else { (void) strcpy(name, "??"); } - mdb_printf("%-20s ", name); + mdb_printf("%-19s ", name); /* * Display the requested ZSD entries. diff --git a/usr/src/cmd/mdb/common/modules/genunix/zone.h b/usr/src/cmd/mdb/common/modules/genunix/zone.h index 0881f9bbae..94a383e41c 100644 --- a/usr/src/cmd/mdb/common/modules/genunix/zone.h +++ b/usr/src/cmd/mdb/common/modules/genunix/zone.h @@ -34,6 +34,7 @@ extern "C" { #endif extern int zid2zone(uintptr_t, uint_t, int argc, const mdb_arg_t *); +extern int zdid2zone(uintptr_t, uint_t, int argc, const mdb_arg_t *); extern int zoneprt(uintptr_t, uint_t, int argc, const mdb_arg_t *); extern int zone_walk_init(mdb_walk_state_t *); diff --git a/usr/src/cmd/mdb/common/modules/ipc/ipc.c b/usr/src/cmd/mdb/common/modules/ipc/ipc.c index bc87716015..04db8f7fcf 100644 --- a/usr/src/cmd/mdb/common/modules/ipc/ipc.c +++ b/usr/src/cmd/mdb/common/modules/ipc/ipc.c @@ -21,6 +21,7 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * Copyright 2016 Joyent, Inc. */ #include <mdb/mdb_modapi.h> @@ -228,7 +229,9 @@ shm_print(kshmid_t *shmid, uintptr_t addr) printtime_nice("ctime: ", shmid->shm_ctime); mdb_printf("sptinfo: %-?p sptseg: %-?p\n", shmid->shm_sptinfo, shmid->shm_sptseg); - mdb_printf("sptprot: <%lb>\n", shmid->shm_sptprot, prot_flag_bits); + mdb_printf("opts: rmpend: %d prot: <%b>\n", + ((shmid->shm_opts & SHM_RM_PENDING) != 0), + (shmid->shm_opts & SHM_PROT_MASK), prot_flag_bits); } diff --git a/usr/src/cmd/mdb/common/modules/libc/libc.c b/usr/src/cmd/mdb/common/modules/libc/libc.c index 69f4beda74..8ee6af407e 100644 --- a/usr/src/cmd/mdb/common/modules/libc/libc.c +++ b/usr/src/cmd/mdb/common/modules/libc/libc.c @@ -138,6 +138,8 @@ d_ucontext(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) uc.uc_stack.ss_sp, uc.uc_stack.ss_size, stack_flags(&uc.uc_stack)); mdb_printf(" mcontext = 0x%p\n", addr + OFFSETOF(ucontext_t, uc_mcontext)); + mdb_printf(" brand = 0x%p 0x%p 0x%p\n", + uc.uc_brand_data[0], uc.uc_brand_data[1], uc.uc_brand_data[2]); return (DCMD_OK); } @@ -849,14 +851,19 @@ d_uberdata(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) prt_addr(uberdata.all_lwps, 1), prt_addr(uberdata.all_zombies, 0)); - HD("nthreads nzombies ndaemons pid sigacthandler"); - mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %s\n", + HD("nthreads nzombies ndaemons pid"); + mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d\n", OFFSET(nthreads), uberdata.nthreads, uberdata.nzombies, uberdata.ndaemons, - (int)uberdata.pid, - prt_addr((void *)uberdata.sigacthandler, 0)); + (int)uberdata.pid); + + HD("sigacthandler setctxt"); + mdb_printf(OFFSTR "%s %s\n", + OFFSET(sigacthandler), + prt_addr((void *)uberdata.sigacthandler, 1), + prt_addr((void *)uberdata.setctxt, 1)); HD("lwp_stacks lwp_laststack nfreestack stk_cache"); mdb_printf(OFFSTR "%s %s %-10d %d\n", @@ -879,12 +886,17 @@ d_uberdata(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) prt_addr(uberdata.ulwp_replace_last, 1), prt_addr(uberdata.atforklist, 0)); - HD("robustlocks robustlist progname"); - mdb_printf(OFFSTR "%s %s %s\n", + HD("robustlocks robustlist"); + mdb_printf(OFFSTR "%s %s\n", OFFSET(robustlocks), prt_addr(uberdata.robustlocks, 1), - prt_addr(uberdata.robustlist, 1), - prt_addr(uberdata.progname, 0)); + prt_addr(uberdata.robustlist, 1)); + + HD("progname ub_broot"); + mdb_printf(OFFSTR "%s %s\n", + OFFSET(progname), + prt_addr(uberdata.progname, 1), + prt_addr(uberdata.ub_broot, 1)); HD("tdb_bootstrap tdb_sync_addr_hash tdb_'count tdb_'fail"); mdb_printf(OFFSTR "%s %s %-10d %d\n", diff --git a/usr/src/cmd/mdb/common/modules/mdb_ks/mdb_ks.c b/usr/src/cmd/mdb/common/modules/mdb_ks/mdb_ks.c index 85f3839c96..68b2e9d362 100644 --- a/usr/src/cmd/mdb/common/modules/mdb_ks/mdb_ks.c +++ b/usr/src/cmd/mdb/common/modules/mdb_ks/mdb_ks.c @@ -60,6 +60,12 @@ #define MDB_PATH_NELEM 256 /* Maximum path components */ +/* + * Due to mdb_param.h shenanigans, there's no simple way to include string.h + * here... + */ +extern char *strtok(char *restrict, const char *restrict); + typedef struct mdb_path { size_t mdp_nelem; /* Number of components */ uint_t mdp_complete; /* Path completely resolved? */ @@ -1811,18 +1817,73 @@ mdb_get_lbolt(void) return ((ts/nsec) - lbi.lbi_debug_time); } +#define startswith(a, b) (strncmp((a), (b), strlen(b)) == 0) + +/* + * Dig out the branch and revision of the illumos-joyent repo, if we were + * provided with it. This is a rather fragile JSON parser, in that it requires + * JSON formatted exactly as per the boot_archive.gitstatus file that + * "buildversion" is built from. + */ void mdb_print_buildversion(void) { + boolean_t in_joyent = B_FALSE; GElf_Sym sym; - if (mdb_lookup_by_name("buildversion", &sym) != 0) - return; + if (mdb_lookup_by_name("buildversion", &sym) != 0) { + /* Older kernels used this name. */ + if (mdb_lookup_by_name("gitstatus_start", &sym) != 0) + return; + } char *str = mdb_zalloc(4096, UM_SLEEP | UM_GC); if (mdb_readstr(str, 4096, sym.st_value) < 1) return; - mdb_printf("build version: %s\n", str); + /* + * Each line is of the form + * + * "repo": "smartos-live", + */ + for (char *line = strtok(str, "\n"); line != NULL; + line = strtok(NULL, "\n")) { + /* skip whitespace and first " */ + line += strspn(line, " \t\""); + + if (startswith(line, "repo")) { + line += sizeof ("repo") - 1; + line += strspn(line, " \t\":"); + + if (startswith(line, "illumos-joyent")) + in_joyent = B_TRUE; + else if (in_joyent) + return; + continue; + } + + if (!in_joyent) + continue; + + if (startswith(line, "branch")) { + char *trail = strrchr(line, '"'); + if (trail != NULL) + *trail = '\0'; + line += sizeof ("branch") - 1; + line += strspn(line, " \t\":"); + mdb_printf("git branch: %s\n", line); + continue; + } + + if (startswith(line, "rev")) { + char *trail = strrchr(line, '"'); + if (trail != NULL) + *trail = '\0'; + line += sizeof ("rev") - 1; + line += strspn(line, " \t\":"); + mdb_printf("git rev: %s\n", line); + continue; + } + } } diff --git a/usr/src/cmd/mdb/common/modules/random/random.c b/usr/src/cmd/mdb/common/modules/random/random.c index a1b41f0eb8..2da56dae32 100644 --- a/usr/src/cmd/mdb/common/modules/random/random.c +++ b/usr/src/cmd/mdb/common/modules/random/random.c @@ -24,7 +24,9 @@ * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Copyright 2019 Joyent, Inc. + */ #include <sys/mdb_modapi.h> #include <mdb/mdb_ctf.h> @@ -39,10 +41,9 @@ rnd_get_stats(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { rnd_stats_t rnd_stats, rnd_stats_cpu; uint32_t random_max_ncpus; - size_t rndmag_t_size; + size_t rndmag_pad_t_size; ulong_t rndmag_t_offset; uintptr_t rndmag; - mdb_ctf_id_t rndmag_id; int i; if ((flags & DCMD_ADDRSPEC) || argc != 0) @@ -53,23 +54,20 @@ rnd_get_stats(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) return (DCMD_ERR); } - if ((mdb_ctf_lookup_by_name("rndmag_t", &rndmag_id) != 0) || - (mdb_ctf_offsetof(rndmag_id, "rm_stats", &rndmag_t_offset) != 0) || + if (((rndmag_t_offset = mdb_ctf_offsetof_by_name("rndmag_t", "rm_stats")) == -1) || (mdb_readvar(&random_max_ncpus, "random_max_ncpus") == -1) || (mdb_readvar(&rndmag, "rndmag") == -1) || - ((rndmag_t_size = mdb_ctf_type_size(rndmag_id)) == 0)) { + ((rndmag_pad_t_size = mdb_ctf_sizeof_by_name("rndmag_pad_t")) == -1)) { /* Can't find per-cpu stats. Don't add them in. */ random_max_ncpus = 0; } - rndmag_t_offset /= 8; - /* * Read and aggregate per-cpu stats if we have them. */ for (i = 0; i < random_max_ncpus; i++) { mdb_vread(&rnd_stats_cpu, sizeof (rnd_stats_cpu), - rndmag + rndmag_t_offset + i * rndmag_t_size); + rndmag + rndmag_t_offset + i * rndmag_pad_t_size); rnd_stats.rs_rndOut += rnd_stats_cpu.rs_rndOut; rnd_stats.rs_rndcOut += rnd_stats_cpu.rs_rndcOut; diff --git a/usr/src/cmd/mdb/common/modules/xhci/xhci.c b/usr/src/cmd/mdb/common/modules/xhci/xhci.c new file mode 100644 index 0000000000..1a1882e738 --- /dev/null +++ b/usr/src/cmd/mdb/common/modules/xhci/xhci.c @@ -0,0 +1,893 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2019 Joyent, Inc. + */ + +#include <sys/mdb_modapi.h> +#include <sys/usb/hcd/xhci/xhci.h> + +#define XHCI_MDB_TRB_INDENT 4 + +static const char *xhci_mdb_epctx_eptypes[] = { + "Not Valid", + "ISOCH OUT", + "BULK OUT", + "INTR OUT", + "CONTROL", + "ISOCH IN", + "BULK IN", + "INTR IN" +}; + +static const char *xhci_mdb_epctx_states[] = { + "Disabled", + "Running", + "Halted", + "Stopped", + "Error", + "<Unknown>", + "<Unknown>", + "<Unknown>" +}; + +static const mdb_bitmask_t xhci_mdb_trb_flags[] = { + { "C", XHCI_TRB_CYCLE, XHCI_TRB_CYCLE }, + { "ENT", XHCI_TRB_ENT, XHCI_TRB_ENT }, + { "ISP", XHCI_TRB_ISP, XHCI_TRB_ISP }, + { "NS", XHCI_TRB_NOSNOOP, XHCI_TRB_NOSNOOP }, + { "CH", XHCI_TRB_CHAIN, XHCI_TRB_CHAIN }, + { "IOC", XHCI_TRB_IOC, XHCI_TRB_IOC }, + { "IDT", XHCI_TRB_IDT, XHCI_TRB_IDT }, + { "BEI", XHCI_TRB_BEI, XHCI_TRB_BEI }, + { NULL, 0, 0 } +}; + +typedef struct xhci_mdb_walk_endpoint { + xhci_device_t xmwe_device; + uint_t xmwe_ep; +} xhci_mdb_walk_endpoint_t; + +static const char * +xhci_mdb_trb_code_to_str(int code) +{ + switch (code) { + case XHCI_CODE_INVALID: + return ("Invalid"); + case XHCI_CODE_SUCCESS: + return ("Success"); + case XHCI_CODE_DATA_BUF: + return ("Data Overrun or Underrun"); + case XHCI_CODE_BABBLE: + return ("Babble"); + case XHCI_CODE_TXERR: + return ("Transaction Error"); + case XHCI_CODE_TRB: + return ("Invalid TRB"); + case XHCI_CODE_STALL: + return ("Stall"); + case XHCI_CODE_RESOURCE: + return ("No Resources Available"); + case XHCI_CODE_BANDWIDTH: + return ("No Bandwidth Available"); + case XHCI_CODE_NO_SLOTS: + return ("No Slots Available"); + case XHCI_CODE_STREAM_TYPE: + return ("Stream Context Type Detected"); + case XHCI_CODE_SLOT_NOT_ON: + return ("Slot disabled"); + case XHCI_CODE_ENDP_NOT_ON: + return ("Endpoint disabled"); + case XHCI_CODE_SHORT_XFER: + return ("Short Transfer"); + case XHCI_CODE_RING_UNDERRUN: + return ("Isoch. Ring Underrun"); + case XHCI_CODE_RING_OVERRUN: + return ("Isoch. Ring Overrun"); + case XHCI_CODE_VF_RING_FULL: + return ("VF Ring Full"); + case XHCI_CODE_PARAMETER: + return ("Invalid Context Paramenter"); + case XHCI_CODE_BW_OVERRUN: + return ("Bandwidth Overrun"); + case XHCI_CODE_CONTEXT_STATE: + return ("Illegal Context Transition"); + case XHCI_CODE_NO_PING_RESP: + return ("Failed to Complete Periodic Transfer"); + case XHCI_CODE_EV_RING_FULL: + return ("Event Ring Full"); + case XHCI_CODE_INCOMPAT_DEV: + return ("Incompatible Device"); + case XHCI_CODE_MISSED_SRV: + return ("Missed Isoch. Service Window"); + case XHCI_CODE_CMD_RING_STOP: + return ("Command Ring Stop"); + case XHCI_CODE_CMD_ABORTED: + return ("Command Aborted"); + case XHCI_CODE_XFER_STOPPED: + return ("Transfer Stopped"); + case XHCI_CODE_XFER_STOPINV: + return ("Invalid Transfer Length"); + case XHCI_CODE_XFER_STOPSHORT: + return ("Stopped before End of Transfer Descriptor"); + case XHCI_CODE_MELAT: + return ("Max Exit Latency too large"); + case XHCI_CODE_RESERVED: + return ("Reserved"); + case XHCI_CODE_ISOC_OVERRUN: + return ("Isochronus Overrun"); + case XHCI_CODE_EVENT_LOST: + return ("Event Lost"); + case XHCI_CODE_UNDEFINED: + return ("Undefined Fatal Error"); + case XHCI_CODE_INVALID_SID: + return ("Invalid Stream ID"); + case XHCI_CODE_SEC_BW: + return ("Secondary Bandwith Allocation Failure"); + case XHCI_CODE_SPLITERR: + return ("USB2 SPlit Transaction Error"); + default: + break; + } + + if (code >= 192 && code <= 223) + return ("Vendor Defined Error"); + if (code >= 224 && code <= 255) + return ("Vendor Defined Info"); + + return ("Reserved"); +} + +static const char * +xhci_mdb_trb_type_to_str(int code) +{ + /* + * The macros for the types are all already shifted over based on their + * place in the TRB, so shift there again ourselves. + */ + switch (code << 10) { + case XHCI_TRB_TYPE_NORMAL: + return ("Normal"); + case XHCI_TRB_TYPE_SETUP: + return ("Setup"); + case XHCI_TRB_TYPE_DATA: + return ("Data"); + case XHCI_TRB_TYPE_STATUS: + return ("Status"); + case XHCI_TRB_TYPE_LINK: + return ("Link"); + case XHCI_TRB_TYPE_EVENT: + return ("Event"); + case XHCI_TRB_TYPE_NOOP: + return ("No-Op"); + case XHCI_CMD_ENABLE_SLOT: + return ("Enable Slot"); + case XHCI_CMD_DISABLE_SLOT: + return ("Disable Slot"); + case XHCI_CMD_ADDRESS_DEVICE: + return ("Address Device"); + case XHCI_CMD_CONFIG_EP: + return ("Configure Endpoint"); + case XHCI_CMD_EVAL_CTX: + return ("Evaluate Context"); + case XHCI_CMD_RESET_EP: + return ("Reset Endpoint"); + case XHCI_CMD_STOP_EP: + return ("Stop Endpoint"); + case XHCI_CMD_SET_TR_DEQ: + return ("Set Transfer Ring Dequeue Pointer"); + case XHCI_CMD_RESET_DEV: + return ("Reset Device"); + case XHCI_CMD_FEVENT: + return ("Force Event"); + case XHCI_CMD_NEG_BW: + return ("Negotiate Bandwidth"); + case XHCI_CMD_SET_LT: + return ("Set Latency Tolerance"); + case XHCI_CMD_GET_BW: + return ("Get Bandwidth"); + case XHCI_CMD_FHEADER: + return ("Force Header"); + case XHCI_CMD_NOOP: + return ("No-Op Command"); + case XHCI_EVT_XFER: + return ("Transfer Event"); + case XHCI_EVT_CMD_COMPLETE: + return ("Command Completion Event"); + case XHCI_EVT_PORT_CHANGE: + return ("Port Status Change Event"); + case XHCI_EVT_BW_REQUEST: + return ("Bandwidth Request Event"); + case XHCI_EVT_DOORBELL: + return ("Doorbell Event"); + case XHCI_EVT_HOST_CTRL: + return ("Host Controller Event"); + case XHCI_EVT_DEVICE_NOTIFY: + return ("Device Notification Event"); + case XHCI_EVT_MFINDEX_WRAP: + return ("MFINDEX Wrap Event"); + default: + break; + } + + if (code >= 43 && code <= 63) + return ("Vendor Defiend"); + return ("Reserved"); +} + +/* ARGSUSED */ +static int +xhci_mdb_print_epctx(uintptr_t addr, uint_t flags, int argc, + const mdb_arg_t *argv) +{ + uint32_t info, info2, txinfo; + xhci_endpoint_context_t epctx; + + if (!(flags & DCMD_ADDRSPEC)) { + mdb_warn("::xhci_epctx requires an address\n"); + return (DCMD_USAGE); + } + + if (mdb_vread(&epctx, sizeof (epctx), addr) != sizeof (epctx)) { + mdb_warn("failed to read xhci_endpoint_context_t at %p", addr); + return (DCMD_ERR); + } + + info = LE_32(epctx.xec_info); + info2 = LE_32(epctx.xec_info2); + txinfo = LE_32(epctx.xec_txinfo); + + mdb_printf("Endpoint State: %s (%d)\n", + xhci_mdb_epctx_states[XHCI_EPCTX_STATE(info)], + XHCI_EPCTX_STATE(info)); + + mdb_printf("Mult: %d\n", XHCI_EPCTX_GET_MULT(info)); + mdb_printf("Max Streams: %d\n", XHCI_EPCTX_GET_MAXP_STREAMS(info)); + mdb_printf("LSA: %d\n", XHCI_EPCTX_GET_LSA(info)); + mdb_printf("Interval: %d\n", XHCI_EPCTX_GET_IVAL(info)); + mdb_printf("Max ESIT Hi: %d\n", XHCI_EPCTX_GET_MAX_ESIT_HI(info)); + + mdb_printf("CErr: %d\n", XHCI_EPCTX_GET_CERR(info2)); + mdb_printf("EP Type: %s (%d)\n", + xhci_mdb_epctx_eptypes[XHCI_EPCTX_GET_EPTYPE(info2)], + XHCI_EPCTX_GET_EPTYPE(info2)); + mdb_printf("Host Initiate Disable: %d\n", XHCI_EPCTX_GET_HID(info2)); + mdb_printf("Max Burst: %d\n", XHCI_EPCTX_GET_MAXB(info2)); + mdb_printf("Max Packet Size: %d\n", XHCI_EPCTX_GET_MPS(info2)); + + mdb_printf("Ring DCS: %d\n", LE_64(epctx.xec_dequeue) & 0x1); + mdb_printf("Ring PA: 0x%lx\n", LE_64(epctx.xec_dequeue) & ~0xf); + + mdb_printf("Average TRB Length: %d\n", XHCI_EPCTX_AVG_TRB_LEN(txinfo)); + mdb_printf("Max ESIT: %d\n", XHCI_EPCTX_GET_MAX_ESIT_PAYLOAD(txinfo)); + + return (DCMD_OK); +} + +/* ARGSUSED */ +static int +xhci_mdb_print_slotctx(uintptr_t addr, uint_t flags, int argc, + const mdb_arg_t *argv) +{ + uint32_t info, info2, tt, state; + xhci_slot_context_t sctx; + + if (!(flags & DCMD_ADDRSPEC)) { + mdb_warn("::xhci_slotctx requires an address\n"); + return (DCMD_USAGE); + } + + if (mdb_vread(&sctx, sizeof (sctx), addr) != sizeof (sctx)) { + mdb_warn("failed to read xhci_slot_context_t at %p", addr); + return (DCMD_ERR); + } + + info = LE_32(sctx.xsc_info); + info2 = LE_32(sctx.xsc_info2); + tt = LE_32(sctx.xsc_tt); + state = LE_32(sctx.xsc_state); + + mdb_printf("Route: 0x%x\n", XHCI_SCTX_GET_ROUTE(info)); + + mdb_printf("Slot Speed: "); + switch (XHCI_SCTX_GET_SPEED(info)) { + case XHCI_SPEED_FULL: + mdb_printf("Full"); + break; + case XHCI_SPEED_LOW: + mdb_printf("Low"); + break; + case XHCI_SPEED_HIGH: + mdb_printf("High"); + break; + case XHCI_SPEED_SUPER: + mdb_printf("Super"); + break; + default: + mdb_printf("Unknown"); + break; + } + mdb_printf(" (%d)\n", XHCI_SCTX_GET_SPEED(info)); + + + mdb_printf("MTT: %d\n", XHCI_SCTX_GET_MTT(info)); + mdb_printf("HUB: %d\n", XHCI_SCTX_GET_HUB(info)); + mdb_printf("DCI: %d\n", XHCI_SCTX_GET_DCI(info)); + + mdb_printf("Max Exit Latency: %d\n", XHCI_SCTX_GET_MAX_EL(info2)); + mdb_printf("Root Hub Port: %d\n", XHCI_SCTX_GET_RHPORT(info2)); + mdb_printf("Hub Number of Ports: %d\n", XHCI_SCTX_GET_NPORTS(info2)); + + mdb_printf("TT Hub Slot id: %d\n", XHCI_SCTX_GET_TT_HUB_SID(tt)); + mdb_printf("TT Port Number: %d\n", XHCI_SCTX_GET_TT_PORT_NUM(tt)); + mdb_printf("TT Think Time: %d\n", XHCI_SCTX_GET_TT_THINK_TIME(tt)); + mdb_printf("IRQ Target: %d\n", XHCI_SCTX_GET_IRQ_TARGET(tt)); + + mdb_printf("Device Address: 0x%x\n", XHCI_SCTX_GET_DEV_ADDR(state)); + mdb_printf("Slot State: "); + switch (XHCI_SCTX_GET_SLOT_STATE(state)) { + case XHCI_SLOT_DIS_ENAB: + mdb_printf("Disabled/Enabled"); + break; + case XHCI_SLOT_DEFAULT: + mdb_printf("Default"); + break; + case XHCI_SLOT_ADDRESSED: + mdb_printf("Addressed"); + break; + case XHCI_SLOT_CONFIGURED: + mdb_printf("Configured"); + break; + default: + mdb_printf("Unknown"); + break; + } + mdb_printf(" (%d)\n", XHCI_SCTX_GET_SLOT_STATE(state)); + + return (DCMD_OK); +} + +static int +xhci_mdb_print_transfer_event(uint64_t pa, uint32_t status, uint32_t flags) +{ + mdb_printf("TRB Address: 0x%lx\n", pa); + mdb_printf("Transfer Length (Remain): %d\n", XHCI_TRB_REMAIN(status)); + mdb_printf("Completion Code: %s (%d)\n", + xhci_mdb_trb_code_to_str(XHCI_TRB_GET_CODE(status)), + XHCI_TRB_GET_CODE(status)); + + mdb_printf("Cycle: %d\n", XHCI_TRB_GET_CYCLE(flags)); + mdb_printf("Event Data: %d\n", XHCI_TRB_GET_ED(flags)); + mdb_printf("Endpoint ID: %d\n", XHCI_TRB_GET_EP(flags)); + mdb_printf("Slot ID: %d\n", XHCI_TRB_GET_SLOT(flags)); + mdb_dec_indent(XHCI_MDB_TRB_INDENT); + + return (DCMD_OK); +} + +static int +xhci_mdb_print_command_event(uint64_t pa, uint32_t status, uint32_t flags) +{ + mdb_printf("TRB Address: 0x%lx\n", pa); + mdb_printf("Command Param: 0x%x\n", XHCI_TRB_REMAIN(status)); + mdb_printf("Completion Code: %s (%d)\n", + xhci_mdb_trb_code_to_str(XHCI_TRB_GET_CODE(status)), + XHCI_TRB_GET_CODE(status)); + + mdb_printf("Cycle: %d\n", XHCI_TRB_GET_CYCLE(flags)); + /* Skip VF ID as we don't support VFs */ + mdb_printf("Slot ID: %d\n", XHCI_TRB_GET_SLOT(flags)); + mdb_dec_indent(XHCI_MDB_TRB_INDENT); + + return (DCMD_OK); +} + +/* ARGSUSED */ +static int +xhci_mdb_print_psc(uint64_t pa, uint32_t status, uint32_t flags) +{ + mdb_printf("Port: %d\n", XHCI_TRB_PORTID(pa)); + mdb_printf("Completion Code: %s (%d)\n", + xhci_mdb_trb_code_to_str(XHCI_TRB_GET_CODE(status)), + XHCI_TRB_GET_CODE(status)); + mdb_dec_indent(XHCI_MDB_TRB_INDENT); + return (DCMD_OK); +} + +static int +xhci_mdb_print_normal_trb(uint64_t pa, uint32_t status, uint32_t flags) +{ + mdb_printf("TRB Address: 0x%lx\n", pa); + mdb_printf("TRB Length: %d bytes\n", XHCI_TRB_LEN(status)); + mdb_printf("TRB TD Size: %d packets\n", XHCI_TRB_GET_TDREM(status)); + mdb_printf("TRB Interrupt: %d\n", XHCI_TRB_GET_INTR(status)); + mdb_printf("TRB Flags: %b (0x%x)\n", flags, xhci_mdb_trb_flags, + XHCI_TRB_GET_FLAGS(flags)); + mdb_dec_indent(XHCI_MDB_TRB_INDENT); + + return (DCMD_OK); +} + +/* ARGSUSED */ +static int +xhci_mdb_print_trb(uintptr_t addr, uint_t flags, int argc, + const mdb_arg_t *argv) +{ + xhci_trb_t trb; + uint64_t pa; + uint32_t status, trbflags, type; + + if (!(flags & DCMD_ADDRSPEC)) { + mdb_warn("::xhci_trb expects an address\n"); + return (DCMD_USAGE); + } + + if (mdb_vread(&trb, sizeof (trb), addr) != sizeof (trb)) { + mdb_warn("failed to read xhci_trb_t at 0x%x", addr); + return (DCMD_ERR); + } + + pa = LE_64(trb.trb_addr); + status = LE_32(trb.trb_status); + trbflags = LE_32(trb.trb_flags); + + type = XHCI_TRB_GET_TYPE(trbflags); + + if ((flags & DCMD_LOOP) && !(flags & DCMD_LOOPFIRST)) + mdb_printf("\n"); + + mdb_set_dot(addr + sizeof (xhci_trb_t)); + mdb_printf("%s TRB (%d)\n", xhci_mdb_trb_type_to_str(type), type); + mdb_inc_indent(XHCI_MDB_TRB_INDENT); + + switch (XHCI_RING_TYPE_SHIFT(type)) { + case XHCI_EVT_XFER: + return (xhci_mdb_print_transfer_event(pa, status, trbflags)); + case XHCI_EVT_CMD_COMPLETE: + return (xhci_mdb_print_command_event(pa, status, trbflags)); + case XHCI_EVT_PORT_CHANGE: + return (xhci_mdb_print_psc(pa, status, trbflags)); + case XHCI_TRB_TYPE_NORMAL: + return (xhci_mdb_print_normal_trb(pa, status, trbflags)); + } + + /* + * Just print generic information if we don't have a specific printer + * for that TRB type. + */ + mdb_printf("TRB Address: 0x%lx\n", pa); + mdb_printf("TRB Status: 0x%x\n", status); + mdb_printf("TRB Flags: 0x%x\n", trbflags); + mdb_dec_indent(XHCI_MDB_TRB_INDENT); + + return (DCMD_OK); +} + +static int +xhci_mdb_walk_xhci_init(mdb_walk_state_t *wsp) +{ + GElf_Sym sym; + uintptr_t addr; + + if (wsp->walk_addr != 0) { + mdb_warn("::walk xhci only supports global walks\n"); + return (WALK_ERR); + } + + if (mdb_lookup_by_obj("xhci", "xhci_soft_state", &sym) != 0) { + mdb_warn("failed to find xhci_soft_state symbol"); + return (WALK_ERR); + } + + if (mdb_vread(&addr, sizeof (addr), sym.st_value) != sizeof (addr)) { + mdb_warn("failed to read xhci_soft_state at %p", addr); + return (WALK_ERR); + } + + wsp->walk_addr = addr; + if (mdb_layered_walk("softstate", wsp) != 0) { + mdb_warn("failed to walk softstate"); + return (WALK_ERR); + } + + return (WALK_NEXT); +} + +static int +xhci_mdb_walk_xhci_step(mdb_walk_state_t *wsp) +{ + xhci_t xhci; + + if (mdb_vread(&xhci, sizeof (xhci), wsp->walk_addr) != sizeof (xhci)) { + mdb_warn("failed to read xhci_t at %p", wsp->walk_addr); + return (WALK_ERR); + } + + return (wsp->walk_callback(wsp->walk_addr, &xhci, wsp->walk_cbdata)); +} + +static int +xhci_mdb_walk_xhci_device_init(mdb_walk_state_t *wsp) +{ + uintptr_t addr; + + if (wsp->walk_addr == 0) { + mdb_warn("::walk xhci_device requires an xhci_t\n"); + return (WALK_ERR); + } + + addr = wsp->walk_addr; + addr += offsetof(xhci_t, xhci_usba); + addr += offsetof(xhci_usba_t, xa_devices); + wsp->walk_addr = (uintptr_t)addr; + if (mdb_layered_walk("list", wsp) != 0) { + mdb_warn("failed to walk list"); + return (WALK_ERR); + } + + return (WALK_NEXT); +} + +static int +xhci_mdb_walk_xhci_device_step(mdb_walk_state_t *wsp) +{ + xhci_device_t xd; + + if (mdb_vread(&xd, sizeof (xd), wsp->walk_addr) != sizeof (xd)) { + mdb_warn("failed to read xhci_device_t at %p", wsp->walk_addr); + return (WALK_ERR); + } + + return (wsp->walk_callback(wsp->walk_addr, &xd, wsp->walk_cbdata)); +} + +static int +xhci_mdb_walk_xhci_endpoint_init(mdb_walk_state_t *wsp) +{ + xhci_mdb_walk_endpoint_t *xm; + xhci_device_t *xd; + + if (wsp->walk_addr == 0) { + mdb_warn("::walk xhci_endpoint requires an xhci_device_t\n"); + return (WALK_ERR); + } + + xm = mdb_alloc(sizeof (xhci_mdb_walk_endpoint_t), UM_SLEEP | UM_GC); + xm->xmwe_ep = 0; + xd = &xm->xmwe_device; + if (mdb_vread(xd, sizeof (*xd), wsp->walk_addr) != sizeof (*xd)) { + mdb_warn("failed to read xhci_endpoint_t at %p", + wsp->walk_addr); + return (WALK_ERR); + } + wsp->walk_data = xm; + + return (WALK_NEXT); +} + +static int +xhci_mdb_walk_xhci_endpoint_step(mdb_walk_state_t *wsp) +{ + int ret; + uintptr_t addr; + xhci_mdb_walk_endpoint_t *xm = wsp->walk_data; + + if (xm->xmwe_ep >= XHCI_NUM_ENDPOINTS) + return (WALK_DONE); + + addr = (uintptr_t)xm->xmwe_device.xd_endpoints[xm->xmwe_ep]; + if (addr != (uintptr_t)NULL) { + xhci_endpoint_t xe; + + if (mdb_vread(&xe, sizeof (xe), addr) != sizeof (xe)) { + mdb_warn("failed to read xhci_endpoint_t at %p", + xm->xmwe_device.xd_endpoints[xm->xmwe_ep]); + return (WALK_ERR); + } + + ret = wsp->walk_callback(addr, &xe, wsp->walk_cbdata); + } else { + ret = WALK_NEXT; + } + xm->xmwe_ep++; + + return (ret); +} + +typedef struct xhci_mdb_find { + int xmf_slot; + int xmf_ep; + uintptr_t xmf_addr; +} xhci_mdb_find_t; + +static int +xhci_mdb_find_endpoint_cb(uintptr_t addr, const void *data, void *arg) +{ + const xhci_endpoint_t *xep = data; + xhci_mdb_find_t *xmf = arg; + + /* + * The endpoints that are presented here are off by one from the actual + * endpoint ID in the xhci_endpoint_t, as we're really displaying the + * index into the device input context. + */ + if (xep->xep_num + 1 == xmf->xmf_ep) { + xmf->xmf_addr = addr; + return (WALK_DONE); + } + + return (WALK_NEXT); +} + +static int +xhci_mdb_find_device_cb(uintptr_t addr, const void *data, void *arg) +{ + const xhci_device_t *xd = data; + xhci_mdb_find_t *xmf = arg; + + if (xd->xd_slot == xmf->xmf_slot) { + if (xmf->xmf_ep == -1) { + xmf->xmf_addr = addr; + return (WALK_DONE); + } + + if (mdb_pwalk("xhci`xhci_endpoint", xhci_mdb_find_endpoint_cb, + xmf, addr) == -1) { + mdb_warn("failed to walk xhci_endpoint at %p", addr); + return (WALK_ERR); + } + + return (WALK_DONE); + } + + return (WALK_NEXT); +} + +static int +xhci_mdb_find(uintptr_t addr, uint_t flags, int argc, + const mdb_arg_t *argv) +{ + uintptr_t ep, slot; + boolean_t ep_set, slot_set; + xhci_mdb_find_t xmf; + + if ((flags & DCMD_ADDRSPEC) == 0) + return (DCMD_USAGE); + + ep_set = slot_set = B_FALSE; + if (mdb_getopts(argc, argv, 'e', MDB_OPT_UINTPTR_SET, &ep_set, &ep, + 's', MDB_OPT_UINTPTR_SET, &slot_set, &slot, NULL) != argc) + return (DCMD_USAGE); + + if (!slot_set) { + mdb_warn("-s is required\n"); + return (DCMD_USAGE); + } + + xmf.xmf_slot = (int)slot; + if (ep_set) + xmf.xmf_ep = (int)ep; + else + xmf.xmf_ep = -1; + xmf.xmf_addr = 0; + + if (mdb_pwalk("xhci`xhci_device", xhci_mdb_find_device_cb, + &xmf, addr) == -1) { + mdb_warn("failed to walk xhci_device at %p", addr); + return (DCMD_ERR); + } + + if (xmf.xmf_addr == 0) { + if (ep_set) { + mdb_warn("failed to find xhci_endpoint_t for slot %d " + "and endpoint %d\n", slot, ep); + } else { + mdb_warn("failed to find xhci_device_t for slot %d\n", + slot); + } + return (DCMD_ERR); + } + + mdb_printf("%p\n", xmf.xmf_addr); + return (DCMD_OK); +} + +/* ARGSUSED */ +static int +xhci_mdb_endpoint_count(uintptr_t addr, const void *ep, void *arg) +{ + int *countp = arg; + + *countp += 1; + return (WALK_NEXT); +} + +/* ARGSUSED */ +static int +xhci_mdb_print_endpoint_summary(uintptr_t addr, const void *ep, void *arg) +{ + const xhci_device_t *xd = arg; + const xhci_endpoint_t *xep = ep; + const char *type; + const char *state; + xhci_endpoint_context_t epctx; + int eptype; + + if (mdb_vread(&epctx, sizeof (epctx), + (uintptr_t)xd->xd_endout[xep->xep_num]) != sizeof (epctx)) { + mdb_warn("failed to read endpoint context at %p", + xd->xd_endout[xep->xep_num]); + return (WALK_ERR); + } + + eptype = XHCI_EPCTX_GET_EPTYPE(LE_32(epctx.xec_info2)); + type = xhci_mdb_epctx_eptypes[eptype]; + state = xhci_mdb_epctx_states[XHCI_EPCTX_STATE(LE_32(epctx.xec_info))]; + + mdb_printf("%-4d %-10s %-10s 0x%-04x 0x%-04x\n", xep->xep_num, type, + state, xep->xep_ring.xr_head, xep->xep_ring.xr_tail); + + return (WALK_NEXT); +} + +/* ARGSUSED */ +static int +xhci_mdb_print_device(uintptr_t addr, uint_t flags, int argc, + const mdb_arg_t *argv) +{ + int count; + xhci_device_t xd; + usba_device_t ud; + char product[256], mfg[256]; + + if (!(flags & DCMD_ADDRSPEC)) { + return (mdb_eval("::walk xhci`xhci | ::walk xhci`xhci_device | " + "::xhci_device")); + } + + if (mdb_vread(&xd, sizeof (xd), addr) != sizeof (xd)) { + mdb_warn("failed to read xhci_device_t at 0x%x", addr); + return (DCMD_ERR); + } + + if (mdb_vread(&ud, sizeof (ud), (uintptr_t)xd.xd_usbdev) != + sizeof (ud)) { + mdb_warn("failed to read usba_device_t at %p\n", xd.xd_usbdev); + return (DCMD_ERR); + } + + if (ud.usb_mfg_str == NULL || mdb_readstr(mfg, sizeof (mfg), + (uintptr_t)ud.usb_mfg_str) <= 0) { + (void) strlcpy(mfg, "Unknown Manufacturer", sizeof (mfg)); + } + + if (ud.usb_product_str == NULL || mdb_readstr(product, sizeof (product), + (uintptr_t)ud.usb_product_str) <= 0) { + (void) strlcpy(product, "Unknown Product", sizeof (product)); + } + + mdb_printf("%<b>%s - %s%</b>\n", mfg, product); + + count = 0; + if (mdb_pwalk("xhci`xhci_endpoint", xhci_mdb_endpoint_count, &count, + addr) == -1) { + mdb_warn("failed to walk xhci_endpoint rooted at 0x%x", addr); + return (DCMD_ERR); + } + + mdb_printf("Port %02d | Slot %02d | # Endpoints %02d\n", xd.xd_port, + xd.xd_slot, count); + mdb_printf("%<u>%-4s %-10s %-10s %-6s %-6s%</u>\n", "EP", "Type", + "State", "Head", "Tail"); + + if (mdb_pwalk("xhci`xhci_endpoint", xhci_mdb_print_endpoint_summary, + &xd, addr) == -1) { + mdb_warn("failed to walk xhci_endpoint rooted at 0x%x", addr); + return (DCMD_ERR); + } + + + mdb_printf("\n"); + + return (DCMD_OK); +} + +static int +xhci_mdb_find_trb(uintptr_t addr, uint_t flags, int argc, + const mdb_arg_t *argv) +{ + xhci_ring_t xr; + uint64_t base, max, target; + + if (!(flags & DCMD_ADDRSPEC)) { + mdb_warn("missing required xhci_ring_t\n"); + return (DCMD_USAGE); + } + + if (argc == 0) { + mdb_warn("missing required PA of ring\n"); + return (DCMD_USAGE); + } + + if (argc > 1) { + mdb_warn("too many arguments\n"); + return (DCMD_USAGE); + } + + if (mdb_vread(&xr, sizeof (xr), addr) != sizeof (xr)) { + mdb_warn("failed to read xhci_ring_t at %p", addr); + return (DCMD_USAGE); + } + + if (argv[0].a_type == MDB_TYPE_IMMEDIATE) { + target = argv[0].a_un.a_val; + } else if (argv[0].a_type == MDB_TYPE_STRING) { + target = mdb_strtoull(argv[0].a_un.a_str); + } else { + mdb_warn("argument is an unknown supported type: %d\n", + argv[0].a_type); + return (DCMD_USAGE); + } + target = roundup(target, sizeof (xhci_trb_t)); + + base = xr.xr_dma.xdb_cookies[0].dmac_laddress; + max = base + xr.xr_ntrb * sizeof (xhci_trb_t); + + if (target < base || target > max) { + mdb_warn("target address %p is outside the range of PAs for " + "TRBs in the ring [%p, %p)", target, base, max); + return (DCMD_ERR); + } + target -= base; + mdb_printf("0x%" PRIx64 "\n", target + (uintptr_t)xr.xr_trb); + + return (DCMD_OK); +} + +static const mdb_dcmd_t xhci_dcmds[] = { + { "xhci_epctx", ":", "print endpoint context", + xhci_mdb_print_epctx, NULL }, + { "xhci_slotctx", ":", "print slot context", + xhci_mdb_print_slotctx, NULL }, + { "xhci_trb", ":", "print TRB", + xhci_mdb_print_trb, NULL }, + { "xhci_find", ": -s slot [-e endpiont]", + "find given xhci slot or endpoint", + xhci_mdb_find, NULL }, + { "xhci_device", ":", "device summary", + xhci_mdb_print_device, NULL }, + { "xhci_find_trb", ": pa", "find trb with PA in ring", + xhci_mdb_find_trb, NULL }, + { NULL } +}; + +static const mdb_walker_t xhci_walkers[] = { + { "xhci", "walk list of xhci_t structures", + xhci_mdb_walk_xhci_init, xhci_mdb_walk_xhci_step, NULL }, + { "xhci_device", "walk list of xhci_device_t structures", + xhci_mdb_walk_xhci_device_init, xhci_mdb_walk_xhci_device_step, + NULL }, + { "xhci_endpoint", "walk list of xhci_endpoint_t structures", + xhci_mdb_walk_xhci_endpoint_init, xhci_mdb_walk_xhci_endpoint_step, + NULL }, + { NULL } +}; + +static const mdb_modinfo_t xhci_modinfo = { + MDB_API_VERSION, xhci_dcmds, xhci_walkers +}; + +const mdb_modinfo_t * +_mdb_init(void) +{ + return (&xhci_modinfo); +} |