static int stacks_has_caller(stacks_entry_t *sep, uintptr_t addr) { uintptr_t laddr = addr; uintptr_t haddr = addr + 1; int idx; char c[MDB_SYM_NAMLEN]; GElf_Sym sym; if (mdb_lookup_by_addr(addr, MDB_SYM_FUZZY, c, sizeof (c), &sym) != -1 && addr == (uintptr_t)sym.st_value) { laddr = (uintptr_t)sym.st_value; haddr = (uintptr_t)sym.st_value + sym.st_size; } for (idx = 0; idx < sep->se_depth; idx++) if (sep->se_stack[idx] >= laddr && sep->se_stack[idx] < haddr) return (1); return (0); }
static int fmd_timer(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { char name[32], func[MDB_SYM_NAMLEN]; fmd_timer_t t; if (!(flags & DCMD_ADDRSPEC)) { if (mdb_walk_dcmd("fmd_timerq", "fmd_timer", argc, argv) != 0) { mdb_warn("failed to walk fmd_timerq"); return (DCMD_ERR); } return (DCMD_OK); } if (mdb_vread(&t, sizeof (t), addr) != sizeof (t)) { mdb_warn("failed to read fmd_timer at %p", addr); return (DCMD_ERR); } if (DCMD_HDRSPEC(flags)) { mdb_printf("%<u>%-8s %-20s %-4s %-18s %-8s %s%</u>\n", "ADDR", "MODULE", "ID", "HRTIME", "ARG", "FUNC"); } if (mdb_readstr(name, sizeof (name), (uintptr_t) t.tmr_ids + OFFSETOF(fmd_idspace_t, ids_name)) <= 0) (void) mdb_snprintf(name, sizeof (name), "<%p>", t.tmr_ids); if (mdb_lookup_by_addr((uintptr_t)t.tmr_func, MDB_SYM_FUZZY, func, sizeof (func), NULL) != 0) (void) mdb_snprintf(func, sizeof (func), "<%p>", t.tmr_func); mdb_printf("%-8p %-20s %4d 0x%-16llx %-8p %s\n", addr, name, t.tmr_id, t.tmr_hrt, t.tmr_arg, func); return (DCMD_OK); }
/* * This is used to both compare stacks for equality and to sort the final * list of unique stacks. forsort specifies the latter behavior, which * additionally: * compares se_count, and * sorts the stacks by text function name. * * The equality test is independent of se_count, and doesn't care about * relative ordering, so we don't do the extra work of looking up symbols * for the stack addresses. */ int stacks_entry_comp_impl(stacks_entry_t *l, stacks_entry_t *r, uint_t forsort) { int idx; int depth = MIN(l->se_depth, r->se_depth); /* no matter what, panic stacks come last. */ if (l->se_panic > r->se_panic) return (1); if (l->se_panic < r->se_panic) return (-1); if (forsort) { /* put large counts earlier */ if (l->se_count > r->se_count) return (-1); if (l->se_count < r->se_count) return (1); } if (l->se_tstate > r->se_tstate) return (1); if (l->se_tstate < r->se_tstate) return (-1); if (l->se_failed > r->se_failed) return (1); if (l->se_failed < r->se_failed) return (-1); for (idx = 0; idx < depth; idx++) { char lbuf[MDB_SYM_NAMLEN]; char rbuf[MDB_SYM_NAMLEN]; int rval; uintptr_t laddr = l->se_stack[idx]; uintptr_t raddr = r->se_stack[idx]; if (laddr == raddr) continue; if (forsort && mdb_lookup_by_addr(laddr, MDB_SYM_FUZZY, lbuf, sizeof (lbuf), NULL) != -1 && mdb_lookup_by_addr(raddr, MDB_SYM_FUZZY, rbuf, sizeof (rbuf), NULL) != -1 && (rval = strcmp(lbuf, rbuf)) != 0) return (rval); if (laddr > raddr) return (1); return (-1); } if (l->se_overflow > r->se_overflow) return (-1); if (l->se_overflow < r->se_overflow) return (1); if (l->se_depth > r->se_depth) return (1); if (l->se_depth < r->se_depth) return (-1); if (l->se_sobj_ops > r->se_sobj_ops) return (1); if (l->se_sobj_ops < r->se_sobj_ops) return (-1); return (0); }
/* * Utility routine to read in a filesystem name given a vfs pointer. If * no vfssw entry for the vfs is available (as is the case with some pseudo- * filesystems), we check against some known problem fs's: doorfs and * portfs. If that fails, we try to guess the filesystem name using * symbol names. fsname should be a buffer of size _ST_FSTYPSZ. */ static int read_fsname(uintptr_t vfsp, char *fsname) { vfs_t vfs; struct vfssw vfssw_entry; GElf_Sym vfssw_sym, test_sym; char testname[MDB_SYM_NAMLEN]; if (mdb_vread(&vfs, sizeof (vfs), vfsp) == -1) { mdb_warn("failed to read vfs %p", vfsp); return (-1); } if (mdb_lookup_by_name("vfssw", &vfssw_sym) == -1) { mdb_warn("failed to find vfssw"); return (-1); } /* * vfssw is an array; we need vfssw[vfs.vfs_fstype]. */ if (mdb_vread(&vfssw_entry, sizeof (vfssw_entry), vfssw_sym.st_value + (sizeof (struct vfssw) * vfs.vfs_fstype)) == -1) { mdb_warn("failed to read vfssw index %d", vfs.vfs_fstype); return (-1); } if (vfs.vfs_fstype != 0) { if (mdb_readstr(fsname, _ST_FSTYPSZ, (uintptr_t)vfssw_entry.vsw_name) == -1) { mdb_warn("failed to find fs name %p", vfssw_entry.vsw_name); return (-1); } return (0); } /* * Do precise detection for certain filesystem types that we * know do not appear in vfssw[], and that we depend upon in other * parts of the code: doorfs and portfs. */ if (mdb_lookup_by_name("door_vfs", &test_sym) != -1) { if (test_sym.st_value == vfsp) { strcpy(fsname, "doorfs"); return (0); } } if (mdb_lookup_by_name("port_vfs", &test_sym) != -1) { if (test_sym.st_value == vfsp) { strcpy(fsname, "portfs"); return (0); } } /* * Heuristic detection for other filesystems that don't have a * vfssw[] entry. These tend to be named <fsname>_vfs, so we do a * lookup_by_addr and see if we find a symbol of that name. */ if (mdb_lookup_by_addr(vfsp, MDB_SYM_EXACT, testname, sizeof (testname), &test_sym) != -1) { if ((strlen(testname) > 4) && (strcmp(testname + strlen(testname) - 4, "_vfs") == 0)) { testname[strlen(testname) - 4] = '\0'; strncpy(fsname, testname, _ST_FSTYPSZ); return (0); } } mdb_warn("unknown filesystem type for vfs %p", vfsp); return (-1); }
/* * Display selected fields of the flow_entry_t structure */ static int mac_flow_dcmd_output(uintptr_t addr, uint_t flags, uint_t args) { static const mdb_bitmask_t flow_type_bits[] = { {"P", FLOW_PRIMARY_MAC, FLOW_PRIMARY_MAC}, {"V", FLOW_VNIC_MAC, FLOW_VNIC_MAC}, {"M", FLOW_MCAST, FLOW_MCAST}, {"O", FLOW_OTHER, FLOW_OTHER}, {"U", FLOW_USER, FLOW_USER}, {"V", FLOW_VNIC, FLOW_VNIC}, {"NS", FLOW_NO_STATS, FLOW_NO_STATS}, { NULL, 0, 0 } }; #define FLOW_MAX_TYPE (sizeof (flow_type_bits) / sizeof (mdb_bitmask_t)) static const mdb_bitmask_t flow_flag_bits[] = { {"Q", FE_QUIESCE, FE_QUIESCE}, {"W", FE_WAITER, FE_WAITER}, {"T", FE_FLOW_TAB, FE_FLOW_TAB}, {"G", FE_G_FLOW_HASH, FE_G_FLOW_HASH}, {"I", FE_INCIPIENT, FE_INCIPIENT}, {"C", FE_CONDEMNED, FE_CONDEMNED}, {"NU", FE_UF_NO_DATAPATH, FE_UF_NO_DATAPATH}, {"NC", FE_MC_NO_DATAPATH, FE_MC_NO_DATAPATH}, { NULL, 0, 0 } }; #define FLOW_MAX_FLAGS (sizeof (flow_flag_bits) / sizeof (mdb_bitmask_t)) flow_entry_t fe; mac_client_impl_t mcip; mac_impl_t mip; if (mdb_vread(&fe, sizeof (fe), addr) == -1) { mdb_warn("failed to read struct flow_entry_s at %p", addr); return (DCMD_ERR); } if (args & MAC_FLOW_USER) { args &= ~MAC_FLOW_USER; if (fe.fe_type & FLOW_MCAST) { if (DCMD_HDRSPEC(flags)) mac_flow_print_header(args); return (DCMD_OK); } } if (DCMD_HDRSPEC(flags)) mac_flow_print_header(args); bzero(&mcip, sizeof (mcip)); bzero(&mip, sizeof (mip)); if (fe.fe_mcip != NULL && mdb_vread(&mcip, sizeof (mcip), (uintptr_t)fe.fe_mcip) == sizeof (mcip)) { (void) mdb_vread(&mip, sizeof (mip), (uintptr_t)mcip.mci_mip); } switch (args) { case MAC_FLOW_NONE: { mdb_printf("%?p %-20s %4d %?p " "%?p %-16s\n", addr, fe.fe_flow_name, fe.fe_link_id, fe.fe_mcip, mcip.mci_mip, mip.mi_name); break; } case MAC_FLOW_ATTR: { struct in_addr in4; uintptr_t desc_addr; flow_desc_t fdesc; desc_addr = addr + OFFSETOF(flow_entry_t, fe_flow_desc); if (mdb_vread(&fdesc, sizeof (fdesc), desc_addr) == -1) { mdb_warn("failed to read struct flow_description at %p", desc_addr); return (DCMD_ERR); } mdb_printf("%?p %-32s " "%-7s %6d " "%4d:%-4d ", addr, fe.fe_flow_name, mac_flow_proto2str(fdesc.fd_protocol), fdesc.fd_local_port, fdesc.fd_dsfield, fdesc.fd_dsfield_mask); if (fdesc.fd_ipversion == IPV4_VERSION) { IN6_V4MAPPED_TO_INADDR(&fdesc.fd_local_addr, &in4); mdb_printf("%I", in4.s_addr); } else if (fdesc.fd_ipversion == IPV6_VERSION) { mdb_printf("%N", &fdesc.fd_local_addr); } else { mdb_printf("%s", "--"); } mdb_printf("\n"); break; } case MAC_FLOW_PROP: { uintptr_t prop_addr; char bwstr[STRSIZE]; mac_resource_props_t fprop; prop_addr = addr + OFFSETOF(flow_entry_t, fe_resource_props); if (mdb_vread(&fprop, sizeof (fprop), prop_addr) == -1) { mdb_warn("failed to read struct mac_resoource_props " "at %p", prop_addr); return (DCMD_ERR); } mdb_printf("%?p %-32s " "%8s %9s\n", addr, fe.fe_flow_name, mac_flow_bw2str(fprop.mrp_maxbw, bwstr, STRSIZE), mac_flow_priority2str(fprop.mrp_priority)); break; } case MAC_FLOW_MISC: { char flow_flags[2 * FLOW_MAX_FLAGS]; char flow_type[2 * FLOW_MAX_TYPE]; GElf_Sym sym; char func_name[MDB_SYM_NAMLEN] = ""; uintptr_t func, match_addr; match_addr = addr + OFFSETOF(flow_entry_t, fe_match); (void) mdb_vread(&func, sizeof (func), match_addr); (void) mdb_lookup_by_addr(func, MDB_SYM_EXACT, func_name, MDB_SYM_NAMLEN, &sym); mdb_snprintf(flow_flags, 2 * FLOW_MAX_FLAGS, "%hb", fe.fe_flags, flow_flag_bits); mdb_snprintf(flow_type, 2 * FLOW_MAX_TYPE, "%hb", fe.fe_type, flow_type_bits); mdb_printf("%?p %-24s %10s %10s %20s\n", addr, fe.fe_flow_name, flow_type, flow_flags, func_name); break; } case MAC_FLOW_RX: { uintptr_t rxaddr, rx_srs[MAX_RINGS_PER_GROUP] = {0}; int i; rxaddr = addr + OFFSETOF(flow_entry_t, fe_rx_srs); (void) mdb_vread(rx_srs, MAC_RX_SRS_SIZE, rxaddr); mdb_printf("%?p %-24s %3d ", addr, fe.fe_flow_name, fe.fe_rx_srs_cnt); for (i = 0; i < MAX_RINGS_PER_GROUP; i++) { if (rx_srs[i] == 0) continue; mdb_printf("%p ", rx_srs[i]); } mdb_printf("\n"); break; } case MAC_FLOW_TX: { uintptr_t tx_srs = 0, txaddr; txaddr = addr + OFFSETOF(flow_entry_t, fe_tx_srs); (void) mdb_vread(&tx_srs, sizeof (uintptr_t), txaddr); mdb_printf("%?p %-32s %?p\n", addr, fe.fe_flow_name, fe.fe_tx_srs); break; } case MAC_FLOW_STATS: { uint64_t totibytes = 0; uint64_t totobytes = 0; mac_soft_ring_set_t *mac_srs; mac_rx_stats_t mac_rx_stat; mac_tx_stats_t mac_tx_stat; int i; /* * Sum bytes for all Rx SRS. */ for (i = 0; i < fe.fe_rx_srs_cnt; i++) { mac_srs = (mac_soft_ring_set_t *)(fe.fe_rx_srs[i]); if (mdb_vread(&mac_rx_stat, sizeof (mac_rx_stats_t), (uintptr_t)&mac_srs->srs_rx.sr_stat) == -1) { mdb_warn("failed to read mac_rx_stats_t at %p", &mac_srs->srs_rx.sr_stat); return (DCMD_ERR); } totibytes += mac_rx_stat.mrs_intrbytes + mac_rx_stat.mrs_pollbytes + mac_rx_stat.mrs_lclbytes; } /* * Sum bytes for Tx SRS. */ mac_srs = (mac_soft_ring_set_t *)(fe.fe_tx_srs); if (mac_srs != NULL) { if (mdb_vread(&mac_tx_stat, sizeof (mac_tx_stats_t), (uintptr_t)&mac_srs->srs_tx.st_stat) == -1) { mdb_warn("failed to read max_tx_stats_t at %p", &mac_srs->srs_tx.st_stat); return (DCMD_ERR); } totobytes = mac_tx_stat.mts_obytes; } mdb_printf("%?p %-32s %16llu %16llu\n", addr, fe.fe_flow_name, totibytes, totobytes); break; } } return (DCMD_OK); }
int print_type_info(struct type_info *tinfo, long long offset, char *data) { int btype; int ret; GElf_Sym sym; switch(tinfo->type) { case BASIC_TYPE : if (tinfo->info.btype.sign) { switch (tinfo->info.btype.size) { case 1 : my_printf("0x%x", (char)*data); return 1; case 2 : my_printf("0x%hx", *((short*)data)); return 2; case 4 : my_printf("0x%lx",*((int*)data)); return 4; case 8 : my_printf("0x%llx", *((long*)data)); return 8; } } else { switch (tinfo->info.btype.size) { case 1 : my_printf("0x%x", (unsigned char)*data); return 1; case 2 : my_printf("0x%hx", *((unsigned short*)data)); return 2; case 4 : my_printf("0x%lx",*((unsigned int*)data)); return 4; case 8 : my_printf("0x%llx", *((unsigned long*)data)); return 8; } } break; case FLOAT_TYPE : switch(tinfo->info.ftype.size) { case 4 : my_printf(" float "); return 4; case 8 : my_printf(" double "); return 8; } break; case EQUAL : return print_id(tinfo->id, offset, data); case POINTER : /* print strings for char data type else print %p */ if (sizeof(void*) == 8) my_printf("0x%llx", *((long*)data)); else my_printf("0x%x", *((long*)data)); btype = base_type(tinfo->id); if (btype == CHAR || btype == UCHAR) { if (*(long*)data == 0) return 8; memset(str, 0, MAX_STR_LEN); ret = mdb_readstr(str, MAX_STR_LEN, *((long*)data)); if (ret <= 0) return 8; my_printf(" \"%s\"", str); } if (btype == TYPE_FUNCTION_PTR) { memset(str, 0, MAX_STR_LEN); ret= mdb_lookup_by_addr(*(long*)data, MDB_SYM_EXACT, str, MAX_STR_LEN, &sym); if (ret != -1) my_printf(" \"%s\" ", str); } return 8; case ARRAY : return print_array(tinfo, offset, data); case FORWARD_REF : return print_id(tinfo->id, offset, data); default : my_printf("error"); } }
/*ARGSUSED*/ static int ippops( uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { ipp_ops_t *ippo; GElf_Sym sym; char buf[MDB_SYM_NAMLEN]; if ((flags & DCMD_ADDRSPEC) == 0) return (DCMD_ERR); ippo = mdb_alloc(sizeof (ipp_ops_t), UM_SLEEP); if (mdb_vread(ippo, sizeof (ipp_ops_t), addr) == -1) { mdb_warn("failed to read ipp_ops_t at %p", addr); mdb_free(ippo, sizeof (ipp_ops_t)); return (DCMD_ERR); } mdb_printf("%?p: %20s = %d\n", addr, "rev", ippo->ippo_rev); if (mdb_lookup_by_addr((uintptr_t)ippo->ippo_action_create, MDB_SYM_EXACT, buf, MDB_SYM_NAMLEN, &sym) == 0) mdb_printf("%?s %20s = %s\n", "", "action_create", buf); else mdb_printf("%?s %20s = 0x%p\n", "", "action_create", ippo->ippo_action_create); if (mdb_lookup_by_addr((uintptr_t)ippo->ippo_action_modify, MDB_SYM_EXACT, buf, MDB_SYM_NAMLEN, &sym) == 0) mdb_printf("%?s %20s = %s\n", "", "action_modify", buf); else mdb_printf("%?s %20s = 0x%p\n", "", "action_modify", ippo->ippo_action_modify); if (mdb_lookup_by_addr((uintptr_t)ippo->ippo_action_destroy, MDB_SYM_EXACT, buf, MDB_SYM_NAMLEN, &sym) == 0) mdb_printf("%?s %20s = %s\n", "", "action_destroy", buf); else mdb_printf("%?s %20s = 0x%p\n", "", "action_destroy", ippo->ippo_action_destroy); if (mdb_lookup_by_addr((uintptr_t)ippo->ippo_action_info, MDB_SYM_EXACT, buf, MDB_SYM_NAMLEN, &sym) == 0) mdb_printf("%?s %20s = %s\n", "", "action_info", buf); else mdb_printf("%?s %20s = 0x%p\n", "", "action_info", ippo->ippo_action_info); if (mdb_lookup_by_addr((uintptr_t)ippo->ippo_action_invoke, MDB_SYM_EXACT, buf, MDB_SYM_NAMLEN, &sym) == 0) mdb_printf("%?s %20s = %s\n", "", "action_invoke", buf); else mdb_printf("%?s %20s = 0x%p\n", "", "action_invoke", ippo->ippo_action_invoke); mdb_printf("\n"); mdb_free(ippo, sizeof (ipp_ops_t)); return (DCMD_OK); }
/*ARGSUSED*/ int cmd_wp(uintptr_t x, uint_t flags, int argc, const mdb_arg_t *argv) { mdb_tgt_addr_t addr = mdb_get_dot(); char *opt_c = NULL; uint_t opt_i = FALSE; uint_t opt_l = FALSE; uint64_t opt_L = 0; uintptr_t opt_n = 0; uint_t opt_o = FALSE; uint_t opt_p = FALSE; uint_t opt_rwx = 0; int id; char buf[MDB_SYM_NAMLEN]; GElf_Sym gsym; int size; if ((argv = ev_getopts(addr, flags, argc, argv, &flags, &opt_c, &opt_i, &opt_l, &opt_L, &opt_n, &opt_o, &opt_p, &opt_rwx)) == NULL || opt_o || (opt_p && opt_i)) return (DCMD_USAGE); #ifndef _KMDB if (opt_i) return (DCMD_USAGE); #endif if (argv->a_type != MDB_TYPE_IMMEDIATE) return (DCMD_USAGE); if (opt_rwx == 0) { mdb_warn("at least one of -r, -w, or -x must be specified\n"); return (DCMD_USAGE); } if ((opt_l) + (opt_L > 0) + (mdb.m_dcount != 1) > 1) { mdb_warn("only one of -l, -L, or command count can be " "specified\n"); return (DCMD_ABORT); } if (opt_l) { if (mdb_lookup_by_addr(addr, MDB_SYM_EXACT, buf, sizeof (buf), &gsym) == -1) { mdb_warn("failed to lookup symbol at %p", addr); return (DCMD_ERR); } if (gsym.st_size == 0) { mdb_warn("cannot set watchpoint: symbol '%s' has zero " "size\n", buf); return (DCMD_ERR); } size = gsym.st_size; } else if (opt_L != 0) { size = opt_L; } else size = mdb.m_dcount; if (opt_p) { id = mdb_tgt_add_pwapt(mdb.m_target, addr, size, opt_rwx, flags, cmd_event, NULL); } else if (opt_i) { id = mdb_tgt_add_iowapt(mdb.m_target, addr, size, opt_rwx, flags, cmd_event, NULL); } else { id = mdb_tgt_add_vwapt(mdb.m_target, addr, size, opt_rwx, flags, cmd_event, NULL); } if (id == 0) { mdb_warn("failed to set watchpoint at %p", addr); return ((opt_l || opt_L) ? DCMD_ERR : DCMD_ABORT); } if (opt_c || opt_n) ev_setopts(mdb.m_target, id, opt_c, opt_n); /* * We use m_dcount as an argument; don't loop. We ignore this * restriction with the -l and -L options, since we read the size from * the symbol and don't rely on the count. */ return ((opt_l || opt_L) ? DCMD_OK : DCMD_ABORT); }