/*ARGSUSED*/ static int scalehrtime_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { uint32_t nsec_scale; hrtime_t tsc = addr, hrt; unsigned int *tscp = (unsigned int *)&tsc; uintptr_t scalehrtimef; uint64_t scale; GElf_Sym sym; if (!(flags & DCMD_ADDRSPEC)) { if (argc != 1) return (DCMD_USAGE); switch (argv[0].a_type) { case MDB_TYPE_STRING: tsc = mdb_strtoull(argv[0].a_un.a_str); break; case MDB_TYPE_IMMEDIATE: tsc = argv[0].a_un.a_val; break; default: return (DCMD_USAGE); } } if (mdb_readsym(&scalehrtimef, sizeof (scalehrtimef), "scalehrtimef") == -1) { mdb_warn("couldn't read 'scalehrtimef'"); return (DCMD_ERR); } if (mdb_lookup_by_name("tsc_scalehrtime", &sym) == -1) { mdb_warn("couldn't find 'tsc_scalehrtime'"); return (DCMD_ERR); } if (sym.st_value != scalehrtimef) { mdb_warn("::scalehrtime requires that scalehrtimef " "be set to tsc_scalehrtime\n"); return (DCMD_ERR); } if (mdb_readsym(&nsec_scale, sizeof (nsec_scale), "nsec_scale") == -1) { mdb_warn("couldn't read 'nsec_scale'"); return (DCMD_ERR); } scale = (uint64_t)nsec_scale; hrt = ((uint64_t)tscp[1] * scale) << NSEC_SHIFT; hrt += ((uint64_t)tscp[0] * scale) >> (32 - NSEC_SHIFT); mdb_printf("0x%llx\n", hrt); return (DCMD_OK); }
/*ARGSUSED*/ static int find_uhci_instance(uintptr_t uhci_instancep, const void *local_ss, void *cb_arg) { int td_pool_size, qh_pool_size; find_instance_cb_t *cb_data = (find_instance_cb_t *)cb_arg; uhci_state_t *uhcip = cb_data->fic_uhci_statep; if (mdb_vread(cb_data->fic_uhci_statep, sizeof (uhci_state_t), uhci_instancep) == -1) { mdb_warn("failed to read uhci_state at %p", uhci_instancep); return (-1); } if (mdb_readsym(&td_pool_size, sizeof (int), "uhci_td_pool_size") == -1) { mdb_warn("failed to read uhci_td_pool_size"); return (-1); } if (mdb_readsym(&qh_pool_size, sizeof (int), "uhci_qh_pool_size") == -1) { mdb_warn("failed to read uhci_td_pool_size"); return (-1); } /* * See if the addr is within the appropriate pool for this instance. */ if ((cb_data->fic_td_or_qh == UHCI_TD && ((uhci_td_t *)cb_data->fic_td_qh >= uhcip->uhci_td_pool_addr && (uhci_td_t *)cb_data->fic_td_qh <= (uhcip->uhci_td_pool_addr + td_pool_size - sizeof (uhci_td_t)))) || (cb_data->fic_td_or_qh == UHCI_QH && ((queue_head_t *)cb_data->fic_td_qh >= uhcip->uhci_qh_pool_addr && (queue_head_t *)cb_data->fic_td_qh <= (uhcip->uhci_qh_pool_addr + qh_pool_size - sizeof (queue_head_t))))) { /* td/qh address is within pool for this instance of uhci. */ cb_data->fic_found = TRUE; return (WALK_DONE); } return (WALK_NEXT); }
int ttrace_walk_init(mdb_walk_state_t *wsp) { trap_trace_ctl_t *ttcp; size_t ttc_size = sizeof (trap_trace_ctl_t) * NCPU; int i; if (!ttrace_ttr_size_check()) return (WALK_ERR); ttcp = mdb_zalloc(ttc_size, UM_SLEEP); if (wsp->walk_addr != NULL) { mdb_warn("ttrace only supports global walks\n"); return (WALK_ERR); } if (mdb_readsym(ttcp, ttc_size, "trap_trace_ctl") == -1) { mdb_warn("symbol 'trap_trace_ctl' not found; " "non-TRAPTRACE kernel?\n"); mdb_free(ttcp, ttc_size); return (WALK_ERR); } /* * We'll poach the ttc_current pointer (which isn't used for * anything) to store a pointer to our current TRAPTRACE record. * This allows us to only keep the array of trap_trace_ctl structures * as our walker state (ttc_current may be the only kernel data * structure member added exclusively to make writing the mdb walker * a little easier). */ for (i = 0; i < NCPU; i++) { trap_trace_ctl_t *ttc = &ttcp[i]; if (ttc->ttc_first == NULL) continue; /* * Assign ttc_current to be the last completed record. * Note that the error checking (i.e. in the ttc_next == * ttc_first case) is performed in the step function. */ ttc->ttc_current = ttc->ttc_next - sizeof (trap_trace_rec_t); } wsp->walk_data = ttcp; return (WALK_NEXT); }
/* * Figure out which instance of uhci owns a td/qh. * * - td_qh: a pointer to a uhci td or qh * - td_or_qh: a flag indicating which it is (td/qh), * - uhci_statep, pointer to a uhci_state_t, to be filled in with data from * the found instance of uhci_state_t. * * Only works for Cntl/Interrupt tds/qhs; others are dynamically allocated * and so cannot be found with this method. * * Returns 0 on success (no match found), 1 on success (match found), * -1 on errors. */ static int find_uhci_statep(void *td_qh, boolean_t td_or_qh, uhci_state_t *uhci_statep) { find_instance_cb_t cb_data; uintptr_t uhci_ss; if (uhci_statep == NULL) { mdb_warn("failed to find uhci statep: " "NULL uhci_statep param\n"); return (-1); } cb_data.fic_td_qh = td_qh; cb_data.fic_td_or_qh = td_or_qh; cb_data.fic_found = FALSE; cb_data.fic_uhci_statep = uhci_statep; if (mdb_readsym(&uhci_ss, sizeof (uhci_statep), "uhci_statep") == -1) { mdb_warn("failed to read uhci_statep"); return (-1); } /* * Walk all instances of uhci. * The callback func checks if td_qh belongs to a given instance * of uhci. */ if (mdb_pwalk("softstate", find_uhci_instance, &cb_data, uhci_ss) != 0) { mdb_warn("failed to walk softstate"); return (-1); } if (cb_data.fic_found == TRUE) { return (1); } return (0); }
/*ARGSUSED*/ static int ii_info_all(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { uintptr_t myaddr; /* * we use the global address. */ if (flags & DCMD_ADDRSPEC) return (DCMD_USAGE); if (mdb_readsym(&myaddr, sizeof (myaddr), "_ii_info_top") != sizeof (myaddr)) { return (DCMD_ERR); } mdb_printf("_ii_info_top contains 0x%lx\n", myaddr); while (myaddr) { ii_info(myaddr, DCMD_ADDRSPEC, 0, NULL); myaddr = nextaddr; } return (DCMD_OK); }
/* * read mmu parameters from kernel */ static void init_mmu(void) { struct as kas; if (mmu.num_level != 0) return; if (mdb_readsym(&mmu, sizeof (mmu), "mmu") == -1) mdb_warn("Can't use HAT information before mmu_init()\n"); if (mdb_readsym(&kas, sizeof (kas), "kas") == -1) mdb_warn("Couldn't find kas - kernel's struct as\n"); if (mdb_readsym(&kernelbase, sizeof (kernelbase), "kernelbase") == -1) mdb_warn("Couldn't find kernelbase\n"); khat = kas.a_hat; /* * Is this a paravirtualized domain image? */ if (mdb_readsym(&mfn_list_addr, sizeof (mfn_list_addr), "mfn_list") == -1 || mdb_readsym(&xen_virt_start, sizeof (xen_virt_start), "xen_virt_start") == -1 || mdb_readsym(&mfn_count, sizeof (mfn_count), "mfn_count") == -1) { mfn_list_addr = NULL; } is_xpv = mfn_list_addr != NULL; #ifndef _KMDB /* * recreate the local mfn_list */ if (is_xpv) { size_t sz = mfn_count * sizeof (pfn_t); mfn_list = mdb_zalloc(sz, UM_SLEEP); if (mdb_vread(mfn_list, sz, (uintptr_t)mfn_list_addr) == -1) { mdb_warn("Failed to read MFN list\n"); mdb_free(mfn_list, sz); mfn_list = NULL; } } #endif }
/*ARGSUSED*/ static int v8cfg_target_readsym(v8_cfg_t *cfgp, const char *name, intptr_t *valp) { return (mdb_readsym(valp, sizeof (valp), name)); }
int mdb_ia32_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp, mdb_tgt_stack_f *func, void *arg) { mdb_tgt_gregset_t gregs; kreg_t *kregs = &gregs.kregs[0]; int got_pc = (gsp->kregs[KREG_EIP] != 0); int err; struct fr { uintptr_t fr_savfp; uintptr_t fr_savpc; long fr_argv[32]; } fr; uintptr_t fp = gsp->kregs[KREG_EBP]; uintptr_t pc = gsp->kregs[KREG_EIP]; uintptr_t lastfp = 0; ssize_t size; uint_t argc; int detect_exception_frames = 0; int advance_tortoise = 1; uintptr_t tortoise_fp = 0; #ifndef _KMDB int xp; if ((mdb_readsym(&xp, sizeof (xp), "xpv_panicking") != -1) && (xp > 0)) detect_exception_frames = 1; #endif bcopy(gsp, &gregs, sizeof (gregs)); while (fp != 0) { if (fp & (STACK_ALIGN - 1)) { err = EMDB_STKALIGN; goto badfp; } if ((size = mdb_tgt_vread(t, &fr, sizeof (fr), fp)) >= (ssize_t)(2 * sizeof (uintptr_t))) { size -= (ssize_t)(2 * sizeof (uintptr_t)); argc = kvm_argcount(t, fr.fr_savpc, size); } else { err = EMDB_NOMAP; goto badfp; } if (tortoise_fp == 0) { tortoise_fp = fp; } else { /* * Advance tortoise_fp every other frame, so we detect * cycles with Floyd's tortoise/hare. */ if (advance_tortoise != 0) { struct fr tfr; if (mdb_tgt_vread(t, &tfr, sizeof (tfr), tortoise_fp) != sizeof (tfr)) { err = EMDB_NOMAP; goto badfp; } tortoise_fp = tfr.fr_savfp; } if (fp == tortoise_fp) { err = EMDB_STKFRAME; goto badfp; } } advance_tortoise = !advance_tortoise; if (got_pc && func(arg, pc, argc, fr.fr_argv, &gregs) != 0) break; kregs[KREG_ESP] = kregs[KREG_EBP]; lastfp = fp; fp = fr.fr_savfp; /* * The Xen hypervisor marks a stack frame as belonging to * an exception by inverting the bits of the pointer to * that frame. We attempt to identify these frames by * inverting the pointer and seeing if it is within 0xfff * bytes of the last frame. */ if (detect_exception_frames) if ((fp != 0) && (fp < lastfp) && ((lastfp ^ ~fp) < 0xfff)) fp = ~fp; kregs[KREG_EBP] = fp; kregs[KREG_EIP] = pc = fr.fr_savpc; got_pc = (pc != 0); } return (0); badfp: mdb_printf("%p [%s]", fp, mdb_strerror(err)); return (set_errno(err)); }
int ttrace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { ttrace_dcmd_t dcmd; trap_trace_ctl_t *ttc = dcmd.ttd_ttc; trap_trace_rec_t rec; size_t ttc_size = sizeof (trap_trace_ctl_t) * NCPU; if (!ttrace_ttr_size_check()) return (WALK_ERR); bzero(&dcmd, sizeof (dcmd)); dcmd.ttd_cpu = -1; dcmd.ttd_extended = FALSE; if (mdb_readsym(ttc, ttc_size, "trap_trace_ctl") == -1) { mdb_warn("symbol 'trap_trace_ctl' not found; " "non-TRAPTRACE kernel?\n"); return (DCMD_ERR); } if (mdb_getopts(argc, argv, 'x', MDB_OPT_SETBITS, TRUE, &dcmd.ttd_extended, 't', MDB_OPT_UINTPTR, &dcmd.ttd_kthread, NULL) != argc) return (DCMD_USAGE); if (DCMD_HDRSPEC(flags)) { mdb_printf("%3s %15s %4s %2s %-*s%s\n", "CPU", "TIMESTAMP", "TYPE", "Vec", TT_HDLR_WIDTH, "HANDLER", " EIP"); } if (flags & DCMD_ADDRSPEC) { if (addr >= NCPU) { if (mdb_vread(&rec, sizeof (rec), addr) == -1) { mdb_warn("couldn't read trap trace record " "at %p", addr); return (DCMD_ERR); } if (ttrace_walk(addr, &rec, &dcmd) == WALK_ERR) return (DCMD_ERR); return (DCMD_OK); } dcmd.ttd_cpu = addr; } if (mdb_readvar(&use_apix, "apix_enable") == -1) { mdb_warn("failed to read apix_enable"); use_apix = 0; } if (use_apix) { if (mdb_readvar(&d_apixs, "apixs") == -1) { mdb_warn("\nfailed to read apixs."); return (DCMD_ERR); } /* change to apix ttrace interrupt handler */ ttrace_hdlr[4].t_hdlr = ttrace_apix_interrupt; } if (mdb_walk("ttrace", (mdb_walk_cb_t)ttrace_walk, &dcmd) == -1) { mdb_warn("couldn't walk 'ttrace'"); return (DCMD_ERR); } return (DCMD_OK); }