1843e1988Sjohnlev /* 2843e1988Sjohnlev * CDDL HEADER START 3843e1988Sjohnlev * 4843e1988Sjohnlev * The contents of this file are subject to the terms of the 5843e1988Sjohnlev * Common Development and Distribution License (the "License"). 6843e1988Sjohnlev * You may not use this file except in compliance with the License. 7843e1988Sjohnlev * 8843e1988Sjohnlev * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9843e1988Sjohnlev * or http://www.opensolaris.org/os/licensing. 10843e1988Sjohnlev * See the License for the specific language governing permissions 11843e1988Sjohnlev * and limitations under the License. 12843e1988Sjohnlev * 13843e1988Sjohnlev * When distributing Covered Code, include this CDDL HEADER in each 14843e1988Sjohnlev * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15843e1988Sjohnlev * If applicable, add the following below this CDDL HEADER, with the 16843e1988Sjohnlev * fields enclosed by brackets "[]" replaced with your own identifying 17843e1988Sjohnlev * information: Portions Copyright [yyyy] [name of copyright owner] 18843e1988Sjohnlev * 19843e1988Sjohnlev * CDDL HEADER END 20843e1988Sjohnlev */ 21843e1988Sjohnlev /* 22*349b53ddSStuart Maybee * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23843e1988Sjohnlev * Use is subject to license terms. 24843e1988Sjohnlev */ 25843e1988Sjohnlev 26843e1988Sjohnlev /* 27a576ab5bSrab * KVM backend for hypervisor domain dumps. We don't use libkvm for 28a576ab5bSrab * such dumps, since they do not have a namelist file or the typical 29a576ab5bSrab * dump structures we expect to aid bootstrapping. Instead, we 30a576ab5bSrab * bootstrap based upon a debug_info structure at a known VA, using the 31a576ab5bSrab * guest's own page tables to resolve to physical addresses, and 32a576ab5bSrab * construct the namelist in a manner similar to ksyms_snapshot(). 33a576ab5bSrab * 34a576ab5bSrab * Note that there are two formats understood by this module: the older, 35a576ab5bSrab * ad hoc format, which we call 'core' within this file, and an 36a576ab5bSrab * ELF-based format, known as 'elf'. 37a576ab5bSrab * 38a576ab5bSrab * We only support the older format generated on Solaris dom0: before we 39a576ab5bSrab * fixed it, core dump files were broken whenever a PFN didn't map a 40a576ab5bSrab * real MFN (!). 41843e1988Sjohnlev */ 42843e1988Sjohnlev 43843e1988Sjohnlev #include <strings.h> 44843e1988Sjohnlev #include <stdio.h> 45843e1988Sjohnlev #include <stdlib.h> 46843e1988Sjohnlev #include <stddef.h> 47843e1988Sjohnlev #include <stdarg.h> 48843e1988Sjohnlev #include <unistd.h> 49843e1988Sjohnlev #include <fcntl.h> 50843e1988Sjohnlev #include <gelf.h> 51843e1988Sjohnlev #include <errno.h> 52843e1988Sjohnlev 53843e1988Sjohnlev #include <sys/mman.h> 54843e1988Sjohnlev #include <sys/stat.h> 55843e1988Sjohnlev #include <sys/debug_info.h> 56843e1988Sjohnlev #include <sys/xen_mmu.h> 57843e1988Sjohnlev #include <sys/elf.h> 58843e1988Sjohnlev #include <sys/machelf.h> 59843e1988Sjohnlev #include <sys/modctl.h> 60843e1988Sjohnlev #include <sys/kobj.h> 61843e1988Sjohnlev #include <sys/kobj_impl.h> 62843e1988Sjohnlev #include <sys/sysmacros.h> 63843e1988Sjohnlev #include <sys/privmregs.h> 64843e1988Sjohnlev #include <vm/as.h> 65843e1988Sjohnlev 66843e1988Sjohnlev #include <mdb/mdb_io.h> 67843e1988Sjohnlev #include <mdb/mdb_kb.h> 68843e1988Sjohnlev #include <mdb/mdb_target_impl.h> 69843e1988Sjohnlev 70843e1988Sjohnlev #include <xen/public/xen.h> 71a576ab5bSrab #include <xen/public/version.h> 72a576ab5bSrab #include <xen/public/elfnote.h> 73843e1988Sjohnlev 74843e1988Sjohnlev #define XKB_SHDR_NULL 0 75843e1988Sjohnlev #define XKB_SHDR_SYMTAB 1 76843e1988Sjohnlev #define XKB_SHDR_STRTAB 2 77843e1988Sjohnlev #define XKB_SHDR_SHSTRTAB 3 78843e1988Sjohnlev #define XKB_SHDR_NUM 4 79843e1988Sjohnlev 80843e1988Sjohnlev #define XKB_WALK_LOCAL 0x1 81843e1988Sjohnlev #define XKB_WALK_GLOBAL 0x2 82843e1988Sjohnlev #define XKB_WALK_STR 0x4 83843e1988Sjohnlev #define XKB_WALK_ALL (XKB_WALK_LOCAL | XKB_WALK_GLOBAL | XKB_WALK_STR) 84843e1988Sjohnlev 85a576ab5bSrab #if defined(__i386) 86a576ab5bSrab #define DEBUG_INFO 0xf4bff000 875d2eda97SJohn Levon #define DEBUG_INFO_HVM 0xfe7ff000 88a576ab5bSrab #elif defined(__amd64) 89a576ab5bSrab #define DEBUG_INFO 0xfffffffffb7ff000 905d2eda97SJohn Levon #define DEBUG_INFO_HVM 0xfffffffffb7ff000 91a576ab5bSrab #endif 92a576ab5bSrab 93843e1988Sjohnlev #define PAGE_SIZE 0x1000 94843e1988Sjohnlev #define PAGE_SHIFT 12 95843e1988Sjohnlev #define PAGE_OFFSET(a) ((a) & (PAGE_SIZE - 1)) 96843e1988Sjohnlev #define PAGE_MASK(a) ((a) & ~(PAGE_SIZE - 1)) 97a576ab5bSrab #define PAGE_ALIGNED(a) (((a) & (PAGE_SIZE -1)) == 0) 985d2eda97SJohn Levon #define PT_PADDR_LGPG 0x000fffffffffe000ull 99843e1988Sjohnlev #define PT_PADDR 0x000ffffffffff000ull 100843e1988Sjohnlev #define PT_VALID 0x1 1015d2eda97SJohn Levon #define PT_PAGESIZE 0x080 1025d2eda97SJohn Levon #define PTE_IS_LGPG(p, l) ((l) > 0 && ((p) & PT_PAGESIZE)) 103843e1988Sjohnlev 104843e1988Sjohnlev #define XC_CORE_MAGIC 0xF00FEBED 105843e1988Sjohnlev #define XC_CORE_MAGIC_HVM 0xF00FEBEE 106843e1988Sjohnlev 107843e1988Sjohnlev #define VGCF_HVM_GUEST (1<<1) 108843e1988Sjohnlev 109843e1988Sjohnlev typedef struct xc_core_header { 110843e1988Sjohnlev unsigned int xch_magic; 111843e1988Sjohnlev unsigned int xch_nr_vcpus; 112843e1988Sjohnlev unsigned int xch_nr_pages; 113843e1988Sjohnlev unsigned int xch_ctxt_offset; 114843e1988Sjohnlev unsigned int xch_index_offset; 115843e1988Sjohnlev unsigned int xch_pages_offset; 116843e1988Sjohnlev } xc_core_header_t; 117843e1988Sjohnlev 118a576ab5bSrab struct xc_elf_header { 119a576ab5bSrab uint64_t xeh_magic; 120a576ab5bSrab uint64_t xeh_nr_vcpus; 121a576ab5bSrab uint64_t xeh_nr_pages; 122a576ab5bSrab uint64_t xeh_page_size; 123a576ab5bSrab }; 124a576ab5bSrab 125a576ab5bSrab struct xc_elf_version { 126a576ab5bSrab uint64_t xev_major; 127a576ab5bSrab uint64_t xev_minor; 128a576ab5bSrab xen_extraversion_t xev_extra; 129a576ab5bSrab xen_compile_info_t xev_compile_info; 130a576ab5bSrab xen_capabilities_info_t xev_capabilities; 131a576ab5bSrab xen_changeset_info_t xev_changeset; 132a576ab5bSrab xen_platform_parameters_t xev_platform_parameters; 133a576ab5bSrab uint64_t xev_pagesize; 134a576ab5bSrab }; 135a576ab5bSrab 136a576ab5bSrab /* 137a576ab5bSrab * Either an old-style (3.0.4) core format, or the ELF format. 138a576ab5bSrab */ 139a576ab5bSrab typedef enum { 140a576ab5bSrab XKB_FORMAT_UNKNOWN = 0, 141a576ab5bSrab XKB_FORMAT_CORE = 1, 142a576ab5bSrab XKB_FORMAT_ELF = 2 143a576ab5bSrab } xkb_type_t; 144a576ab5bSrab 145843e1988Sjohnlev typedef struct mfn_map { 146843e1988Sjohnlev mfn_t mm_mfn; 147843e1988Sjohnlev char *mm_map; 148843e1988Sjohnlev } mfn_map_t; 149843e1988Sjohnlev 150843e1988Sjohnlev typedef struct mmu_info { 151843e1988Sjohnlev size_t mi_max; 152843e1988Sjohnlev size_t mi_shift[4]; 153843e1988Sjohnlev size_t mi_ptes; 154843e1988Sjohnlev size_t mi_ptesize; 155843e1988Sjohnlev } mmu_info_t; 156843e1988Sjohnlev 157a576ab5bSrab typedef struct xkb_core { 158a576ab5bSrab xc_core_header_t xc_hdr; 159a576ab5bSrab void *xc_p2m_buf; 160a576ab5bSrab } xkb_core_t; 161a576ab5bSrab 162a576ab5bSrab typedef struct xkb_elf { 163a576ab5bSrab mdb_gelf_file_t *xe_gelf; 164a576ab5bSrab size_t *xe_off; 165a576ab5bSrab struct xc_elf_header xe_hdr; 166a576ab5bSrab struct xc_elf_version xe_version; 167a576ab5bSrab } xkb_elf_t; 168a576ab5bSrab 169843e1988Sjohnlev typedef struct xkb { 170843e1988Sjohnlev char *xkb_path; 171843e1988Sjohnlev int xkb_fd; 1725d2eda97SJohn Levon int xkb_is_hvm; 173a576ab5bSrab 174a576ab5bSrab xkb_type_t xkb_type; 175a576ab5bSrab xkb_core_t xkb_core; 176a576ab5bSrab xkb_elf_t xkb_elf; 177a576ab5bSrab 178a576ab5bSrab size_t xkb_nr_vcpus; 179a576ab5bSrab size_t xkb_nr_pages; 180a576ab5bSrab size_t xkb_pages_off; 181a576ab5bSrab xen_pfn_t xkb_max_pfn; 182843e1988Sjohnlev mfn_t xkb_max_mfn; 183a576ab5bSrab int xkb_is_pae; 184a576ab5bSrab 185843e1988Sjohnlev mmu_info_t xkb_mmu; 186a576ab5bSrab debug_info_t xkb_info; 187a576ab5bSrab 188*349b53ddSStuart Maybee void *xkb_vcpu_data; 189*349b53ddSStuart Maybee size_t xkb_vcpu_data_sz; 190*349b53ddSStuart Maybee struct vcpu_guest_context **xkb_vcpus; 191a576ab5bSrab 192843e1988Sjohnlev char *xkb_pages; 193843e1988Sjohnlev mfn_t *xkb_p2m; 194843e1988Sjohnlev xen_pfn_t *xkb_m2p; 195843e1988Sjohnlev mfn_map_t xkb_pt_map[4]; 196843e1988Sjohnlev mfn_map_t xkb_map; 197a576ab5bSrab 198a576ab5bSrab char *xkb_namelist; 199a576ab5bSrab size_t xkb_namesize; 200843e1988Sjohnlev } xkb_t; 201843e1988Sjohnlev 202843e1988Sjohnlev static const char xkb_shstrtab[] = "\0.symtab\0.strtab\0.shstrtab\0"; 203843e1988Sjohnlev 204843e1988Sjohnlev typedef struct xkb_namelist { 205843e1988Sjohnlev Ehdr kh_elf_hdr; 206843e1988Sjohnlev Phdr kh_text_phdr; 207843e1988Sjohnlev Phdr kh_data_phdr; 208843e1988Sjohnlev Shdr kh_shdr[XKB_SHDR_NUM]; 209843e1988Sjohnlev char shstrings[sizeof (xkb_shstrtab)]; 210843e1988Sjohnlev } xkb_namelist_t; 211843e1988Sjohnlev 212843e1988Sjohnlev static int xkb_build_ksyms(xkb_t *); 213843e1988Sjohnlev static offset_t xkb_mfn_to_offset(xkb_t *, mfn_t); 214843e1988Sjohnlev static mfn_t xkb_va_to_mfn(xkb_t *, uintptr_t, mfn_t); 215843e1988Sjohnlev static ssize_t xkb_read(xkb_t *, uintptr_t, void *, size_t); 216843e1988Sjohnlev static int xkb_read_word(xkb_t *, uintptr_t, uintptr_t *); 217843e1988Sjohnlev static char *xkb_map_mfn(xkb_t *, mfn_t, mfn_map_t *); 218843e1988Sjohnlev static int xkb_close(xkb_t *); 219843e1988Sjohnlev 220a576ab5bSrab /* 221a576ab5bSrab * Jump through the hoops we need to to correctly identify a core file 222a576ab5bSrab * of either the old or new format. 223a576ab5bSrab */ 224843e1988Sjohnlev int 225843e1988Sjohnlev xkb_identify(const char *file, int *longmode) 226843e1988Sjohnlev { 227843e1988Sjohnlev xc_core_header_t header; 228a576ab5bSrab mdb_gelf_file_t *gf = NULL; 229a576ab5bSrab mdb_gelf_sect_t *sect = NULL; 230a576ab5bSrab mdb_io_t *io = NULL; 231a576ab5bSrab char *notes = NULL; 232a576ab5bSrab char *pos; 233a576ab5bSrab int ret = 0; 234843e1988Sjohnlev size_t sz; 235843e1988Sjohnlev int fd; 236843e1988Sjohnlev 237843e1988Sjohnlev if ((fd = open64(file, O_RDONLY)) == -1) 238843e1988Sjohnlev return (-1); 239843e1988Sjohnlev 240843e1988Sjohnlev if (pread64(fd, &header, sizeof (header), 0) != sizeof (header)) { 241843e1988Sjohnlev (void) close(fd); 242843e1988Sjohnlev return (0); 243843e1988Sjohnlev } 244843e1988Sjohnlev 245843e1988Sjohnlev (void) close(fd); 246843e1988Sjohnlev 247a576ab5bSrab if (header.xch_magic == XC_CORE_MAGIC) { 248a576ab5bSrab *longmode = 0; 249843e1988Sjohnlev 250a576ab5bSrab /* 251a576ab5bSrab * Indeed. 252a576ab5bSrab */ 253a576ab5bSrab sz = header.xch_index_offset - header.xch_ctxt_offset; 254843e1988Sjohnlev #ifdef _LP64 255a576ab5bSrab if (sizeof (struct vcpu_guest_context) * 256a576ab5bSrab header.xch_nr_vcpus == sz) 257a576ab5bSrab *longmode = 1; 258843e1988Sjohnlev #else 259a576ab5bSrab if (sizeof (struct vcpu_guest_context) * 260a576ab5bSrab header.xch_nr_vcpus != sz) 261a576ab5bSrab *longmode = 1; 262843e1988Sjohnlev #endif /* _LP64 */ 263843e1988Sjohnlev 264a576ab5bSrab return (1); 265a576ab5bSrab } 266a576ab5bSrab 267a576ab5bSrab if ((io = mdb_fdio_create_path(NULL, file, O_RDONLY, 0)) == NULL) 268a576ab5bSrab return (-1); 269a576ab5bSrab 270a576ab5bSrab if ((gf = mdb_gelf_create(io, ET_NONE, GF_FILE)) == NULL) 271a576ab5bSrab goto out; 272a576ab5bSrab 273a576ab5bSrab if ((sect = mdb_gelf_sect_by_name(gf, ".note.Xen")) == NULL) 274a576ab5bSrab goto out; 275a576ab5bSrab 276a576ab5bSrab if ((notes = mdb_gelf_sect_load(gf, sect)) == NULL) 277a576ab5bSrab goto out; 278a576ab5bSrab 279a576ab5bSrab for (pos = notes; pos < notes + sect->gs_shdr.sh_size; ) { 280a576ab5bSrab struct xc_elf_version *vers; 281a576ab5bSrab /* LINTED - alignment */ 282a576ab5bSrab Elf64_Nhdr *nhdr = (Elf64_Nhdr *)pos; 283a576ab5bSrab char *desc; 284a576ab5bSrab char *name; 285a576ab5bSrab 286a576ab5bSrab name = pos + sizeof (*nhdr); 287a576ab5bSrab desc = (char *)P2ROUNDUP((uintptr_t)name + nhdr->n_namesz, 4); 288a576ab5bSrab 289a576ab5bSrab pos = desc + nhdr->n_descsz; 290a576ab5bSrab 291a576ab5bSrab if (nhdr->n_type != XEN_ELFNOTE_DUMPCORE_XEN_VERSION) 292a576ab5bSrab continue; 293a576ab5bSrab 294a576ab5bSrab /* 295a576ab5bSrab * The contents of this struct differ between 32 and 64 296a576ab5bSrab * bit; however, not until past the 'xev_capabilities' 297a576ab5bSrab * member, so we can just about get away with this. 298a576ab5bSrab */ 299a576ab5bSrab 300a576ab5bSrab /* LINTED - alignment */ 301a576ab5bSrab vers = (struct xc_elf_version *)desc; 302a576ab5bSrab 303a576ab5bSrab if (strstr(vers->xev_capabilities, "x86_64")) { 304*349b53ddSStuart Maybee /* 305*349b53ddSStuart Maybee * 64-bit hypervisor, but it can still be 306*349b53ddSStuart Maybee * a 32-bit domain core. 32-bit domain cores 307*349b53ddSStuart Maybee * are also dumped in Elf64 format, but they 308*349b53ddSStuart Maybee * have e_machine set to EM_386, not EM_AMD64. 309*349b53ddSStuart Maybee */ 310*349b53ddSStuart Maybee if (gf->gf_ehdr.e_machine == EM_386) 311*349b53ddSStuart Maybee *longmode = 0; 312*349b53ddSStuart Maybee else 313*349b53ddSStuart Maybee *longmode = 1; 314a576ab5bSrab } else if (strstr(vers->xev_capabilities, "x86_32") || 315a576ab5bSrab strstr(vers->xev_capabilities, "x86_32p")) { 316*349b53ddSStuart Maybee /* 317*349b53ddSStuart Maybee * 32-bit hypervisor, can only be a 32-bit core. 318*349b53ddSStuart Maybee */ 319a576ab5bSrab *longmode = 0; 320a576ab5bSrab } else { 321a576ab5bSrab mdb_warn("couldn't derive word size of dump; " 322a576ab5bSrab "assuming 64-bit"); 323a576ab5bSrab *longmode = 1; 324a576ab5bSrab } 325a576ab5bSrab } 326a576ab5bSrab 327a576ab5bSrab ret = 1; 328a576ab5bSrab 329a576ab5bSrab out: 330a576ab5bSrab if (gf != NULL) 331a576ab5bSrab mdb_gelf_destroy(gf); 332a576ab5bSrab else if (io != NULL) 333a576ab5bSrab mdb_io_destroy(io); 334a576ab5bSrab return (ret); 335843e1988Sjohnlev } 336843e1988Sjohnlev 337843e1988Sjohnlev static void * 338843e1988Sjohnlev xkb_fail(xkb_t *xkb, const char *msg, ...) 339843e1988Sjohnlev { 340843e1988Sjohnlev va_list args; 341843e1988Sjohnlev 342843e1988Sjohnlev va_start(args, msg); 343843e1988Sjohnlev if (xkb != NULL) 344843e1988Sjohnlev (void) fprintf(stderr, "%s: ", xkb->xkb_path); 345843e1988Sjohnlev (void) vfprintf(stderr, msg, args); 346843e1988Sjohnlev (void) fprintf(stderr, "\n"); 347843e1988Sjohnlev va_end(args); 348843e1988Sjohnlev if (xkb != NULL) 349843e1988Sjohnlev (void) xkb_close(xkb); 350a576ab5bSrab 351a576ab5bSrab errno = ENOEXEC; 352a576ab5bSrab 353843e1988Sjohnlev return (NULL); 354843e1988Sjohnlev } 355843e1988Sjohnlev 356843e1988Sjohnlev static int 357843e1988Sjohnlev xkb_build_m2p(xkb_t *xkb) 358843e1988Sjohnlev { 359843e1988Sjohnlev size_t i; 360843e1988Sjohnlev 361a576ab5bSrab for (i = 0; i <= xkb->xkb_max_pfn; i++) { 362843e1988Sjohnlev if (xkb->xkb_p2m[i] != MFN_INVALID && 363843e1988Sjohnlev xkb->xkb_p2m[i] > xkb->xkb_max_mfn) 364843e1988Sjohnlev xkb->xkb_max_mfn = xkb->xkb_p2m[i]; 365843e1988Sjohnlev } 366843e1988Sjohnlev 367843e1988Sjohnlev xkb->xkb_m2p = mdb_alloc((xkb->xkb_max_mfn + 1) * sizeof (xen_pfn_t), 368843e1988Sjohnlev UM_SLEEP); 369843e1988Sjohnlev 370843e1988Sjohnlev for (i = 0; i <= xkb->xkb_max_mfn; i++) 371843e1988Sjohnlev xkb->xkb_m2p[i] = PFN_INVALID; 372843e1988Sjohnlev 373a576ab5bSrab for (i = 0; i <= xkb->xkb_max_pfn; i++) { 374843e1988Sjohnlev if (xkb->xkb_p2m[i] != MFN_INVALID) 375843e1988Sjohnlev xkb->xkb_m2p[xkb->xkb_p2m[i]] = i; 376843e1988Sjohnlev } 377843e1988Sjohnlev 378843e1988Sjohnlev return (1); 379843e1988Sjohnlev } 380843e1988Sjohnlev 381843e1988Sjohnlev /* 382a576ab5bSrab * With FORMAT_CORE, we can use the table in the dump file directly. 383a576ab5bSrab * Just to make things fun, they've not page-aligned the p2m table. 384843e1988Sjohnlev */ 385843e1988Sjohnlev static int 386843e1988Sjohnlev xkb_map_p2m(xkb_t *xkb) 387843e1988Sjohnlev { 388843e1988Sjohnlev offset_t off; 389843e1988Sjohnlev size_t size; 390a576ab5bSrab xkb_core_t *xc = &xkb->xkb_core; 391a576ab5bSrab size_t count = xkb->xkb_nr_pages; 392a576ab5bSrab size_t boff = xc->xc_hdr.xch_index_offset; 393843e1988Sjohnlev 394a576ab5bSrab size = (sizeof (mfn_t) * count) + (PAGE_SIZE * 2); 395843e1988Sjohnlev size = PAGE_MASK(size); 396843e1988Sjohnlev off = PAGE_MASK(boff); 397843e1988Sjohnlev 398843e1988Sjohnlev /* LINTED - alignment */ 399a576ab5bSrab xc->xc_p2m_buf = (mfn_t *)mmap(NULL, size, PROT_READ, 400843e1988Sjohnlev MAP_SHARED, xkb->xkb_fd, off); 401843e1988Sjohnlev 402a576ab5bSrab if (xc->xc_p2m_buf == (xen_pfn_t *)MAP_FAILED) { 403843e1988Sjohnlev (void) xkb_fail(xkb, "cannot map p2m table"); 404843e1988Sjohnlev return (0); 405843e1988Sjohnlev } 406843e1988Sjohnlev 407843e1988Sjohnlev /* LINTED - alignment */ 408a576ab5bSrab xkb->xkb_p2m = (mfn_t *)((char *)xc->xc_p2m_buf + 409843e1988Sjohnlev PAGE_OFFSET(boff)); 410843e1988Sjohnlev 411843e1988Sjohnlev return (1); 412843e1988Sjohnlev } 413843e1988Sjohnlev 414a576ab5bSrab /* 415a576ab5bSrab * With FORMAT_ELF, we have a set of <pfn,mfn> pairs, which we convert 416a576ab5bSrab * into a linear array indexed by pfn for convenience. We also need to 417a576ab5bSrab * track the mapping between mfn and the offset in the file: a pfn with 418a576ab5bSrab * no mfn will not appear in the core file. 419a576ab5bSrab */ 420a576ab5bSrab static int 421a576ab5bSrab xkb_build_p2m(xkb_t *xkb) 422a576ab5bSrab { 423a576ab5bSrab xkb_elf_t *xe = &xkb->xkb_elf; 424a576ab5bSrab mdb_gelf_sect_t *sect; 425a576ab5bSrab size_t size; 426a576ab5bSrab size_t i; 427a576ab5bSrab 428a576ab5bSrab struct elf_p2m { 429a576ab5bSrab uint64_t pfn; 430a576ab5bSrab uint64_t gmfn; 431a576ab5bSrab } *p2m; 432a576ab5bSrab 433a576ab5bSrab sect = mdb_gelf_sect_by_name(xe->xe_gelf, ".xen_p2m"); 434a576ab5bSrab 435a576ab5bSrab if (sect == NULL) { 436a576ab5bSrab (void) xkb_fail(xkb, "cannot find section .xen_p2m"); 437a576ab5bSrab return (0); 438a576ab5bSrab } 439a576ab5bSrab 440a576ab5bSrab if ((p2m = mdb_gelf_sect_load(xe->xe_gelf, sect)) == NULL) { 441a576ab5bSrab (void) xkb_fail(xkb, "couldn't read .xen_p2m"); 442a576ab5bSrab return (0); 443a576ab5bSrab } 444a576ab5bSrab 445a576ab5bSrab for (i = 0; i < xkb->xkb_nr_pages; i++) { 446a576ab5bSrab if (p2m[i].pfn > xkb->xkb_max_pfn) 447a576ab5bSrab xkb->xkb_max_pfn = p2m[i].pfn; 448a576ab5bSrab } 449a576ab5bSrab 450a576ab5bSrab size = sizeof (xen_pfn_t) * (xkb->xkb_max_pfn + 1); 451a576ab5bSrab xkb->xkb_p2m = mdb_alloc(size, UM_SLEEP); 452a576ab5bSrab size = sizeof (size_t) * (xkb->xkb_max_pfn + 1); 453a576ab5bSrab xe->xe_off = mdb_alloc(size, UM_SLEEP); 454a576ab5bSrab 455a576ab5bSrab for (i = 0; i <= xkb->xkb_max_pfn; i++) { 456a576ab5bSrab xkb->xkb_p2m[i] = PFN_INVALID; 457a576ab5bSrab xe->xe_off[i] = (size_t)-1; 458a576ab5bSrab } 459a576ab5bSrab 460a576ab5bSrab for (i = 0; i < xkb->xkb_nr_pages; i++) { 461a576ab5bSrab xkb->xkb_p2m[p2m[i].pfn] = p2m[i].gmfn; 462a576ab5bSrab xe->xe_off[p2m[i].pfn] = i; 463a576ab5bSrab } 464a576ab5bSrab 465a576ab5bSrab return (1); 466a576ab5bSrab } 467a576ab5bSrab 4685d2eda97SJohn Levon /* 4695d2eda97SJohn Levon * For HVM images, we don't have the corresponding MFN list; the table 4705d2eda97SJohn Levon * is just a mapping from page index in the dump to the corresponding 4715d2eda97SJohn Levon * PFN. To simplify the other code, we'll pretend that these PFNs are 4725d2eda97SJohn Levon * really MFNs as well, by populating xkb_p2m. 4735d2eda97SJohn Levon */ 4745d2eda97SJohn Levon static int 4755d2eda97SJohn Levon xkb_build_fake_p2m(xkb_t *xkb) 4765d2eda97SJohn Levon { 4775d2eda97SJohn Levon xkb_elf_t *xe = &xkb->xkb_elf; 4785d2eda97SJohn Levon mdb_gelf_sect_t *sect; 4795d2eda97SJohn Levon size_t size; 4805d2eda97SJohn Levon size_t i; 4815d2eda97SJohn Levon 4825d2eda97SJohn Levon uint64_t *p2pfn; 4835d2eda97SJohn Levon 4845d2eda97SJohn Levon sect = mdb_gelf_sect_by_name(xe->xe_gelf, ".xen_pfn"); 4855d2eda97SJohn Levon 4865d2eda97SJohn Levon if (sect == NULL) { 4875d2eda97SJohn Levon (void) xkb_fail(xkb, "cannot find section .xen_pfn"); 4885d2eda97SJohn Levon return (0); 4895d2eda97SJohn Levon } 4905d2eda97SJohn Levon 4915d2eda97SJohn Levon if ((p2pfn = mdb_gelf_sect_load(xe->xe_gelf, sect)) == NULL) { 4925d2eda97SJohn Levon (void) xkb_fail(xkb, "couldn't read .xen_pfn"); 4935d2eda97SJohn Levon return (0); 4945d2eda97SJohn Levon } 4955d2eda97SJohn Levon 4965d2eda97SJohn Levon for (i = 0; i < xkb->xkb_nr_pages; i++) { 497*349b53ddSStuart Maybee if (p2pfn[i] != PFN_INVALID && p2pfn[i] > xkb->xkb_max_pfn) 4985d2eda97SJohn Levon xkb->xkb_max_pfn = p2pfn[i]; 4995d2eda97SJohn Levon } 5005d2eda97SJohn Levon 5015d2eda97SJohn Levon size = sizeof (xen_pfn_t) * (xkb->xkb_max_pfn + 1); 5025d2eda97SJohn Levon xkb->xkb_p2m = mdb_alloc(size, UM_SLEEP); 503*349b53ddSStuart Maybee 5045d2eda97SJohn Levon size = sizeof (size_t) * (xkb->xkb_max_pfn + 1); 5055d2eda97SJohn Levon xe->xe_off = mdb_alloc(size, UM_SLEEP); 5065d2eda97SJohn Levon 5075d2eda97SJohn Levon for (i = 0; i <= xkb->xkb_max_pfn; i++) { 5085d2eda97SJohn Levon xkb->xkb_p2m[i] = PFN_INVALID; 5095d2eda97SJohn Levon xe->xe_off[i] = (size_t)-1; 5105d2eda97SJohn Levon } 5115d2eda97SJohn Levon 5125d2eda97SJohn Levon for (i = 0; i < xkb->xkb_nr_pages; i++) { 513*349b53ddSStuart Maybee if (p2pfn[i] == PFN_INVALID) 514*349b53ddSStuart Maybee continue; 5155d2eda97SJohn Levon xkb->xkb_p2m[p2pfn[i]] = p2pfn[i]; 5165d2eda97SJohn Levon xe->xe_off[p2pfn[i]] = i; 5175d2eda97SJohn Levon } 5185d2eda97SJohn Levon 5195d2eda97SJohn Levon return (1); 5205d2eda97SJohn Levon } 5215d2eda97SJohn Levon 522843e1988Sjohnlev /* 523843e1988Sjohnlev * Return the MFN of the top-level page table for the given as. 524843e1988Sjohnlev */ 525843e1988Sjohnlev static mfn_t 526843e1988Sjohnlev xkb_as_to_mfn(xkb_t *xkb, struct as *as) 527843e1988Sjohnlev { 528843e1988Sjohnlev uintptr_t asp = (uintptr_t)as; 529843e1988Sjohnlev uintptr_t hatp; 530843e1988Sjohnlev uintptr_t htablep; 531843e1988Sjohnlev uintptr_t pfn; 532843e1988Sjohnlev 533843e1988Sjohnlev if (!xkb_read_word(xkb, asp + offsetof(struct as, a_hat), &hatp)) 534843e1988Sjohnlev return (MFN_INVALID); 535843e1988Sjohnlev if (!xkb_read_word(xkb, hatp + xkb->xkb_info.di_hat_htable_off, 536843e1988Sjohnlev &htablep)) 537843e1988Sjohnlev return (MFN_INVALID); 538843e1988Sjohnlev if (!xkb_read_word(xkb, htablep + xkb->xkb_info.di_ht_pfn_off, 539843e1988Sjohnlev &pfn)) 540843e1988Sjohnlev return (MFN_INVALID); 541843e1988Sjohnlev 542a576ab5bSrab if (pfn > xkb->xkb_max_pfn) 543843e1988Sjohnlev return (MFN_INVALID); 544843e1988Sjohnlev 545843e1988Sjohnlev return (xkb->xkb_p2m[pfn]); 546843e1988Sjohnlev } 547843e1988Sjohnlev 5485d2eda97SJohn Levon static mfn_t 5495d2eda97SJohn Levon xkb_cr3_to_pfn(xkb_t *xkb) 5505d2eda97SJohn Levon { 551*349b53ddSStuart Maybee uint64_t cr3 = xkb->xkb_vcpus[0]->ctrlreg[3]; 5525d2eda97SJohn Levon if (xkb->xkb_is_hvm) 5535d2eda97SJohn Levon return (cr3 >> PAGE_SHIFT); 5545d2eda97SJohn Levon return (xen_cr3_to_pfn(cr3)); 5555d2eda97SJohn Levon } 5565d2eda97SJohn Levon 557843e1988Sjohnlev static ssize_t 558843e1988Sjohnlev xkb_read_helper(xkb_t *xkb, struct as *as, int phys, uint64_t addr, 559843e1988Sjohnlev void *buf, size_t size) 560843e1988Sjohnlev { 561843e1988Sjohnlev size_t left = size; 562a576ab5bSrab int windowed = (xkb->xkb_pages == NULL); 5635d2eda97SJohn Levon mfn_t tlmfn = xkb_cr3_to_pfn(xkb); 564843e1988Sjohnlev 565843e1988Sjohnlev if (as != NULL && (tlmfn = xkb_as_to_mfn(xkb, as)) == MFN_INVALID) 566843e1988Sjohnlev return (-1); 567843e1988Sjohnlev 568843e1988Sjohnlev while (left) { 569843e1988Sjohnlev uint64_t pos = addr + (size - left); 570843e1988Sjohnlev char *outpos = (char *)buf + (size - left); 571843e1988Sjohnlev size_t pageoff = PAGE_OFFSET(pos); 572843e1988Sjohnlev size_t sz = MIN(left, PAGE_SIZE - pageoff); 573843e1988Sjohnlev mfn_t mfn; 574843e1988Sjohnlev 575843e1988Sjohnlev if (!phys) { 576843e1988Sjohnlev mfn = xkb_va_to_mfn(xkb, pos, tlmfn); 577843e1988Sjohnlev if (mfn == MFN_INVALID) 578843e1988Sjohnlev return (-1); 579843e1988Sjohnlev } else { 580843e1988Sjohnlev xen_pfn_t pfn = pos >> PAGE_SHIFT; 581a576ab5bSrab if (pfn > xkb->xkb_max_pfn) 582843e1988Sjohnlev return (-1); 583843e1988Sjohnlev mfn = xkb->xkb_p2m[pfn]; 584843e1988Sjohnlev if (mfn == MFN_INVALID) 585843e1988Sjohnlev return (-1); 586843e1988Sjohnlev } 587843e1988Sjohnlev 588843e1988Sjohnlev /* 589843e1988Sjohnlev * If we're windowed then pread() is much faster. 590843e1988Sjohnlev */ 591843e1988Sjohnlev if (windowed) { 592843e1988Sjohnlev offset_t off = xkb_mfn_to_offset(xkb, mfn); 593843e1988Sjohnlev int ret; 594843e1988Sjohnlev 595843e1988Sjohnlev if (off == ~1ULL) 596843e1988Sjohnlev return (-1); 597843e1988Sjohnlev 598843e1988Sjohnlev off += pageoff; 599843e1988Sjohnlev 600843e1988Sjohnlev ret = pread64(xkb->xkb_fd, outpos, sz, off); 601843e1988Sjohnlev if (ret == -1) 602843e1988Sjohnlev return (-1); 603843e1988Sjohnlev if (ret != sz) 604843e1988Sjohnlev return ((size - left) + ret); 605843e1988Sjohnlev 606843e1988Sjohnlev left -= ret; 607843e1988Sjohnlev } else { 608843e1988Sjohnlev if (xkb_map_mfn(xkb, mfn, &xkb->xkb_map) == NULL) 609843e1988Sjohnlev return (-1); 610843e1988Sjohnlev 611843e1988Sjohnlev bcopy(xkb->xkb_map.mm_map + pageoff, outpos, sz); 612843e1988Sjohnlev 613843e1988Sjohnlev left -= sz; 614843e1988Sjohnlev } 615843e1988Sjohnlev } 616843e1988Sjohnlev 617843e1988Sjohnlev return (size); 618843e1988Sjohnlev } 619843e1988Sjohnlev 620843e1988Sjohnlev static ssize_t 621843e1988Sjohnlev xkb_pread(xkb_t *xkb, uint64_t addr, void *buf, size_t size) 622843e1988Sjohnlev { 623843e1988Sjohnlev return (xkb_read_helper(xkb, NULL, 1, addr, buf, size)); 624843e1988Sjohnlev } 625843e1988Sjohnlev 626843e1988Sjohnlev static ssize_t 627843e1988Sjohnlev xkb_aread(xkb_t *xkb, uintptr_t addr, void *buf, size_t size, struct as *as) 628843e1988Sjohnlev { 629843e1988Sjohnlev return (xkb_read_helper(xkb, as, 0, addr, buf, size)); 630843e1988Sjohnlev } 631843e1988Sjohnlev 632843e1988Sjohnlev static ssize_t 633843e1988Sjohnlev xkb_read(xkb_t *xkb, uintptr_t addr, void *buf, size_t size) 634843e1988Sjohnlev { 635843e1988Sjohnlev return (xkb_aread(xkb, addr, buf, size, NULL)); 636843e1988Sjohnlev } 637843e1988Sjohnlev 638843e1988Sjohnlev static int 639843e1988Sjohnlev xkb_read_word(xkb_t *xkb, uintptr_t addr, uintptr_t *buf) 640843e1988Sjohnlev { 641843e1988Sjohnlev if (xkb_read(xkb, addr, buf, sizeof (uintptr_t)) != 642843e1988Sjohnlev sizeof (uintptr_t)) 643843e1988Sjohnlev return (0); 644843e1988Sjohnlev return (1); 645843e1988Sjohnlev } 646843e1988Sjohnlev 647843e1988Sjohnlev static char * 648843e1988Sjohnlev xkb_readstr(xkb_t *xkb, uintptr_t addr) 649843e1988Sjohnlev { 650843e1988Sjohnlev char *str = mdb_alloc(1024, UM_SLEEP); 651843e1988Sjohnlev size_t i; 652843e1988Sjohnlev 653843e1988Sjohnlev for (i = 0; i < 1024; i++) { 654843e1988Sjohnlev if (xkb_read(xkb, addr + i, &str[i], 1) != 1) { 655843e1988Sjohnlev mdb_free(str, 1024); 656843e1988Sjohnlev return (NULL); 657843e1988Sjohnlev } 658843e1988Sjohnlev 659843e1988Sjohnlev if (str[i] == '\0') 660843e1988Sjohnlev break; 661843e1988Sjohnlev } 662843e1988Sjohnlev 663843e1988Sjohnlev if (i == 1024) { 664843e1988Sjohnlev mdb_free(str, 1024); 665843e1988Sjohnlev return (NULL); 666843e1988Sjohnlev } 667843e1988Sjohnlev 668843e1988Sjohnlev return (str); 669843e1988Sjohnlev } 670843e1988Sjohnlev 671a576ab5bSrab static offset_t 672a576ab5bSrab xkb_pfn_to_off(xkb_t *xkb, xen_pfn_t pfn) 673a576ab5bSrab { 674a576ab5bSrab if (pfn == PFN_INVALID || pfn > xkb->xkb_max_pfn) 675a576ab5bSrab return (-1ULL); 676a576ab5bSrab 677a576ab5bSrab if (xkb->xkb_type == XKB_FORMAT_CORE) 678a576ab5bSrab return (PAGE_SIZE * pfn); 679a576ab5bSrab 680a576ab5bSrab return (PAGE_SIZE * (xkb->xkb_elf.xe_off[pfn])); 681a576ab5bSrab } 682a576ab5bSrab 683843e1988Sjohnlev static offset_t 684843e1988Sjohnlev xkb_mfn_to_offset(xkb_t *xkb, mfn_t mfn) 685843e1988Sjohnlev { 686843e1988Sjohnlev xen_pfn_t pfn; 687843e1988Sjohnlev 688843e1988Sjohnlev if (mfn > xkb->xkb_max_mfn) 689843e1988Sjohnlev return (-1ULL); 690843e1988Sjohnlev 691843e1988Sjohnlev pfn = xkb->xkb_m2p[mfn]; 692843e1988Sjohnlev 693843e1988Sjohnlev if (pfn == PFN_INVALID) 694843e1988Sjohnlev return (-1ULL); 695843e1988Sjohnlev 696a576ab5bSrab return (xkb->xkb_pages_off + xkb_pfn_to_off(xkb, pfn)); 697843e1988Sjohnlev } 698843e1988Sjohnlev 699843e1988Sjohnlev static char * 700843e1988Sjohnlev xkb_map_mfn(xkb_t *xkb, mfn_t mfn, mfn_map_t *mm) 701843e1988Sjohnlev { 702a576ab5bSrab int windowed = (xkb->xkb_pages == NULL); 703843e1988Sjohnlev offset_t off; 704843e1988Sjohnlev 705843e1988Sjohnlev if (mm->mm_mfn == mfn) 706843e1988Sjohnlev return (mm->mm_map); 707843e1988Sjohnlev 708843e1988Sjohnlev mm->mm_mfn = mfn; 709843e1988Sjohnlev 710843e1988Sjohnlev if (windowed) { 711843e1988Sjohnlev if (mm->mm_map != (char *)MAP_FAILED) { 712843e1988Sjohnlev (void) munmap(mm->mm_map, PAGE_SIZE); 713843e1988Sjohnlev mm->mm_map = (void *)MAP_FAILED; 714843e1988Sjohnlev } 715843e1988Sjohnlev 716843e1988Sjohnlev if ((off = xkb_mfn_to_offset(xkb, mfn)) == (-1ULL)) 717843e1988Sjohnlev return (NULL); 718843e1988Sjohnlev 719843e1988Sjohnlev mm->mm_map = mmap(NULL, PAGE_SIZE, PROT_READ, MAP_SHARED, 720843e1988Sjohnlev xkb->xkb_fd, off); 721843e1988Sjohnlev 722843e1988Sjohnlev if (mm->mm_map == (char *)MAP_FAILED) 723843e1988Sjohnlev return (NULL); 724843e1988Sjohnlev } else { 725843e1988Sjohnlev xen_pfn_t pfn; 726843e1988Sjohnlev 727843e1988Sjohnlev mm->mm_map = NULL; 728843e1988Sjohnlev 729843e1988Sjohnlev if (mfn > xkb->xkb_max_mfn) 730843e1988Sjohnlev return (NULL); 731843e1988Sjohnlev 732843e1988Sjohnlev pfn = xkb->xkb_m2p[mfn]; 733843e1988Sjohnlev 734843e1988Sjohnlev if (pfn == PFN_INVALID) 735843e1988Sjohnlev return (NULL); 736843e1988Sjohnlev 737a576ab5bSrab mm->mm_map = xkb->xkb_pages + xkb_pfn_to_off(xkb, pfn); 738843e1988Sjohnlev } 739843e1988Sjohnlev 740843e1988Sjohnlev return (mm->mm_map); 741843e1988Sjohnlev } 742843e1988Sjohnlev 7435d2eda97SJohn Levon static uint64_t 7445d2eda97SJohn Levon xkb_get_pte(mmu_info_t *mmu, char *ptep) 745843e1988Sjohnlev { 746a576ab5bSrab uint64_t pte = 0; 747843e1988Sjohnlev 748a576ab5bSrab if (mmu->mi_ptesize == 8) { 749a576ab5bSrab /* LINTED - alignment */ 750a576ab5bSrab pte = *((uint64_t *)ptep); 751a576ab5bSrab } else { 752843e1988Sjohnlev /* LINTED - alignment */ 753843e1988Sjohnlev pte = *((uint32_t *)ptep); 754843e1988Sjohnlev } 755843e1988Sjohnlev 7565d2eda97SJohn Levon return (pte); 7575d2eda97SJohn Levon } 758843e1988Sjohnlev 7595d2eda97SJohn Levon static mfn_t 7605d2eda97SJohn Levon xkb_pte_to_base_mfn(uint64_t pte, size_t level) 7615d2eda97SJohn Levon { 7625d2eda97SJohn Levon if (PTE_IS_LGPG(pte, level)) { 7635d2eda97SJohn Levon pte &= PT_PADDR_LGPG; 7645d2eda97SJohn Levon } else { 7655d2eda97SJohn Levon pte &= PT_PADDR; 7665d2eda97SJohn Levon } 767843e1988Sjohnlev 768843e1988Sjohnlev return (pte >> PAGE_SHIFT); 769843e1988Sjohnlev } 770843e1988Sjohnlev 771843e1988Sjohnlev /* 772843e1988Sjohnlev * Resolve the given VA into an MFN, using the provided mfn as a top-level page 773843e1988Sjohnlev * table. 774843e1988Sjohnlev */ 775843e1988Sjohnlev static mfn_t 776843e1988Sjohnlev xkb_va_to_mfn(xkb_t *xkb, uintptr_t va, mfn_t mfn) 777843e1988Sjohnlev { 778843e1988Sjohnlev mmu_info_t *mmu = &xkb->xkb_mmu; 7795d2eda97SJohn Levon uint64_t pte; 780843e1988Sjohnlev size_t level; 781843e1988Sjohnlev 782843e1988Sjohnlev for (level = mmu->mi_max; ; --level) { 783843e1988Sjohnlev size_t entry; 784843e1988Sjohnlev 785843e1988Sjohnlev if (xkb_map_mfn(xkb, mfn, &xkb->xkb_pt_map[level]) == NULL) 786843e1988Sjohnlev return (MFN_INVALID); 787843e1988Sjohnlev 788843e1988Sjohnlev entry = (va >> mmu->mi_shift[level]) & (mmu->mi_ptes - 1); 789843e1988Sjohnlev 7905d2eda97SJohn Levon pte = xkb_get_pte(mmu, (char *)xkb->xkb_pt_map[level].mm_map + 7915d2eda97SJohn Levon entry * mmu->mi_ptesize); 792843e1988Sjohnlev 7935d2eda97SJohn Levon if ((mfn = xkb_pte_to_base_mfn(pte, level)) == MFN_INVALID) 794843e1988Sjohnlev return (MFN_INVALID); 795843e1988Sjohnlev 796843e1988Sjohnlev if (level == 0) 797843e1988Sjohnlev break; 7985d2eda97SJohn Levon 7995d2eda97SJohn Levon /* 8005d2eda97SJohn Levon * Currently 'mfn' refers to the base MFN of the 8015d2eda97SJohn Levon * large-page mapping. Add on the 4K-sized index into 8025d2eda97SJohn Levon * the large-page mapping to get the right MFN within 8035d2eda97SJohn Levon * the mapping. 8045d2eda97SJohn Levon */ 8055d2eda97SJohn Levon if (PTE_IS_LGPG(pte, level)) { 8065d2eda97SJohn Levon mfn += (va & ((1 << mmu->mi_shift[level]) - 1)) >> 8075d2eda97SJohn Levon PAGE_SHIFT; 8085d2eda97SJohn Levon break; 8095d2eda97SJohn Levon } 810843e1988Sjohnlev } 811843e1988Sjohnlev 812843e1988Sjohnlev return (mfn); 813843e1988Sjohnlev } 814843e1988Sjohnlev 815843e1988Sjohnlev static int 816843e1988Sjohnlev xkb_read_module(xkb_t *xkb, uintptr_t modulep, struct module *module, 817843e1988Sjohnlev uintptr_t *sym_addr, uintptr_t *sym_count, uintptr_t *str_addr) 818843e1988Sjohnlev { 819843e1988Sjohnlev if (xkb_read(xkb, modulep, module, sizeof (struct module)) != 820843e1988Sjohnlev sizeof (struct module)) 821843e1988Sjohnlev return (0); 822843e1988Sjohnlev 823843e1988Sjohnlev if (!xkb_read_word(xkb, (uintptr_t)module->symhdr + 824843e1988Sjohnlev offsetof(Shdr, sh_addr), sym_addr)) 825843e1988Sjohnlev return (0); 826843e1988Sjohnlev 827843e1988Sjohnlev if (!xkb_read_word(xkb, (uintptr_t)module->strhdr + 828843e1988Sjohnlev offsetof(Shdr, sh_addr), str_addr)) 829843e1988Sjohnlev return (0); 830843e1988Sjohnlev 831843e1988Sjohnlev if (!xkb_read_word(xkb, (uintptr_t)module->symhdr + 832843e1988Sjohnlev offsetof(Shdr, sh_size), sym_count)) 833843e1988Sjohnlev return (0); 834843e1988Sjohnlev *sym_count /= sizeof (Sym); 835843e1988Sjohnlev 836843e1988Sjohnlev return (1); 837843e1988Sjohnlev } 838843e1988Sjohnlev 839843e1988Sjohnlev static int 840843e1988Sjohnlev xkb_read_modsyms(xkb_t *xkb, char **buf, size_t *sizes, int types, 841843e1988Sjohnlev uintptr_t sym_addr, uintptr_t str_addr, uintptr_t sym_count) 842843e1988Sjohnlev { 843843e1988Sjohnlev size_t i; 844843e1988Sjohnlev 845843e1988Sjohnlev for (i = 0; i < sym_count; i++) { 846843e1988Sjohnlev Sym sym; 847843e1988Sjohnlev char *name; 848843e1988Sjohnlev size_t sz; 849843e1988Sjohnlev int type = XKB_WALK_GLOBAL; 850843e1988Sjohnlev 851843e1988Sjohnlev if (xkb_read(xkb, sym_addr + i * sizeof (sym), &sym, 852843e1988Sjohnlev sizeof (sym)) != sizeof (sym)) 853843e1988Sjohnlev return (0); 854843e1988Sjohnlev 855843e1988Sjohnlev if (GELF_ST_BIND(sym.st_info) == STB_LOCAL) 856843e1988Sjohnlev type = XKB_WALK_LOCAL; 857843e1988Sjohnlev 858843e1988Sjohnlev name = xkb_readstr(xkb, str_addr + sym.st_name); 859843e1988Sjohnlev 860843e1988Sjohnlev sym.st_shndx = SHN_ABS; 861843e1988Sjohnlev sym.st_name = sizes[XKB_WALK_STR]; 862843e1988Sjohnlev 863843e1988Sjohnlev sizes[type] += sizeof (sym); 864843e1988Sjohnlev sz = strlen(name) + 1; 865843e1988Sjohnlev sizes[XKB_WALK_STR] += sz; 866843e1988Sjohnlev 867843e1988Sjohnlev if (buf != NULL) { 868843e1988Sjohnlev if (types & type) { 869843e1988Sjohnlev bcopy(&sym, *buf, sizeof (sym)); 870843e1988Sjohnlev *buf += sizeof (sym); 871843e1988Sjohnlev } 872843e1988Sjohnlev if (types & XKB_WALK_STR) { 873843e1988Sjohnlev bcopy(name, *buf, sz); 874843e1988Sjohnlev *buf += sz; 875843e1988Sjohnlev } 876843e1988Sjohnlev } 877843e1988Sjohnlev 878843e1988Sjohnlev mdb_free(name, 1024); 879843e1988Sjohnlev } 880843e1988Sjohnlev 881843e1988Sjohnlev return (1); 882843e1988Sjohnlev } 883843e1988Sjohnlev 884843e1988Sjohnlev static int 885843e1988Sjohnlev xkb_walk_syms(xkb_t *xkb, uintptr_t modhead, char **buf, 886843e1988Sjohnlev size_t *sizes, int types) 887843e1988Sjohnlev { 888843e1988Sjohnlev uintptr_t modctl = modhead; 889843e1988Sjohnlev uintptr_t modulep; 890843e1988Sjohnlev struct module module; 891843e1988Sjohnlev uintptr_t sym_count; 892843e1988Sjohnlev uintptr_t sym_addr; 893843e1988Sjohnlev uintptr_t str_addr; 894843e1988Sjohnlev size_t max_iter = 500; 895843e1988Sjohnlev 896843e1988Sjohnlev bzero(sizes, sizeof (*sizes) * (XKB_WALK_STR + 1)); 897843e1988Sjohnlev 898843e1988Sjohnlev /* 899843e1988Sjohnlev * empty first symbol 900843e1988Sjohnlev */ 901843e1988Sjohnlev sizes[XKB_WALK_LOCAL] += sizeof (Sym); 902843e1988Sjohnlev sizes[XKB_WALK_STR] += 1; 903843e1988Sjohnlev 904843e1988Sjohnlev if (buf != NULL) { 905843e1988Sjohnlev if (types & XKB_WALK_LOCAL) { 906843e1988Sjohnlev Sym tmp; 907843e1988Sjohnlev bzero(&tmp, sizeof (tmp)); 908843e1988Sjohnlev bcopy(&tmp, *buf, sizeof (tmp)); 909843e1988Sjohnlev *buf += sizeof (tmp); 910843e1988Sjohnlev } 911843e1988Sjohnlev if (types & XKB_WALK_STR) { 912843e1988Sjohnlev **buf = '\0'; 913843e1988Sjohnlev (*buf)++; 914843e1988Sjohnlev } 915843e1988Sjohnlev } 916843e1988Sjohnlev 917843e1988Sjohnlev for (;;) { 918843e1988Sjohnlev if (!xkb_read_word(xkb, 919843e1988Sjohnlev modctl + offsetof(struct modctl, mod_mp), &modulep)) 920843e1988Sjohnlev return (0); 921843e1988Sjohnlev 922843e1988Sjohnlev if (modulep == NULL) 923843e1988Sjohnlev goto next; 924843e1988Sjohnlev 925843e1988Sjohnlev if (!xkb_read_module(xkb, modulep, &module, &sym_addr, 926843e1988Sjohnlev &sym_count, &str_addr)) 927843e1988Sjohnlev return (0); 928843e1988Sjohnlev 929843e1988Sjohnlev if ((module.flags & KOBJ_NOKSYMS)) 930843e1988Sjohnlev goto next; 931843e1988Sjohnlev 932843e1988Sjohnlev if (!xkb_read_modsyms(xkb, buf, sizes, types, sym_addr, 933843e1988Sjohnlev str_addr, sym_count)) 934843e1988Sjohnlev return (0); 935843e1988Sjohnlev 936843e1988Sjohnlev next: 937843e1988Sjohnlev if (!xkb_read_word(xkb, 938843e1988Sjohnlev modctl + offsetof(struct modctl, mod_next), &modctl)) 939843e1988Sjohnlev return (0); 940843e1988Sjohnlev 941843e1988Sjohnlev if (modctl == modhead) 942843e1988Sjohnlev break; 943843e1988Sjohnlev /* 944843e1988Sjohnlev * Try and prevent us looping forever if we have a broken list. 945843e1988Sjohnlev */ 946843e1988Sjohnlev if (--max_iter == 0) 947843e1988Sjohnlev break; 948843e1988Sjohnlev } 949843e1988Sjohnlev 950843e1988Sjohnlev return (1); 951843e1988Sjohnlev } 952843e1988Sjohnlev 953843e1988Sjohnlev /* 954843e1988Sjohnlev * Userspace equivalent of ksyms_snapshot(). Since we don't have a namelist 955843e1988Sjohnlev * file for hypervisor images, we fabricate one here using code similar 956843e1988Sjohnlev * to that of /dev/ksyms. 957843e1988Sjohnlev */ 958843e1988Sjohnlev static int 959843e1988Sjohnlev xkb_build_ksyms(xkb_t *xkb) 960843e1988Sjohnlev { 961843e1988Sjohnlev debug_info_t *info = &xkb->xkb_info; 962843e1988Sjohnlev size_t sizes[XKB_WALK_STR + 1]; 963843e1988Sjohnlev xkb_namelist_t *hdr; 964843e1988Sjohnlev char *buf; 965843e1988Sjohnlev struct modctl modules; 966843e1988Sjohnlev uintptr_t module; 967843e1988Sjohnlev Shdr *shp; 968843e1988Sjohnlev 969843e1988Sjohnlev if (xkb_read(xkb, info->di_modules, &modules, 970843e1988Sjohnlev sizeof (struct modctl)) != sizeof (struct modctl)) 971843e1988Sjohnlev return (0); 972843e1988Sjohnlev 973843e1988Sjohnlev module = (uintptr_t)modules.mod_mp; 974843e1988Sjohnlev 975843e1988Sjohnlev if (!xkb_walk_syms(xkb, info->di_modules, NULL, sizes, 976843e1988Sjohnlev XKB_WALK_LOCAL | XKB_WALK_GLOBAL | XKB_WALK_STR)) 977843e1988Sjohnlev return (0); 978843e1988Sjohnlev 979843e1988Sjohnlev xkb->xkb_namesize = sizeof (xkb_namelist_t); 980843e1988Sjohnlev xkb->xkb_namesize += sizes[XKB_WALK_LOCAL]; 981843e1988Sjohnlev xkb->xkb_namesize += sizes[XKB_WALK_GLOBAL]; 982843e1988Sjohnlev xkb->xkb_namesize += sizes[XKB_WALK_STR]; 983843e1988Sjohnlev 984843e1988Sjohnlev if ((xkb->xkb_namelist = mdb_zalloc(xkb->xkb_namesize, UM_SLEEP)) 985843e1988Sjohnlev == NULL) 986843e1988Sjohnlev return (0); 987843e1988Sjohnlev 988843e1988Sjohnlev /* LINTED - alignment */ 989843e1988Sjohnlev hdr = (xkb_namelist_t *)xkb->xkb_namelist; 990843e1988Sjohnlev 991843e1988Sjohnlev if (xkb_read(xkb, module + offsetof(struct module, hdr), 992843e1988Sjohnlev &hdr->kh_elf_hdr, sizeof (Ehdr)) != sizeof (Ehdr)) 993843e1988Sjohnlev return (0); 994843e1988Sjohnlev 995843e1988Sjohnlev hdr->kh_elf_hdr.e_phoff = offsetof(xkb_namelist_t, kh_text_phdr); 996843e1988Sjohnlev hdr->kh_elf_hdr.e_shoff = offsetof(xkb_namelist_t, kh_shdr); 997843e1988Sjohnlev hdr->kh_elf_hdr.e_phnum = 2; 998843e1988Sjohnlev hdr->kh_elf_hdr.e_shnum = XKB_SHDR_NUM; 999843e1988Sjohnlev hdr->kh_elf_hdr.e_shstrndx = XKB_SHDR_SHSTRTAB; 1000843e1988Sjohnlev 1001843e1988Sjohnlev hdr->kh_text_phdr.p_type = PT_LOAD; 1002843e1988Sjohnlev hdr->kh_text_phdr.p_vaddr = (Addr)info->di_s_text; 1003843e1988Sjohnlev hdr->kh_text_phdr.p_memsz = (Word)(info->di_e_text - info->di_s_text); 1004843e1988Sjohnlev hdr->kh_text_phdr.p_flags = PF_R | PF_X; 1005843e1988Sjohnlev 1006843e1988Sjohnlev hdr->kh_data_phdr.p_type = PT_LOAD; 1007843e1988Sjohnlev hdr->kh_data_phdr.p_vaddr = (Addr)info->di_s_data; 1008843e1988Sjohnlev hdr->kh_data_phdr.p_memsz = (Word)(info->di_e_data - info->di_s_data); 1009843e1988Sjohnlev hdr->kh_data_phdr.p_flags = PF_R | PF_W | PF_X; 1010843e1988Sjohnlev 1011843e1988Sjohnlev shp = &hdr->kh_shdr[XKB_SHDR_SYMTAB]; 1012843e1988Sjohnlev shp->sh_name = 1; /* xkb_shstrtab[1] = ".symtab" */ 1013843e1988Sjohnlev shp->sh_type = SHT_SYMTAB; 1014843e1988Sjohnlev shp->sh_offset = sizeof (xkb_namelist_t); 1015843e1988Sjohnlev shp->sh_size = sizes[XKB_WALK_LOCAL] + sizes[XKB_WALK_GLOBAL]; 1016843e1988Sjohnlev shp->sh_link = XKB_SHDR_STRTAB; 1017843e1988Sjohnlev shp->sh_info = sizes[XKB_WALK_LOCAL] / sizeof (Sym); 1018843e1988Sjohnlev shp->sh_addralign = sizeof (Addr); 1019843e1988Sjohnlev shp->sh_entsize = sizeof (Sym); 1020843e1988Sjohnlev shp->sh_addr = (Addr)(xkb->xkb_namelist + shp->sh_offset); 1021843e1988Sjohnlev 1022843e1988Sjohnlev 1023843e1988Sjohnlev shp = &hdr->kh_shdr[XKB_SHDR_STRTAB]; 1024843e1988Sjohnlev shp->sh_name = 9; /* xkb_shstrtab[9] = ".strtab" */ 1025843e1988Sjohnlev shp->sh_type = SHT_STRTAB; 1026843e1988Sjohnlev shp->sh_offset = sizeof (xkb_namelist_t) + 1027843e1988Sjohnlev sizes[XKB_WALK_LOCAL] + sizes[XKB_WALK_GLOBAL]; 1028843e1988Sjohnlev shp->sh_size = sizes[XKB_WALK_STR]; 1029843e1988Sjohnlev shp->sh_addralign = 1; 1030843e1988Sjohnlev shp->sh_addr = (Addr)(xkb->xkb_namelist + shp->sh_offset); 1031843e1988Sjohnlev 1032843e1988Sjohnlev 1033843e1988Sjohnlev shp = &hdr->kh_shdr[XKB_SHDR_SHSTRTAB]; 1034843e1988Sjohnlev shp->sh_name = 17; /* xkb_shstrtab[17] = ".shstrtab" */ 1035843e1988Sjohnlev shp->sh_type = SHT_STRTAB; 1036843e1988Sjohnlev shp->sh_offset = offsetof(xkb_namelist_t, shstrings); 1037843e1988Sjohnlev shp->sh_size = sizeof (xkb_shstrtab); 1038843e1988Sjohnlev shp->sh_addralign = 1; 1039843e1988Sjohnlev shp->sh_addr = (Addr)(xkb->xkb_namelist + shp->sh_offset); 1040843e1988Sjohnlev 1041843e1988Sjohnlev bcopy(xkb_shstrtab, hdr->shstrings, sizeof (xkb_shstrtab)); 1042843e1988Sjohnlev 1043843e1988Sjohnlev buf = xkb->xkb_namelist + sizeof (xkb_namelist_t); 1044843e1988Sjohnlev 1045843e1988Sjohnlev if (!xkb_walk_syms(xkb, info->di_modules, &buf, sizes, 1046843e1988Sjohnlev XKB_WALK_LOCAL)) 1047843e1988Sjohnlev return (0); 1048843e1988Sjohnlev if (!xkb_walk_syms(xkb, info->di_modules, &buf, sizes, 1049843e1988Sjohnlev XKB_WALK_GLOBAL)) 1050843e1988Sjohnlev return (0); 1051843e1988Sjohnlev if (!xkb_walk_syms(xkb, info->di_modules, &buf, sizes, 1052843e1988Sjohnlev XKB_WALK_STR)) 1053843e1988Sjohnlev return (0); 1054843e1988Sjohnlev 1055843e1988Sjohnlev return (1); 1056843e1988Sjohnlev } 1057843e1988Sjohnlev 1058a576ab5bSrab static xkb_t * 1059a576ab5bSrab xkb_open_core(xkb_t *xkb) 1060843e1988Sjohnlev { 1061a576ab5bSrab xkb_core_t *xc = &xkb->xkb_core; 1062843e1988Sjohnlev size_t sz; 1063*349b53ddSStuart Maybee int i; 1064*349b53ddSStuart Maybee struct vcpu_guest_context *vcp; 1065843e1988Sjohnlev 1066a576ab5bSrab xkb->xkb_type = XKB_FORMAT_CORE; 1067843e1988Sjohnlev 1068a576ab5bSrab if ((xkb->xkb_fd = open64(xkb->xkb_path, O_RDONLY)) == -1) 1069a576ab5bSrab return (xkb_fail(xkb, "cannot open %s", xkb->xkb_path)); 1070843e1988Sjohnlev 1071a576ab5bSrab if (pread64(xkb->xkb_fd, &xc->xc_hdr, sizeof (xc->xc_hdr), 0) != 1072a576ab5bSrab sizeof (xc->xc_hdr)) 1073a576ab5bSrab return (xkb_fail(xkb, "invalid dump file")); 1074843e1988Sjohnlev 1075a576ab5bSrab if (xc->xc_hdr.xch_magic == XC_CORE_MAGIC_HVM) 1076a576ab5bSrab return (xkb_fail(xkb, "cannot process HVM images")); 1077843e1988Sjohnlev 1078a576ab5bSrab if (xc->xc_hdr.xch_magic != XC_CORE_MAGIC) { 1079a576ab5bSrab return (xkb_fail(xkb, "invalid magic %d", 1080a576ab5bSrab xc->xc_hdr.xch_magic)); 1081a576ab5bSrab } 1082843e1988Sjohnlev 1083a576ab5bSrab /* 1084a576ab5bSrab * With FORMAT_CORE, all pages are in the dump (non-existing 1085a576ab5bSrab * ones are zeroed out). 1086a576ab5bSrab */ 1087a576ab5bSrab xkb->xkb_nr_pages = xc->xc_hdr.xch_nr_pages; 1088a576ab5bSrab xkb->xkb_pages_off = xc->xc_hdr.xch_pages_offset; 1089a576ab5bSrab xkb->xkb_max_pfn = xc->xc_hdr.xch_nr_pages - 1; 1090a576ab5bSrab xkb->xkb_nr_vcpus = xc->xc_hdr.xch_nr_vcpus; 1091843e1988Sjohnlev 1092*349b53ddSStuart Maybee sz = xkb->xkb_nr_vcpus * sizeof (struct vcpu_guest_context); 1093*349b53ddSStuart Maybee xkb->xkb_vcpu_data_sz = sz; 1094*349b53ddSStuart Maybee xkb->xkb_vcpu_data = mdb_alloc(sz, UM_SLEEP); 1095843e1988Sjohnlev 1096*349b53ddSStuart Maybee if (pread64(xkb->xkb_fd, xkb->xkb_vcpu_data, sz, 1097a576ab5bSrab xc->xc_hdr.xch_ctxt_offset) != sz) 1098a576ab5bSrab return (xkb_fail(xkb, "cannot read VCPU contexts")); 1099843e1988Sjohnlev 1100*349b53ddSStuart Maybee sz = xkb->xkb_nr_vcpus * sizeof (struct vcpu_guest_context *); 1101*349b53ddSStuart Maybee xkb->xkb_vcpus = mdb_alloc(sz, UM_SLEEP); 1102*349b53ddSStuart Maybee 1103*349b53ddSStuart Maybee vcp = xkb->xkb_vcpu_data; 1104*349b53ddSStuart Maybee for (i = 0; i < xkb->xkb_nr_vcpus; i++) 1105*349b53ddSStuart Maybee xkb->xkb_vcpus[i] = &vcp[i]; 1106*349b53ddSStuart Maybee 1107a576ab5bSrab /* 1108a576ab5bSrab * Try to map all the data pages. If we can't, fall back to the 1109a576ab5bSrab * window/pread() approach, which is significantly slower. 1110a576ab5bSrab */ 1111a576ab5bSrab xkb->xkb_pages = mmap(NULL, PAGE_SIZE * xkb->xkb_nr_pages, 1112a576ab5bSrab PROT_READ, MAP_SHARED, xkb->xkb_fd, xc->xc_hdr.xch_pages_offset); 1113a576ab5bSrab 1114a576ab5bSrab if (xkb->xkb_pages == (char *)MAP_FAILED) 1115a576ab5bSrab xkb->xkb_pages = NULL; 1116a576ab5bSrab 1117a576ab5bSrab /* 1118a576ab5bSrab * We'd like to adapt for correctness' sake, but we have no way of 1119a576ab5bSrab * detecting a PAE guest, since cr4 writes are disallowed. 1120a576ab5bSrab */ 1121a576ab5bSrab xkb->xkb_is_pae = 1; 1122a576ab5bSrab 1123a576ab5bSrab if (!xkb_map_p2m(xkb)) 1124a576ab5bSrab return (NULL); 1125a576ab5bSrab 1126a576ab5bSrab return (xkb); 1127a576ab5bSrab } 1128a576ab5bSrab 1129a576ab5bSrab static xkb_t * 1130a576ab5bSrab xkb_open_elf(xkb_t *xkb) 1131a576ab5bSrab { 1132a576ab5bSrab xkb_elf_t *xe = &xkb->xkb_elf; 1133a576ab5bSrab mdb_gelf_sect_t *sect; 1134a576ab5bSrab char *notes; 1135a576ab5bSrab char *pos; 1136a576ab5bSrab mdb_io_t *io; 1137*349b53ddSStuart Maybee size_t sz; 1138*349b53ddSStuart Maybee int i; 1139*349b53ddSStuart Maybee void *dp; 1140a576ab5bSrab 1141a576ab5bSrab if ((io = mdb_fdio_create_path(NULL, xkb->xkb_path, 1142a576ab5bSrab O_RDONLY, 0)) == NULL) 1143a576ab5bSrab return (xkb_fail(xkb, "failed to open")); 1144a576ab5bSrab 1145a576ab5bSrab xe->xe_gelf = mdb_gelf_create(io, ET_NONE, GF_FILE); 1146a576ab5bSrab 1147a576ab5bSrab if (xe->xe_gelf == NULL) { 1148a576ab5bSrab mdb_io_destroy(io); 1149a576ab5bSrab return (xkb); 1150843e1988Sjohnlev } 1151843e1988Sjohnlev 1152a576ab5bSrab xkb->xkb_fd = mdb_fdio_fileno(io); 1153843e1988Sjohnlev 1154a576ab5bSrab sect = mdb_gelf_sect_by_name(xe->xe_gelf, ".note.Xen"); 1155843e1988Sjohnlev 1156a576ab5bSrab if (sect == NULL) 1157a576ab5bSrab return (xkb); 1158a576ab5bSrab 1159a576ab5bSrab if ((notes = mdb_gelf_sect_load(xe->xe_gelf, sect)) == NULL) 1160a576ab5bSrab return (xkb); 1161a576ab5bSrab 1162a576ab5bSrab /* 1163a576ab5bSrab * Now we know this is indeed a hypervisor core dump, even if 1164a576ab5bSrab * it's corrupted. 1165a576ab5bSrab */ 1166a576ab5bSrab xkb->xkb_type = XKB_FORMAT_ELF; 1167a576ab5bSrab 1168a576ab5bSrab for (pos = notes; pos < notes + sect->gs_shdr.sh_size; ) { 1169a576ab5bSrab /* LINTED - alignment */ 1170a576ab5bSrab Elf64_Nhdr *nhdr = (Elf64_Nhdr *)pos; 1171a576ab5bSrab uint64_t vers; 1172a576ab5bSrab char *desc; 1173a576ab5bSrab char *name; 1174a576ab5bSrab 1175a576ab5bSrab name = pos + sizeof (*nhdr); 1176a576ab5bSrab desc = (char *)P2ROUNDUP((uintptr_t)name + nhdr->n_namesz, 4); 1177a576ab5bSrab 1178a576ab5bSrab pos = desc + nhdr->n_descsz; 1179a576ab5bSrab 1180a576ab5bSrab switch (nhdr->n_type) { 1181a576ab5bSrab case XEN_ELFNOTE_DUMPCORE_NONE: 1182a576ab5bSrab break; 1183843e1988Sjohnlev 1184a576ab5bSrab case XEN_ELFNOTE_DUMPCORE_HEADER: 1185a576ab5bSrab if (nhdr->n_descsz != sizeof (struct xc_elf_header)) { 1186a576ab5bSrab return (xkb_fail(xkb, "invalid ELF note " 1187a576ab5bSrab "XEN_ELFNOTE_DUMPCORE_HEADER\n")); 1188a576ab5bSrab } 1189a576ab5bSrab 1190a576ab5bSrab bcopy(desc, &xe->xe_hdr, 1191a576ab5bSrab sizeof (struct xc_elf_header)); 1192a576ab5bSrab break; 1193a576ab5bSrab 1194a576ab5bSrab case XEN_ELFNOTE_DUMPCORE_XEN_VERSION: 1195*349b53ddSStuart Maybee if (nhdr->n_descsz < sizeof (struct xc_elf_version)) { 1196a576ab5bSrab return (xkb_fail(xkb, "invalid ELF note " 1197a576ab5bSrab "XEN_ELFNOTE_DUMPCORE_XEN_VERSION\n")); 1198a576ab5bSrab } 1199a576ab5bSrab 1200a576ab5bSrab bcopy(desc, &xe->xe_version, 1201a576ab5bSrab sizeof (struct xc_elf_version)); 1202a576ab5bSrab break; 1203a576ab5bSrab 1204a576ab5bSrab case XEN_ELFNOTE_DUMPCORE_FORMAT_VERSION: 1205a576ab5bSrab /* LINTED - alignment */ 1206a576ab5bSrab vers = *((uint64_t *)desc); 1207a576ab5bSrab if ((vers >> 32) != 0) { 1208a576ab5bSrab return (xkb_fail(xkb, "unknown major " 1209a576ab5bSrab "version %d (expected 0)\n", 1210a576ab5bSrab (int)(vers >> 32))); 1211a576ab5bSrab } 1212a576ab5bSrab 1213a576ab5bSrab if ((vers & 0xffffffff) != 1) { 1214a576ab5bSrab mdb_warn("unexpected dump minor number " 1215a576ab5bSrab "version %d (expected 1)\n", 1216a576ab5bSrab (int)(vers & 0xffffffff)); 1217a576ab5bSrab } 1218a576ab5bSrab break; 1219a576ab5bSrab 1220a576ab5bSrab default: 1221a576ab5bSrab mdb_warn("unknown ELF note %d(%s)\n", 1222a576ab5bSrab nhdr->n_type, name); 1223a576ab5bSrab break; 1224a576ab5bSrab } 1225a576ab5bSrab } 1226a576ab5bSrab 12275d2eda97SJohn Levon xkb->xkb_is_hvm = xe->xe_hdr.xeh_magic == XC_CORE_MAGIC_HVM; 1228843e1988Sjohnlev 12295d2eda97SJohn Levon if (xe->xe_hdr.xeh_magic != XC_CORE_MAGIC && 12305d2eda97SJohn Levon xe->xe_hdr.xeh_magic != XC_CORE_MAGIC_HVM) { 1231a576ab5bSrab return (xkb_fail(xkb, "invalid magic %d", 1232a576ab5bSrab xe->xe_hdr.xeh_magic)); 1233a576ab5bSrab } 1234a576ab5bSrab 1235a576ab5bSrab xkb->xkb_nr_pages = xe->xe_hdr.xeh_nr_pages; 1236a576ab5bSrab xkb->xkb_is_pae = (strstr(xe->xe_version.xev_capabilities, 1237a576ab5bSrab "x86_32p") != NULL); 1238a576ab5bSrab 1239a576ab5bSrab sect = mdb_gelf_sect_by_name(xe->xe_gelf, ".xen_prstatus"); 1240a576ab5bSrab 1241a576ab5bSrab if (sect == NULL) 1242a576ab5bSrab return (xkb_fail(xkb, "cannot find section .xen_prstatus")); 1243a576ab5bSrab 1244*349b53ddSStuart Maybee if (sect->gs_shdr.sh_entsize < sizeof (vcpu_guest_context_t)) 1245a576ab5bSrab return (xkb_fail(xkb, "invalid section .xen_prstatus")); 1246a576ab5bSrab 1247a576ab5bSrab xkb->xkb_nr_vcpus = sect->gs_shdr.sh_size / sect->gs_shdr.sh_entsize; 1248a576ab5bSrab 1249*349b53ddSStuart Maybee xkb->xkb_vcpu_data = mdb_gelf_sect_load(xe->xe_gelf, sect); 1250*349b53ddSStuart Maybee if (xkb->xkb_vcpu_data == NULL) 1251a576ab5bSrab return (xkb_fail(xkb, "cannot load section .xen_prstatus")); 1252*349b53ddSStuart Maybee xkb->xkb_vcpu_data_sz = sect->gs_shdr.sh_size; 1253*349b53ddSStuart Maybee 1254*349b53ddSStuart Maybee /* 1255*349b53ddSStuart Maybee * The vcpu_guest_context structures saved in the core file 1256*349b53ddSStuart Maybee * are actually unions of the 64-bit and 32-bit versions. 1257*349b53ddSStuart Maybee * Don't rely on the entry size to match the size of 1258*349b53ddSStuart Maybee * the structure, but set up an array of pointers. 1259*349b53ddSStuart Maybee */ 1260*349b53ddSStuart Maybee sz = xkb->xkb_nr_vcpus * sizeof (struct vcpu_guest_context *); 1261*349b53ddSStuart Maybee xkb->xkb_vcpus = mdb_alloc(sz, UM_SLEEP); 1262*349b53ddSStuart Maybee for (i = 0; i < xkb->xkb_nr_vcpus; i++) { 1263*349b53ddSStuart Maybee dp = ((char *)xkb->xkb_vcpu_data + 1264*349b53ddSStuart Maybee i * sect->gs_shdr.sh_entsize); 1265*349b53ddSStuart Maybee xkb->xkb_vcpus[i] = dp; 1266*349b53ddSStuart Maybee } 1267a576ab5bSrab 1268a576ab5bSrab sect = mdb_gelf_sect_by_name(xe->xe_gelf, ".xen_pages"); 1269a576ab5bSrab 1270a576ab5bSrab if (sect == NULL) 1271a576ab5bSrab return (xkb_fail(xkb, "cannot find section .xen_pages")); 1272a576ab5bSrab 1273a576ab5bSrab if (!PAGE_ALIGNED(sect->gs_shdr.sh_offset)) 1274a576ab5bSrab return (xkb_fail(xkb, ".xen_pages is not page aligned")); 1275a576ab5bSrab 1276a576ab5bSrab if (sect->gs_shdr.sh_entsize != PAGE_SIZE) 1277a576ab5bSrab return (xkb_fail(xkb, "invalid section .xen_pages")); 1278a576ab5bSrab 1279a576ab5bSrab xkb->xkb_pages_off = sect->gs_shdr.sh_offset; 1280a576ab5bSrab 1281843e1988Sjohnlev /* 1282843e1988Sjohnlev * Try to map all the data pages. If we can't, fall back to the 1283843e1988Sjohnlev * window/pread() approach, which is significantly slower. 1284843e1988Sjohnlev */ 1285a576ab5bSrab xkb->xkb_pages = mmap(NULL, PAGE_SIZE * xkb->xkb_nr_pages, 1286a576ab5bSrab PROT_READ, MAP_SHARED, xkb->xkb_fd, xkb->xkb_pages_off); 1287843e1988Sjohnlev 1288843e1988Sjohnlev if (xkb->xkb_pages == (char *)MAP_FAILED) 1289843e1988Sjohnlev xkb->xkb_pages = NULL; 1290843e1988Sjohnlev 12915d2eda97SJohn Levon if (xkb->xkb_is_hvm) { 12925d2eda97SJohn Levon if (!xkb_build_fake_p2m(xkb)) 12935d2eda97SJohn Levon return (NULL); 12945d2eda97SJohn Levon } else { 12955d2eda97SJohn Levon if (!xkb_build_p2m(xkb)) 12965d2eda97SJohn Levon return (NULL); 12975d2eda97SJohn Levon } 1298a576ab5bSrab 1299a576ab5bSrab return (xkb); 1300a576ab5bSrab } 1301a576ab5bSrab 1302a576ab5bSrab static void 1303a576ab5bSrab xkb_init_mmu(xkb_t *xkb) 1304a576ab5bSrab { 1305843e1988Sjohnlev #if defined(__amd64) 1306843e1988Sjohnlev xkb->xkb_mmu.mi_max = 3; 1307843e1988Sjohnlev xkb->xkb_mmu.mi_shift[0] = 12; 1308843e1988Sjohnlev xkb->xkb_mmu.mi_shift[1] = 21; 1309843e1988Sjohnlev xkb->xkb_mmu.mi_shift[2] = 30; 1310843e1988Sjohnlev xkb->xkb_mmu.mi_shift[3] = 39; 1311843e1988Sjohnlev xkb->xkb_mmu.mi_ptes = 512; 1312843e1988Sjohnlev xkb->xkb_mmu.mi_ptesize = 8; 1313843e1988Sjohnlev #elif defined(__i386) 1314a576ab5bSrab if (xkb->xkb_is_pae) { 1315a576ab5bSrab xkb->xkb_mmu.mi_max = 2; 1316a576ab5bSrab xkb->xkb_mmu.mi_shift[0] = 12; 1317a576ab5bSrab xkb->xkb_mmu.mi_shift[1] = 21; 1318a576ab5bSrab xkb->xkb_mmu.mi_shift[2] = 30; 1319a576ab5bSrab xkb->xkb_mmu.mi_ptes = 512; 1320a576ab5bSrab xkb->xkb_mmu.mi_ptesize = 8; 1321a576ab5bSrab } else { 1322a576ab5bSrab xkb->xkb_mmu.mi_max = 1; 1323a576ab5bSrab xkb->xkb_mmu.mi_shift[0] = 12; 1324a576ab5bSrab xkb->xkb_mmu.mi_shift[1] = 22; 1325a576ab5bSrab xkb->xkb_mmu.mi_ptes = 1024; 1326a576ab5bSrab xkb->xkb_mmu.mi_ptesize = 4; 1327a576ab5bSrab } 1328843e1988Sjohnlev #endif 1329a576ab5bSrab } 1330843e1988Sjohnlev 1331a576ab5bSrab /*ARGSUSED*/ 1332a576ab5bSrab xkb_t * 1333a576ab5bSrab xkb_open(const char *namelist, const char *corefile, const char *swapfile, 1334a576ab5bSrab int flag, const char *err) 1335a576ab5bSrab { 13365d2eda97SJohn Levon uintptr_t debug_info = DEBUG_INFO; 1337a576ab5bSrab struct stat64 corestat; 1338a576ab5bSrab xkb_t *xkb = NULL; 1339a576ab5bSrab size_t i; 1340a576ab5bSrab 1341a576ab5bSrab if (stat64(corefile, &corestat) == -1) 1342a576ab5bSrab return (xkb_fail(xkb, "cannot stat %s", corefile)); 1343a576ab5bSrab 1344a576ab5bSrab if (flag != O_RDONLY) 1345a576ab5bSrab return (xkb_fail(xkb, "invalid open flags")); 1346a576ab5bSrab 1347a576ab5bSrab xkb = mdb_zalloc(sizeof (*xkb), UM_SLEEP); 1348a576ab5bSrab 13495d2eda97SJohn Levon for (i = 0; i < 4; i++) { 13505d2eda97SJohn Levon xkb->xkb_pt_map[i].mm_mfn = MFN_INVALID; 1351a576ab5bSrab xkb->xkb_pt_map[i].mm_map = (char *)MAP_FAILED; 13525d2eda97SJohn Levon } 1353a576ab5bSrab 1354a576ab5bSrab xkb->xkb_type = XKB_FORMAT_UNKNOWN; 13555d2eda97SJohn Levon xkb->xkb_map.mm_mfn = MFN_INVALID; 1356a576ab5bSrab xkb->xkb_map.mm_map = (char *)MAP_FAILED; 1357a576ab5bSrab xkb->xkb_core.xc_p2m_buf = (char *)MAP_FAILED; 1358a576ab5bSrab xkb->xkb_fd = -1; 1359a576ab5bSrab 1360a576ab5bSrab xkb->xkb_path = strdup(corefile); 1361a576ab5bSrab 1362a576ab5bSrab if ((xkb = xkb_open_elf(xkb)) == NULL) 1363843e1988Sjohnlev return (NULL); 1364843e1988Sjohnlev 1365a576ab5bSrab if (xkb->xkb_type == XKB_FORMAT_UNKNOWN) { 1366a576ab5bSrab if (!xkb_open_core(xkb)) 1367a576ab5bSrab return (NULL); 1368a576ab5bSrab } 1369a576ab5bSrab 1370a576ab5bSrab xkb_init_mmu(xkb); 1371a576ab5bSrab 1372843e1988Sjohnlev if (!xkb_build_m2p(xkb)) 1373843e1988Sjohnlev return (NULL); 1374843e1988Sjohnlev 13755d2eda97SJohn Levon if (xkb->xkb_is_hvm) 13765d2eda97SJohn Levon debug_info = DEBUG_INFO_HVM; 13775d2eda97SJohn Levon 13785d2eda97SJohn Levon if (xkb_read(xkb, debug_info, &xkb->xkb_info, 1379843e1988Sjohnlev sizeof (xkb->xkb_info)) != sizeof (xkb->xkb_info)) 1380843e1988Sjohnlev return (xkb_fail(xkb, "cannot read debug_info")); 1381843e1988Sjohnlev 1382843e1988Sjohnlev if (xkb->xkb_info.di_magic != DEBUG_INFO_MAGIC) { 1383843e1988Sjohnlev return (xkb_fail(xkb, "invalid debug info magic %d", 1384843e1988Sjohnlev xkb->xkb_info.di_magic)); 1385843e1988Sjohnlev } 1386843e1988Sjohnlev 1387843e1988Sjohnlev if (xkb->xkb_info.di_version != DEBUG_INFO_VERSION) { 1388843e1988Sjohnlev return (xkb_fail(xkb, "unknown debug info version %d", 1389843e1988Sjohnlev xkb->xkb_info.di_version)); 1390843e1988Sjohnlev } 1391843e1988Sjohnlev 1392843e1988Sjohnlev if (!xkb_build_ksyms(xkb)) 1393843e1988Sjohnlev return (xkb_fail(xkb, "cannot construct namelist")); 1394843e1988Sjohnlev 1395843e1988Sjohnlev return (xkb); 1396843e1988Sjohnlev } 1397843e1988Sjohnlev 1398843e1988Sjohnlev int 1399843e1988Sjohnlev xkb_close(xkb_t *xkb) 1400843e1988Sjohnlev { 1401*349b53ddSStuart Maybee size_t i, sz; 1402843e1988Sjohnlev 1403843e1988Sjohnlev if (xkb == NULL) 1404843e1988Sjohnlev return (0); 1405843e1988Sjohnlev 1406843e1988Sjohnlev if (xkb->xkb_m2p != NULL) { 1407843e1988Sjohnlev mdb_free(xkb->xkb_m2p, 1408843e1988Sjohnlev (xkb->xkb_max_mfn + 1) * sizeof (xen_pfn_t)); 1409843e1988Sjohnlev } 1410843e1988Sjohnlev 1411843e1988Sjohnlev if (xkb->xkb_pages != NULL) { 1412843e1988Sjohnlev (void) munmap((void *)xkb->xkb_pages, 1413a576ab5bSrab PAGE_SIZE * xkb->xkb_nr_pages); 1414843e1988Sjohnlev } else { 1415843e1988Sjohnlev for (i = 0; i < 4; i++) { 1416843e1988Sjohnlev char *addr = xkb->xkb_pt_map[i].mm_map; 1417843e1988Sjohnlev if (addr != (char *)MAP_FAILED) 1418843e1988Sjohnlev (void) munmap((void *)addr, PAGE_SIZE); 1419843e1988Sjohnlev } 1420843e1988Sjohnlev if (xkb->xkb_map.mm_map != (char *)MAP_FAILED) { 1421843e1988Sjohnlev (void) munmap((void *)xkb->xkb_map.mm_map, 1422843e1988Sjohnlev PAGE_SIZE); 1423843e1988Sjohnlev } 1424843e1988Sjohnlev } 1425843e1988Sjohnlev 1426843e1988Sjohnlev if (xkb->xkb_namelist != NULL) 1427843e1988Sjohnlev mdb_free(xkb->xkb_namelist, xkb->xkb_namesize); 1428843e1988Sjohnlev 1429a576ab5bSrab if (xkb->xkb_type == XKB_FORMAT_ELF) { 1430a576ab5bSrab xkb_elf_t *xe = &xkb->xkb_elf; 1431a576ab5bSrab 1432a576ab5bSrab if (xe->xe_gelf != NULL) 1433a576ab5bSrab mdb_gelf_destroy(xe->xe_gelf); 1434a576ab5bSrab 1435a576ab5bSrab sz = sizeof (xen_pfn_t) * (xkb->xkb_max_pfn + 1); 1436a576ab5bSrab 1437a576ab5bSrab if (xkb->xkb_p2m != NULL) 1438a576ab5bSrab mdb_free(xkb->xkb_p2m, sz); 1439a576ab5bSrab 1440a576ab5bSrab sz = sizeof (size_t) * (xkb->xkb_max_pfn + 1); 1441a576ab5bSrab 1442a576ab5bSrab if (xe->xe_off != NULL) 1443a576ab5bSrab mdb_free(xe->xe_off, sz); 1444*349b53ddSStuart Maybee 1445a576ab5bSrab } else if (xkb->xkb_type == XKB_FORMAT_CORE) { 1446a576ab5bSrab xkb_core_t *xc = &xkb->xkb_core; 1447a576ab5bSrab 1448a576ab5bSrab if (xkb->xkb_fd != -1) 1449a576ab5bSrab (void) close(xkb->xkb_fd); 1450a576ab5bSrab 1451a576ab5bSrab sz = (xkb->xkb_nr_pages * sizeof (mfn_t)) + (PAGE_SIZE * 2); 1452a576ab5bSrab sz = PAGE_MASK(sz); 1453a576ab5bSrab 1454a576ab5bSrab if (xc->xc_p2m_buf != (xen_pfn_t *)MAP_FAILED) 1455a576ab5bSrab (void) munmap(xc->xc_p2m_buf, sz); 1456a576ab5bSrab 1457*349b53ddSStuart Maybee if (xkb->xkb_vcpu_data != NULL) 1458*349b53ddSStuart Maybee mdb_free(xkb->xkb_vcpu_data, xkb->xkb_vcpu_data_sz); 1459*349b53ddSStuart Maybee } 1460*349b53ddSStuart Maybee 1461*349b53ddSStuart Maybee if (xkb->xkb_vcpus != NULL) { 1462*349b53ddSStuart Maybee sz = sizeof (struct vcpu_guest_context *) * 1463*349b53ddSStuart Maybee xkb->xkb_nr_vcpus; 1464*349b53ddSStuart Maybee mdb_free(xkb->xkb_vcpus, sz); 1465a576ab5bSrab } 1466843e1988Sjohnlev 1467843e1988Sjohnlev free(xkb->xkb_path); 1468843e1988Sjohnlev 1469843e1988Sjohnlev mdb_free(xkb, sizeof (*xkb)); 1470843e1988Sjohnlev return (0); 1471843e1988Sjohnlev } 1472843e1988Sjohnlev 1473843e1988Sjohnlev /*ARGSUSED*/ 1474843e1988Sjohnlev static mdb_io_t * 1475843e1988Sjohnlev xkb_sym_io(xkb_t *xkb, const char *symfile) 1476843e1988Sjohnlev { 1477843e1988Sjohnlev mdb_io_t *io = mdb_memio_create(xkb->xkb_namelist, xkb->xkb_namesize); 1478843e1988Sjohnlev 1479843e1988Sjohnlev if (io == NULL) 1480843e1988Sjohnlev mdb_warn("failed to create namelist from %s", xkb->xkb_path); 1481843e1988Sjohnlev 1482843e1988Sjohnlev return (io); 1483843e1988Sjohnlev } 1484843e1988Sjohnlev 1485843e1988Sjohnlev uint64_t 1486843e1988Sjohnlev xkb_vtop(xkb_t *xkb, struct as *as, uintptr_t addr) 1487843e1988Sjohnlev { 14885d2eda97SJohn Levon mfn_t tlmfn = xkb_cr3_to_pfn(xkb); 1489843e1988Sjohnlev mfn_t mfn; 1490843e1988Sjohnlev 1491843e1988Sjohnlev if (as != NULL && (tlmfn = xkb_as_to_mfn(xkb, as)) == MFN_INVALID) 1492843e1988Sjohnlev return (-1ULL); 1493843e1988Sjohnlev 1494843e1988Sjohnlev mfn = xkb_va_to_mfn(xkb, addr, tlmfn); 1495843e1988Sjohnlev 1496843e1988Sjohnlev if (mfn == MFN_INVALID || mfn > xkb->xkb_max_mfn) 1497843e1988Sjohnlev return (-1ULL); 1498843e1988Sjohnlev 1499843e1988Sjohnlev return (((uint64_t)xkb->xkb_m2p[mfn] << PAGE_SHIFT) 1500843e1988Sjohnlev | PAGE_OFFSET(addr)); 1501843e1988Sjohnlev } 1502843e1988Sjohnlev 1503843e1988Sjohnlev static int 1504843e1988Sjohnlev xkb_getmregs(xkb_t *xkb, uint_t cpu, struct privmregs *mregs) 1505843e1988Sjohnlev { 1506843e1988Sjohnlev struct vcpu_guest_context *vcpu; 1507843e1988Sjohnlev struct cpu_user_regs *ur; 1508843e1988Sjohnlev struct regs *regs; 1509843e1988Sjohnlev 1510a576ab5bSrab if (cpu >= xkb->xkb_nr_vcpus) { 1511843e1988Sjohnlev errno = EINVAL; 1512843e1988Sjohnlev return (-1); 1513843e1988Sjohnlev } 1514843e1988Sjohnlev 1515843e1988Sjohnlev bzero(mregs, sizeof (*mregs)); 1516843e1988Sjohnlev 1517*349b53ddSStuart Maybee vcpu = xkb->xkb_vcpus[cpu]; 1518843e1988Sjohnlev ur = &vcpu->user_regs; 1519843e1988Sjohnlev regs = &mregs->pm_gregs; 1520843e1988Sjohnlev 1521843e1988Sjohnlev regs->r_ss = ur->ss; 1522843e1988Sjohnlev regs->r_cs = ur->cs; 1523843e1988Sjohnlev regs->r_ds = ur->ds; 1524843e1988Sjohnlev regs->r_es = ur->es; 1525843e1988Sjohnlev regs->r_fs = ur->fs; 1526843e1988Sjohnlev regs->r_gs = ur->gs; 1527843e1988Sjohnlev regs->r_trapno = ur->entry_vector; 1528843e1988Sjohnlev regs->r_err = ur->error_code; 1529843e1988Sjohnlev #ifdef __amd64 1530843e1988Sjohnlev regs->r_savfp = ur->rbp; 1531843e1988Sjohnlev regs->r_savpc = ur->rip; 1532843e1988Sjohnlev regs->r_rdi = ur->rdi; 1533843e1988Sjohnlev regs->r_rsi = ur->rsi; 1534843e1988Sjohnlev regs->r_rdx = ur->rdx; 1535843e1988Sjohnlev regs->r_rcx = ur->rcx; 1536843e1988Sjohnlev regs->r_r8 = ur->r8; 1537843e1988Sjohnlev regs->r_r9 = ur->r9; 1538843e1988Sjohnlev regs->r_rax = ur->rax; 1539843e1988Sjohnlev regs->r_rbx = ur->rbx; 1540843e1988Sjohnlev regs->r_rbp = ur->rbp; 1541843e1988Sjohnlev regs->r_r10 = ur->r10; 1542843e1988Sjohnlev regs->r_r11 = ur->r11; 1543843e1988Sjohnlev regs->r_r12 = ur->r12; 1544843e1988Sjohnlev regs->r_r13 = ur->r13; 1545843e1988Sjohnlev regs->r_r14 = ur->r14; 1546843e1988Sjohnlev regs->r_r15 = ur->r15; 1547843e1988Sjohnlev regs->r_rip = ur->rip; 1548843e1988Sjohnlev regs->r_rfl = ur->rflags; 1549843e1988Sjohnlev regs->r_rsp = ur->rsp; 1550843e1988Sjohnlev #else 1551843e1988Sjohnlev regs->r_savfp = ur->ebp; 1552843e1988Sjohnlev regs->r_savpc = ur->eip; 1553843e1988Sjohnlev regs->r_edi = ur->edi; 1554843e1988Sjohnlev regs->r_esi = ur->esi; 1555843e1988Sjohnlev regs->r_ebp = ur->ebp; 1556843e1988Sjohnlev regs->r_esp = ur->esp; 1557843e1988Sjohnlev regs->r_ebx = ur->ebx; 1558843e1988Sjohnlev regs->r_edx = ur->edx; 1559843e1988Sjohnlev regs->r_ecx = ur->ecx; 1560843e1988Sjohnlev regs->r_eax = ur->eax; 1561843e1988Sjohnlev regs->r_eip = ur->eip; 1562843e1988Sjohnlev regs->r_efl = ur->eflags; 1563843e1988Sjohnlev regs->r_uesp = 0; 1564843e1988Sjohnlev #endif 1565843e1988Sjohnlev 1566843e1988Sjohnlev bcopy(&vcpu->ctrlreg, &mregs->pm_cr, 8 * sizeof (ulong_t)); 1567843e1988Sjohnlev bcopy(&vcpu->debugreg, &mregs->pm_dr, 8 * sizeof (ulong_t)); 1568843e1988Sjohnlev 1569843e1988Sjohnlev mregs->pm_flags = PM_GREGS | PM_CRREGS | PM_DRREGS; 1570843e1988Sjohnlev 1571843e1988Sjohnlev return (0); 1572843e1988Sjohnlev } 1573843e1988Sjohnlev 1574843e1988Sjohnlev static mdb_kb_ops_t xpv_kb_ops = { 1575843e1988Sjohnlev .kb_open = (void *(*)())xkb_open, 1576843e1988Sjohnlev .kb_close = (int (*)())xkb_close, 1577843e1988Sjohnlev .kb_sym_io = (mdb_io_t *(*)())xkb_sym_io, 1578843e1988Sjohnlev .kb_kread = (ssize_t (*)())xkb_read, 1579843e1988Sjohnlev .kb_kwrite = (ssize_t (*)())mdb_tgt_notsup, 1580843e1988Sjohnlev .kb_aread = (ssize_t (*)())xkb_aread, 1581843e1988Sjohnlev .kb_awrite = (ssize_t (*)())mdb_tgt_notsup, 1582843e1988Sjohnlev .kb_pread = (ssize_t (*)())xkb_pread, 1583843e1988Sjohnlev .kb_pwrite = (ssize_t (*)())mdb_tgt_notsup, 1584843e1988Sjohnlev .kb_vtop = (uint64_t (*)())xkb_vtop, 1585843e1988Sjohnlev .kb_getmregs = (int (*)())xkb_getmregs 1586843e1988Sjohnlev }; 1587843e1988Sjohnlev 1588843e1988Sjohnlev mdb_kb_ops_t * 1589843e1988Sjohnlev mdb_kb_ops(void) 1590843e1988Sjohnlev { 1591843e1988Sjohnlev return (&xpv_kb_ops); 1592843e1988Sjohnlev } 1593843e1988Sjohnlev 1594843e1988Sjohnlev static const mdb_dcmd_t dcmds[] = { NULL, }; 1595843e1988Sjohnlev static const mdb_walker_t walkers[] = { NULL, }; 1596843e1988Sjohnlev static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers }; 1597843e1988Sjohnlev 1598843e1988Sjohnlev const mdb_modinfo_t * 1599843e1988Sjohnlev _mdb_init(void) 1600843e1988Sjohnlev { 1601843e1988Sjohnlev return (&modinfo); 1602843e1988Sjohnlev } 1603843e1988Sjohnlev 1604843e1988Sjohnlev void 1605843e1988Sjohnlev _mdb_fini(void) 1606843e1988Sjohnlev { 1607843e1988Sjohnlev } 1608