17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5ae115bc7Smrj * Common Development and Distribution License (the "License"). 6ae115bc7Smrj * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22f6e214c7SGavin Maltby * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. 237c478bd9Sstevel@tonic-gate */ 247c478bd9Sstevel@tonic-gate 251320caf7SBryan Cantrill /* 268eb8717cSJohn Levon * Copyright 2019 Joyent, Inc. 271320caf7SBryan Cantrill */ 281320caf7SBryan Cantrill 297c478bd9Sstevel@tonic-gate /* 307c478bd9Sstevel@tonic-gate * Libkvm Kernel Target 317c478bd9Sstevel@tonic-gate * 327c478bd9Sstevel@tonic-gate * The libkvm kernel target provides access to both crash dumps and live 337c478bd9Sstevel@tonic-gate * kernels through /dev/ksyms and /dev/kmem, using the facilities provided by 347c478bd9Sstevel@tonic-gate * the libkvm.so library. The target-specific data structures are shared 357c478bd9Sstevel@tonic-gate * between this file (common code) and the ISA-dependent parts of the target, 367c478bd9Sstevel@tonic-gate * and so they are defined in the mdb_kvm.h header. The target processes an 377c478bd9Sstevel@tonic-gate * "executable" (/dev/ksyms or the unix.X file) which contains a primary 387c478bd9Sstevel@tonic-gate * .symtab and .dynsym, and then also iterates over the krtld module chain in 397c478bd9Sstevel@tonic-gate * the kernel in order to obtain a list of loaded modules and per-module symbol 407c478bd9Sstevel@tonic-gate * tables. To improve startup performance, the per-module symbol tables are 417c478bd9Sstevel@tonic-gate * instantiated on-the-fly whenever an address lookup falls within the text 427c478bd9Sstevel@tonic-gate * section of a given module. The target also relies on services from the 437c478bd9Sstevel@tonic-gate * mdb_ks (kernel support) module, which contains pieces of the implementation 447c478bd9Sstevel@tonic-gate * that must be compiled against the kernel implementation. 457c478bd9Sstevel@tonic-gate */ 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 487c478bd9Sstevel@tonic-gate #include <sys/kobj.h> 497c478bd9Sstevel@tonic-gate #include <sys/kobj_impl.h> 507c478bd9Sstevel@tonic-gate #include <sys/utsname.h> 517c478bd9Sstevel@tonic-gate #include <sys/panic.h> 527c478bd9Sstevel@tonic-gate #include <sys/dumphdr.h> 537c478bd9Sstevel@tonic-gate #include <sys/dumpadm.h> 548eb8717cSJohn Levon #include <sys/uuid.h> 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate #include <dlfcn.h> 577c478bd9Sstevel@tonic-gate #include <libctf.h> 587c478bd9Sstevel@tonic-gate #include <string.h> 597c478bd9Sstevel@tonic-gate #include <fcntl.h> 607c478bd9Sstevel@tonic-gate #include <errno.h> 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate #include <mdb/mdb_target_impl.h> 637c478bd9Sstevel@tonic-gate #include <mdb/mdb_err.h> 647c478bd9Sstevel@tonic-gate #include <mdb/mdb_debug.h> 657c478bd9Sstevel@tonic-gate #include <mdb/mdb_string.h> 667c478bd9Sstevel@tonic-gate #include <mdb/mdb_modapi.h> 677c478bd9Sstevel@tonic-gate #include <mdb/mdb_io_impl.h> 687c478bd9Sstevel@tonic-gate #include <mdb/mdb_ctf.h> 697c478bd9Sstevel@tonic-gate #include <mdb/mdb_kvm.h> 707c478bd9Sstevel@tonic-gate #include <mdb/mdb_module.h> 71843e1988Sjohnlev #include <mdb/mdb_kb.h> 728eb8717cSJohn Levon #include <mdb/mdb_ks.h> 737c478bd9Sstevel@tonic-gate #include <mdb/mdb.h> 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate #define KT_RELOC_BUF(buf, obase, nbase) \ 767c478bd9Sstevel@tonic-gate ((uintptr_t)(buf) - (uintptr_t)(obase) + (uintptr_t)(nbase)) 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate #define KT_BAD_BUF(buf, base, size) \ 797c478bd9Sstevel@tonic-gate ((uintptr_t)(buf) < (uintptr_t)(base) || \ 807c478bd9Sstevel@tonic-gate ((uintptr_t)(buf) >= (uintptr_t)(base) + (uintptr_t)(size))) 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate typedef struct kt_symarg { 837c478bd9Sstevel@tonic-gate mdb_tgt_sym_f *sym_cb; /* Caller's callback function */ 847c478bd9Sstevel@tonic-gate void *sym_data; /* Callback function argument */ 857c478bd9Sstevel@tonic-gate uint_t sym_type; /* Symbol type/binding filter */ 867c478bd9Sstevel@tonic-gate mdb_syminfo_t sym_info; /* Symbol id and table id */ 877c478bd9Sstevel@tonic-gate const char *sym_obj; /* Containing object */ 887c478bd9Sstevel@tonic-gate } kt_symarg_t; 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate typedef struct kt_maparg { 917c478bd9Sstevel@tonic-gate mdb_tgt_t *map_target; /* Target used for mapping iter */ 927c478bd9Sstevel@tonic-gate mdb_tgt_map_f *map_cb; /* Caller's callback function */ 937c478bd9Sstevel@tonic-gate void *map_data; /* Callback function argument */ 947c478bd9Sstevel@tonic-gate } kt_maparg_t; 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate static const char KT_MODULE[] = "mdb_ks"; 977c478bd9Sstevel@tonic-gate static const char KT_CTFPARENT[] = "genunix"; 987c478bd9Sstevel@tonic-gate 998eb8717cSJohn Levon static void (*print_buildversion)(void); 1008eb8717cSJohn Levon 1017c478bd9Sstevel@tonic-gate static void 1027c478bd9Sstevel@tonic-gate kt_load_module(kt_data_t *kt, mdb_tgt_t *t, kt_module_t *km) 1037c478bd9Sstevel@tonic-gate { 1047c478bd9Sstevel@tonic-gate km->km_data = mdb_alloc(km->km_datasz, UM_SLEEP); 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate (void) mdb_tgt_vread(t, km->km_data, km->km_datasz, km->km_symspace_va); 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate km->km_symbuf = (void *) 1097c478bd9Sstevel@tonic-gate KT_RELOC_BUF(km->km_symtab_va, km->km_symspace_va, km->km_data); 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate km->km_strtab = (char *) 1127c478bd9Sstevel@tonic-gate KT_RELOC_BUF(km->km_strtab_va, km->km_symspace_va, km->km_data); 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate km->km_symtab = mdb_gelf_symtab_create_raw(&kt->k_file->gf_ehdr, 1157c478bd9Sstevel@tonic-gate &km->km_symtab_hdr, km->km_symbuf, 1167c478bd9Sstevel@tonic-gate &km->km_strtab_hdr, km->km_strtab, MDB_TGT_SYMTAB); 1177c478bd9Sstevel@tonic-gate } 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate static void 1207c478bd9Sstevel@tonic-gate kt_load_modules(kt_data_t *kt, mdb_tgt_t *t) 1217c478bd9Sstevel@tonic-gate { 1227c478bd9Sstevel@tonic-gate char name[MAXNAMELEN]; 1237c478bd9Sstevel@tonic-gate uintptr_t addr, head; 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate struct module kmod; 1267c478bd9Sstevel@tonic-gate struct modctl ctl; 1277c478bd9Sstevel@tonic-gate Shdr symhdr, strhdr; 1287c478bd9Sstevel@tonic-gate GElf_Sym sym; 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate kt_module_t *km; 1317c478bd9Sstevel@tonic-gate 1327c478bd9Sstevel@tonic-gate if (mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC, 1337c478bd9Sstevel@tonic-gate "modules", &sym, NULL) == -1) { 1347c478bd9Sstevel@tonic-gate warn("failed to get 'modules' symbol"); 1357c478bd9Sstevel@tonic-gate return; 1367c478bd9Sstevel@tonic-gate } 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate if (mdb_tgt_readsym(t, MDB_TGT_AS_VIRT, &ctl, sizeof (ctl), 1397c478bd9Sstevel@tonic-gate MDB_TGT_OBJ_EXEC, "modules") != sizeof (ctl)) { 1407c478bd9Sstevel@tonic-gate warn("failed to read 'modules' struct"); 1417c478bd9Sstevel@tonic-gate return; 1427c478bd9Sstevel@tonic-gate } 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate addr = head = (uintptr_t)sym.st_value; 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate do { 147892ad162SToomas Soome if (addr == 0) 1487c478bd9Sstevel@tonic-gate break; /* Avoid spurious NULL pointers in list */ 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate if (mdb_tgt_vread(t, &ctl, sizeof (ctl), addr) == -1) { 1517c478bd9Sstevel@tonic-gate warn("failed to read modctl at %p", (void *)addr); 1527c478bd9Sstevel@tonic-gate return; 1537c478bd9Sstevel@tonic-gate } 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate if (ctl.mod_mp == NULL) 1567c478bd9Sstevel@tonic-gate continue; /* No associated krtld structure */ 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate if (mdb_tgt_readstr(t, MDB_TGT_AS_VIRT, name, MAXNAMELEN, 1597c478bd9Sstevel@tonic-gate (uintptr_t)ctl.mod_modname) <= 0) { 1607c478bd9Sstevel@tonic-gate warn("failed to read module name at %p", 1617c478bd9Sstevel@tonic-gate (void *)ctl.mod_modname); 1627c478bd9Sstevel@tonic-gate continue; 1637c478bd9Sstevel@tonic-gate } 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_KMOD, "reading mod %s (%p)\n", 1667c478bd9Sstevel@tonic-gate name, (void *)addr); 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate if (mdb_nv_lookup(&kt->k_modules, name) != NULL) { 1697c478bd9Sstevel@tonic-gate warn("skipping duplicate module '%s', id=%d\n", 1707c478bd9Sstevel@tonic-gate name, ctl.mod_id); 1717c478bd9Sstevel@tonic-gate continue; 1727c478bd9Sstevel@tonic-gate } 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate if (mdb_tgt_vread(t, &kmod, sizeof (kmod), 1757c478bd9Sstevel@tonic-gate (uintptr_t)ctl.mod_mp) == -1) { 1767c478bd9Sstevel@tonic-gate warn("failed to read module at %p\n", 1777c478bd9Sstevel@tonic-gate (void *)ctl.mod_mp); 1787c478bd9Sstevel@tonic-gate continue; 1797c478bd9Sstevel@tonic-gate } 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate if (kmod.symspace == NULL || kmod.symhdr == NULL || 1827c478bd9Sstevel@tonic-gate kmod.strhdr == NULL) { 1837c478bd9Sstevel@tonic-gate /* 1847c478bd9Sstevel@tonic-gate * If no buffer for the symbols has been allocated, 1857c478bd9Sstevel@tonic-gate * or the shdrs for .symtab and .strtab are missing, 1867c478bd9Sstevel@tonic-gate * then we're out of luck. 1877c478bd9Sstevel@tonic-gate */ 1887c478bd9Sstevel@tonic-gate continue; 1897c478bd9Sstevel@tonic-gate } 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate if (mdb_tgt_vread(t, &symhdr, sizeof (Shdr), 1927c478bd9Sstevel@tonic-gate (uintptr_t)kmod.symhdr) == -1) { 1937c478bd9Sstevel@tonic-gate warn("failed to read .symtab header for '%s', id=%d", 1947c478bd9Sstevel@tonic-gate name, ctl.mod_id); 1957c478bd9Sstevel@tonic-gate continue; 1967c478bd9Sstevel@tonic-gate } 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate if (mdb_tgt_vread(t, &strhdr, sizeof (Shdr), 1997c478bd9Sstevel@tonic-gate (uintptr_t)kmod.strhdr) == -1) { 2007c478bd9Sstevel@tonic-gate warn("failed to read .strtab header for '%s', id=%d", 2017c478bd9Sstevel@tonic-gate name, ctl.mod_id); 2027c478bd9Sstevel@tonic-gate continue; 2037c478bd9Sstevel@tonic-gate } 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate /* 2067c478bd9Sstevel@tonic-gate * Now get clever: f(*^ing krtld didn't used to bother updating 2077c478bd9Sstevel@tonic-gate * its own kmod.symsize value. We know that prior to this bug 2087c478bd9Sstevel@tonic-gate * being fixed, symspace was a contiguous buffer containing 2097c478bd9Sstevel@tonic-gate * .symtab, .strtab, and the symbol hash table in that order. 2107c478bd9Sstevel@tonic-gate * So if symsize is zero, recompute it as the size of .symtab 2117c478bd9Sstevel@tonic-gate * plus the size of .strtab. We don't need to load the hash 2127c478bd9Sstevel@tonic-gate * table anyway since we re-hash all the symbols internally. 2137c478bd9Sstevel@tonic-gate */ 2147c478bd9Sstevel@tonic-gate if (kmod.symsize == 0) 2157c478bd9Sstevel@tonic-gate kmod.symsize = symhdr.sh_size + strhdr.sh_size; 2167c478bd9Sstevel@tonic-gate 2177c478bd9Sstevel@tonic-gate /* 2187c478bd9Sstevel@tonic-gate * Similar logic can be used to make educated guesses 2197c478bd9Sstevel@tonic-gate * at the values of kmod.symtbl and kmod.strings. 2207c478bd9Sstevel@tonic-gate */ 2217c478bd9Sstevel@tonic-gate if (kmod.symtbl == NULL) 2227c478bd9Sstevel@tonic-gate kmod.symtbl = kmod.symspace; 2237c478bd9Sstevel@tonic-gate if (kmod.strings == NULL) 2247c478bd9Sstevel@tonic-gate kmod.strings = kmod.symspace + symhdr.sh_size; 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate /* 2277c478bd9Sstevel@tonic-gate * Make sure things seem reasonable before we proceed 2287c478bd9Sstevel@tonic-gate * to actually read and decipher the symspace. 2297c478bd9Sstevel@tonic-gate */ 2307c478bd9Sstevel@tonic-gate if (KT_BAD_BUF(kmod.symtbl, kmod.symspace, kmod.symsize) || 2317c478bd9Sstevel@tonic-gate KT_BAD_BUF(kmod.strings, kmod.symspace, kmod.symsize)) { 2327c478bd9Sstevel@tonic-gate warn("skipping module '%s', id=%d (corrupt symspace)\n", 2337c478bd9Sstevel@tonic-gate name, ctl.mod_id); 2347c478bd9Sstevel@tonic-gate continue; 2357c478bd9Sstevel@tonic-gate } 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate km = mdb_zalloc(sizeof (kt_module_t), UM_SLEEP); 2387c478bd9Sstevel@tonic-gate km->km_name = strdup(name); 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate (void) mdb_nv_insert(&kt->k_modules, km->km_name, NULL, 2417c478bd9Sstevel@tonic-gate (uintptr_t)km, MDB_NV_EXTNAME); 2427c478bd9Sstevel@tonic-gate 2437c478bd9Sstevel@tonic-gate km->km_datasz = kmod.symsize; 2447c478bd9Sstevel@tonic-gate km->km_symspace_va = (uintptr_t)kmod.symspace; 2457c478bd9Sstevel@tonic-gate km->km_symtab_va = (uintptr_t)kmod.symtbl; 2467c478bd9Sstevel@tonic-gate km->km_strtab_va = (uintptr_t)kmod.strings; 2477c478bd9Sstevel@tonic-gate km->km_symtab_hdr = symhdr; 2487c478bd9Sstevel@tonic-gate km->km_strtab_hdr = strhdr; 2497c478bd9Sstevel@tonic-gate km->km_text_va = (uintptr_t)kmod.text; 2507c478bd9Sstevel@tonic-gate km->km_text_size = kmod.text_size; 2517c478bd9Sstevel@tonic-gate km->km_data_va = (uintptr_t)kmod.data; 2527c478bd9Sstevel@tonic-gate km->km_data_size = kmod.data_size; 2537c478bd9Sstevel@tonic-gate km->km_bss_va = (uintptr_t)kmod.bss; 2547c478bd9Sstevel@tonic-gate km->km_bss_size = kmod.bss_size; 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate if (kt->k_ctfvalid) { 2577c478bd9Sstevel@tonic-gate km->km_ctf_va = (uintptr_t)kmod.ctfdata; 2587c478bd9Sstevel@tonic-gate km->km_ctf_size = kmod.ctfsize; 2597c478bd9Sstevel@tonic-gate } 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate /* 2627c478bd9Sstevel@tonic-gate * Add the module to the end of the list of modules in load- 2637c478bd9Sstevel@tonic-gate * dependency order. This is needed to load the corresponding 2647c478bd9Sstevel@tonic-gate * debugger modules in the same order for layering purposes. 2657c478bd9Sstevel@tonic-gate */ 2667c478bd9Sstevel@tonic-gate mdb_list_append(&kt->k_modlist, km); 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate if (t->t_flags & MDB_TGT_F_PRELOAD) { 2697c478bd9Sstevel@tonic-gate mdb_iob_printf(mdb.m_out, " %s", name); 2707c478bd9Sstevel@tonic-gate mdb_iob_flush(mdb.m_out); 2717c478bd9Sstevel@tonic-gate kt_load_module(kt, t, km); 2727c478bd9Sstevel@tonic-gate } 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate } while ((addr = (uintptr_t)ctl.mod_next) != head); 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate int 2787c478bd9Sstevel@tonic-gate kt_setflags(mdb_tgt_t *t, int flags) 2797c478bd9Sstevel@tonic-gate { 2807c478bd9Sstevel@tonic-gate int iochg = ((flags ^ t->t_flags) & MDB_TGT_F_ALLOWIO) && 2817c478bd9Sstevel@tonic-gate !mdb_prop_postmortem; 2827c478bd9Sstevel@tonic-gate int rwchg = (flags ^ t->t_flags) & MDB_TGT_F_RDWR; 2837c478bd9Sstevel@tonic-gate kt_data_t *kt = t->t_data; 2847c478bd9Sstevel@tonic-gate const char *kvmfile; 285843e1988Sjohnlev void *cookie; 2867c478bd9Sstevel@tonic-gate int mode; 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate if (!iochg && !rwchg) 2897c478bd9Sstevel@tonic-gate return (0); 2907c478bd9Sstevel@tonic-gate 291843e1988Sjohnlev if (kt->k_xpv_domu) { 292843e1988Sjohnlev warn("read-only target"); 293843e1988Sjohnlev return (-1); 294843e1988Sjohnlev } 295843e1988Sjohnlev 2967c478bd9Sstevel@tonic-gate if (iochg) { 2977c478bd9Sstevel@tonic-gate kvmfile = (flags & MDB_TGT_F_ALLOWIO) ? "/dev/allkmem" : 2987c478bd9Sstevel@tonic-gate "/dev/kmem"; 2997c478bd9Sstevel@tonic-gate } else { 3007c478bd9Sstevel@tonic-gate kvmfile = kt->k_kvmfile; 3017c478bd9Sstevel@tonic-gate } 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate mode = (flags & MDB_TGT_F_RDWR) ? O_RDWR : O_RDONLY; 3047c478bd9Sstevel@tonic-gate 305843e1988Sjohnlev if ((cookie = kt->k_kb_ops->kb_open(kt->k_symfile, kvmfile, NULL, mode, 3067c478bd9Sstevel@tonic-gate mdb.m_pname)) == NULL) { 3077c478bd9Sstevel@tonic-gate /* We failed to re-open, so don't change t_flags */ 3087c478bd9Sstevel@tonic-gate warn("failed to re-open target"); 3097c478bd9Sstevel@tonic-gate return (-1); 3107c478bd9Sstevel@tonic-gate } 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate /* 3137c478bd9Sstevel@tonic-gate * We successfully reopened the target, so update k_kvmfile. Also set 3147c478bd9Sstevel@tonic-gate * the RDWR and ALLOWIO bits in t_flags to match those in flags. 3157c478bd9Sstevel@tonic-gate */ 316843e1988Sjohnlev (void) kt->k_kb_ops->kb_close(kt->k_cookie); 3177c478bd9Sstevel@tonic-gate kt->k_cookie = cookie; 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate if (kvmfile != kt->k_kvmfile) { 3207c478bd9Sstevel@tonic-gate strfree(kt->k_kvmfile); 3217c478bd9Sstevel@tonic-gate kt->k_kvmfile = strdup(kvmfile); 3227c478bd9Sstevel@tonic-gate } 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate t->t_flags = (t->t_flags & ~(MDB_TGT_F_RDWR | MDB_TGT_F_ALLOWIO)) | 3257c478bd9Sstevel@tonic-gate (flags & (MDB_TGT_F_RDWR | MDB_TGT_F_ALLOWIO)); 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate return (0); 3287c478bd9Sstevel@tonic-gate } 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate /* 3317c478bd9Sstevel@tonic-gate * Determine which PIDs (if any) have their pages saved in the dump. We 3327c478bd9Sstevel@tonic-gate * do this by looking for content flags in dump_flags in the header. These 3337c478bd9Sstevel@tonic-gate * flags, which won't be set in older dumps, tell us whether a single process 3347c478bd9Sstevel@tonic-gate * has had its pages included in the dump. If a single process has been 3357c478bd9Sstevel@tonic-gate * included, we need to get the PID for that process from the dump_pids 3367c478bd9Sstevel@tonic-gate * array in the dump. 3377c478bd9Sstevel@tonic-gate */ 3387c478bd9Sstevel@tonic-gate static int 3397c478bd9Sstevel@tonic-gate kt_find_dump_contents(kt_data_t *kt) 3407c478bd9Sstevel@tonic-gate { 3417c478bd9Sstevel@tonic-gate dumphdr_t *dh = kt->k_dumphdr; 3427c478bd9Sstevel@tonic-gate pid_t pid = -1; 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate if (dh->dump_flags & DF_ALL) 3457c478bd9Sstevel@tonic-gate return (KT_DUMPCONTENT_ALL); 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate if (dh->dump_flags & DF_CURPROC) { 3487c478bd9Sstevel@tonic-gate if ((pid = kt->k_dump_find_curproc()) == -1) 3497c478bd9Sstevel@tonic-gate return (KT_DUMPCONTENT_INVALID); 3507c478bd9Sstevel@tonic-gate else 3517c478bd9Sstevel@tonic-gate return (pid); 3527c478bd9Sstevel@tonic-gate } else { 3537c478bd9Sstevel@tonic-gate return (KT_DUMPCONTENT_KERNEL); 3547c478bd9Sstevel@tonic-gate } 3557c478bd9Sstevel@tonic-gate } 3567c478bd9Sstevel@tonic-gate 3577c478bd9Sstevel@tonic-gate static int 3587c478bd9Sstevel@tonic-gate kt_dump_contains_proc(mdb_tgt_t *t, void *context) 3597c478bd9Sstevel@tonic-gate { 3607c478bd9Sstevel@tonic-gate kt_data_t *kt = t->t_data; 3617c478bd9Sstevel@tonic-gate pid_t (*f_pid)(uintptr_t); 3627c478bd9Sstevel@tonic-gate pid_t reqpid; 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate switch (kt->k_dumpcontent) { 3657c478bd9Sstevel@tonic-gate case KT_DUMPCONTENT_KERNEL: 3667c478bd9Sstevel@tonic-gate return (0); 3677c478bd9Sstevel@tonic-gate case KT_DUMPCONTENT_ALL: 3687c478bd9Sstevel@tonic-gate return (1); 3697c478bd9Sstevel@tonic-gate case KT_DUMPCONTENT_INVALID: 3707c478bd9Sstevel@tonic-gate goto procnotfound; 3717c478bd9Sstevel@tonic-gate default: 3727c478bd9Sstevel@tonic-gate f_pid = (pid_t (*)()) dlsym(RTLD_NEXT, "mdb_kproc_pid"); 3737c478bd9Sstevel@tonic-gate if (f_pid == NULL) 3747c478bd9Sstevel@tonic-gate goto procnotfound; 3757c478bd9Sstevel@tonic-gate 3767c478bd9Sstevel@tonic-gate reqpid = f_pid((uintptr_t)context); 3777c478bd9Sstevel@tonic-gate if (reqpid == -1) 3787c478bd9Sstevel@tonic-gate goto procnotfound; 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate return (kt->k_dumpcontent == reqpid); 3817c478bd9Sstevel@tonic-gate } 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate procnotfound: 3847c478bd9Sstevel@tonic-gate warn("unable to determine whether dump contains proc %p\n", context); 3857c478bd9Sstevel@tonic-gate return (1); 3867c478bd9Sstevel@tonic-gate } 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate int 3897c478bd9Sstevel@tonic-gate kt_setcontext(mdb_tgt_t *t, void *context) 3907c478bd9Sstevel@tonic-gate { 3917c478bd9Sstevel@tonic-gate if (context != NULL) { 3927c478bd9Sstevel@tonic-gate const char *argv[2]; 3937c478bd9Sstevel@tonic-gate int argc = 0; 3947c478bd9Sstevel@tonic-gate mdb_tgt_t *ct; 3957c478bd9Sstevel@tonic-gate kt_data_t *kt = t->t_data; 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate argv[argc++] = (const char *)context; 3987c478bd9Sstevel@tonic-gate argv[argc] = NULL; 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate if (kt->k_dumphdr != NULL && 4017c478bd9Sstevel@tonic-gate !kt_dump_contains_proc(t, context)) { 4027c478bd9Sstevel@tonic-gate warn("dump does not contain pages for proc %p\n", 4037c478bd9Sstevel@tonic-gate context); 4047c478bd9Sstevel@tonic-gate return (-1); 4057c478bd9Sstevel@tonic-gate } 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate if ((ct = mdb_tgt_create(mdb_kproc_tgt_create, 4087c478bd9Sstevel@tonic-gate t->t_flags, argc, argv)) == NULL) 4097c478bd9Sstevel@tonic-gate return (-1); 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate mdb_printf("debugger context set to proc %p\n", context); 4127c478bd9Sstevel@tonic-gate mdb_tgt_activate(ct); 4137c478bd9Sstevel@tonic-gate } else 4147c478bd9Sstevel@tonic-gate mdb_printf("debugger context set to kernel\n"); 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate return (0); 4177c478bd9Sstevel@tonic-gate } 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate static int 4207c478bd9Sstevel@tonic-gate kt_stack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 4217c478bd9Sstevel@tonic-gate { 4227c478bd9Sstevel@tonic-gate kt_data_t *kt = mdb.m_target->t_data; 4237c478bd9Sstevel@tonic-gate return (kt->k_dcmd_stack(addr, flags, argc, argv)); 4247c478bd9Sstevel@tonic-gate } 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate static int 4277c478bd9Sstevel@tonic-gate kt_stackv(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 4287c478bd9Sstevel@tonic-gate { 4297c478bd9Sstevel@tonic-gate kt_data_t *kt = mdb.m_target->t_data; 4307c478bd9Sstevel@tonic-gate return (kt->k_dcmd_stackv(addr, flags, argc, argv)); 4317c478bd9Sstevel@tonic-gate } 4327c478bd9Sstevel@tonic-gate 4337c478bd9Sstevel@tonic-gate static int 4347c478bd9Sstevel@tonic-gate kt_stackr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 4357c478bd9Sstevel@tonic-gate { 4367c478bd9Sstevel@tonic-gate kt_data_t *kt = mdb.m_target->t_data; 4377c478bd9Sstevel@tonic-gate return (kt->k_dcmd_stackr(addr, flags, argc, argv)); 4387c478bd9Sstevel@tonic-gate } 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate static int 4417c478bd9Sstevel@tonic-gate kt_regs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 4427c478bd9Sstevel@tonic-gate { 4437c478bd9Sstevel@tonic-gate kt_data_t *kt = mdb.m_target->t_data; 444843e1988Sjohnlev 445843e1988Sjohnlev if (argc != 0 || (flags & DCMD_ADDRSPEC)) 446843e1988Sjohnlev return (DCMD_USAGE); 447843e1988Sjohnlev 448843e1988Sjohnlev addr = (uintptr_t)kt->k_regs; 449843e1988Sjohnlev 4507c478bd9Sstevel@tonic-gate return (kt->k_dcmd_regs(addr, flags, argc, argv)); 4517c478bd9Sstevel@tonic-gate } 4527c478bd9Sstevel@tonic-gate 453843e1988Sjohnlev #ifdef __x86 454843e1988Sjohnlev static int 455843e1988Sjohnlev kt_cpustack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 456843e1988Sjohnlev { 457843e1988Sjohnlev kt_data_t *kt = mdb.m_target->t_data; 458843e1988Sjohnlev return (kt->k_dcmd_cpustack(addr, flags, argc, argv)); 459843e1988Sjohnlev } 460843e1988Sjohnlev 461843e1988Sjohnlev static int 462843e1988Sjohnlev kt_cpuregs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 463843e1988Sjohnlev { 464843e1988Sjohnlev kt_data_t *kt = mdb.m_target->t_data; 465843e1988Sjohnlev return (kt->k_dcmd_cpuregs(addr, flags, argc, argv)); 466843e1988Sjohnlev } 467843e1988Sjohnlev #endif /* __x86 */ 468843e1988Sjohnlev 4697c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4707c478bd9Sstevel@tonic-gate static int 4717c478bd9Sstevel@tonic-gate kt_status_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 4727c478bd9Sstevel@tonic-gate { 4737c478bd9Sstevel@tonic-gate kt_data_t *kt = mdb.m_target->t_data; 4747c478bd9Sstevel@tonic-gate struct utsname uts; 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate bzero(&uts, sizeof (uts)); 4777c478bd9Sstevel@tonic-gate (void) strcpy(uts.nodename, "unknown machine"); 4787c478bd9Sstevel@tonic-gate (void) kt_uname(mdb.m_target, &uts); 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate if (mdb_prop_postmortem) { 481843e1988Sjohnlev mdb_printf("debugging %scrash dump %s (%d-bit) from %s\n", 482843e1988Sjohnlev kt->k_xpv_domu ? "domain " : "", kt->k_kvmfile, 483843e1988Sjohnlev (int)(sizeof (void *) * NBBY), uts.nodename); 4847c478bd9Sstevel@tonic-gate } else { 4857c478bd9Sstevel@tonic-gate mdb_printf("debugging live kernel (%d-bit) on %s\n", 4867c478bd9Sstevel@tonic-gate (int)(sizeof (void *) * NBBY), uts.nodename); 4877c478bd9Sstevel@tonic-gate } 4887c478bd9Sstevel@tonic-gate 4897c478bd9Sstevel@tonic-gate mdb_printf("operating system: %s %s (%s)\n", 4907c478bd9Sstevel@tonic-gate uts.release, uts.version, uts.machine); 4917c478bd9Sstevel@tonic-gate 4928eb8717cSJohn Levon if (print_buildversion != NULL) 4938eb8717cSJohn Levon print_buildversion(); 4948eb8717cSJohn Levon 4957c478bd9Sstevel@tonic-gate if (kt->k_dumphdr) { 4967c478bd9Sstevel@tonic-gate dumphdr_t *dh = kt->k_dumphdr; 4977c478bd9Sstevel@tonic-gate 498f6e214c7SGavin Maltby mdb_printf("image uuid: %s\n", dh->dump_uuid[0] != '\0' ? 499f6e214c7SGavin Maltby dh->dump_uuid : "(not set)"); 5007c478bd9Sstevel@tonic-gate mdb_printf("panic message: %s\n", dh->dump_panicstring); 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate kt->k_dump_print_content(dh, kt->k_dumpcontent); 503f6e214c7SGavin Maltby } else { 5048eb8717cSJohn Levon char uuid[UUID_PRINTABLE_STRING_LENGTH]; 505f6e214c7SGavin Maltby 5068eb8717cSJohn Levon if (mdb_readsym(uuid, sizeof (uuid), 5078eb8717cSJohn Levon "dump_osimage_uuid") == sizeof (uuid) && 5088eb8717cSJohn Levon uuid[sizeof (uuid) - 1] == '\0') { 5098eb8717cSJohn Levon mdb_printf("image uuid: %s\n", uuid[0] != '\0' ? 5108eb8717cSJohn Levon uuid : "(not set)"); 511f6e214c7SGavin Maltby } 5127c478bd9Sstevel@tonic-gate } 5137c478bd9Sstevel@tonic-gate 5147c478bd9Sstevel@tonic-gate return (DCMD_OK); 5157c478bd9Sstevel@tonic-gate } 5167c478bd9Sstevel@tonic-gate 5177c478bd9Sstevel@tonic-gate static const mdb_dcmd_t kt_dcmds[] = { 5187c478bd9Sstevel@tonic-gate { "$c", "?[cnt]", "print stack backtrace", kt_stack }, 5197c478bd9Sstevel@tonic-gate { "$C", "?[cnt]", "print stack backtrace", kt_stackv }, 5207c478bd9Sstevel@tonic-gate { "$r", NULL, "print general-purpose registers", kt_regs }, 5217c478bd9Sstevel@tonic-gate { "$?", NULL, "print status and registers", kt_regs }, 5227c478bd9Sstevel@tonic-gate { "regs", NULL, "print general-purpose registers", kt_regs }, 5237c478bd9Sstevel@tonic-gate { "stack", "?[cnt]", "print stack backtrace", kt_stack }, 5247c478bd9Sstevel@tonic-gate { "stackregs", "?", "print stack backtrace and registers", kt_stackr }, 525843e1988Sjohnlev #ifdef __x86 526843e1988Sjohnlev { "cpustack", "?[-v] [-c cpuid] [cnt]", "print stack backtrace for a " 527843e1988Sjohnlev "specific CPU", kt_cpustack }, 528843e1988Sjohnlev { "cpuregs", "?[-c cpuid]", "print general-purpose registers for a " 529843e1988Sjohnlev "specific CPU", kt_cpuregs }, 530843e1988Sjohnlev #endif 5317c478bd9Sstevel@tonic-gate { "status", NULL, "print summary of current target", kt_status_dcmd }, 5327c478bd9Sstevel@tonic-gate { NULL } 5337c478bd9Sstevel@tonic-gate }; 5347c478bd9Sstevel@tonic-gate 5357c478bd9Sstevel@tonic-gate static uintmax_t 5367c478bd9Sstevel@tonic-gate reg_disc_get(const mdb_var_t *v) 5377c478bd9Sstevel@tonic-gate { 5387c478bd9Sstevel@tonic-gate mdb_tgt_t *t = MDB_NV_COOKIE(v); 5397c478bd9Sstevel@tonic-gate kt_data_t *kt = t->t_data; 5407c478bd9Sstevel@tonic-gate mdb_tgt_reg_t r = 0; 5417c478bd9Sstevel@tonic-gate 5427c478bd9Sstevel@tonic-gate (void) mdb_tgt_getareg(t, kt->k_tid, mdb_nv_get_name(v), &r); 5437c478bd9Sstevel@tonic-gate return (r); 5447c478bd9Sstevel@tonic-gate } 5457c478bd9Sstevel@tonic-gate 546ae115bc7Smrj static kt_module_t * 547ae115bc7Smrj kt_module_by_name(kt_data_t *kt, const char *name) 548ae115bc7Smrj { 549ae115bc7Smrj kt_module_t *km; 550ae115bc7Smrj 551ae115bc7Smrj for (km = mdb_list_next(&kt->k_modlist); km; km = mdb_list_next(km)) { 552ae115bc7Smrj if (strcmp(name, km->km_name) == 0) 553ae115bc7Smrj return (km); 554ae115bc7Smrj } 555ae115bc7Smrj 556ae115bc7Smrj return (NULL); 557ae115bc7Smrj } 558ae115bc7Smrj 5597c478bd9Sstevel@tonic-gate void 5607c478bd9Sstevel@tonic-gate kt_activate(mdb_tgt_t *t) 5617c478bd9Sstevel@tonic-gate { 5627c478bd9Sstevel@tonic-gate static const mdb_nv_disc_t reg_disc = { NULL, reg_disc_get }; 5637c478bd9Sstevel@tonic-gate kt_data_t *kt = t->t_data; 5647c478bd9Sstevel@tonic-gate void *sym; 5657c478bd9Sstevel@tonic-gate 5667c478bd9Sstevel@tonic-gate int oflag; 5677c478bd9Sstevel@tonic-gate 568843e1988Sjohnlev mdb_prop_postmortem = kt->k_xpv_domu || (kt->k_dumphdr != NULL); 5697c478bd9Sstevel@tonic-gate mdb_prop_kernel = TRUE; 5707c478bd9Sstevel@tonic-gate mdb_prop_datamodel = MDB_TGT_MODEL_NATIVE; 5717c478bd9Sstevel@tonic-gate 5727c478bd9Sstevel@tonic-gate if (kt->k_activated == FALSE) { 5737c478bd9Sstevel@tonic-gate struct utsname u1, u2; 5747c478bd9Sstevel@tonic-gate /* 5757c478bd9Sstevel@tonic-gate * If we're examining a crash dump, root is /, and uname(2) 5767c478bd9Sstevel@tonic-gate * does not match the utsname in the dump, issue a warning. 5777c478bd9Sstevel@tonic-gate * Note that we are assuming that the modules and macros in 5787c478bd9Sstevel@tonic-gate * /usr/lib are compiled against the kernel from uname -rv. 5797c478bd9Sstevel@tonic-gate */ 5807c478bd9Sstevel@tonic-gate if (mdb_prop_postmortem && strcmp(mdb.m_root, "/") == 0 && 5817c478bd9Sstevel@tonic-gate uname(&u1) >= 0 && kt_uname(t, &u2) >= 0 && 5827c478bd9Sstevel@tonic-gate (strcmp(u1.release, u2.release) || 5837c478bd9Sstevel@tonic-gate strcmp(u1.version, u2.version))) { 5847c478bd9Sstevel@tonic-gate mdb_warn("warning: dump is from %s %s %s; dcmds and " 5857c478bd9Sstevel@tonic-gate "macros may not match kernel implementation\n", 5867c478bd9Sstevel@tonic-gate u2.sysname, u2.release, u2.version); 5877c478bd9Sstevel@tonic-gate } 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate if (mdb_module_load(KT_MODULE, MDB_MOD_GLOBAL) < 0) { 5907c478bd9Sstevel@tonic-gate warn("failed to load kernel support module -- " 5917c478bd9Sstevel@tonic-gate "some modules may not load\n"); 5927c478bd9Sstevel@tonic-gate } 5937c478bd9Sstevel@tonic-gate 5948eb8717cSJohn Levon print_buildversion = (void (*)(void))dlsym(RTLD_NEXT, 5958eb8717cSJohn Levon "mdb_print_buildversion"); 5968eb8717cSJohn Levon 597843e1988Sjohnlev if (mdb_prop_postmortem && kt->k_dumphdr != NULL) { 5987c478bd9Sstevel@tonic-gate sym = dlsym(RTLD_NEXT, "mdb_dump_print_content"); 5997c478bd9Sstevel@tonic-gate if (sym != NULL) 6007c478bd9Sstevel@tonic-gate kt->k_dump_print_content = (void (*)())sym; 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate sym = dlsym(RTLD_NEXT, "mdb_dump_find_curproc"); 6037c478bd9Sstevel@tonic-gate if (sym != NULL) 6047c478bd9Sstevel@tonic-gate kt->k_dump_find_curproc = (int (*)())sym; 6057c478bd9Sstevel@tonic-gate 6067c478bd9Sstevel@tonic-gate kt->k_dumpcontent = kt_find_dump_contents(kt); 6077c478bd9Sstevel@tonic-gate } 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate if (t->t_flags & MDB_TGT_F_PRELOAD) { 6107c478bd9Sstevel@tonic-gate oflag = mdb_iob_getflags(mdb.m_out) & MDB_IOB_PGENABLE; 6117c478bd9Sstevel@tonic-gate 6127c478bd9Sstevel@tonic-gate mdb_iob_clrflags(mdb.m_out, oflag); 6137c478bd9Sstevel@tonic-gate mdb_iob_puts(mdb.m_out, "Preloading module symbols: ["); 6147c478bd9Sstevel@tonic-gate mdb_iob_flush(mdb.m_out); 6157c478bd9Sstevel@tonic-gate } 6167c478bd9Sstevel@tonic-gate 617ae115bc7Smrj if (!(t->t_flags & MDB_TGT_F_NOLOAD)) { 6187c478bd9Sstevel@tonic-gate kt_load_modules(kt, t); 6197c478bd9Sstevel@tonic-gate 620ae115bc7Smrj /* 621ae115bc7Smrj * Determine where the CTF data for krtld is. If krtld 622ae115bc7Smrj * is rolled into unix, force load the MDB krtld 623ae115bc7Smrj * module. 624ae115bc7Smrj */ 625ae115bc7Smrj kt->k_rtld_name = "krtld"; 626ae115bc7Smrj 627ae115bc7Smrj if (kt_module_by_name(kt, "krtld") == NULL) { 628ae115bc7Smrj (void) mdb_module_load("krtld", MDB_MOD_SILENT); 629ae115bc7Smrj kt->k_rtld_name = "unix"; 630ae115bc7Smrj } 631ae115bc7Smrj } 632ae115bc7Smrj 633ae115bc7Smrj 6347c478bd9Sstevel@tonic-gate if (t->t_flags & MDB_TGT_F_PRELOAD) { 6357c478bd9Sstevel@tonic-gate mdb_iob_puts(mdb.m_out, " ]\n"); 6367c478bd9Sstevel@tonic-gate mdb_iob_setflags(mdb.m_out, oflag); 6377c478bd9Sstevel@tonic-gate } 6387c478bd9Sstevel@tonic-gate 6397c478bd9Sstevel@tonic-gate kt->k_activated = TRUE; 6407c478bd9Sstevel@tonic-gate } 6417c478bd9Sstevel@tonic-gate 6427c478bd9Sstevel@tonic-gate (void) mdb_tgt_register_dcmds(t, &kt_dcmds[0], MDB_MOD_FORCE); 6437c478bd9Sstevel@tonic-gate 6447c478bd9Sstevel@tonic-gate /* Export some of our registers as named variables */ 6457c478bd9Sstevel@tonic-gate mdb_tgt_register_regvars(t, kt->k_rds, ®_disc, MDB_NV_RDONLY); 6467c478bd9Sstevel@tonic-gate 6477c478bd9Sstevel@tonic-gate mdb_tgt_elf_export(kt->k_file); 6487c478bd9Sstevel@tonic-gate } 6497c478bd9Sstevel@tonic-gate 6507c478bd9Sstevel@tonic-gate void 6517c478bd9Sstevel@tonic-gate kt_deactivate(mdb_tgt_t *t) 6527c478bd9Sstevel@tonic-gate { 6537c478bd9Sstevel@tonic-gate kt_data_t *kt = t->t_data; 6547c478bd9Sstevel@tonic-gate 6557c478bd9Sstevel@tonic-gate const mdb_tgt_regdesc_t *rdp; 6567c478bd9Sstevel@tonic-gate const mdb_dcmd_t *dcp; 6577c478bd9Sstevel@tonic-gate 6587c478bd9Sstevel@tonic-gate for (rdp = kt->k_rds; rdp->rd_name != NULL; rdp++) { 6597c478bd9Sstevel@tonic-gate mdb_var_t *v; 6607c478bd9Sstevel@tonic-gate 6617c478bd9Sstevel@tonic-gate if (!(rdp->rd_flags & MDB_TGT_R_EXPORT)) 6627c478bd9Sstevel@tonic-gate continue; /* Didn't export register as a variable */ 6637c478bd9Sstevel@tonic-gate 6647c478bd9Sstevel@tonic-gate if ((v = mdb_nv_lookup(&mdb.m_nv, rdp->rd_name)) != NULL) { 6657c478bd9Sstevel@tonic-gate v->v_flags &= ~MDB_NV_PERSIST; 6667c478bd9Sstevel@tonic-gate mdb_nv_remove(&mdb.m_nv, v); 6677c478bd9Sstevel@tonic-gate } 6687c478bd9Sstevel@tonic-gate } 6697c478bd9Sstevel@tonic-gate 6707c478bd9Sstevel@tonic-gate for (dcp = &kt_dcmds[0]; dcp->dc_name != NULL; dcp++) { 6717c478bd9Sstevel@tonic-gate if (mdb_module_remove_dcmd(t->t_module, dcp->dc_name) == -1) 6727c478bd9Sstevel@tonic-gate warn("failed to remove dcmd %s", dcp->dc_name); 6737c478bd9Sstevel@tonic-gate } 6747c478bd9Sstevel@tonic-gate 6757c478bd9Sstevel@tonic-gate mdb_prop_postmortem = FALSE; 6767c478bd9Sstevel@tonic-gate mdb_prop_kernel = FALSE; 6777c478bd9Sstevel@tonic-gate mdb_prop_datamodel = MDB_TGT_MODEL_UNKNOWN; 6787c478bd9Sstevel@tonic-gate } 6797c478bd9Sstevel@tonic-gate 6807c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6817c478bd9Sstevel@tonic-gate const char * 6827c478bd9Sstevel@tonic-gate kt_name(mdb_tgt_t *t) 6837c478bd9Sstevel@tonic-gate { 6847c478bd9Sstevel@tonic-gate return ("kvm"); 6857c478bd9Sstevel@tonic-gate } 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate const char * 6887c478bd9Sstevel@tonic-gate kt_platform(mdb_tgt_t *t) 6897c478bd9Sstevel@tonic-gate { 6907c478bd9Sstevel@tonic-gate kt_data_t *kt = t->t_data; 6917c478bd9Sstevel@tonic-gate return (kt->k_platform); 6927c478bd9Sstevel@tonic-gate } 6937c478bd9Sstevel@tonic-gate 6947c478bd9Sstevel@tonic-gate int 6957c478bd9Sstevel@tonic-gate kt_uname(mdb_tgt_t *t, struct utsname *utsp) 6967c478bd9Sstevel@tonic-gate { 6977c478bd9Sstevel@tonic-gate return (mdb_tgt_readsym(t, MDB_TGT_AS_VIRT, utsp, 6987c478bd9Sstevel@tonic-gate sizeof (struct utsname), MDB_TGT_OBJ_EXEC, "utsname")); 6997c478bd9Sstevel@tonic-gate } 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 7027c478bd9Sstevel@tonic-gate int 7037c478bd9Sstevel@tonic-gate kt_dmodel(mdb_tgt_t *t) 7047c478bd9Sstevel@tonic-gate { 7057c478bd9Sstevel@tonic-gate return (MDB_TGT_MODEL_NATIVE); 7067c478bd9Sstevel@tonic-gate } 7077c478bd9Sstevel@tonic-gate 7087c478bd9Sstevel@tonic-gate ssize_t 7097c478bd9Sstevel@tonic-gate kt_aread(mdb_tgt_t *t, mdb_tgt_as_t as, void *buf, 7107c478bd9Sstevel@tonic-gate size_t nbytes, mdb_tgt_addr_t addr) 7117c478bd9Sstevel@tonic-gate { 7127c478bd9Sstevel@tonic-gate kt_data_t *kt = t->t_data; 7137c478bd9Sstevel@tonic-gate ssize_t rval; 7147c478bd9Sstevel@tonic-gate 715843e1988Sjohnlev if ((rval = kt->k_kb_ops->kb_aread(kt->k_cookie, addr, buf, 716843e1988Sjohnlev nbytes, as)) == -1) 7177c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOMAP)); 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate return (rval); 7207c478bd9Sstevel@tonic-gate } 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate ssize_t 7237c478bd9Sstevel@tonic-gate kt_awrite(mdb_tgt_t *t, mdb_tgt_as_t as, const void *buf, 7247c478bd9Sstevel@tonic-gate size_t nbytes, mdb_tgt_addr_t addr) 7257c478bd9Sstevel@tonic-gate { 7267c478bd9Sstevel@tonic-gate kt_data_t *kt = t->t_data; 7277c478bd9Sstevel@tonic-gate ssize_t rval; 7287c478bd9Sstevel@tonic-gate 729843e1988Sjohnlev if ((rval = kt->k_kb_ops->kb_awrite(kt->k_cookie, addr, buf, 730843e1988Sjohnlev nbytes, as)) == -1) 7317c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOMAP)); 7327c478bd9Sstevel@tonic-gate 7337c478bd9Sstevel@tonic-gate return (rval); 7347c478bd9Sstevel@tonic-gate } 7357c478bd9Sstevel@tonic-gate 7367c478bd9Sstevel@tonic-gate ssize_t 7377c478bd9Sstevel@tonic-gate kt_vread(mdb_tgt_t *t, void *buf, size_t nbytes, uintptr_t addr) 7387c478bd9Sstevel@tonic-gate { 7397c478bd9Sstevel@tonic-gate kt_data_t *kt = t->t_data; 7407c478bd9Sstevel@tonic-gate ssize_t rval; 7417c478bd9Sstevel@tonic-gate 742843e1988Sjohnlev if ((rval = kt->k_kb_ops->kb_kread(kt->k_cookie, addr, buf, 743843e1988Sjohnlev nbytes)) == -1) 7447c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOMAP)); 7457c478bd9Sstevel@tonic-gate 7467c478bd9Sstevel@tonic-gate return (rval); 7477c478bd9Sstevel@tonic-gate } 7487c478bd9Sstevel@tonic-gate 7497c478bd9Sstevel@tonic-gate ssize_t 7507c478bd9Sstevel@tonic-gate kt_vwrite(mdb_tgt_t *t, const void *buf, size_t nbytes, uintptr_t addr) 7517c478bd9Sstevel@tonic-gate { 7527c478bd9Sstevel@tonic-gate kt_data_t *kt = t->t_data; 7537c478bd9Sstevel@tonic-gate ssize_t rval; 7547c478bd9Sstevel@tonic-gate 755843e1988Sjohnlev if ((rval = kt->k_kb_ops->kb_kwrite(kt->k_cookie, addr, buf, 756843e1988Sjohnlev nbytes)) == -1) 7577c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOMAP)); 7587c478bd9Sstevel@tonic-gate 7597c478bd9Sstevel@tonic-gate return (rval); 7607c478bd9Sstevel@tonic-gate } 7617c478bd9Sstevel@tonic-gate 7627c478bd9Sstevel@tonic-gate ssize_t 7637c478bd9Sstevel@tonic-gate kt_fread(mdb_tgt_t *t, void *buf, size_t nbytes, uintptr_t addr) 7647c478bd9Sstevel@tonic-gate { 7657c478bd9Sstevel@tonic-gate return (kt_vread(t, buf, nbytes, addr)); 7667c478bd9Sstevel@tonic-gate } 7677c478bd9Sstevel@tonic-gate 7687c478bd9Sstevel@tonic-gate ssize_t 7697c478bd9Sstevel@tonic-gate kt_fwrite(mdb_tgt_t *t, const void *buf, size_t nbytes, uintptr_t addr) 7707c478bd9Sstevel@tonic-gate { 7717c478bd9Sstevel@tonic-gate return (kt_vwrite(t, buf, nbytes, addr)); 7727c478bd9Sstevel@tonic-gate } 7737c478bd9Sstevel@tonic-gate 7747c478bd9Sstevel@tonic-gate ssize_t 7757c478bd9Sstevel@tonic-gate kt_pread(mdb_tgt_t *t, void *buf, size_t nbytes, physaddr_t addr) 7767c478bd9Sstevel@tonic-gate { 7777c478bd9Sstevel@tonic-gate kt_data_t *kt = t->t_data; 7787c478bd9Sstevel@tonic-gate ssize_t rval; 7797c478bd9Sstevel@tonic-gate 780843e1988Sjohnlev if ((rval = kt->k_kb_ops->kb_pread(kt->k_cookie, addr, buf, 781843e1988Sjohnlev nbytes)) == -1) 7827c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOMAP)); 7837c478bd9Sstevel@tonic-gate 7847c478bd9Sstevel@tonic-gate return (rval); 7857c478bd9Sstevel@tonic-gate } 7867c478bd9Sstevel@tonic-gate 7877c478bd9Sstevel@tonic-gate ssize_t 7887c478bd9Sstevel@tonic-gate kt_pwrite(mdb_tgt_t *t, const void *buf, size_t nbytes, physaddr_t addr) 7897c478bd9Sstevel@tonic-gate { 7907c478bd9Sstevel@tonic-gate kt_data_t *kt = t->t_data; 7917c478bd9Sstevel@tonic-gate ssize_t rval; 7927c478bd9Sstevel@tonic-gate 793843e1988Sjohnlev if ((rval = kt->k_kb_ops->kb_pwrite(kt->k_cookie, addr, buf, 794843e1988Sjohnlev nbytes)) == -1) 7957c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOMAP)); 7967c478bd9Sstevel@tonic-gate 7977c478bd9Sstevel@tonic-gate return (rval); 7987c478bd9Sstevel@tonic-gate } 7997c478bd9Sstevel@tonic-gate 8007c478bd9Sstevel@tonic-gate int 8017c478bd9Sstevel@tonic-gate kt_vtop(mdb_tgt_t *t, mdb_tgt_as_t as, uintptr_t va, physaddr_t *pap) 8027c478bd9Sstevel@tonic-gate { 8037c478bd9Sstevel@tonic-gate kt_data_t *kt = t->t_data; 8047c478bd9Sstevel@tonic-gate 8057c478bd9Sstevel@tonic-gate struct as *asp; 8067c478bd9Sstevel@tonic-gate physaddr_t pa; 8077c478bd9Sstevel@tonic-gate mdb_module_t *mod; 8087c478bd9Sstevel@tonic-gate mdb_var_t *v; 8097c478bd9Sstevel@tonic-gate int (*fptr)(uintptr_t, struct as *, physaddr_t *); 8107c478bd9Sstevel@tonic-gate 8117c478bd9Sstevel@tonic-gate switch ((uintptr_t)as) { 8127c478bd9Sstevel@tonic-gate case (uintptr_t)MDB_TGT_AS_PHYS: 8137c478bd9Sstevel@tonic-gate case (uintptr_t)MDB_TGT_AS_FILE: 8147c478bd9Sstevel@tonic-gate case (uintptr_t)MDB_TGT_AS_IO: 8157c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 8167c478bd9Sstevel@tonic-gate case (uintptr_t)MDB_TGT_AS_VIRT: 817*9c3024a3SHans Rosenfeld case (uintptr_t)MDB_TGT_AS_VIRT_I: 818*9c3024a3SHans Rosenfeld case (uintptr_t)MDB_TGT_AS_VIRT_S: 8197c478bd9Sstevel@tonic-gate asp = kt->k_as; 8207c478bd9Sstevel@tonic-gate break; 8217c478bd9Sstevel@tonic-gate default: 8227c478bd9Sstevel@tonic-gate asp = (struct as *)as; 8237c478bd9Sstevel@tonic-gate } 8247c478bd9Sstevel@tonic-gate 825843e1988Sjohnlev if ((pa = kt->k_kb_ops->kb_vtop(kt->k_cookie, asp, va)) != -1ULL) { 8267c478bd9Sstevel@tonic-gate *pap = pa; 8277c478bd9Sstevel@tonic-gate return (0); 8287c478bd9Sstevel@tonic-gate } 8297c478bd9Sstevel@tonic-gate 8307c478bd9Sstevel@tonic-gate if ((v = mdb_nv_lookup(&mdb.m_modules, "unix")) != NULL && 8317c478bd9Sstevel@tonic-gate (mod = mdb_nv_get_cookie(v)) != NULL) { 8327c478bd9Sstevel@tonic-gate 8337c478bd9Sstevel@tonic-gate fptr = (int (*)(uintptr_t, struct as *, physaddr_t *)) 834843e1988Sjohnlev dlsym(mod->mod_hdl, "platform_vtop"); 8357c478bd9Sstevel@tonic-gate 8367c478bd9Sstevel@tonic-gate if ((fptr != NULL) && ((*fptr)(va, asp, pap) == 0)) 8377c478bd9Sstevel@tonic-gate return (0); 8387c478bd9Sstevel@tonic-gate } 8397c478bd9Sstevel@tonic-gate 8407c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOMAP)); 8417c478bd9Sstevel@tonic-gate } 8427c478bd9Sstevel@tonic-gate 8437c478bd9Sstevel@tonic-gate int 8447c478bd9Sstevel@tonic-gate kt_lookup_by_name(mdb_tgt_t *t, const char *obj, const char *name, 8457c478bd9Sstevel@tonic-gate GElf_Sym *symp, mdb_syminfo_t *sip) 8467c478bd9Sstevel@tonic-gate { 8477c478bd9Sstevel@tonic-gate kt_data_t *kt = t->t_data; 8487c478bd9Sstevel@tonic-gate kt_module_t *km, kmod; 8497c478bd9Sstevel@tonic-gate mdb_var_t *v; 8507c478bd9Sstevel@tonic-gate int n; 8517c478bd9Sstevel@tonic-gate 8527c478bd9Sstevel@tonic-gate /* 8537c478bd9Sstevel@tonic-gate * To simplify the implementation, we create a fake module on the stack 8547c478bd9Sstevel@tonic-gate * which is "prepended" to k_modlist and whose symtab is kt->k_symtab. 8557c478bd9Sstevel@tonic-gate */ 8567c478bd9Sstevel@tonic-gate kmod.km_symtab = kt->k_symtab; 8577c478bd9Sstevel@tonic-gate kmod.km_list.ml_next = mdb_list_next(&kt->k_modlist); 8587c478bd9Sstevel@tonic-gate 8597c478bd9Sstevel@tonic-gate switch ((uintptr_t)obj) { 8607c478bd9Sstevel@tonic-gate case (uintptr_t)MDB_TGT_OBJ_EXEC: 8617c478bd9Sstevel@tonic-gate km = &kmod; 8627c478bd9Sstevel@tonic-gate n = 1; 8637c478bd9Sstevel@tonic-gate break; 8647c478bd9Sstevel@tonic-gate 8657c478bd9Sstevel@tonic-gate case (uintptr_t)MDB_TGT_OBJ_EVERY: 8667c478bd9Sstevel@tonic-gate km = &kmod; 8677c478bd9Sstevel@tonic-gate n = mdb_nv_size(&kt->k_modules) + 1; 8687c478bd9Sstevel@tonic-gate break; 8697c478bd9Sstevel@tonic-gate 8707c478bd9Sstevel@tonic-gate case (uintptr_t)MDB_TGT_OBJ_RTLD: 871ae115bc7Smrj obj = kt->k_rtld_name; 8727c478bd9Sstevel@tonic-gate /*FALLTHRU*/ 8737c478bd9Sstevel@tonic-gate 8747c478bd9Sstevel@tonic-gate default: 8757c478bd9Sstevel@tonic-gate if ((v = mdb_nv_lookup(&kt->k_modules, obj)) == NULL) 8767c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOOBJ)); 8777c478bd9Sstevel@tonic-gate 8787c478bd9Sstevel@tonic-gate km = mdb_nv_get_cookie(v); 8797c478bd9Sstevel@tonic-gate n = 1; 8807c478bd9Sstevel@tonic-gate 8817c478bd9Sstevel@tonic-gate if (km->km_symtab == NULL) 8827c478bd9Sstevel@tonic-gate kt_load_module(kt, t, km); 8837c478bd9Sstevel@tonic-gate } 8847c478bd9Sstevel@tonic-gate 8857c478bd9Sstevel@tonic-gate for (; n > 0; n--, km = mdb_list_next(km)) { 8867c478bd9Sstevel@tonic-gate if (mdb_gelf_symtab_lookup_by_name(km->km_symtab, name, 8877c478bd9Sstevel@tonic-gate symp, &sip->sym_id) == 0) { 8887c478bd9Sstevel@tonic-gate sip->sym_table = MDB_TGT_SYMTAB; 8897c478bd9Sstevel@tonic-gate return (0); 8907c478bd9Sstevel@tonic-gate } 8917c478bd9Sstevel@tonic-gate } 8927c478bd9Sstevel@tonic-gate 8937c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOSYM)); 8947c478bd9Sstevel@tonic-gate } 8957c478bd9Sstevel@tonic-gate 8967c478bd9Sstevel@tonic-gate int 8977c478bd9Sstevel@tonic-gate kt_lookup_by_addr(mdb_tgt_t *t, uintptr_t addr, uint_t flags, 8987c478bd9Sstevel@tonic-gate char *buf, size_t nbytes, GElf_Sym *symp, mdb_syminfo_t *sip) 8997c478bd9Sstevel@tonic-gate { 9007c478bd9Sstevel@tonic-gate kt_data_t *kt = t->t_data; 9017c478bd9Sstevel@tonic-gate kt_module_t kmods[3], *kmods_begin = &kmods[0], *kmods_end; 9027c478bd9Sstevel@tonic-gate const char *name; 9037c478bd9Sstevel@tonic-gate 9047c478bd9Sstevel@tonic-gate kt_module_t *km = &kmods[0]; /* Point km at first fake module */ 9057c478bd9Sstevel@tonic-gate kt_module_t *sym_km = NULL; /* Module associated with best sym */ 9067c478bd9Sstevel@tonic-gate GElf_Sym sym; /* Best symbol found so far if !exact */ 9077c478bd9Sstevel@tonic-gate uint_t symid; /* ID of best symbol found so far */ 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate /* 9107c478bd9Sstevel@tonic-gate * To simplify the implementation, we create fake modules on the stack 9117c478bd9Sstevel@tonic-gate * that are "prepended" to k_modlist and whose symtab is set to 9127c478bd9Sstevel@tonic-gate * each of three special symbol tables, in order of precedence. 9137c478bd9Sstevel@tonic-gate */ 9147c478bd9Sstevel@tonic-gate km->km_symtab = mdb.m_prsym; 9157c478bd9Sstevel@tonic-gate 9167c478bd9Sstevel@tonic-gate if (kt->k_symtab != NULL) { 9177c478bd9Sstevel@tonic-gate km->km_list.ml_next = (mdb_list_t *)(km + 1); 9187c478bd9Sstevel@tonic-gate km = mdb_list_next(km); 9197c478bd9Sstevel@tonic-gate km->km_symtab = kt->k_symtab; 9207c478bd9Sstevel@tonic-gate } 9217c478bd9Sstevel@tonic-gate 9227c478bd9Sstevel@tonic-gate if (kt->k_dynsym != NULL) { 9237c478bd9Sstevel@tonic-gate km->km_list.ml_next = (mdb_list_t *)(km + 1); 9247c478bd9Sstevel@tonic-gate km = mdb_list_next(km); 9257c478bd9Sstevel@tonic-gate km->km_symtab = kt->k_dynsym; 9267c478bd9Sstevel@tonic-gate } 9277c478bd9Sstevel@tonic-gate 9287c478bd9Sstevel@tonic-gate km->km_list.ml_next = mdb_list_next(&kt->k_modlist); 9297c478bd9Sstevel@tonic-gate kmods_end = km; 9307c478bd9Sstevel@tonic-gate 9317c478bd9Sstevel@tonic-gate /* 9327c478bd9Sstevel@tonic-gate * Now iterate over the list of fake and real modules. If the module 9337c478bd9Sstevel@tonic-gate * has no symbol table and the address is in the text section, 9347c478bd9Sstevel@tonic-gate * instantiate the module's symbol table. In exact mode, we can 9357c478bd9Sstevel@tonic-gate * jump to 'found' immediately if we match. Otherwise we continue 9367c478bd9Sstevel@tonic-gate * looking and improve our choice if we find a closer symbol. 9377c478bd9Sstevel@tonic-gate */ 9387c478bd9Sstevel@tonic-gate for (km = &kmods[0]; km != NULL; km = mdb_list_next(km)) { 9397c478bd9Sstevel@tonic-gate if (km->km_symtab == NULL && addr >= km->km_text_va && 9407c478bd9Sstevel@tonic-gate addr < km->km_text_va + km->km_text_size) 9417c478bd9Sstevel@tonic-gate kt_load_module(kt, t, km); 9427c478bd9Sstevel@tonic-gate 9437c478bd9Sstevel@tonic-gate if (mdb_gelf_symtab_lookup_by_addr(km->km_symtab, addr, 9447c478bd9Sstevel@tonic-gate flags, buf, nbytes, symp, &sip->sym_id) != 0 || 9457c478bd9Sstevel@tonic-gate symp->st_value == 0) 9467c478bd9Sstevel@tonic-gate continue; 9477c478bd9Sstevel@tonic-gate 9487c478bd9Sstevel@tonic-gate if (flags & MDB_TGT_SYM_EXACT) { 9497c478bd9Sstevel@tonic-gate sym_km = km; 9507c478bd9Sstevel@tonic-gate goto found; 9517c478bd9Sstevel@tonic-gate } 9527c478bd9Sstevel@tonic-gate 9537c478bd9Sstevel@tonic-gate if (sym_km == NULL || mdb_gelf_sym_closer(symp, &sym, addr)) { 9547c478bd9Sstevel@tonic-gate sym_km = km; 9557c478bd9Sstevel@tonic-gate sym = *symp; 9567c478bd9Sstevel@tonic-gate symid = sip->sym_id; 9577c478bd9Sstevel@tonic-gate } 9587c478bd9Sstevel@tonic-gate } 9597c478bd9Sstevel@tonic-gate 9607c478bd9Sstevel@tonic-gate if (sym_km == NULL) 9617c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOSYMADDR)); 9627c478bd9Sstevel@tonic-gate 9637c478bd9Sstevel@tonic-gate *symp = sym; /* Copy our best symbol into the caller's symbol */ 9647c478bd9Sstevel@tonic-gate sip->sym_id = symid; 9657c478bd9Sstevel@tonic-gate found: 9667c478bd9Sstevel@tonic-gate /* 9677c478bd9Sstevel@tonic-gate * Once we've found something, copy the final name into the caller's 9687c478bd9Sstevel@tonic-gate * buffer and prefix it with the load object name if appropriate. 9697c478bd9Sstevel@tonic-gate */ 970843e1988Sjohnlev if (sym_km != NULL) { 971843e1988Sjohnlev name = mdb_gelf_sym_name(sym_km->km_symtab, symp); 972843e1988Sjohnlev 973843e1988Sjohnlev if (sym_km < kmods_begin || sym_km > kmods_end) { 974843e1988Sjohnlev (void) mdb_snprintf(buf, nbytes, "%s`%s", 975843e1988Sjohnlev sym_km->km_name, name); 976843e1988Sjohnlev } else if (nbytes > 0) { 977843e1988Sjohnlev (void) strncpy(buf, name, nbytes); 978843e1988Sjohnlev buf[nbytes - 1] = '\0'; 979843e1988Sjohnlev } 9807c478bd9Sstevel@tonic-gate 981843e1988Sjohnlev if (sym_km->km_symtab == mdb.m_prsym) 982843e1988Sjohnlev sip->sym_table = MDB_TGT_PRVSYM; 983843e1988Sjohnlev else 984843e1988Sjohnlev sip->sym_table = MDB_TGT_SYMTAB; 985843e1988Sjohnlev } else { 9867c478bd9Sstevel@tonic-gate sip->sym_table = MDB_TGT_SYMTAB; 987843e1988Sjohnlev } 9887c478bd9Sstevel@tonic-gate 9897c478bd9Sstevel@tonic-gate return (0); 9907c478bd9Sstevel@tonic-gate } 9917c478bd9Sstevel@tonic-gate 9927c478bd9Sstevel@tonic-gate static int 9937c478bd9Sstevel@tonic-gate kt_symtab_func(void *data, const GElf_Sym *sym, const char *name, uint_t id) 9947c478bd9Sstevel@tonic-gate { 9957c478bd9Sstevel@tonic-gate kt_symarg_t *argp = data; 9967c478bd9Sstevel@tonic-gate 9977c478bd9Sstevel@tonic-gate if (mdb_tgt_sym_match(sym, argp->sym_type)) { 9987c478bd9Sstevel@tonic-gate argp->sym_info.sym_id = id; 9997c478bd9Sstevel@tonic-gate 10007c478bd9Sstevel@tonic-gate return (argp->sym_cb(argp->sym_data, sym, name, 10017c478bd9Sstevel@tonic-gate &argp->sym_info, argp->sym_obj)); 10027c478bd9Sstevel@tonic-gate } 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate return (0); 10057c478bd9Sstevel@tonic-gate } 10067c478bd9Sstevel@tonic-gate 10077c478bd9Sstevel@tonic-gate static void 10087c478bd9Sstevel@tonic-gate kt_symtab_iter(mdb_gelf_symtab_t *gst, uint_t type, const char *obj, 10097c478bd9Sstevel@tonic-gate mdb_tgt_sym_f *cb, void *p) 10107c478bd9Sstevel@tonic-gate { 10117c478bd9Sstevel@tonic-gate kt_symarg_t arg; 10127c478bd9Sstevel@tonic-gate 10137c478bd9Sstevel@tonic-gate arg.sym_cb = cb; 10147c478bd9Sstevel@tonic-gate arg.sym_data = p; 10157c478bd9Sstevel@tonic-gate arg.sym_type = type; 10167c478bd9Sstevel@tonic-gate arg.sym_info.sym_table = gst->gst_tabid; 10177c478bd9Sstevel@tonic-gate arg.sym_obj = obj; 10187c478bd9Sstevel@tonic-gate 10197c478bd9Sstevel@tonic-gate mdb_gelf_symtab_iter(gst, kt_symtab_func, &arg); 10207c478bd9Sstevel@tonic-gate } 10217c478bd9Sstevel@tonic-gate 10227c478bd9Sstevel@tonic-gate int 10237c478bd9Sstevel@tonic-gate kt_symbol_iter(mdb_tgt_t *t, const char *obj, uint_t which, uint_t type, 10247c478bd9Sstevel@tonic-gate mdb_tgt_sym_f *cb, void *data) 10257c478bd9Sstevel@tonic-gate { 10267c478bd9Sstevel@tonic-gate kt_data_t *kt = t->t_data; 10277c478bd9Sstevel@tonic-gate kt_module_t *km; 10287c478bd9Sstevel@tonic-gate 10297c478bd9Sstevel@tonic-gate mdb_gelf_symtab_t *symtab = NULL; 10307c478bd9Sstevel@tonic-gate mdb_var_t *v; 10317c478bd9Sstevel@tonic-gate 10327c478bd9Sstevel@tonic-gate switch ((uintptr_t)obj) { 10337c478bd9Sstevel@tonic-gate case (uintptr_t)MDB_TGT_OBJ_EXEC: 10347c478bd9Sstevel@tonic-gate if (which == MDB_TGT_SYMTAB) 10357c478bd9Sstevel@tonic-gate symtab = kt->k_symtab; 10367c478bd9Sstevel@tonic-gate else 10377c478bd9Sstevel@tonic-gate symtab = kt->k_dynsym; 10387c478bd9Sstevel@tonic-gate break; 10397c478bd9Sstevel@tonic-gate 10407c478bd9Sstevel@tonic-gate case (uintptr_t)MDB_TGT_OBJ_EVERY: 10417c478bd9Sstevel@tonic-gate if (which == MDB_TGT_DYNSYM) { 10427c478bd9Sstevel@tonic-gate symtab = kt->k_dynsym; 10437c478bd9Sstevel@tonic-gate obj = MDB_TGT_OBJ_EXEC; 10447c478bd9Sstevel@tonic-gate break; 10457c478bd9Sstevel@tonic-gate } 10467c478bd9Sstevel@tonic-gate 10477c478bd9Sstevel@tonic-gate mdb_nv_rewind(&kt->k_modules); 10487c478bd9Sstevel@tonic-gate while ((v = mdb_nv_advance(&kt->k_modules)) != NULL) { 10497c478bd9Sstevel@tonic-gate km = mdb_nv_get_cookie(v); 10507c478bd9Sstevel@tonic-gate 10517c478bd9Sstevel@tonic-gate if (km->km_symtab == NULL) 10527c478bd9Sstevel@tonic-gate kt_load_module(kt, t, km); 10537c478bd9Sstevel@tonic-gate 10547c478bd9Sstevel@tonic-gate if (km->km_symtab != NULL) 10557c478bd9Sstevel@tonic-gate kt_symtab_iter(km->km_symtab, type, 10567c478bd9Sstevel@tonic-gate km->km_name, cb, data); 10577c478bd9Sstevel@tonic-gate } 10587c478bd9Sstevel@tonic-gate break; 10597c478bd9Sstevel@tonic-gate 10607c478bd9Sstevel@tonic-gate case (uintptr_t)MDB_TGT_OBJ_RTLD: 1061ae115bc7Smrj obj = kt->k_rtld_name; 10627c478bd9Sstevel@tonic-gate /*FALLTHRU*/ 10637c478bd9Sstevel@tonic-gate 10647c478bd9Sstevel@tonic-gate default: 10657c478bd9Sstevel@tonic-gate v = mdb_nv_lookup(&kt->k_modules, obj); 10667c478bd9Sstevel@tonic-gate 10677c478bd9Sstevel@tonic-gate if (v == NULL) 10687c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOOBJ)); 10697c478bd9Sstevel@tonic-gate 10707c478bd9Sstevel@tonic-gate km = mdb_nv_get_cookie(v); 10717c478bd9Sstevel@tonic-gate 10727c478bd9Sstevel@tonic-gate if (km->km_symtab == NULL) 10737c478bd9Sstevel@tonic-gate kt_load_module(kt, t, km); 10747c478bd9Sstevel@tonic-gate 10757c478bd9Sstevel@tonic-gate symtab = km->km_symtab; 10767c478bd9Sstevel@tonic-gate } 10777c478bd9Sstevel@tonic-gate 10787c478bd9Sstevel@tonic-gate if (symtab) 10797c478bd9Sstevel@tonic-gate kt_symtab_iter(symtab, type, obj, cb, data); 10807c478bd9Sstevel@tonic-gate 10817c478bd9Sstevel@tonic-gate return (0); 10827c478bd9Sstevel@tonic-gate } 10837c478bd9Sstevel@tonic-gate 10847c478bd9Sstevel@tonic-gate static int 10857c478bd9Sstevel@tonic-gate kt_mapping_walk(uintptr_t addr, const void *data, kt_maparg_t *marg) 10867c478bd9Sstevel@tonic-gate { 10877c478bd9Sstevel@tonic-gate /* 10887c478bd9Sstevel@tonic-gate * This is a bit sketchy but avoids problematic compilation of this 10897c478bd9Sstevel@tonic-gate * target against the current VM implementation. Now that we have 10907c478bd9Sstevel@tonic-gate * vmem, we can make this less broken and more informative by changing 10917c478bd9Sstevel@tonic-gate * this code to invoke the vmem walker in the near future. 10927c478bd9Sstevel@tonic-gate */ 10937c478bd9Sstevel@tonic-gate const struct kt_seg { 10947c478bd9Sstevel@tonic-gate caddr_t s_base; 10957c478bd9Sstevel@tonic-gate size_t s_size; 10967c478bd9Sstevel@tonic-gate } *segp = (const struct kt_seg *)data; 10977c478bd9Sstevel@tonic-gate 10987c478bd9Sstevel@tonic-gate mdb_map_t map; 10997c478bd9Sstevel@tonic-gate GElf_Sym sym; 11007c478bd9Sstevel@tonic-gate mdb_syminfo_t info; 11017c478bd9Sstevel@tonic-gate 11027c478bd9Sstevel@tonic-gate map.map_base = (uintptr_t)segp->s_base; 11037c478bd9Sstevel@tonic-gate map.map_size = segp->s_size; 11047c478bd9Sstevel@tonic-gate map.map_flags = MDB_TGT_MAP_R | MDB_TGT_MAP_W | MDB_TGT_MAP_X; 11057c478bd9Sstevel@tonic-gate 11067c478bd9Sstevel@tonic-gate if (kt_lookup_by_addr(marg->map_target, addr, MDB_TGT_SYM_EXACT, 11077c478bd9Sstevel@tonic-gate map.map_name, MDB_TGT_MAPSZ, &sym, &info) == -1) { 11087c478bd9Sstevel@tonic-gate 11097c478bd9Sstevel@tonic-gate (void) mdb_iob_snprintf(map.map_name, MDB_TGT_MAPSZ, 11107c478bd9Sstevel@tonic-gate "%lr", addr); 11117c478bd9Sstevel@tonic-gate } 11127c478bd9Sstevel@tonic-gate 11137c478bd9Sstevel@tonic-gate return (marg->map_cb(marg->map_data, &map, map.map_name)); 11147c478bd9Sstevel@tonic-gate } 11157c478bd9Sstevel@tonic-gate 11167c478bd9Sstevel@tonic-gate int 11177c478bd9Sstevel@tonic-gate kt_mapping_iter(mdb_tgt_t *t, mdb_tgt_map_f *func, void *private) 11187c478bd9Sstevel@tonic-gate { 11197c478bd9Sstevel@tonic-gate kt_data_t *kt = t->t_data; 11207c478bd9Sstevel@tonic-gate kt_maparg_t m; 11217c478bd9Sstevel@tonic-gate 11227c478bd9Sstevel@tonic-gate m.map_target = t; 11237c478bd9Sstevel@tonic-gate m.map_cb = func; 11247c478bd9Sstevel@tonic-gate m.map_data = private; 11257c478bd9Sstevel@tonic-gate 11267c478bd9Sstevel@tonic-gate return (mdb_pwalk("seg", (mdb_walk_cb_t)kt_mapping_walk, &m, 11277c478bd9Sstevel@tonic-gate (uintptr_t)kt->k_as)); 11287c478bd9Sstevel@tonic-gate } 11297c478bd9Sstevel@tonic-gate 11307c478bd9Sstevel@tonic-gate static const mdb_map_t * 11317c478bd9Sstevel@tonic-gate kt_module_to_map(kt_module_t *km, mdb_map_t *map) 11327c478bd9Sstevel@tonic-gate { 11337c478bd9Sstevel@tonic-gate (void) strncpy(map->map_name, km->km_name, MDB_TGT_MAPSZ); 11347c478bd9Sstevel@tonic-gate map->map_name[MDB_TGT_MAPSZ - 1] = '\0'; 11357c478bd9Sstevel@tonic-gate map->map_base = km->km_text_va; 11367c478bd9Sstevel@tonic-gate map->map_size = km->km_text_size; 11377c478bd9Sstevel@tonic-gate map->map_flags = MDB_TGT_MAP_R | MDB_TGT_MAP_W | MDB_TGT_MAP_X; 11387c478bd9Sstevel@tonic-gate 11397c478bd9Sstevel@tonic-gate return (map); 11407c478bd9Sstevel@tonic-gate } 11417c478bd9Sstevel@tonic-gate 11427c478bd9Sstevel@tonic-gate int 11437c478bd9Sstevel@tonic-gate kt_object_iter(mdb_tgt_t *t, mdb_tgt_map_f *func, void *private) 11447c478bd9Sstevel@tonic-gate { 11457c478bd9Sstevel@tonic-gate kt_data_t *kt = t->t_data; 11467c478bd9Sstevel@tonic-gate kt_module_t *km; 11477c478bd9Sstevel@tonic-gate mdb_map_t m; 11487c478bd9Sstevel@tonic-gate 11497c478bd9Sstevel@tonic-gate for (km = mdb_list_next(&kt->k_modlist); km; km = mdb_list_next(km)) { 11507c478bd9Sstevel@tonic-gate if (func(private, kt_module_to_map(km, &m), km->km_name) == -1) 11517c478bd9Sstevel@tonic-gate break; 11527c478bd9Sstevel@tonic-gate } 11537c478bd9Sstevel@tonic-gate 11547c478bd9Sstevel@tonic-gate return (0); 11557c478bd9Sstevel@tonic-gate } 11567c478bd9Sstevel@tonic-gate 11577c478bd9Sstevel@tonic-gate const mdb_map_t * 11587c478bd9Sstevel@tonic-gate kt_addr_to_map(mdb_tgt_t *t, uintptr_t addr) 11597c478bd9Sstevel@tonic-gate { 11607c478bd9Sstevel@tonic-gate kt_data_t *kt = t->t_data; 11617c478bd9Sstevel@tonic-gate kt_module_t *km; 11627c478bd9Sstevel@tonic-gate 11637c478bd9Sstevel@tonic-gate for (km = mdb_list_next(&kt->k_modlist); km; km = mdb_list_next(km)) { 11647c478bd9Sstevel@tonic-gate if (addr - km->km_text_va < km->km_text_size || 11657c478bd9Sstevel@tonic-gate addr - km->km_data_va < km->km_data_size || 11667c478bd9Sstevel@tonic-gate addr - km->km_bss_va < km->km_bss_size) 11677c478bd9Sstevel@tonic-gate return (kt_module_to_map(km, &kt->k_map)); 11687c478bd9Sstevel@tonic-gate } 11697c478bd9Sstevel@tonic-gate 11707c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_NOMAP); 11717c478bd9Sstevel@tonic-gate return (NULL); 11727c478bd9Sstevel@tonic-gate } 11737c478bd9Sstevel@tonic-gate 11747c478bd9Sstevel@tonic-gate const mdb_map_t * 11757c478bd9Sstevel@tonic-gate kt_name_to_map(mdb_tgt_t *t, const char *name) 11767c478bd9Sstevel@tonic-gate { 11777c478bd9Sstevel@tonic-gate kt_data_t *kt = t->t_data; 11787c478bd9Sstevel@tonic-gate kt_module_t *km; 11797c478bd9Sstevel@tonic-gate mdb_map_t m; 11807c478bd9Sstevel@tonic-gate 11817c478bd9Sstevel@tonic-gate /* 11827c478bd9Sstevel@tonic-gate * If name is MDB_TGT_OBJ_EXEC, return the first module on the list, 11837c478bd9Sstevel@tonic-gate * which will be unix since we keep k_modlist in load order. 11847c478bd9Sstevel@tonic-gate */ 11857c478bd9Sstevel@tonic-gate if (name == MDB_TGT_OBJ_EXEC) 11867c478bd9Sstevel@tonic-gate return (kt_module_to_map(mdb_list_next(&kt->k_modlist), &m)); 11877c478bd9Sstevel@tonic-gate 11887c478bd9Sstevel@tonic-gate if (name == MDB_TGT_OBJ_RTLD) 1189ae115bc7Smrj name = kt->k_rtld_name; 11907c478bd9Sstevel@tonic-gate 1191ae115bc7Smrj if ((km = kt_module_by_name(kt, name)) != NULL) 1192ae115bc7Smrj return (kt_module_to_map(km, &m)); 11937c478bd9Sstevel@tonic-gate 11947c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_NOOBJ); 11957c478bd9Sstevel@tonic-gate return (NULL); 11967c478bd9Sstevel@tonic-gate } 11977c478bd9Sstevel@tonic-gate 11987c478bd9Sstevel@tonic-gate static ctf_file_t * 11997c478bd9Sstevel@tonic-gate kt_load_ctfdata(mdb_tgt_t *t, kt_module_t *km) 12007c478bd9Sstevel@tonic-gate { 12017c478bd9Sstevel@tonic-gate kt_data_t *kt = t->t_data; 12027c478bd9Sstevel@tonic-gate int err; 12037c478bd9Sstevel@tonic-gate 12047c478bd9Sstevel@tonic-gate if (km->km_ctfp != NULL) 12057c478bd9Sstevel@tonic-gate return (km->km_ctfp); 12067c478bd9Sstevel@tonic-gate 1207892ad162SToomas Soome if (km->km_ctf_va == 0) { 12087c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_NOCTF); 12097c478bd9Sstevel@tonic-gate return (NULL); 12107c478bd9Sstevel@tonic-gate } 12117c478bd9Sstevel@tonic-gate 12127c478bd9Sstevel@tonic-gate if (km->km_symtab == NULL) 12137c478bd9Sstevel@tonic-gate kt_load_module(t->t_data, t, km); 12147c478bd9Sstevel@tonic-gate 12157c478bd9Sstevel@tonic-gate if ((km->km_ctf_buf = mdb_alloc(km->km_ctf_size, UM_NOSLEEP)) == NULL) { 12167c478bd9Sstevel@tonic-gate warn("failed to allocate memory to load %s debugging " 12177c478bd9Sstevel@tonic-gate "information", km->km_name); 12187c478bd9Sstevel@tonic-gate return (NULL); 12197c478bd9Sstevel@tonic-gate } 12207c478bd9Sstevel@tonic-gate 12217c478bd9Sstevel@tonic-gate if (mdb_tgt_vread(t, km->km_ctf_buf, km->km_ctf_size, 12227c478bd9Sstevel@tonic-gate km->km_ctf_va) != km->km_ctf_size) { 12237c478bd9Sstevel@tonic-gate warn("failed to read %lu bytes of debug data for %s at %p", 12247c478bd9Sstevel@tonic-gate (ulong_t)km->km_ctf_size, km->km_name, 12257c478bd9Sstevel@tonic-gate (void *)km->km_ctf_va); 12267c478bd9Sstevel@tonic-gate mdb_free(km->km_ctf_buf, km->km_ctf_size); 12277c478bd9Sstevel@tonic-gate km->km_ctf_buf = NULL; 12287c478bd9Sstevel@tonic-gate return (NULL); 12297c478bd9Sstevel@tonic-gate } 12307c478bd9Sstevel@tonic-gate 12317c478bd9Sstevel@tonic-gate if ((km->km_ctfp = mdb_ctf_bufopen((const void *)km->km_ctf_buf, 12327c478bd9Sstevel@tonic-gate km->km_ctf_size, km->km_symbuf, &km->km_symtab_hdr, 12337c478bd9Sstevel@tonic-gate km->km_strtab, &km->km_strtab_hdr, &err)) == NULL) { 12347c478bd9Sstevel@tonic-gate mdb_free(km->km_ctf_buf, km->km_ctf_size); 12357c478bd9Sstevel@tonic-gate km->km_ctf_buf = NULL; 12367c478bd9Sstevel@tonic-gate (void) set_errno(ctf_to_errno(err)); 12377c478bd9Sstevel@tonic-gate return (NULL); 12387c478bd9Sstevel@tonic-gate } 12397c478bd9Sstevel@tonic-gate 12407c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_KMOD, "loaded %lu bytes of CTF data for %s\n", 12417c478bd9Sstevel@tonic-gate (ulong_t)km->km_ctf_size, km->km_name); 12427c478bd9Sstevel@tonic-gate 12437c478bd9Sstevel@tonic-gate if (ctf_parent_name(km->km_ctfp) != NULL) { 12447c478bd9Sstevel@tonic-gate mdb_var_t *v; 12457c478bd9Sstevel@tonic-gate 12467c478bd9Sstevel@tonic-gate if ((v = mdb_nv_lookup(&kt->k_modules, 12477c478bd9Sstevel@tonic-gate ctf_parent_name(km->km_ctfp))) == NULL) { 12487c478bd9Sstevel@tonic-gate warn("failed to load CTF data for %s - parent %s not " 12497c478bd9Sstevel@tonic-gate "loaded\n", km->km_name, 12507c478bd9Sstevel@tonic-gate ctf_parent_name(km->km_ctfp)); 12517c478bd9Sstevel@tonic-gate } 12527c478bd9Sstevel@tonic-gate 12537c478bd9Sstevel@tonic-gate if (v != NULL) { 12547c478bd9Sstevel@tonic-gate kt_module_t *pm = mdb_nv_get_cookie(v); 12557c478bd9Sstevel@tonic-gate 12567c478bd9Sstevel@tonic-gate if (pm->km_ctfp == NULL) 12577c478bd9Sstevel@tonic-gate (void) kt_load_ctfdata(t, pm); 12587c478bd9Sstevel@tonic-gate 12597c478bd9Sstevel@tonic-gate if (pm->km_ctfp != NULL && ctf_import(km->km_ctfp, 12607c478bd9Sstevel@tonic-gate pm->km_ctfp) == CTF_ERR) { 12617c478bd9Sstevel@tonic-gate warn("failed to import parent types into " 12627c478bd9Sstevel@tonic-gate "%s: %s\n", km->km_name, 12637c478bd9Sstevel@tonic-gate ctf_errmsg(ctf_errno(km->km_ctfp))); 12647c478bd9Sstevel@tonic-gate } 12657c478bd9Sstevel@tonic-gate } 12667c478bd9Sstevel@tonic-gate } 12677c478bd9Sstevel@tonic-gate 12687c478bd9Sstevel@tonic-gate return (km->km_ctfp); 12697c478bd9Sstevel@tonic-gate } 12707c478bd9Sstevel@tonic-gate 12717c478bd9Sstevel@tonic-gate ctf_file_t * 12727c478bd9Sstevel@tonic-gate kt_addr_to_ctf(mdb_tgt_t *t, uintptr_t addr) 12737c478bd9Sstevel@tonic-gate { 12747c478bd9Sstevel@tonic-gate kt_data_t *kt = t->t_data; 12757c478bd9Sstevel@tonic-gate kt_module_t *km; 12767c478bd9Sstevel@tonic-gate 12777c478bd9Sstevel@tonic-gate for (km = mdb_list_next(&kt->k_modlist); km; km = mdb_list_next(km)) { 12787c478bd9Sstevel@tonic-gate if (addr - km->km_text_va < km->km_text_size || 12797c478bd9Sstevel@tonic-gate addr - km->km_data_va < km->km_data_size || 12807c478bd9Sstevel@tonic-gate addr - km->km_bss_va < km->km_bss_size) 12817c478bd9Sstevel@tonic-gate return (kt_load_ctfdata(t, km)); 12827c478bd9Sstevel@tonic-gate } 12837c478bd9Sstevel@tonic-gate 12847c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_NOMAP); 12857c478bd9Sstevel@tonic-gate return (NULL); 12867c478bd9Sstevel@tonic-gate } 12877c478bd9Sstevel@tonic-gate 12887c478bd9Sstevel@tonic-gate ctf_file_t * 12897c478bd9Sstevel@tonic-gate kt_name_to_ctf(mdb_tgt_t *t, const char *name) 12907c478bd9Sstevel@tonic-gate { 12917c478bd9Sstevel@tonic-gate kt_data_t *kt = t->t_data; 12927c478bd9Sstevel@tonic-gate kt_module_t *km; 12937c478bd9Sstevel@tonic-gate 12947c478bd9Sstevel@tonic-gate if (name == MDB_TGT_OBJ_EXEC) 1295ae115bc7Smrj name = KT_CTFPARENT; 12967c478bd9Sstevel@tonic-gate else if (name == MDB_TGT_OBJ_RTLD) 1297ae115bc7Smrj name = kt->k_rtld_name; 12987c478bd9Sstevel@tonic-gate 1299ae115bc7Smrj if ((km = kt_module_by_name(kt, name)) != NULL) 1300ae115bc7Smrj return (kt_load_ctfdata(t, km)); 13017c478bd9Sstevel@tonic-gate 13027c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_NOOBJ); 13037c478bd9Sstevel@tonic-gate return (NULL); 13047c478bd9Sstevel@tonic-gate } 13057c478bd9Sstevel@tonic-gate 1306843e1988Sjohnlev /*ARGSUSED*/ 13077c478bd9Sstevel@tonic-gate int 13087c478bd9Sstevel@tonic-gate kt_status(mdb_tgt_t *t, mdb_tgt_status_t *tsp) 13097c478bd9Sstevel@tonic-gate { 13107c478bd9Sstevel@tonic-gate kt_data_t *kt = t->t_data; 13117c478bd9Sstevel@tonic-gate bzero(tsp, sizeof (mdb_tgt_status_t)); 1312843e1988Sjohnlev tsp->st_state = (kt->k_xpv_domu || (kt->k_dumphdr != NULL)) ? 1313843e1988Sjohnlev MDB_TGT_DEAD : MDB_TGT_RUNNING; 13147c478bd9Sstevel@tonic-gate return (0); 13157c478bd9Sstevel@tonic-gate } 13167c478bd9Sstevel@tonic-gate 13177c478bd9Sstevel@tonic-gate static ssize_t 13187c478bd9Sstevel@tonic-gate kt_xd_dumphdr(mdb_tgt_t *t, void *buf, size_t nbytes) 13197c478bd9Sstevel@tonic-gate { 13207c478bd9Sstevel@tonic-gate kt_data_t *kt = t->t_data; 13217c478bd9Sstevel@tonic-gate 13227c478bd9Sstevel@tonic-gate if (buf == NULL && nbytes == 0) 13237c478bd9Sstevel@tonic-gate return (sizeof (dumphdr_t)); 13247c478bd9Sstevel@tonic-gate 13257c478bd9Sstevel@tonic-gate if (kt->k_dumphdr == NULL) 13267c478bd9Sstevel@tonic-gate return (set_errno(ENODATA)); 13277c478bd9Sstevel@tonic-gate 13287c478bd9Sstevel@tonic-gate nbytes = MIN(nbytes, sizeof (dumphdr_t)); 13297c478bd9Sstevel@tonic-gate bcopy(kt->k_dumphdr, buf, nbytes); 13307c478bd9Sstevel@tonic-gate 13317c478bd9Sstevel@tonic-gate return (nbytes); 13327c478bd9Sstevel@tonic-gate } 13337c478bd9Sstevel@tonic-gate 13347c478bd9Sstevel@tonic-gate void 13357c478bd9Sstevel@tonic-gate kt_destroy(mdb_tgt_t *t) 13367c478bd9Sstevel@tonic-gate { 13377c478bd9Sstevel@tonic-gate kt_data_t *kt = t->t_data; 13387c478bd9Sstevel@tonic-gate kt_module_t *km, *nkm; 13397c478bd9Sstevel@tonic-gate 13407c478bd9Sstevel@tonic-gate (void) mdb_module_unload(KT_MODULE, 0); 13417c478bd9Sstevel@tonic-gate 13427c478bd9Sstevel@tonic-gate if (kt->k_regs != NULL) 13437c478bd9Sstevel@tonic-gate mdb_free(kt->k_regs, kt->k_regsize); 13447c478bd9Sstevel@tonic-gate 13457c478bd9Sstevel@tonic-gate if (kt->k_symtab != NULL) 13467c478bd9Sstevel@tonic-gate mdb_gelf_symtab_destroy(kt->k_symtab); 13477c478bd9Sstevel@tonic-gate 13487c478bd9Sstevel@tonic-gate if (kt->k_dynsym != NULL) 13497c478bd9Sstevel@tonic-gate mdb_gelf_symtab_destroy(kt->k_dynsym); 13507c478bd9Sstevel@tonic-gate 13517c478bd9Sstevel@tonic-gate if (kt->k_dumphdr != NULL) 13527c478bd9Sstevel@tonic-gate mdb_free(kt->k_dumphdr, sizeof (dumphdr_t)); 13537c478bd9Sstevel@tonic-gate 13547c478bd9Sstevel@tonic-gate mdb_gelf_destroy(kt->k_file); 1355843e1988Sjohnlev 1356843e1988Sjohnlev (void) kt->k_kb_ops->kb_close(kt->k_cookie); 13577c478bd9Sstevel@tonic-gate 13587c478bd9Sstevel@tonic-gate for (km = mdb_list_next(&kt->k_modlist); km; km = nkm) { 13597c478bd9Sstevel@tonic-gate if (km->km_symtab) 13607c478bd9Sstevel@tonic-gate mdb_gelf_symtab_destroy(km->km_symtab); 13617c478bd9Sstevel@tonic-gate 13627c478bd9Sstevel@tonic-gate if (km->km_data) 13637c478bd9Sstevel@tonic-gate mdb_free(km->km_data, km->km_datasz); 13647c478bd9Sstevel@tonic-gate 13657c478bd9Sstevel@tonic-gate if (km->km_ctfp) 13667c478bd9Sstevel@tonic-gate ctf_close(km->km_ctfp); 13677c478bd9Sstevel@tonic-gate 13687c478bd9Sstevel@tonic-gate if (km->km_ctf_buf != NULL) 13697c478bd9Sstevel@tonic-gate mdb_free(km->km_ctf_buf, km->km_ctf_size); 13707c478bd9Sstevel@tonic-gate 13717c478bd9Sstevel@tonic-gate nkm = mdb_list_next(km); 13727c478bd9Sstevel@tonic-gate strfree(km->km_name); 13737c478bd9Sstevel@tonic-gate mdb_free(km, sizeof (kt_module_t)); 13747c478bd9Sstevel@tonic-gate } 13757c478bd9Sstevel@tonic-gate 13767c478bd9Sstevel@tonic-gate mdb_nv_destroy(&kt->k_modules); 13777c478bd9Sstevel@tonic-gate 13787c478bd9Sstevel@tonic-gate strfree(kt->k_kvmfile); 1379843e1988Sjohnlev if (kt->k_symfile != NULL) 1380843e1988Sjohnlev strfree(kt->k_symfile); 13817c478bd9Sstevel@tonic-gate 13827c478bd9Sstevel@tonic-gate mdb_free(kt, sizeof (kt_data_t)); 13837c478bd9Sstevel@tonic-gate } 13847c478bd9Sstevel@tonic-gate 13857c478bd9Sstevel@tonic-gate static int 13867c478bd9Sstevel@tonic-gate kt_data_stub(void) 13877c478bd9Sstevel@tonic-gate { 13887c478bd9Sstevel@tonic-gate return (-1); 13897c478bd9Sstevel@tonic-gate } 13907c478bd9Sstevel@tonic-gate 13917c478bd9Sstevel@tonic-gate int 13927c478bd9Sstevel@tonic-gate mdb_kvm_tgt_create(mdb_tgt_t *t, int argc, const char *argv[]) 13937c478bd9Sstevel@tonic-gate { 13947c478bd9Sstevel@tonic-gate kt_data_t *kt = mdb_zalloc(sizeof (kt_data_t), UM_SLEEP); 1395843e1988Sjohnlev mdb_kb_ops_t *kvm_kb_ops = libkvm_kb_ops(); 13967c478bd9Sstevel@tonic-gate int oflag = (t->t_flags & MDB_TGT_F_RDWR) ? O_RDWR : O_RDONLY; 13977c478bd9Sstevel@tonic-gate struct utsname uts; 13987c478bd9Sstevel@tonic-gate GElf_Sym sym; 13997c478bd9Sstevel@tonic-gate pgcnt_t pmem; 14007c478bd9Sstevel@tonic-gate 1401843e1988Sjohnlev 1402843e1988Sjohnlev if (argc == 2) { 1403843e1988Sjohnlev kt->k_symfile = strdup(argv[0]); 1404843e1988Sjohnlev kt->k_kvmfile = strdup(argv[1]); 1405843e1988Sjohnlev 1406843e1988Sjohnlev kt->k_cookie = kvm_kb_ops->kb_open(kt->k_symfile, 1407843e1988Sjohnlev kt->k_kvmfile, NULL, oflag, (char *)mdb.m_pname); 1408843e1988Sjohnlev 1409843e1988Sjohnlev if (kt->k_cookie == NULL) 1410843e1988Sjohnlev goto err; 1411843e1988Sjohnlev 1412843e1988Sjohnlev kt->k_xpv_domu = 0; 1413843e1988Sjohnlev kt->k_kb_ops = kvm_kb_ops; 1414843e1988Sjohnlev } else { 1415843e1988Sjohnlev #ifndef __x86 14167c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 1417843e1988Sjohnlev #else 1418843e1988Sjohnlev mdb_kb_ops_t *(*getops)(void); 14197c478bd9Sstevel@tonic-gate 1420843e1988Sjohnlev kt->k_symfile = NULL; 1421843e1988Sjohnlev kt->k_kvmfile = strdup(argv[0]); 14227c478bd9Sstevel@tonic-gate 1423843e1988Sjohnlev getops = (mdb_kb_ops_t *(*)())dlsym(RTLD_NEXT, "mdb_kb_ops"); 14247c478bd9Sstevel@tonic-gate 1425a576ab5bSrab /* 1426a576ab5bSrab * Load mdb_kb if it's not already loaded during 1427a576ab5bSrab * identification. 1428a576ab5bSrab */ 1429a576ab5bSrab if (getops == NULL) { 1430a576ab5bSrab (void) mdb_module_load("mdb_kb", 1431a576ab5bSrab MDB_MOD_GLOBAL | MDB_MOD_SILENT); 1432a576ab5bSrab getops = (mdb_kb_ops_t *(*)()) 1433a576ab5bSrab dlsym(RTLD_NEXT, "mdb_kb_ops"); 1434a576ab5bSrab } 1435a576ab5bSrab 1436843e1988Sjohnlev if (getops == NULL || (kt->k_kb_ops = getops()) == NULL) { 1437843e1988Sjohnlev warn("failed to load KVM backend ops\n"); 1438843e1988Sjohnlev goto err; 1439843e1988Sjohnlev } 1440843e1988Sjohnlev 1441843e1988Sjohnlev kt->k_cookie = kt->k_kb_ops->kb_open(NULL, kt->k_kvmfile, NULL, 1442843e1988Sjohnlev oflag, (char *)mdb.m_pname); 1443843e1988Sjohnlev 1444843e1988Sjohnlev if (kt->k_cookie == NULL) 1445843e1988Sjohnlev goto err; 1446843e1988Sjohnlev 1447843e1988Sjohnlev kt->k_xpv_domu = 1; 1448843e1988Sjohnlev #endif 14497c478bd9Sstevel@tonic-gate } 14507c478bd9Sstevel@tonic-gate 1451843e1988Sjohnlev if ((kt->k_fio = kt->k_kb_ops->kb_sym_io(kt->k_cookie, 1452843e1988Sjohnlev kt->k_symfile)) == NULL) 1453843e1988Sjohnlev goto err; 1454843e1988Sjohnlev 14557c478bd9Sstevel@tonic-gate if ((kt->k_file = mdb_gelf_create(kt->k_fio, 14567c478bd9Sstevel@tonic-gate ET_EXEC, GF_FILE)) == NULL) { 14577c478bd9Sstevel@tonic-gate mdb_io_destroy(kt->k_fio); 14587c478bd9Sstevel@tonic-gate goto err; 14597c478bd9Sstevel@tonic-gate } 14607c478bd9Sstevel@tonic-gate 14617c478bd9Sstevel@tonic-gate kt->k_symtab = 14627c478bd9Sstevel@tonic-gate mdb_gelf_symtab_create_file(kt->k_file, SHT_SYMTAB, MDB_TGT_SYMTAB); 14637c478bd9Sstevel@tonic-gate 14647c478bd9Sstevel@tonic-gate kt->k_dynsym = 14657c478bd9Sstevel@tonic-gate mdb_gelf_symtab_create_file(kt->k_file, SHT_DYNSYM, MDB_TGT_DYNSYM); 14667c478bd9Sstevel@tonic-gate 14677c478bd9Sstevel@tonic-gate if (mdb_gelf_symtab_lookup_by_name(kt->k_symtab, "kas", 14687c478bd9Sstevel@tonic-gate &sym, NULL) == -1) { 14697c478bd9Sstevel@tonic-gate warn("'kas' symbol is missing from kernel\n"); 14707c478bd9Sstevel@tonic-gate goto err; 14717c478bd9Sstevel@tonic-gate } 14727c478bd9Sstevel@tonic-gate 14737c478bd9Sstevel@tonic-gate kt->k_as = (struct as *)(uintptr_t)sym.st_value; 14747c478bd9Sstevel@tonic-gate 14757c478bd9Sstevel@tonic-gate if (mdb_gelf_symtab_lookup_by_name(kt->k_symtab, "platform", 14767c478bd9Sstevel@tonic-gate &sym, NULL) == -1) { 14777c478bd9Sstevel@tonic-gate warn("'platform' symbol is missing from kernel\n"); 14787c478bd9Sstevel@tonic-gate goto err; 14797c478bd9Sstevel@tonic-gate } 14807c478bd9Sstevel@tonic-gate 1481843e1988Sjohnlev if (kt->k_kb_ops->kb_kread(kt->k_cookie, sym.st_value, 14827c478bd9Sstevel@tonic-gate kt->k_platform, MAXNAMELEN) <= 0) { 14837c478bd9Sstevel@tonic-gate warn("failed to read 'platform' string from kernel"); 14847c478bd9Sstevel@tonic-gate goto err; 14857c478bd9Sstevel@tonic-gate } 14867c478bd9Sstevel@tonic-gate 14877c478bd9Sstevel@tonic-gate if (mdb_gelf_symtab_lookup_by_name(kt->k_symtab, "utsname", 14887c478bd9Sstevel@tonic-gate &sym, NULL) == -1) { 14897c478bd9Sstevel@tonic-gate warn("'utsname' symbol is missing from kernel\n"); 14907c478bd9Sstevel@tonic-gate goto err; 14917c478bd9Sstevel@tonic-gate } 14927c478bd9Sstevel@tonic-gate 1493843e1988Sjohnlev if (kt->k_kb_ops->kb_kread(kt->k_cookie, sym.st_value, &uts, 1494843e1988Sjohnlev sizeof (uts)) <= 0) { 14957c478bd9Sstevel@tonic-gate warn("failed to read 'utsname' struct from kernel"); 14967c478bd9Sstevel@tonic-gate goto err; 14977c478bd9Sstevel@tonic-gate } 14987c478bd9Sstevel@tonic-gate 14992c687d68SToomas Soome kt->k_dump_print_content = (void (*)())(uintptr_t)kt_data_stub; 15007c478bd9Sstevel@tonic-gate kt->k_dump_find_curproc = kt_data_stub; 15017c478bd9Sstevel@tonic-gate 15027c478bd9Sstevel@tonic-gate /* 15037c478bd9Sstevel@tonic-gate * We set k_ctfvalid based on the presence of the CTF vmem arena 15047c478bd9Sstevel@tonic-gate * symbol. The CTF members were added to the end of struct module at 15057c478bd9Sstevel@tonic-gate * the same time, so this allows us to know whether we can use them. 15067c478bd9Sstevel@tonic-gate */ 15077c478bd9Sstevel@tonic-gate if (mdb_gelf_symtab_lookup_by_name(kt->k_symtab, "ctf_arena", &sym, 15087c478bd9Sstevel@tonic-gate NULL) == 0 && !(mdb.m_flags & MDB_FL_NOCTF)) 15097c478bd9Sstevel@tonic-gate kt->k_ctfvalid = 1; 15107c478bd9Sstevel@tonic-gate 15117c478bd9Sstevel@tonic-gate (void) mdb_nv_create(&kt->k_modules, UM_SLEEP); 15127c478bd9Sstevel@tonic-gate t->t_pshandle = kt->k_cookie; 15137c478bd9Sstevel@tonic-gate t->t_data = kt; 15147c478bd9Sstevel@tonic-gate 15157c478bd9Sstevel@tonic-gate #if defined(__sparc) 15167c478bd9Sstevel@tonic-gate #if defined(__sparcv9) 15177c478bd9Sstevel@tonic-gate kt_sparcv9_init(t); 15187c478bd9Sstevel@tonic-gate #else 15197c478bd9Sstevel@tonic-gate kt_sparcv7_init(t); 15207c478bd9Sstevel@tonic-gate #endif 15217c478bd9Sstevel@tonic-gate #elif defined(__amd64) 15227c478bd9Sstevel@tonic-gate kt_amd64_init(t); 15237c478bd9Sstevel@tonic-gate #elif defined(__i386) 15247c478bd9Sstevel@tonic-gate kt_ia32_init(t); 15257c478bd9Sstevel@tonic-gate #else 15267c478bd9Sstevel@tonic-gate #error "unknown ISA" 15277c478bd9Sstevel@tonic-gate #endif 15287c478bd9Sstevel@tonic-gate 15297c478bd9Sstevel@tonic-gate /* 15307c478bd9Sstevel@tonic-gate * We read our representative thread ID (address) from the kernel's 15317c478bd9Sstevel@tonic-gate * global panic_thread. It will remain 0 if this is a live kernel. 15327c478bd9Sstevel@tonic-gate */ 15337c478bd9Sstevel@tonic-gate (void) mdb_tgt_readsym(t, MDB_TGT_AS_VIRT, &kt->k_tid, sizeof (void *), 15347c478bd9Sstevel@tonic-gate MDB_TGT_OBJ_EXEC, "panic_thread"); 15357c478bd9Sstevel@tonic-gate 15367c478bd9Sstevel@tonic-gate if ((mdb.m_flags & MDB_FL_ADB) && mdb_tgt_readsym(t, MDB_TGT_AS_VIRT, 15377c478bd9Sstevel@tonic-gate &pmem, sizeof (pmem), MDB_TGT_OBJ_EXEC, "physmem") == sizeof (pmem)) 15387c478bd9Sstevel@tonic-gate mdb_printf("physmem %lx\n", (ulong_t)pmem); 15397c478bd9Sstevel@tonic-gate 15407c478bd9Sstevel@tonic-gate /* 1541843e1988Sjohnlev * If this is not a live kernel or a hypervisor dump, read the dump 1542843e1988Sjohnlev * header. We don't have to sanity-check the header, as the open would 1543843e1988Sjohnlev * not have succeeded otherwise. 15447c478bd9Sstevel@tonic-gate */ 1545843e1988Sjohnlev if (!kt->k_xpv_domu && strcmp(kt->k_symfile, "/dev/ksyms") != 0) { 15467c478bd9Sstevel@tonic-gate mdb_io_t *vmcore; 15477c478bd9Sstevel@tonic-gate 15487c478bd9Sstevel@tonic-gate kt->k_dumphdr = mdb_alloc(sizeof (dumphdr_t), UM_SLEEP); 15497c478bd9Sstevel@tonic-gate 15507c478bd9Sstevel@tonic-gate if ((vmcore = mdb_fdio_create_path(NULL, kt->k_kvmfile, 15517c478bd9Sstevel@tonic-gate O_RDONLY, 0)) == NULL) { 15527c478bd9Sstevel@tonic-gate mdb_warn("failed to open %s", kt->k_kvmfile); 15537c478bd9Sstevel@tonic-gate goto err; 15547c478bd9Sstevel@tonic-gate } 15557c478bd9Sstevel@tonic-gate 15567c478bd9Sstevel@tonic-gate if (IOP_READ(vmcore, kt->k_dumphdr, sizeof (dumphdr_t)) != 15577c478bd9Sstevel@tonic-gate sizeof (dumphdr_t)) { 15587c478bd9Sstevel@tonic-gate mdb_warn("failed to read dump header"); 15597c478bd9Sstevel@tonic-gate mdb_io_destroy(vmcore); 15607c478bd9Sstevel@tonic-gate goto err; 15617c478bd9Sstevel@tonic-gate } 15627c478bd9Sstevel@tonic-gate 15637c478bd9Sstevel@tonic-gate mdb_io_destroy(vmcore); 15647c478bd9Sstevel@tonic-gate 15657c478bd9Sstevel@tonic-gate (void) mdb_tgt_xdata_insert(t, "dumphdr", 15667c478bd9Sstevel@tonic-gate "dump header structure", kt_xd_dumphdr); 15677c478bd9Sstevel@tonic-gate } 15687c478bd9Sstevel@tonic-gate 15697c478bd9Sstevel@tonic-gate return (0); 15707c478bd9Sstevel@tonic-gate 15717c478bd9Sstevel@tonic-gate err: 15727c478bd9Sstevel@tonic-gate if (kt->k_dumphdr != NULL) 15737c478bd9Sstevel@tonic-gate mdb_free(kt->k_dumphdr, sizeof (dumphdr_t)); 15747c478bd9Sstevel@tonic-gate 15757c478bd9Sstevel@tonic-gate if (kt->k_symtab != NULL) 15767c478bd9Sstevel@tonic-gate mdb_gelf_symtab_destroy(kt->k_symtab); 15777c478bd9Sstevel@tonic-gate 15787c478bd9Sstevel@tonic-gate if (kt->k_dynsym != NULL) 15797c478bd9Sstevel@tonic-gate mdb_gelf_symtab_destroy(kt->k_dynsym); 15807c478bd9Sstevel@tonic-gate 15817c478bd9Sstevel@tonic-gate if (kt->k_file != NULL) 15827c478bd9Sstevel@tonic-gate mdb_gelf_destroy(kt->k_file); 15837c478bd9Sstevel@tonic-gate 15847c478bd9Sstevel@tonic-gate if (kt->k_cookie != NULL) 1585843e1988Sjohnlev (void) kt->k_kb_ops->kb_close(kt->k_cookie); 15867c478bd9Sstevel@tonic-gate 15877c478bd9Sstevel@tonic-gate mdb_free(kt, sizeof (kt_data_t)); 15887c478bd9Sstevel@tonic-gate return (-1); 15897c478bd9Sstevel@tonic-gate } 1590ca3e8d88SDave Plauger 15911320caf7SBryan Cantrill int 15921320caf7SBryan Cantrill mdb_kvm_is_dump(mdb_io_t *io) 15931320caf7SBryan Cantrill { 15941320caf7SBryan Cantrill dumphdr_t h; 15951320caf7SBryan Cantrill 15961320caf7SBryan Cantrill (void) IOP_SEEK(io, (off64_t)0L, SEEK_SET); 15971320caf7SBryan Cantrill 15981320caf7SBryan Cantrill return (IOP_READ(io, &h, sizeof (dumphdr_t)) == sizeof (dumphdr_t) && 15991320caf7SBryan Cantrill h.dump_magic == DUMP_MAGIC); 16001320caf7SBryan Cantrill } 16011320caf7SBryan Cantrill 1602ca3e8d88SDave Plauger int 1603ca3e8d88SDave Plauger mdb_kvm_is_compressed_dump(mdb_io_t *io) 1604ca3e8d88SDave Plauger { 1605ca3e8d88SDave Plauger dumphdr_t h; 1606ca3e8d88SDave Plauger 16071320caf7SBryan Cantrill (void) IOP_SEEK(io, (off64_t)0L, SEEK_SET); 16081320caf7SBryan Cantrill 1609ca3e8d88SDave Plauger return (IOP_READ(io, &h, sizeof (dumphdr_t)) == sizeof (dumphdr_t) && 1610ca3e8d88SDave Plauger h.dump_magic == DUMP_MAGIC && 1611ca3e8d88SDave Plauger (h.dump_flags & DF_COMPRESSED) != 0); 1612ca3e8d88SDave Plauger } 1613