kmdb_kvm.c revision 7b9b3bf3fd4f7bfad91fce91e3e9fba62ac85c77
/*
* 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
* 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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <kmdb/kmdb_kvm.h>
#include <kmdb/kmdb_kdi.h>
#include <kmdb/kmdb_promif.h>
#include <kmdb/kmdb_module.h>
#include <kmdb/kmdb_asmutil.h>
#include <mdb/mdb_types.h>
#include <mdb/mdb_conf.h>
#include <mdb/mdb_modapi.h>
#include <mdb/mdb_target_impl.h>
#include <mdb/mdb_debug.h>
#include <mdb/mdb_string.h>
#include <mdb/mdb_kreg_impl.h>
#include <strings.h>
#include <dlfcn.h>
#include <sys/isa_defs.h>
#include <sys/kobj_impl.h>
static const char KMT_RTLD_NAME[] = "krtld";
static const char KMT_MODULE[] = "mdb_ks";
static const char KMT_CTFPARENT[] = "genunix";
static int kmt_defbp_lock; /* For list, running kernel holds */
static int kmt_defbp_bpspec; /* vespec for def'd bp activation bp */
static const mdb_se_ops_t kmt_brkpt_ops;
static const mdb_se_ops_t kmt_wapt_ops;
typedef struct kmt_symarg {
void *sym_data; /* Callback function argument */
const char *sym_obj; /* Containing object */
} kmt_symarg_t;
typedef struct kmt_maparg {
void *map_data; /* Callback function argument */
} kmt_maparg_t;
/*ARGSUSED*/
int
{
/*
* We only handle one flag (ALLOWIO), and we can't fail to set or clear
* it, so we just blindly replace the t_flags version with the one
* passed.
*/
(flags & MDB_TGT_F_ALLOWIO);
return (0);
}
/*ARGSUSED*/
const char *
{
return ("kmdb_kvm");
}
/*ARGSUSED*/
static const char *
{
return (mdb_conf_platform());
warn("'platform' symbol is missing from kernel\n");
return ("unknown");
}
return (platform);
}
static int
{
}
/*ARGSUSED*/
static int
kmt_dmodel(mdb_tgt_t *t)
{
return (MDB_TGT_MODEL_NATIVE);
}
/*ARGSUSED*/
{
if (nbytes == 0)
return (0);
/*
* Try to process the entire buffer, as requested. If we catch a fault,
* try smaller chunks. This allows us to handle regions that cross
* mapping boundaries.
*/
ndone = 0;
if (chunksz == 1) {
/* We failed with the smallest chunk - give up */
} else if (chunksz > 4)
chunksz = 4;
else
chunksz = 1;
}
while (nbytes > 0) {
addr += n;
nbytes -= n;
ndone += n;
}
return (ndone);
}
static void
{
/*
* We need to guarantee atomic accesses for certain sizes. bcopy won't
* make that guarantee, so we need to do it ourselves.
*/
#ifdef _LP64
else
#endif
else if (n == 1)
else
}
static ssize_t
{
return (nbytes);
}
{
return (nbytes);
}
/*ARGSUSED*/
static ssize_t
{
/*
* outright.
*/
if (!(t->t_flags & MDB_TGT_F_ALLOWIO) &&
return (set_errno(EMDB_NOMAP));
}
/*ARGSUSED*/
static ssize_t
{
}
/*ARGSUSED*/
{
}
static uintptr_t
{
warn("'kas' symbol is missing from kernel\n");
(void) set_errno(EMDB_NOSYM);
return (0);
}
}
static int
{
mdb_var_t *v;
case (uintptr_t)MDB_TGT_AS_PHYS:
case (uintptr_t)MDB_TGT_AS_FILE:
case (uintptr_t)MDB_TGT_AS_IO:
case (uintptr_t)MDB_TGT_AS_VIRT:
return (-1); /* errno is set for us */
break;
default:
/* We don't support non-kas vtop */
return (set_errno(EMDB_TGTNOTSUP));
}
return (0);
return (0);
}
return (set_errno(EMDB_NOMAP));
}
/*ARGSUSED*/
static int
{
const mdb_tgt_gregset_t *gregs;
int i;
if (flags & DCMD_ADDRSPEC) {
if (argc != 0)
return (DCMD_USAGE);
(void) set_errno(EMDB_NOMAP);
return (DCMD_ERR);
}
}
NULL);
argc -= i;
argv += i;
if (argc != 0)
return (DCMD_USAGE);
return (DCMD_ERR);
}
return (DCMD_OK);
}
static int
{
if (flags & DCMD_ADDRSPEC)
return (DCMD_USAGE);
}
static int
{
int i;
if (flags & DCMD_ADDRSPEC) {
(void) set_errno(EMDB_NOMAP);
return (DCMD_ERR);
}
flags &= ~DCMD_ADDRSPEC;
}
NULL);
argc -= i;
argv += i;
}
/*
* Lasciate ogne speranza, voi ch'intrate.
*/
static int
{
int parse_strings = 1;
int i;
if (!(flags & DCMD_ADDRSPEC))
return (DCMD_USAGE);
STT_FUNC) {
return (DCMD_ERR);
}
parse_strings = 0;
argc--;
argv++;
}
for (i = 0; i < argc; i++) {
case MDB_TYPE_STRING:
/*
* mdb_strtoull doesn't return on error, so we have to
* pre-check strings suspected to contain numbers.
*/
} else
break;
case MDB_TYPE_IMMEDIATE:
break;
default:
return (DCMD_USAGE);
}
}
warn("call failed: caught a trap\n");
return (DCMD_ERR);
}
if (flags & DCMD_PIPE_OUT) {
} else {
/* pretty-print the results */
for (i = 0; i < argc; i++) {
if (i > 0)
mdb_printf(", ");
/* I'm ashamed but amused */
quote);
} else
}
mdb_printf(");\n");
}
return (DCMD_OK);
}
/*ARGSUSED*/
int
{
if (flags & DCMD_ADDRSPEC) {
if (argc != 0)
return (DCMD_USAGE);
} else {
addr = 0;
return (DCMD_USAGE);
}
return (DCMD_OK);
}
/*ARGSUSED*/
static int
{
int a = 0;
return (a/a);
}
static int
{
mdb_var_t *v;
int first = 1, n = 0;
kmc = MDB_NV_COOKIE(v);
continue;
n++;
if (first) {
first = 0;
}
}
}
mdb_printf("\n");
return (n);
}
/*ARGSUSED*/
static int
{
warn("failed to read 'utsname' struct from kernel\n");
}
mdb_printf("debugging live kernel (%d-bit) on %s\n",
(int)(sizeof (void *) * NBBY),
mdb_printf("operating system: %s %s (%s)\n",
mdb_printf("CPU-specific support: %s\n",
}
KDI_DTSTATE_DTRACE_ACTIVE ? "active (debugger breakpoints cannot "
"be armed)" : "inactive"));
(void) kmt_dmod_status("pending dmod unloads:",
return (DCMD_OK);
}
/*ARGSUSED*/
static int
{
return (DCMD_USAGE);
if (kmdb_dpi_switch_master((int)addr) < 0) {
return (DCMD_ERR);
}
return (DCMD_OK);
}
static const mdb_dcmd_t kmt_dcmds[] = {
{ "cpustack", "?[-v] [-c cpuid] [cnt]", "print stack backtrace for a "
"specific CPU", kmt_cpustack_dcmd },
{ "cpuregs", "?[-c cpuid]", "print general-purpose registers for a "
"specific CPU", kmt_cpuregs },
{ "rdpcicfg", ": bus dev func", "read a register in PCI config space",
kmt_rdpcicfg },
{ "wrpcicfg", ": bus dev func val", "write a register in PCI config "
"space", kmt_wrpcicfg },
#endif
{ NULL }
};
static uintmax_t
kmt_reg_disc_get(const mdb_var_t *v)
{
mdb_tgt_reg_t r = 0;
return (r);
}
static void
{
}
static const mdb_nv_disc_t kmt_reg_disc = {
};
/*ARGSUSED*/
static int
{
return (set_errno(EMDB_BADREG));
return (0);
}
/*ARGSUSED*/
static int
{
if (kmdb_dpi_set_register(rname, r) < 0)
return (set_errno(EMDB_BADREG));
return (0);
}
static void
{
}
static kmt_module_t *
{
goto create_module_cleanup;
goto create_module_cleanup;
}
/*
* We don't want everyone rooting around in the module structure, so we
* make copies of the interesting members.
*/
return (km);
return (NULL);
}
static void
{
}
static int
{
mdb_var_t *v;
char name[MAXNAMELEN];
warn("failed to read module name at %p",
(void *)modp->mod_modname);
}
/* We only care about modules that are actually loaded */
if (!kmdb_kdi_mod_isloaded(modp))
return (0);
/*
* Skip the modules we already know about and that haven't
* changed since last time we were here.
*/
km = MDB_NV_COOKIE(v);
/*
* The module has changed since last we saw it. For
* safety, remove our old version, and treat it as a
* new module.
*/
} else {
return (0);
}
}
}
return (0);
}
static void
{
if (kmdb_kdi_mod_iter(kmt_modlist_update_cb, t) < 0) {
warn("failed to complete update of kernel module list\n");
return;
}
/* Reset the mark for next time */
} else {
/*
* We didn't see it on the kernel's module list, so
* remove it from our view of the world.
*/
}
}
}
static void
{
(void) mdb_tgt_status(t, &t->t_status);
}
int
{
const char *name;
/*
* We look through the private symbols (if any), then through the module
* symbols. We can simplify the loop if we pretend the private symbols
* come from a module.
*/
}
/* Symbol resolution isn't available during initialization */
return (set_errno(EMDB_NOSYM));
continue;
continue;
continue;
if (flags & MDB_TGT_SYM_EXACT) {
goto found;
}
/*
* If this is the first match we've found, or if this symbol is
* closer to the specified address than the last one we found,
* use it.
*/
}
}
/*
* kmdb dmods are normal kernel modules, loaded by krtld as such. To
* avoid polluting modinfo, and to keep from confusing the module
* subsystem (many dmods have the same names as real kernel modules),
* kmdb keeps their modctls separate, and doesn't allow their loading
* result, kmdb_kvm doesn't find out about them, and can't turn their
* addresses into symbols. This can be most inconvenient during
* debugger faults, as the dmod frames will show up without names.
* We weren't able to turn the requested address into a symbol, so we'll
* take a spin through the dmods, trying to match our address against
* their symbols.
*/
}
/*
* Once we've found something, copy the final name into the caller's
* buffer and prefix it with the load object name if appropriate.
*/
}
} else {
} else {
}
}
}
return (0);
}
static int
{
mdb_var_t *v;
int n;
if (!kmt->kmt_symavail)
return (set_errno(EMDB_NOSYM));
case (uintptr_t)MDB_TGT_OBJ_EXEC:
case (uintptr_t)MDB_TGT_OBJ_EVERY:
break;
case (uintptr_t)MDB_TGT_OBJ_RTLD:
/*FALLTHROUGH*/
default:
/*
* If this is a request for a dmod symbol, let kmdb_module
* handle it.
*/
}
return (set_errno(EMDB_NOOBJ));
km = mdb_nv_get_cookie(v);
n = 1;
}
/*
* kmdb's kvm target is at a bit of a disadvantage compared to mdb's
* kvm target when it comes to global symbol lookups. mdb has ksyms,
* which hides pesky things like symbols that are undefined in unix,
* but which are defined in genunix. We don't have such a facility -
* we simply iterate through the modules, looking for a given symbol
* in each. Unless we're careful, we'll return the undef in the
* aforementioned case.
*/
break;
}
if (n == 0)
return (set_errno(EMDB_NOSYM));
return (0);
}
static int
{
}
return (0);
}
static void
mdb_tgt_sym_f *cb, void *p)
{
}
static int
{
mdb_var_t *v;
if (which == MDB_TGT_DYNSYM)
return (set_errno(EMDB_TGTNOTSUP));
case (uintptr_t)MDB_TGT_OBJ_EXEC:
case (uintptr_t)MDB_TGT_OBJ_EVERY:
km = mdb_nv_get_cookie(v);
}
}
return (0);
case (uintptr_t)MDB_TGT_OBJ_RTLD:
/*FALLTHROUGH*/
default:
}
return (set_errno(EMDB_NOOBJ));
km = mdb_nv_get_cookie(v);
}
return (0);
}
static int
{
/*
* This is a bit sketchy but avoids problematic compilation of this
* target against the current VM implementation. Now that we have
* vmem, we can make this less broken and more informative by changing
* this code to invoke the vmem walker in the near future.
*/
const struct kmt_seg {
"%lr", addr);
}
}
static int
{
kmt_maparg_t m;
m.map_target = t;
return (-1); /* errno is set for us */
}
static const mdb_map_t *
{
return (map);
}
static int
{
mdb_map_t m;
break;
}
return (0);
}
static const mdb_map_t *
{
}
(void) set_errno(EMDB_NOMAP);
return (NULL);
}
static kmt_module_t *
{
return (km);
}
return (NULL);
}
static const mdb_map_t *
{
mdb_map_t m;
/*
* If name is MDB_TGT_OBJ_EXEC, return the first module on the list,
* which will be unix since we keep kmt_modlist in load order.
*/
if (name == MDB_TGT_OBJ_EXEC) {
&m));
}
if (name == MDB_TGT_OBJ_RTLD)
return (kmt_mod_to_map(km, &m));
(void) set_errno(EMDB_NOOBJ);
return (NULL);
}
static ctf_file_t *
{
int err;
(void) set_errno(EMDB_NOCTF);
return (NULL);
}
return (NULL);
}
mdb_var_t *v;
(void) kmt_load_ctfdata(t, pm);
warn("failed to import parent types into "
}
} else {
warn("failed to load CTF data for %s - parent %s not "
}
}
}
{
return (kmt_load_ctfdata(t, km));
}
return (kmdb_module_addr_to_ctf(addr));
}
{
if (name == MDB_TGT_OBJ_EXEC) {
} else if (name == MDB_TGT_OBJ_RTLD) {
/* Request for CTF data for a DMOD symbol */
}
return (kmt_load_ctfdata(t, km));
(void) set_errno(EMDB_NOOBJ);
return (NULL);
}
/*ARGSUSED*/
static int
{
int state;
case DPI_STATE_INIT:
break;
case DPI_STATE_STOPPED:
break;
case DPI_STATE_FAULTED:
break;
case DPI_STATE_LOST:
break;
}
return (0);
}
/*
* Invoked when kmt_defbp_enter_debugger is called, this routine activates and
* deactivates deferred breakpoints in response to module load and unload
* events.
*/
/*ARGSUSED*/
static void
{
if (kmt_defbp_modchg_isload) {
if (!mdb_tgt_sespec_activate_all(t) &&
/*
* We weren't able to activate the breakpoints.
* If so requested, we'll return without calling
* continue, thus throwing the user into the debugger.
*/
return;
}
} else {
if ((map = kmt_addr_to_map(t,
warn("module unload notification for unknown module %s",
return; /* drop into the debugger */
}
if ((bpmap = kmt_addr_to_map(t,
}
}
}
}
(void) mdb_tgt_continue(t, NULL);
}
static void
kmt_defbp_enter_debugger(void)
{
/*
* The debugger places a breakpoint here. We can't have a simple
* nop function here, because GCC knows much more than we do, and
* will optimize away the call to it.
*/
(void) get_fp();
}
/*
* This routine is called while the kernel is running. It attempts to determine
* whether any deferred breakpoints exist for the module being changed (loaded
* or unloaded). If any such breakpoints exist, the debugger will be entered to
* process them.
*/
static void
{
kmt_defbp_lock = 1;
continue;
/*
* Activate the breakpoint
*/
break;
}
}
kmt_defbp_lock = 0;
}
/*ARGSUSED*/
static int
{
int n;
/*
* The order of the following two calls is important. If there are
* load acks on the work queue, we'll initialize the dmods they
* represent. This will involve a call to _mdb_init, which may very
* well result in a symbol lookup. If we haven't resynced our view
* of symbols with the current state of the world, this lookup could
* end very badly. We therefore make sure to sync before processing
* the work queue.
*/
kmt_sync(t);
if (kmdb_kdi_get_unload_request())
t->t_flags |= MDB_TGT_F_UNLOAD;
(void) mdb_tgt_status(t, &t->t_status);
"s"[n == 1], "s"[n == 1]);
}
return (0);
}
/*ARGSUSED*/
static int
{
int rc;
if ((rc = kmdb_dpi_step()) == 0)
(void) mdb_tgt_status(t, &t->t_status);
return (rc);
}
static int
{
/*
* The routines that add and arm breakpoints will check for the proper
* DTrace state, but they'll just put this breakpoint on the idle list
* if DTrace is active. It'll correctly move to the active list when
* DTrace deactivates, but that's insufficient for our purposes -- we
* need to do extra processing at that point. We won't get to do said
* processing with with a normal idle->active transition, so we just
* won't add it add it until we're sure that it'll stick.
*/
return (set_errno(EMDB_DTACTIVE));
return (0);
}
static void
{
if (kmt_defbp_bpspec != 0) {
if (t != NULL)
(void) mdb_tgt_vespec_delete(t, kmt_defbp_bpspec);
kmt_defbp_bpspec = 0;
}
}
static kmt_defbp_t *
{
if (kmt_defbp_activate(t) < 0)
warn("failed to activate deferred breakpoints");
}
return (dbp);
}
static void
{
dbp->dbp_symname);
}
static void
{
/* We can't remove items from the list while the driver is using it. */
if (kmt_defbp_lock)
return;
continue;
}
}
static void
kmt_defbp_prune(void)
{
}
static void
kmt_defbp_destroy_all(void)
{
}
static void
{
ASSERT(kmt_defbp_num > 0);
if (kmt_defbp_num == 0)
}
static int
{
GElf_Sym s;
(void) mdb_tgt_status(t, &tsp);
return (set_errno(EMDB_NOPROC));
warn("breakpoint %s activation failed",
}
return (-1); /* errno is set for us */
}
}
#ifdef __sparc
return (set_errno(EMDB_BPALIGN));
#endif
return (-1); /* errno is set for us */
warn("breakpoint will not arm until DTrace is inactive\n");
return (0);
}
/*ARGSUSED*/
static void
{
}
/*ARGSUSED*/
static char *
{
} else {
}
} else {
}
return (buf);
}
static int
{
}
}
/*ARGSUSED*/
static int
{
return (0); /* fail if one is symbolic, other is an explicit address */
}
static int
{
int rv;
return (set_errno(EMDB_DTACTIVE));
return (rv);
if (kmt->kmt_narmedbpts++ == 0)
return (0);
}
static int
{
int rv;
return (rv);
if (--kmt->kmt_narmedbpts == 0)
return (0);
}
/*
* Determine whether the specified sespec is an armed watchpoint that overlaps
* with the given breakpoint and has the given flags set. We use this to find
* conflicts with breakpoints, below.
*/
static int
{
}
/*
* We step over breakpoints using our single-stepper. If a conflicting
* watchpoint is present, we must temporarily remove it before stepping over the
* breakpoint so we don't immediately re-trigger the watchpoint. We know the
* watchpoint has already triggered on our trap instruction as part of fetching
* it. Before we return, we must re-install any disabled watchpoints.
*/
static int
{
int status = -1;
int error;
}
}
return (status);
}
/*ARGSUSED*/
static int
{
}
static const mdb_se_ops_t kmt_brkpt_ops = {
kmt_brkpt_ctor, /* se_ctor */
kmt_brkpt_dtor, /* se_dtor */
kmt_brkpt_info, /* se_info */
kmt_brkpt_secmp, /* se_secmp */
kmt_brkpt_vecmp, /* se_vecmp */
kmt_brkpt_arm, /* se_arm */
kmt_brkpt_disarm, /* se_disarm */
kmt_brkpt_cont, /* se_cont */
kmt_brkpt_match /* se_match */
};
static int
{
(void) mdb_tgt_status(t, &tsp);
return (set_errno(EMDB_NOPROC));
if (kmdb_dpi_wapt_reserve(swp) < 0) {
return (-1); /* errno is set for us */
}
return (0);
}
/*ARGSUSED*/
static void
{
}
/*ARGSUSED*/
static char *
{
const char *fmt;
char desc[24];
desc[0] = '\0';
case MDB_TGT_WA_R:
break;
case MDB_TGT_WA_W:
break;
case MDB_TGT_WA_X:
break;
default:
}
case DPI_WAPT_TYPE_PHYS:
fmt = "stop on %s of phys [%p, %p)";
break;
case DPI_WAPT_TYPE_VIRT:
fmt = "stop on %s of [%la, %la)";
break;
case DPI_WAPT_TYPE_IO:
fmt = "stop on %s of I/O port %p";
else
fmt = "stop on %s of I/O port [%p, %p)";
break;
}
return (buf);
}
/*ARGSUSED*/
static int
{
}
/*ARGSUSED*/
static int
{
}
/*ARGSUSED*/
static int
{
return (0);
}
/*ARGSUSED*/
static int
{
return (0);
}
/*
* Determine whether the specified sespec is an armed breakpoint at the given
* %pc. We use this to find conflicts with watchpoints below.
*/
static int
{
}
/*
* We step over watchpoints using our single-stepper. If a conflicting
* breakpoint is present, we must temporarily disarm it before stepping over
* the watchpoint so we do not immediately re-trigger the breakpoint. This is
* similar to the case handled in kmt_brkpt_cont(), above.
*/
static int
{
int status = -1;
/*
* If we stopped for anything other than a watchpoint, check to see
* if there's a breakpoint here.
*/
break;
}
}
}
return (status);
}
/*ARGSUSED*/
static int
{
}
static const mdb_se_ops_t kmt_wapt_ops = {
kmt_wapt_ctor, /* se_ctor */
kmt_wapt_dtor, /* se_dtor */
kmt_wapt_info, /* se_info */
kmt_wapt_secmp, /* se_secmp */
kmt_wapt_vecmp, /* se_vecmp */
kmt_wapt_arm, /* se_arm */
kmt_wapt_disarm, /* se_disarm */
kmt_wapt_cont, /* se_cont */
kmt_wapt_match /* se_match */
};
/*ARGSUSED*/
static int
{
return (0);
}
/*ARGSUSED*/
static char *
{
const char *name;
int trapnum;
else
if (trapnum == KMT_TRAP_ALL)
name = "any trap";
else if (trapnum == KMT_TRAP_NOTENUM)
name = "miscellaneous trap";
else
return (buf);
}
/*ARGSUSED2*/
static int
{
switch (spectt) {
case KMT_TRAP_ALL:
return (1);
case KMT_TRAP_NOTENUM:
default:
}
}
static const mdb_se_ops_t kmt_trap_ops = {
kmt_trap_ctor, /* se_ctor */
no_se_dtor, /* se_dtor */
kmt_trap_info, /* se_info */
no_se_secmp, /* se_secmp */
no_se_vecmp, /* se_vecmp */
no_se_arm, /* se_arm */
no_se_disarm, /* se_disarm */
no_se_cont, /* se_cont */
kmt_trap_match /* se_match */
};
static void
{
}
static int
{
}
static int
{
int serrno;
(void) set_errno(EMDB_NOOBJ);
return (0);
}
/*
* Deferred breakpoints are always scoped. If we didn't find a tick,
* there's no scope. We'll create a vbrkpt, but only if we can turn the
* provided string into an address.
*/
if (strisbasenum(fullname)) {
} else if (mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EVERY,
(void) set_errno(EMDB_NOSYM);
return (0);
} else {
}
}
(void) set_errno(EMDB_NOSYM);
return (0);
}
errno != EMDB_NOOBJ) {
return (0); /* errno is set for us */
}
}
static int
{
/* Assume the watchpoint spaces don't overlap */
return (0);
return (0); /* no range overlap */
return (0); /* no range overlap */
}
static void
{
}
static int
{
if (kmdb_dpi_wapt_validate(wp) < 0)
return (0); /* errno is set for us */
goto wapt_dup;
}
goto wapt_dup;
}
(void) set_errno(EMDB_WPDUP);
return (0);
}
static int
{
}
static int
{
}
static int
{
data, DPI_WAPT_TYPE_IO));
}
static int
void *data)
{
(void) set_errno(EMDB_BADFLTNUM);
return (0);
}
}
}
/*ARGSUSED*/
static uintmax_t
kmt_cpuid_disc_get(const mdb_var_t *v)
{
return (kmdb_dpi_get_master_cpuid());
}
static const mdb_nv_disc_t kmt_cpuid_disc = {
NULL,
};
/*
* This routine executes while the kernel is running.
*/
void
{
/*
* Force load of the MDB krtld module, in case it's been rolled into
* unix.
*/
}
static void
kmt_destroy(mdb_tgt_t *t)
{
}
if (!kmt_defbp_lock)
}
static const mdb_tgt_ops_t kmt_ops = {
kmt_setflags, /* t_setflags */
(int (*)()) mdb_tgt_notsup, /* t_setcontext */
kmt_activate, /* t_activate */
(void (*)()) mdb_tgt_nop, /* t_deactivate */
kmt_periodic, /* t_periodic */
kmt_destroy, /* t_destroy */
kmt_name, /* t_name */
(const char *(*)()) mdb_conf_isa, /* t_isa */
kmt_platform, /* t_platform */
kmt_uname, /* t_uname */
kmt_dmodel, /* t_dmodel */
kmt_read, /* t_vread */
kmt_write, /* t_vwrite */
kmt_pread, /* t_pread */
kmt_pwrite, /* t_pwrite */
kmt_read, /* t_fread */
kmt_write, /* t_fwrite */
kmt_ioread, /* t_ioread */
kmt_iowrite, /* t_iowrite */
kmt_vtop, /* t_vtop */
kmt_lookup_by_name, /* t_lookup_by_name */
kmt_lookup_by_addr, /* t_lookup_by_addr */
kmt_symbol_iter, /* t_symbol_iter */
kmt_mapping_iter, /* t_mapping_iter */
kmt_object_iter, /* t_object_iter */
kmt_addr_to_map, /* t_addr_to_map */
kmt_name_to_map, /* t_name_to_map */
kmt_addr_to_ctf, /* t_addr_to_ctf */
kmt_name_to_ctf, /* t_name_to_ctf */
kmt_status, /* t_status */
(int (*)()) mdb_tgt_notsup, /* t_run */
kmt_step, /* t_step */
kmt_step_out, /* t_step_out */
kmt_step_branch, /* t_step_branch */
kmt_next, /* t_next */
kmt_continue, /* t_cont */
(int (*)()) mdb_tgt_notsup, /* t_signal */
kmt_add_vbrkpt, /* t_add_vbrkpt */
kmt_add_sbrkpt, /* t_add_sbrkpt */
kmt_add_pwapt, /* t_add_pwapt */
kmt_add_vwapt, /* t_add_vwapt */
kmt_add_iowapt, /* t_add_iowapt */
(int (*)()) mdb_tgt_null, /* t_add_sysenter */
(int (*)()) mdb_tgt_null, /* t_add_sysexit */
(int (*)()) mdb_tgt_null, /* t_add_signal */
kmt_add_trap, /* t_add_fault */
kmt_getareg, /* t_getareg */
kmt_putareg, /* t_putareg */
(int (*)()) mdb_tgt_nop, /* XXX t_stack_iter */
(int (*)()) mdb_tgt_notsup /* t_auxv */
};
/*
* Called immediately upon resumption of the system after a step or continue.
* Allows us to synchronize kmt's view of the world with reality.
*/
/*ARGSUSED*/
static void
{
int symavail;
/*
* Resync our view of the world if the modules have changed, or if we
* didn't have any symbols coming into this function. The latter will
* only happen on startup.
*/
if (kmdb_kdi_mods_changed() || !symavail)
/*
* It would be nice if we could run this less frequently, perhaps
* after a dvec-initiated trigger.
*/
if (kmt_defbp_num > 0 && kmt_defbp_bpspec == 0 &&
/*
* Deferred breakpoints were created while DTrace was active,
* and consequently the deferred breakpoint enabling mechanism
* wasn't activated. Activate it now, and then try to activate
* the deferred breakpoints. We do this so that we can catch
* the ones which may apply to modules that have been loaded
* while they were waiting for DTrace to deactivate.
*/
(void) kmt_defbp_activate(t);
(void) mdb_tgt_sespec_activate_all(t);
}
(void) mdb_tgt_status(t, &t->t_status);
}
/*
* This routine executes while the kernel is running.
*/
/*ARGSUSED*/
int
{
if (argc != 0)
kmt_init_isadep(t);
return (0);
kmt_destroy(t);
return (-1);
}
/*
* This routine is called once, when kmdb first has control of the world.
*/
void
kmdb_kvm_startup(void)
{
(void) mdb_module_load_builtin(KMT_MODULE);
/*
* This is here because we need to write the deferred breakpoint
* breakpoint when the debugger starts. Our normal r/o write routines
* don't work when the kernel is running, so we have to do it during
* startup.
*/
}
/*
* This routine is called after kmdb has loaded its initial set of modules.
*/
void
kmdb_kvm_poststartup(void)
{
(void) mdb_dis_select(kmt_def_dismode());
}