#include <mdb/mdb_param.h>
#include <mdb/mdb_modapi.h>
#include <mdb/mdb_ctf.h>
#define _SYS_MACHPARAM_H
#include <sys/vmm_impl.h>
#include <stddef.h>
#include <stdbool.h>
typedef struct mdb_mem_map {
size_t len;
int segid;
} mdb_mem_map_t;
#define MDB_VM_MAX_MEMMAPS 8
typedef struct mdb_vm {
mdb_mem_map_t mem_maps[MDB_VM_MAX_MEMMAPS];
uint16_t sockets, cores, threads;
bool mem_transient;
} mdb_vm_t;
typedef struct mdb_vmm_softc {
mdb_vm_t *vmm_vm;
char vmm_name[VM_MAX_NAMELEN];
zone_t *vmm_zone;
uint_t vmm_flags;
} mdb_vmm_softc_t;
static uintptr_t mdb_zone0;
static int
i_vmm_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
mdb_vmm_softc_t vmm;
const char *vmname = NULL;
mdb_vm_t vm;
if (mdb_getopts(argc, argv,
'n', MDB_OPT_STR, &vmname,
NULL) != argc) {
return (DCMD_USAGE);
}
if (mdb_zone0 == 0) {
GElf_Sym sym;
if (mdb_lookup_by_name("zone0", &sym) == -1)
mdb_warn("failed to find 'zone0'");
else
mdb_zone0 = sym.st_value;
}
if (!(flags & DCMD_PIPE_OUT) && DCMD_HDRSPEC(flags)) {
mdb_printf("%<u>%?s %?s %?s %5s %-6s %-3s %-6s %</u>\n",
"SOFTC", "VM", "ZONE", "TOPO", "MiB", "F", "NAME");
}
if (mdb_ctf_vread(&vmm, "vmm_softc_t", "mdb_vmm_softc_t",
addr, 0) == -1) {
mdb_warn("can't read vmm_softc_t structure at %p", addr);
return (DCMD_ERR);
}
if (vmname && strcmp(vmname, vmm.vmm_name) != 0)
return (DCMD_OK);
if (flags & DCMD_PIPE_OUT) {
mdb_printf("%lr\n", addr);
return (DCMD_OK);
}
if (mdb_ctf_vread(&vm, "struct vm", "mdb_vm_t",
(uintptr_t)vmm.vmm_vm, 0) == -1) {
mdb_warn("can't read struct vm at %p", vmm.vmm_vm);
return (DCMD_ERR);
}
size_t memsize = 0;
for (uint_t i = 0; i < MDB_VM_MAX_MEMMAPS; i++)
memsize += vm.mem_maps[i].len;
mdb_printf("%0?p %0?p %0?p %d/%d/%d %-6d %c%c%c %s \n",
addr, vmm.vmm_vm, vmm.vmm_zone,
vm.sockets, vm.cores, vm.threads,
memsize / (1024 * 1024),
(uintptr_t)vmm.vmm_zone == mdb_zone0 ? 'G' : ' ',
vm.mem_transient ? 'T' : 'R',
(vmm.vmm_flags & VMM_AUTODESTROY) != 0 ? 'D' : ' ',
vmm.vmm_name);
return (DCMD_OK);
}
static int
vmm_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
if ((flags & DCMD_ADDRSPEC))
return (i_vmm_dcmd(addr, flags, argc, argv));
if (mdb_fpwalk_dcmd("vmm", "vmm", argc, argv, 0,
flags & DCMD_PIPE_OUT) == -1) {
mdb_warn("can't walk virtual machines");
return (DCMD_ERR);
}
return (DCMD_OK);
}
static int
vmm_walk_init(mdb_walk_state_t *wsp)
{
GElf_Sym sym;
if (wsp->walk_addr == 0) {
if (mdb_lookup_by_name("vmm_list", &sym) == -1) {
mdb_warn("failed to find 'vmm_list'");
return (WALK_ERR);
}
wsp->walk_addr = (uintptr_t)sym.st_value;
}
if (mdb_layered_walk("list", wsp) == -1) {
mdb_warn("couldn't walk 'list'");
return (WALK_ERR);
}
return (WALK_NEXT);
}
static int
vmm_walk_step(mdb_walk_state_t *wsp)
{
return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer,
wsp->walk_cbdata));
}
static void
vmm_help(void)
{
mdb_printf("Prints summary information about vmm instances.\n");
mdb_printf("\n%s",
"The resulting output is a table of bhyve virtual machines on the "
"system.\n"
"The columns in the output are:\n\n");
mdb_printf("%s",
"SOFTC\t\tSoft state, pointer to vmm_softc_t\n"
"VM\t\tstate, pointer to 'struct vm'\n"
"TOPO\t\ttopology as sockets/cores/threads\n"
"MiB\t\tallocated memory\n"
"F\t\tFlags"
"\tG - VMM is created in the global zone.\n"
"\t\t\tT - VMM is using transient memory.\n"
"\t\t\tR - VMM is using memory from reservoir.\n"
"\t\t\tD - VMM is set to auto-destruct.\n"
"NAME\t\tThe virtual machine name.\n"
"ZONE\t\tThe zone_t pointer to zone where the vm is running.\n");
mdb_dec_indent(2);
mdb_printf("\n%<b>OPTIONS%</b>\n");
mdb_inc_indent(2);
mdb_printf("-n <name>\tOnly show the virtual machine called <name>\n");
mdb_dec_indent(2);
mdb_printf("\n%<b>NOTES%</b>\n");
mdb_inc_indent(2);
mdb_printf("%s",
"The MiB column sums up all memory segments and includes any\n"
"memory allocated for the bootrom or framebuffer.\n"
"\n"
"Passing the output of this command into a pipeline results in\n"
"the address of the vmm_softc_t in '.'\n");
}
static const mdb_dcmd_t dcmds[] = {
{ "vmm", "?[-n vmname]",
"print virtual machine information", vmm_dcmd, vmm_help },
{ NULL }
};
static const mdb_walker_t walkers[] = {
{ "vmm", "walk a list of virtual machines",
vmm_walk_init, vmm_walk_step, NULL },
{ NULL }
};
static const mdb_modinfo_t modinfo = {
MDB_API_VERSION, dcmds, walkers
};
const mdb_modinfo_t *
_mdb_init(void)
{
return (&modinfo);
}