1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* 30*7c478bd9Sstevel@tonic-gate * User Process Target 31*7c478bd9Sstevel@tonic-gate * 32*7c478bd9Sstevel@tonic-gate * The user process target is invoked when the -u or -p command-line options 33*7c478bd9Sstevel@tonic-gate * are used, or when an ELF executable file or ELF core file is specified on 34*7c478bd9Sstevel@tonic-gate * the command-line. This target is also selected by default when no target 35*7c478bd9Sstevel@tonic-gate * options are present. In this case, it defaults the executable name to 36*7c478bd9Sstevel@tonic-gate * "a.out". If no process or core file is currently attached, the target 37*7c478bd9Sstevel@tonic-gate * functions as a kind of virtual /dev/zero (in accordance with adb(1) 38*7c478bd9Sstevel@tonic-gate * semantics); reads from the virtual address space return zeroes and writes 39*7c478bd9Sstevel@tonic-gate * fail silently. The proc target itself is designed as a wrapper around the 40*7c478bd9Sstevel@tonic-gate * services provided by libproc.so: t->t_pshandle is set to the struct 41*7c478bd9Sstevel@tonic-gate * ps_prochandle pointer returned as a handle by libproc. The target also 42*7c478bd9Sstevel@tonic-gate * opens the executable file itself using the MDB GElf services, for 43*7c478bd9Sstevel@tonic-gate * interpreting the .symtab and .dynsym if no libproc handle has been 44*7c478bd9Sstevel@tonic-gate * initialized, and for handling i/o to and from the object file. Currently, 45*7c478bd9Sstevel@tonic-gate * the only ISA-dependent portions of the proc target are the $r and ::fpregs 46*7c478bd9Sstevel@tonic-gate * dcmds, the callbacks for t_next() and t_step_out(), and the list of named 47*7c478bd9Sstevel@tonic-gate * registers; these are linked in from the proc_isadep.c file for each ISA and 48*7c478bd9Sstevel@tonic-gate * called from the common code in this file. 49*7c478bd9Sstevel@tonic-gate * 50*7c478bd9Sstevel@tonic-gate * The user process target implements complete user process control using the 51*7c478bd9Sstevel@tonic-gate * facilities provided by libproc.so. The MDB execution control model and 52*7c478bd9Sstevel@tonic-gate * an overview of software event management is described in mdb_target.c. The 53*7c478bd9Sstevel@tonic-gate * proc target implements breakpoints by replacing the instruction of interest 54*7c478bd9Sstevel@tonic-gate * with a trap instruction, and then restoring the original instruction to step 55*7c478bd9Sstevel@tonic-gate * over the breakpoint. The idea of replacing program text with instructions 56*7c478bd9Sstevel@tonic-gate * that transfer control to the debugger dates back as far as 1951 [1]. When 57*7c478bd9Sstevel@tonic-gate * the target stops, we replace each breakpoint with the original instruction 58*7c478bd9Sstevel@tonic-gate * as part of the disarm operation. This means that no special processing is 59*7c478bd9Sstevel@tonic-gate * required for t_vread() because the instrumented instructions will never be 60*7c478bd9Sstevel@tonic-gate * seen by the debugger once the target stops. Some debuggers have improved 61*7c478bd9Sstevel@tonic-gate * start/stop performance by leaving breakpoint traps in place and then 62*7c478bd9Sstevel@tonic-gate * handling a read from a breakpoint address as a special case. Although this 63*7c478bd9Sstevel@tonic-gate * improves efficiency for a source-level debugger, it runs somewhat contrary 64*7c478bd9Sstevel@tonic-gate * to the philosophy of the low-level debugger. Since we remove the 65*7c478bd9Sstevel@tonic-gate * instructions, users can apply other external debugging tools to the process 66*7c478bd9Sstevel@tonic-gate * once it has stopped (e.g. the proc(1) tools) and not be misled by MDB 67*7c478bd9Sstevel@tonic-gate * instrumentation. The tracing of faults, signals, system calls, and 68*7c478bd9Sstevel@tonic-gate * watchpoints and general process inspection is implemented directly using 69*7c478bd9Sstevel@tonic-gate * the mechanisms provided by /proc, as described originally in [2] and [3]. 70*7c478bd9Sstevel@tonic-gate * 71*7c478bd9Sstevel@tonic-gate * References 72*7c478bd9Sstevel@tonic-gate * 73*7c478bd9Sstevel@tonic-gate * [1] S. Gill, "The Diagnosis Of Mistakes In Programmes on the EDSAC", 74*7c478bd9Sstevel@tonic-gate * Proceedings of the Royal Society Series A Mathematical and Physical 75*7c478bd9Sstevel@tonic-gate * Sciences, Cambridge University Press, 206(1087), May 1951, pp. 538-554. 76*7c478bd9Sstevel@tonic-gate * 77*7c478bd9Sstevel@tonic-gate * [2] T.J. Killian, "Processes as Files", Proceedings of the USENIX Association 78*7c478bd9Sstevel@tonic-gate * Summer Conference, Salt Lake City, June 1984, pp. 203-207. 79*7c478bd9Sstevel@tonic-gate * 80*7c478bd9Sstevel@tonic-gate * [3] Roger Faulkner and Ron Gomes, "The Process File System and Process 81*7c478bd9Sstevel@tonic-gate * Model in UNIX System V", Proceedings of the USENIX Association 82*7c478bd9Sstevel@tonic-gate * Winter Conference, Dallas, January 1991, pp. 243-252. 83*7c478bd9Sstevel@tonic-gate */ 84*7c478bd9Sstevel@tonic-gate 85*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_proc.h> 86*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_disasm.h> 87*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_signal.h> 88*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_string.h> 89*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_module.h> 90*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_debug.h> 91*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_conf.h> 92*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_err.h> 93*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_types.h> 94*7c478bd9Sstevel@tonic-gate #include <mdb/mdb.h> 95*7c478bd9Sstevel@tonic-gate 96*7c478bd9Sstevel@tonic-gate #include <sys/utsname.h> 97*7c478bd9Sstevel@tonic-gate #include <sys/wait.h> 98*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 99*7c478bd9Sstevel@tonic-gate #include <termio.h> 100*7c478bd9Sstevel@tonic-gate #include <signal.h> 101*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 102*7c478bd9Sstevel@tonic-gate #include <string.h> 103*7c478bd9Sstevel@tonic-gate 104*7c478bd9Sstevel@tonic-gate #define PC_FAKE -1UL /* illegal pc value unequal 0 */ 105*7c478bd9Sstevel@tonic-gate 106*7c478bd9Sstevel@tonic-gate static const char PT_EXEC_PATH[] = "a.out"; /* Default executable */ 107*7c478bd9Sstevel@tonic-gate static const char PT_CORE_PATH[] = "core"; /* Default core file */ 108*7c478bd9Sstevel@tonic-gate 109*7c478bd9Sstevel@tonic-gate static const pt_ptl_ops_t proc_lwp_ops; 110*7c478bd9Sstevel@tonic-gate static const pt_ptl_ops_t proc_tdb_ops; 111*7c478bd9Sstevel@tonic-gate static const mdb_se_ops_t proc_brkpt_ops; 112*7c478bd9Sstevel@tonic-gate static const mdb_se_ops_t proc_wapt_ops; 113*7c478bd9Sstevel@tonic-gate 114*7c478bd9Sstevel@tonic-gate static int pt_setrun(mdb_tgt_t *, mdb_tgt_status_t *, int); 115*7c478bd9Sstevel@tonic-gate static void pt_activate_common(mdb_tgt_t *); 116*7c478bd9Sstevel@tonic-gate static mdb_tgt_vespec_f pt_ignore_sig; 117*7c478bd9Sstevel@tonic-gate static mdb_tgt_se_f pt_fork; 118*7c478bd9Sstevel@tonic-gate static mdb_tgt_se_f pt_exec; 119*7c478bd9Sstevel@tonic-gate 120*7c478bd9Sstevel@tonic-gate static int pt_lookup_by_name_thr(mdb_tgt_t *, const char *, 121*7c478bd9Sstevel@tonic-gate const char *, GElf_Sym *, mdb_syminfo_t *, mdb_tgt_tid_t); 122*7c478bd9Sstevel@tonic-gate static int tlsbase(mdb_tgt_t *, mdb_tgt_tid_t, Lmid_t, const char *, 123*7c478bd9Sstevel@tonic-gate psaddr_t *); 124*7c478bd9Sstevel@tonic-gate 125*7c478bd9Sstevel@tonic-gate /* 126*7c478bd9Sstevel@tonic-gate * The Perror_printf() function interposes on the default, empty libproc 127*7c478bd9Sstevel@tonic-gate * definition. It will be called to report additional information on complex 128*7c478bd9Sstevel@tonic-gate * errors, such as a corrupt core file. We just pass the args to vwarn. 129*7c478bd9Sstevel@tonic-gate */ 130*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 131*7c478bd9Sstevel@tonic-gate void 132*7c478bd9Sstevel@tonic-gate Perror_printf(struct ps_prochandle *P, const char *format, ...) 133*7c478bd9Sstevel@tonic-gate { 134*7c478bd9Sstevel@tonic-gate va_list alist; 135*7c478bd9Sstevel@tonic-gate 136*7c478bd9Sstevel@tonic-gate va_start(alist, format); 137*7c478bd9Sstevel@tonic-gate vwarn(format, alist); 138*7c478bd9Sstevel@tonic-gate va_end(alist); 139*7c478bd9Sstevel@tonic-gate } 140*7c478bd9Sstevel@tonic-gate 141*7c478bd9Sstevel@tonic-gate /* 142*7c478bd9Sstevel@tonic-gate * Open the specified i/o backend as the a.out executable file, and attempt to 143*7c478bd9Sstevel@tonic-gate * load its standard and dynamic symbol tables. Note that if mdb_gelf_create 144*7c478bd9Sstevel@tonic-gate * succeeds, io is assigned to p_fio and is automatically held by gelf_create. 145*7c478bd9Sstevel@tonic-gate */ 146*7c478bd9Sstevel@tonic-gate static mdb_gelf_file_t * 147*7c478bd9Sstevel@tonic-gate pt_open_aout(mdb_tgt_t *t, mdb_io_t *io) 148*7c478bd9Sstevel@tonic-gate { 149*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 150*7c478bd9Sstevel@tonic-gate GElf_Sym s1, s2; 151*7c478bd9Sstevel@tonic-gate 152*7c478bd9Sstevel@tonic-gate if ((pt->p_file = mdb_gelf_create(io, ET_NONE, GF_FILE)) == NULL) 153*7c478bd9Sstevel@tonic-gate return (NULL); 154*7c478bd9Sstevel@tonic-gate 155*7c478bd9Sstevel@tonic-gate pt->p_symtab = mdb_gelf_symtab_create_file(pt->p_file, 156*7c478bd9Sstevel@tonic-gate SHT_SYMTAB, MDB_TGT_SYMTAB); 157*7c478bd9Sstevel@tonic-gate pt->p_dynsym = mdb_gelf_symtab_create_file(pt->p_file, 158*7c478bd9Sstevel@tonic-gate SHT_DYNSYM, MDB_TGT_DYNSYM); 159*7c478bd9Sstevel@tonic-gate 160*7c478bd9Sstevel@tonic-gate /* 161*7c478bd9Sstevel@tonic-gate * If we've got an _start symbol with a zero size, prime the private 162*7c478bd9Sstevel@tonic-gate * symbol table with a copy of _start with its size set to the distance 163*7c478bd9Sstevel@tonic-gate * between _mcount and _start. We do this because DevPro has shipped 164*7c478bd9Sstevel@tonic-gate * the Intel crt1.o without proper .size directives for years, which 165*7c478bd9Sstevel@tonic-gate * precludes proper identification of _start in stack traces. 166*7c478bd9Sstevel@tonic-gate */ 167*7c478bd9Sstevel@tonic-gate if (mdb_gelf_symtab_lookup_by_name(pt->p_dynsym, "_start", &s1, 168*7c478bd9Sstevel@tonic-gate NULL) == 0 && s1.st_size == 0 && 169*7c478bd9Sstevel@tonic-gate GELF_ST_TYPE(s1.st_info) == STT_FUNC) { 170*7c478bd9Sstevel@tonic-gate if (mdb_gelf_symtab_lookup_by_name(pt->p_dynsym, "_mcount", 171*7c478bd9Sstevel@tonic-gate &s2, NULL) == 0 && GELF_ST_TYPE(s2.st_info) == STT_FUNC) { 172*7c478bd9Sstevel@tonic-gate s1.st_size = s2.st_value - s1.st_value; 173*7c478bd9Sstevel@tonic-gate mdb_gelf_symtab_insert(mdb.m_prsym, "_start", &s1); 174*7c478bd9Sstevel@tonic-gate } 175*7c478bd9Sstevel@tonic-gate } 176*7c478bd9Sstevel@tonic-gate 177*7c478bd9Sstevel@tonic-gate pt->p_fio = io; 178*7c478bd9Sstevel@tonic-gate return (pt->p_file); 179*7c478bd9Sstevel@tonic-gate } 180*7c478bd9Sstevel@tonic-gate 181*7c478bd9Sstevel@tonic-gate /* 182*7c478bd9Sstevel@tonic-gate * Destroy the symbol tables and GElf file object associated with p_fio. Note 183*7c478bd9Sstevel@tonic-gate * that we do not need to explicitly free p_fio: its reference count is 184*7c478bd9Sstevel@tonic-gate * automatically decremented by mdb_gelf_destroy, which will free it if needed. 185*7c478bd9Sstevel@tonic-gate */ 186*7c478bd9Sstevel@tonic-gate static void 187*7c478bd9Sstevel@tonic-gate pt_close_aout(mdb_tgt_t *t) 188*7c478bd9Sstevel@tonic-gate { 189*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 190*7c478bd9Sstevel@tonic-gate 191*7c478bd9Sstevel@tonic-gate if (pt->p_symtab != NULL) { 192*7c478bd9Sstevel@tonic-gate mdb_gelf_symtab_destroy(pt->p_symtab); 193*7c478bd9Sstevel@tonic-gate pt->p_symtab = NULL; 194*7c478bd9Sstevel@tonic-gate } 195*7c478bd9Sstevel@tonic-gate 196*7c478bd9Sstevel@tonic-gate if (pt->p_dynsym != NULL) { 197*7c478bd9Sstevel@tonic-gate mdb_gelf_symtab_destroy(pt->p_dynsym); 198*7c478bd9Sstevel@tonic-gate pt->p_dynsym = NULL; 199*7c478bd9Sstevel@tonic-gate } 200*7c478bd9Sstevel@tonic-gate 201*7c478bd9Sstevel@tonic-gate if (pt->p_file != NULL) { 202*7c478bd9Sstevel@tonic-gate mdb_gelf_destroy(pt->p_file); 203*7c478bd9Sstevel@tonic-gate pt->p_file = NULL; 204*7c478bd9Sstevel@tonic-gate } 205*7c478bd9Sstevel@tonic-gate 206*7c478bd9Sstevel@tonic-gate mdb_gelf_symtab_delete(mdb.m_prsym, "_start", NULL); 207*7c478bd9Sstevel@tonic-gate pt->p_fio = NULL; 208*7c478bd9Sstevel@tonic-gate } 209*7c478bd9Sstevel@tonic-gate 210*7c478bd9Sstevel@tonic-gate /* 211*7c478bd9Sstevel@tonic-gate * Pobject_iter callback that we use to search for the presence of libthread in 212*7c478bd9Sstevel@tonic-gate * order to load the corresponding libthread_db support. We derive the 213*7c478bd9Sstevel@tonic-gate * libthread_db path dynamically based on the libthread path. If libthread is 214*7c478bd9Sstevel@tonic-gate * found, this function returns 1 (and thus Pobject_iter aborts and returns 1) 215*7c478bd9Sstevel@tonic-gate * regardless of whether it was successful in loading the libthread_db support. 216*7c478bd9Sstevel@tonic-gate * If we iterate over all objects and no libthread is found, 0 is returned. 217*7c478bd9Sstevel@tonic-gate * Since libthread_db support was then merged into libc_db, we load either 218*7c478bd9Sstevel@tonic-gate * libc_db or libthread_db, depending on which library we see first. 219*7c478bd9Sstevel@tonic-gate */ 220*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 221*7c478bd9Sstevel@tonic-gate static int 222*7c478bd9Sstevel@tonic-gate thr_check(mdb_tgt_t *t, const prmap_t *pmp, const char *name) 223*7c478bd9Sstevel@tonic-gate { 224*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 225*7c478bd9Sstevel@tonic-gate const mdb_tdb_ops_t *ops; 226*7c478bd9Sstevel@tonic-gate char *p, *q; 227*7c478bd9Sstevel@tonic-gate 228*7c478bd9Sstevel@tonic-gate char path[MAXPATHLEN + 8]; /* +8 for "/64" "_db" and '\0' */ 229*7c478bd9Sstevel@tonic-gate 230*7c478bd9Sstevel@tonic-gate const char *const libs[] = { "/libc.so", "/libthread.so" }; 231*7c478bd9Sstevel@tonic-gate int libn; 232*7c478bd9Sstevel@tonic-gate 233*7c478bd9Sstevel@tonic-gate if (name == NULL) 234*7c478bd9Sstevel@tonic-gate return (0); /* no rtld_db object name; keep going */ 235*7c478bd9Sstevel@tonic-gate 236*7c478bd9Sstevel@tonic-gate for (libn = 0; libn < sizeof (libs) / sizeof (libs[0]); libn++) { 237*7c478bd9Sstevel@tonic-gate if ((p = strstr(name, libs[libn])) != NULL) 238*7c478bd9Sstevel@tonic-gate break; 239*7c478bd9Sstevel@tonic-gate } 240*7c478bd9Sstevel@tonic-gate 241*7c478bd9Sstevel@tonic-gate if (p == NULL) 242*7c478bd9Sstevel@tonic-gate return (0); /* no match; keep going */ 243*7c478bd9Sstevel@tonic-gate 244*7c478bd9Sstevel@tonic-gate (void) strncpy(path, name, MAXPATHLEN); 245*7c478bd9Sstevel@tonic-gate path[MAXPATHLEN] = '\0'; 246*7c478bd9Sstevel@tonic-gate q = strstr(path, libs[libn]); 247*7c478bd9Sstevel@tonic-gate ASSERT(q != NULL); 248*7c478bd9Sstevel@tonic-gate 249*7c478bd9Sstevel@tonic-gate /* 250*7c478bd9Sstevel@tonic-gate * If the 64-bit debugger is looking at a 32-bit victim, append /64 to 251*7c478bd9Sstevel@tonic-gate * the library directory name so we load the 64-bit version. 252*7c478bd9Sstevel@tonic-gate */ 253*7c478bd9Sstevel@tonic-gate if (Pstatus(t->t_pshandle)->pr_dmodel != PR_MODEL_NATIVE) { 254*7c478bd9Sstevel@tonic-gate (void) strcpy(q, "/64"); 255*7c478bd9Sstevel@tonic-gate q += 3; 256*7c478bd9Sstevel@tonic-gate (void) strcpy(q, p); 257*7c478bd9Sstevel@tonic-gate } 258*7c478bd9Sstevel@tonic-gate 259*7c478bd9Sstevel@tonic-gate p = strchr(p, '.'); 260*7c478bd9Sstevel@tonic-gate q = strchr(q, '.'); 261*7c478bd9Sstevel@tonic-gate (void) strcpy(q, "_db"); 262*7c478bd9Sstevel@tonic-gate q += 3; 263*7c478bd9Sstevel@tonic-gate (void) strcpy(q, p); 264*7c478bd9Sstevel@tonic-gate 265*7c478bd9Sstevel@tonic-gate if ((ops = mdb_tdb_load(path)) == NULL) { 266*7c478bd9Sstevel@tonic-gate if (libn != 0 || errno != ENOENT) 267*7c478bd9Sstevel@tonic-gate warn("failed to load %s", path); 268*7c478bd9Sstevel@tonic-gate goto err; 269*7c478bd9Sstevel@tonic-gate } 270*7c478bd9Sstevel@tonic-gate 271*7c478bd9Sstevel@tonic-gate if (ops == pt->p_tdb_ops) 272*7c478bd9Sstevel@tonic-gate return (1); /* no changes needed */ 273*7c478bd9Sstevel@tonic-gate 274*7c478bd9Sstevel@tonic-gate PTL_DTOR(t); 275*7c478bd9Sstevel@tonic-gate pt->p_tdb_ops = ops; 276*7c478bd9Sstevel@tonic-gate pt->p_ptl_ops = &proc_tdb_ops; 277*7c478bd9Sstevel@tonic-gate pt->p_ptl_hdl = NULL; 278*7c478bd9Sstevel@tonic-gate 279*7c478bd9Sstevel@tonic-gate if (PTL_CTOR(t) == -1) { 280*7c478bd9Sstevel@tonic-gate warn("failed to initialize %s", path); 281*7c478bd9Sstevel@tonic-gate goto err; 282*7c478bd9Sstevel@tonic-gate } 283*7c478bd9Sstevel@tonic-gate 284*7c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_TGT, "loaded %s for debugging %s\n", path, name); 285*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_status(t, &t->t_status); 286*7c478bd9Sstevel@tonic-gate return (1); 287*7c478bd9Sstevel@tonic-gate err: 288*7c478bd9Sstevel@tonic-gate PTL_DTOR(t); 289*7c478bd9Sstevel@tonic-gate pt->p_tdb_ops = NULL; 290*7c478bd9Sstevel@tonic-gate pt->p_ptl_ops = &proc_lwp_ops; 291*7c478bd9Sstevel@tonic-gate pt->p_ptl_hdl = NULL; 292*7c478bd9Sstevel@tonic-gate 293*7c478bd9Sstevel@tonic-gate if (libn != 0 || errno != ENOENT) { 294*7c478bd9Sstevel@tonic-gate warn("warning: debugger will only be able to " 295*7c478bd9Sstevel@tonic-gate "examine raw LWPs\n"); 296*7c478bd9Sstevel@tonic-gate } 297*7c478bd9Sstevel@tonic-gate 298*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_status(t, &t->t_status); 299*7c478bd9Sstevel@tonic-gate return (1); 300*7c478bd9Sstevel@tonic-gate } 301*7c478bd9Sstevel@tonic-gate 302*7c478bd9Sstevel@tonic-gate /* 303*7c478bd9Sstevel@tonic-gate * Whenever the link map is consistent following an add or delete event, we ask 304*7c478bd9Sstevel@tonic-gate * libproc to update its mappings, check to see if we need to load libthread_db, 305*7c478bd9Sstevel@tonic-gate * and then update breakpoints which have been mapped or unmapped. 306*7c478bd9Sstevel@tonic-gate */ 307*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 308*7c478bd9Sstevel@tonic-gate static void 309*7c478bd9Sstevel@tonic-gate pt_rtld_event(mdb_tgt_t *t, int vid, void *private) 310*7c478bd9Sstevel@tonic-gate { 311*7c478bd9Sstevel@tonic-gate struct ps_prochandle *P = t->t_pshandle; 312*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 313*7c478bd9Sstevel@tonic-gate rd_event_msg_t rdm; 314*7c478bd9Sstevel@tonic-gate int docontinue = 1; 315*7c478bd9Sstevel@tonic-gate 316*7c478bd9Sstevel@tonic-gate if (rd_event_getmsg(pt->p_rtld, &rdm) == RD_OK) { 317*7c478bd9Sstevel@tonic-gate 318*7c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_TGT, "rtld event type 0x%x state 0x%x\n", 319*7c478bd9Sstevel@tonic-gate rdm.type, rdm.u.state); 320*7c478bd9Sstevel@tonic-gate 321*7c478bd9Sstevel@tonic-gate if (rdm.type == RD_DLACTIVITY && rdm.u.state == RD_CONSISTENT) { 322*7c478bd9Sstevel@tonic-gate mdb_sespec_t *sep, *nsep = mdb_list_next(&t->t_active); 323*7c478bd9Sstevel@tonic-gate pt_brkpt_t *ptb; 324*7c478bd9Sstevel@tonic-gate 325*7c478bd9Sstevel@tonic-gate Pupdate_maps(P); 326*7c478bd9Sstevel@tonic-gate 327*7c478bd9Sstevel@tonic-gate if (Pobject_iter(P, (proc_map_f *)thr_check, t) == 0 && 328*7c478bd9Sstevel@tonic-gate pt->p_ptl_ops != &proc_lwp_ops) { 329*7c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_TGT, "unloading thread_db " 330*7c478bd9Sstevel@tonic-gate "support after dlclose\n"); 331*7c478bd9Sstevel@tonic-gate PTL_DTOR(t); 332*7c478bd9Sstevel@tonic-gate pt->p_tdb_ops = NULL; 333*7c478bd9Sstevel@tonic-gate pt->p_ptl_ops = &proc_lwp_ops; 334*7c478bd9Sstevel@tonic-gate pt->p_ptl_hdl = NULL; 335*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_status(t, &t->t_status); 336*7c478bd9Sstevel@tonic-gate } 337*7c478bd9Sstevel@tonic-gate 338*7c478bd9Sstevel@tonic-gate for (sep = nsep; sep != NULL; sep = nsep) { 339*7c478bd9Sstevel@tonic-gate nsep = mdb_list_next(sep); 340*7c478bd9Sstevel@tonic-gate ptb = sep->se_data; 341*7c478bd9Sstevel@tonic-gate 342*7c478bd9Sstevel@tonic-gate if (sep->se_ops == &proc_brkpt_ops && 343*7c478bd9Sstevel@tonic-gate Paddr_to_map(P, ptb->ptb_addr) == NULL) 344*7c478bd9Sstevel@tonic-gate mdb_tgt_sespec_idle_one(t, sep, 345*7c478bd9Sstevel@tonic-gate EMDB_NOMAP); 346*7c478bd9Sstevel@tonic-gate } 347*7c478bd9Sstevel@tonic-gate 348*7c478bd9Sstevel@tonic-gate if (!mdb_tgt_sespec_activate_all(t) && 349*7c478bd9Sstevel@tonic-gate (mdb.m_flags & MDB_FL_BPTNOSYMSTOP) && 350*7c478bd9Sstevel@tonic-gate pt->p_rtld_finished) { 351*7c478bd9Sstevel@tonic-gate /* 352*7c478bd9Sstevel@tonic-gate * We weren't able to activate the breakpoints. 353*7c478bd9Sstevel@tonic-gate * If so requested, we'll return without 354*7c478bd9Sstevel@tonic-gate * calling continue, thus throwing the user into 355*7c478bd9Sstevel@tonic-gate * the debugger. 356*7c478bd9Sstevel@tonic-gate */ 357*7c478bd9Sstevel@tonic-gate docontinue = 0; 358*7c478bd9Sstevel@tonic-gate } 359*7c478bd9Sstevel@tonic-gate 360*7c478bd9Sstevel@tonic-gate if (pt->p_rdstate == PT_RD_ADD) 361*7c478bd9Sstevel@tonic-gate pt->p_rdstate = PT_RD_CONSIST; 362*7c478bd9Sstevel@tonic-gate } 363*7c478bd9Sstevel@tonic-gate 364*7c478bd9Sstevel@tonic-gate if (rdm.type == RD_PREINIT) 365*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_sespec_activate_all(t); 366*7c478bd9Sstevel@tonic-gate 367*7c478bd9Sstevel@tonic-gate if (rdm.type == RD_POSTINIT) { 368*7c478bd9Sstevel@tonic-gate pt->p_rtld_finished = TRUE; 369*7c478bd9Sstevel@tonic-gate if (!mdb_tgt_sespec_activate_all(t) && 370*7c478bd9Sstevel@tonic-gate (mdb.m_flags & MDB_FL_BPTNOSYMSTOP)) { 371*7c478bd9Sstevel@tonic-gate /* 372*7c478bd9Sstevel@tonic-gate * Now that rtld has been initialized, we 373*7c478bd9Sstevel@tonic-gate * should be able to initialize all deferred 374*7c478bd9Sstevel@tonic-gate * breakpoints. If we can't, don't let the 375*7c478bd9Sstevel@tonic-gate * target continue. 376*7c478bd9Sstevel@tonic-gate */ 377*7c478bd9Sstevel@tonic-gate docontinue = 0; 378*7c478bd9Sstevel@tonic-gate } 379*7c478bd9Sstevel@tonic-gate } 380*7c478bd9Sstevel@tonic-gate 381*7c478bd9Sstevel@tonic-gate if (rdm.type == RD_DLACTIVITY && rdm.u.state == RD_ADD && 382*7c478bd9Sstevel@tonic-gate pt->p_rtld_finished) 383*7c478bd9Sstevel@tonic-gate pt->p_rdstate = MAX(pt->p_rdstate, PT_RD_ADD); 384*7c478bd9Sstevel@tonic-gate } 385*7c478bd9Sstevel@tonic-gate 386*7c478bd9Sstevel@tonic-gate if (docontinue) 387*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_continue(t, NULL); 388*7c478bd9Sstevel@tonic-gate } 389*7c478bd9Sstevel@tonic-gate 390*7c478bd9Sstevel@tonic-gate static void 391*7c478bd9Sstevel@tonic-gate pt_post_attach(mdb_tgt_t *t) 392*7c478bd9Sstevel@tonic-gate { 393*7c478bd9Sstevel@tonic-gate struct ps_prochandle *P = t->t_pshandle; 394*7c478bd9Sstevel@tonic-gate const lwpstatus_t *psp = &Pstatus(P)->pr_lwp; 395*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 396*7c478bd9Sstevel@tonic-gate int hflag = MDB_TGT_SPEC_HIDDEN; 397*7c478bd9Sstevel@tonic-gate 398*7c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_TGT, "attach pr_flags=0x%x pr_why=%d pr_what=%d\n", 399*7c478bd9Sstevel@tonic-gate psp->pr_flags, psp->pr_why, psp->pr_what); 400*7c478bd9Sstevel@tonic-gate 401*7c478bd9Sstevel@tonic-gate /* 402*7c478bd9Sstevel@tonic-gate * When we grab a process, the initial setting of p_rtld_finished 403*7c478bd9Sstevel@tonic-gate * should be false if the process was just created by exec; otherwise 404*7c478bd9Sstevel@tonic-gate * we permit unscoped references to resolve because we do not know how 405*7c478bd9Sstevel@tonic-gate * far the process has proceeded through linker initialization. 406*7c478bd9Sstevel@tonic-gate */ 407*7c478bd9Sstevel@tonic-gate if ((psp->pr_flags & PR_ISTOP) && psp->pr_why == PR_SYSEXIT && 408*7c478bd9Sstevel@tonic-gate psp->pr_errno == 0 && (psp->pr_what == SYS_exec || 409*7c478bd9Sstevel@tonic-gate psp->pr_what == SYS_execve)) { 410*7c478bd9Sstevel@tonic-gate if (mdb.m_target == NULL) { 411*7c478bd9Sstevel@tonic-gate warn("target performed exec of %s\n", 412*7c478bd9Sstevel@tonic-gate IOP_NAME(pt->p_fio)); 413*7c478bd9Sstevel@tonic-gate } 414*7c478bd9Sstevel@tonic-gate pt->p_rtld_finished = FALSE; 415*7c478bd9Sstevel@tonic-gate } else 416*7c478bd9Sstevel@tonic-gate pt->p_rtld_finished = TRUE; 417*7c478bd9Sstevel@tonic-gate 418*7c478bd9Sstevel@tonic-gate /* 419*7c478bd9Sstevel@tonic-gate * When we grab a process, if it is stopped by job control and part of 420*7c478bd9Sstevel@tonic-gate * the same session (i.e. same controlling tty), set MDB_FL_JOBCTL so 421*7c478bd9Sstevel@tonic-gate * we will know to bring it to the foreground when we continue it. 422*7c478bd9Sstevel@tonic-gate */ 423*7c478bd9Sstevel@tonic-gate if (mdb.m_term != NULL && (psp->pr_flags & PR_STOPPED) && 424*7c478bd9Sstevel@tonic-gate psp->pr_why == PR_JOBCONTROL && getsid(0) == Pstatus(P)->pr_sid) 425*7c478bd9Sstevel@tonic-gate mdb.m_flags |= MDB_FL_JOBCTL; 426*7c478bd9Sstevel@tonic-gate 427*7c478bd9Sstevel@tonic-gate /* 428*7c478bd9Sstevel@tonic-gate * When we grab control of a live process, set F_RDWR so that the 429*7c478bd9Sstevel@tonic-gate * target layer permits writes to the target's address space. 430*7c478bd9Sstevel@tonic-gate */ 431*7c478bd9Sstevel@tonic-gate t->t_flags |= MDB_TGT_F_RDWR; 432*7c478bd9Sstevel@tonic-gate 433*7c478bd9Sstevel@tonic-gate (void) Pfault(P, FLTBPT, TRUE); /* always trace breakpoints */ 434*7c478bd9Sstevel@tonic-gate (void) Pfault(P, FLTWATCH, TRUE); /* always trace watchpoints */ 435*7c478bd9Sstevel@tonic-gate (void) Pfault(P, FLTTRACE, TRUE); /* always trace single-step */ 436*7c478bd9Sstevel@tonic-gate 437*7c478bd9Sstevel@tonic-gate (void) Punsetflags(P, PR_ASYNC); /* require synchronous mode */ 438*7c478bd9Sstevel@tonic-gate (void) Psetflags(P, PR_BPTADJ); /* always adjust eip on x86 */ 439*7c478bd9Sstevel@tonic-gate (void) Psetflags(P, PR_FORK); /* inherit tracing on fork */ 440*7c478bd9Sstevel@tonic-gate 441*7c478bd9Sstevel@tonic-gate /* 442*7c478bd9Sstevel@tonic-gate * Install event specifiers to track fork and exec activities: 443*7c478bd9Sstevel@tonic-gate */ 444*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_sysexit(t, SYS_forkall, hflag, pt_fork, NULL); 445*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_sysexit(t, SYS_fork1, hflag, pt_fork, NULL); 446*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_sysexit(t, SYS_vfork, hflag, pt_fork, NULL); 447*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_sysexit(t, SYS_exec, hflag, pt_exec, NULL); 448*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_sysexit(t, SYS_execve, hflag, pt_exec, NULL); 449*7c478bd9Sstevel@tonic-gate 450*7c478bd9Sstevel@tonic-gate /* 451*7c478bd9Sstevel@tonic-gate * Attempt to instantiate the librtld_db agent and set breakpoints 452*7c478bd9Sstevel@tonic-gate * to track rtld activity. We will legitimately fail to instantiate 453*7c478bd9Sstevel@tonic-gate * the rtld_db agent if the target is statically linked. 454*7c478bd9Sstevel@tonic-gate */ 455*7c478bd9Sstevel@tonic-gate if (pt->p_rtld == NULL && (pt->p_rtld = Prd_agent(P)) != NULL) { 456*7c478bd9Sstevel@tonic-gate rd_notify_t rdn; 457*7c478bd9Sstevel@tonic-gate rd_err_e err; 458*7c478bd9Sstevel@tonic-gate 459*7c478bd9Sstevel@tonic-gate if ((err = rd_event_enable(pt->p_rtld, TRUE)) != RD_OK) { 460*7c478bd9Sstevel@tonic-gate warn("failed to enable rtld_db event tracing: %s\n", 461*7c478bd9Sstevel@tonic-gate rd_errstr(err)); 462*7c478bd9Sstevel@tonic-gate goto out; 463*7c478bd9Sstevel@tonic-gate } 464*7c478bd9Sstevel@tonic-gate 465*7c478bd9Sstevel@tonic-gate if ((err = rd_event_addr(pt->p_rtld, RD_PREINIT, 466*7c478bd9Sstevel@tonic-gate &rdn)) == RD_OK && rdn.type == RD_NOTIFY_BPT) { 467*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_vbrkpt(t, rdn.u.bptaddr, 468*7c478bd9Sstevel@tonic-gate hflag, pt_rtld_event, NULL); 469*7c478bd9Sstevel@tonic-gate } else { 470*7c478bd9Sstevel@tonic-gate warn("failed to install rtld_db preinit tracing: %s\n", 471*7c478bd9Sstevel@tonic-gate rd_errstr(err)); 472*7c478bd9Sstevel@tonic-gate } 473*7c478bd9Sstevel@tonic-gate 474*7c478bd9Sstevel@tonic-gate if ((err = rd_event_addr(pt->p_rtld, RD_POSTINIT, 475*7c478bd9Sstevel@tonic-gate &rdn)) == RD_OK && rdn.type == RD_NOTIFY_BPT) { 476*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_vbrkpt(t, rdn.u.bptaddr, 477*7c478bd9Sstevel@tonic-gate hflag, pt_rtld_event, NULL); 478*7c478bd9Sstevel@tonic-gate } else { 479*7c478bd9Sstevel@tonic-gate warn("failed to install rtld_db postinit tracing: %s\n", 480*7c478bd9Sstevel@tonic-gate rd_errstr(err)); 481*7c478bd9Sstevel@tonic-gate } 482*7c478bd9Sstevel@tonic-gate 483*7c478bd9Sstevel@tonic-gate if ((err = rd_event_addr(pt->p_rtld, RD_DLACTIVITY, 484*7c478bd9Sstevel@tonic-gate &rdn)) == RD_OK && rdn.type == RD_NOTIFY_BPT) { 485*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_vbrkpt(t, rdn.u.bptaddr, 486*7c478bd9Sstevel@tonic-gate hflag, pt_rtld_event, NULL); 487*7c478bd9Sstevel@tonic-gate } else { 488*7c478bd9Sstevel@tonic-gate warn("failed to install rtld_db activity tracing: %s\n", 489*7c478bd9Sstevel@tonic-gate rd_errstr(err)); 490*7c478bd9Sstevel@tonic-gate } 491*7c478bd9Sstevel@tonic-gate } 492*7c478bd9Sstevel@tonic-gate out: 493*7c478bd9Sstevel@tonic-gate Pupdate_maps(P); 494*7c478bd9Sstevel@tonic-gate Psync(P); 495*7c478bd9Sstevel@tonic-gate 496*7c478bd9Sstevel@tonic-gate /* 497*7c478bd9Sstevel@tonic-gate * If librtld_db failed to initialize due to an error or because we are 498*7c478bd9Sstevel@tonic-gate * debugging a statically linked executable, allow unscoped references. 499*7c478bd9Sstevel@tonic-gate */ 500*7c478bd9Sstevel@tonic-gate if (pt->p_rtld == NULL) 501*7c478bd9Sstevel@tonic-gate pt->p_rtld_finished = TRUE; 502*7c478bd9Sstevel@tonic-gate 503*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_sespec_activate_all(t); 504*7c478bd9Sstevel@tonic-gate } 505*7c478bd9Sstevel@tonic-gate 506*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 507*7c478bd9Sstevel@tonic-gate static int 508*7c478bd9Sstevel@tonic-gate pt_vespec_delete(mdb_tgt_t *t, void *private, int id, void *data) 509*7c478bd9Sstevel@tonic-gate { 510*7c478bd9Sstevel@tonic-gate if (id < 0) { 511*7c478bd9Sstevel@tonic-gate ASSERT(data == NULL); /* we don't use any ve_data */ 512*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_vespec_delete(t, id); 513*7c478bd9Sstevel@tonic-gate } 514*7c478bd9Sstevel@tonic-gate return (0); 515*7c478bd9Sstevel@tonic-gate } 516*7c478bd9Sstevel@tonic-gate 517*7c478bd9Sstevel@tonic-gate static void 518*7c478bd9Sstevel@tonic-gate pt_pre_detach(mdb_tgt_t *t, int clear_matched) 519*7c478bd9Sstevel@tonic-gate { 520*7c478bd9Sstevel@tonic-gate const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp; 521*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 522*7c478bd9Sstevel@tonic-gate long cmd = 0; 523*7c478bd9Sstevel@tonic-gate 524*7c478bd9Sstevel@tonic-gate /* 525*7c478bd9Sstevel@tonic-gate * If we are about to release the process and it is stopped on a traced 526*7c478bd9Sstevel@tonic-gate * SIGINT, breakpoint fault, single-step fault, or watchpoint, make 527*7c478bd9Sstevel@tonic-gate * sure to clear this event prior to releasing the process so that it 528*7c478bd9Sstevel@tonic-gate * does not subsequently reissue the fault and die from SIGTRAP. 529*7c478bd9Sstevel@tonic-gate */ 530*7c478bd9Sstevel@tonic-gate if (psp->pr_flags & PR_ISTOP) { 531*7c478bd9Sstevel@tonic-gate if (psp->pr_why == PR_FAULTED && (psp->pr_what == FLTBPT || 532*7c478bd9Sstevel@tonic-gate psp->pr_what == FLTTRACE || psp->pr_what == FLTWATCH)) 533*7c478bd9Sstevel@tonic-gate cmd = PCCFAULT; 534*7c478bd9Sstevel@tonic-gate else if (psp->pr_why == PR_SIGNALLED && psp->pr_what == SIGINT) 535*7c478bd9Sstevel@tonic-gate cmd = PCCSIG; 536*7c478bd9Sstevel@tonic-gate 537*7c478bd9Sstevel@tonic-gate if (cmd != 0) 538*7c478bd9Sstevel@tonic-gate (void) write(Pctlfd(t->t_pshandle), &cmd, sizeof (cmd)); 539*7c478bd9Sstevel@tonic-gate } 540*7c478bd9Sstevel@tonic-gate 541*7c478bd9Sstevel@tonic-gate if (Pstate(t->t_pshandle) == PS_UNDEAD) 542*7c478bd9Sstevel@tonic-gate (void) waitpid(Pstatus(t->t_pshandle)->pr_pid, NULL, WNOHANG); 543*7c478bd9Sstevel@tonic-gate 544*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_vespec_iter(t, pt_vespec_delete, NULL); 545*7c478bd9Sstevel@tonic-gate mdb_tgt_sespec_idle_all(t, EMDB_NOPROC, clear_matched); 546*7c478bd9Sstevel@tonic-gate 547*7c478bd9Sstevel@tonic-gate if (pt->p_fio != pt->p_aout_fio) { 548*7c478bd9Sstevel@tonic-gate pt_close_aout(t); 549*7c478bd9Sstevel@tonic-gate (void) pt_open_aout(t, pt->p_aout_fio); 550*7c478bd9Sstevel@tonic-gate } 551*7c478bd9Sstevel@tonic-gate 552*7c478bd9Sstevel@tonic-gate PTL_DTOR(t); 553*7c478bd9Sstevel@tonic-gate pt->p_tdb_ops = NULL; 554*7c478bd9Sstevel@tonic-gate pt->p_ptl_ops = &proc_lwp_ops; 555*7c478bd9Sstevel@tonic-gate pt->p_ptl_hdl = NULL; 556*7c478bd9Sstevel@tonic-gate 557*7c478bd9Sstevel@tonic-gate pt->p_rtld = NULL; 558*7c478bd9Sstevel@tonic-gate pt->p_signal = 0; 559*7c478bd9Sstevel@tonic-gate pt->p_rtld_finished = FALSE; 560*7c478bd9Sstevel@tonic-gate pt->p_rdstate = PT_RD_NONE; 561*7c478bd9Sstevel@tonic-gate } 562*7c478bd9Sstevel@tonic-gate 563*7c478bd9Sstevel@tonic-gate static void 564*7c478bd9Sstevel@tonic-gate pt_release_parents(mdb_tgt_t *t) 565*7c478bd9Sstevel@tonic-gate { 566*7c478bd9Sstevel@tonic-gate struct ps_prochandle *P = t->t_pshandle; 567*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 568*7c478bd9Sstevel@tonic-gate 569*7c478bd9Sstevel@tonic-gate mdb_sespec_t *sep; 570*7c478bd9Sstevel@tonic-gate pt_vforkp_t *vfp; 571*7c478bd9Sstevel@tonic-gate 572*7c478bd9Sstevel@tonic-gate while ((vfp = mdb_list_next(&pt->p_vforkp)) != NULL) { 573*7c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_TGT, "releasing vfork parent %d\n", 574*7c478bd9Sstevel@tonic-gate (int)Pstatus(vfp->p_pshandle)->pr_pid); 575*7c478bd9Sstevel@tonic-gate 576*7c478bd9Sstevel@tonic-gate /* 577*7c478bd9Sstevel@tonic-gate * To release vfork parents, we must also wipe out any armed 578*7c478bd9Sstevel@tonic-gate * events in the parent by switching t_pshandle and calling 579*7c478bd9Sstevel@tonic-gate * se_disarm(). Do not change states or lose the matched list. 580*7c478bd9Sstevel@tonic-gate */ 581*7c478bd9Sstevel@tonic-gate t->t_pshandle = vfp->p_pshandle; 582*7c478bd9Sstevel@tonic-gate 583*7c478bd9Sstevel@tonic-gate for (sep = mdb_list_next(&t->t_active); sep != NULL; 584*7c478bd9Sstevel@tonic-gate sep = mdb_list_next(sep)) { 585*7c478bd9Sstevel@tonic-gate if (sep->se_state == MDB_TGT_SPEC_ARMED) 586*7c478bd9Sstevel@tonic-gate (void) sep->se_ops->se_disarm(t, sep); 587*7c478bd9Sstevel@tonic-gate } 588*7c478bd9Sstevel@tonic-gate 589*7c478bd9Sstevel@tonic-gate t->t_pshandle = P; 590*7c478bd9Sstevel@tonic-gate 591*7c478bd9Sstevel@tonic-gate Prelease(vfp->p_pshandle, PRELEASE_CLEAR); 592*7c478bd9Sstevel@tonic-gate mdb_list_delete(&pt->p_vforkp, vfp); 593*7c478bd9Sstevel@tonic-gate mdb_free(vfp, sizeof (pt_vforkp_t)); 594*7c478bd9Sstevel@tonic-gate } 595*7c478bd9Sstevel@tonic-gate } 596*7c478bd9Sstevel@tonic-gate 597*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 598*7c478bd9Sstevel@tonic-gate static void 599*7c478bd9Sstevel@tonic-gate pt_fork(mdb_tgt_t *t, int vid, void *private) 600*7c478bd9Sstevel@tonic-gate { 601*7c478bd9Sstevel@tonic-gate struct ps_prochandle *P = t->t_pshandle; 602*7c478bd9Sstevel@tonic-gate const lwpstatus_t *psp = &Pstatus(P)->pr_lwp; 603*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 604*7c478bd9Sstevel@tonic-gate mdb_sespec_t *sep; 605*7c478bd9Sstevel@tonic-gate 606*7c478bd9Sstevel@tonic-gate int follow_parent = mdb.m_forkmode != MDB_FM_CHILD; 607*7c478bd9Sstevel@tonic-gate int is_vfork = psp->pr_what == SYS_vfork; 608*7c478bd9Sstevel@tonic-gate 609*7c478bd9Sstevel@tonic-gate struct ps_prochandle *C; 610*7c478bd9Sstevel@tonic-gate const lwpstatus_t *csp; 611*7c478bd9Sstevel@tonic-gate char sysname[32]; 612*7c478bd9Sstevel@tonic-gate int gcode; 613*7c478bd9Sstevel@tonic-gate char c; 614*7c478bd9Sstevel@tonic-gate 615*7c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_TGT, "parent %s: errno=%d rv1=%ld rv2=%ld\n", 616*7c478bd9Sstevel@tonic-gate proc_sysname(psp->pr_what, sysname, sizeof (sysname)), 617*7c478bd9Sstevel@tonic-gate psp->pr_errno, psp->pr_rval1, psp->pr_rval2); 618*7c478bd9Sstevel@tonic-gate 619*7c478bd9Sstevel@tonic-gate if (psp->pr_errno != 0) { 620*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_continue(t, NULL); 621*7c478bd9Sstevel@tonic-gate return; /* fork failed */ 622*7c478bd9Sstevel@tonic-gate } 623*7c478bd9Sstevel@tonic-gate 624*7c478bd9Sstevel@tonic-gate /* 625*7c478bd9Sstevel@tonic-gate * If forkmode is ASK and stdout is a terminal, then ask the user to 626*7c478bd9Sstevel@tonic-gate * explicitly set the fork behavior for this particular fork. 627*7c478bd9Sstevel@tonic-gate */ 628*7c478bd9Sstevel@tonic-gate if (mdb.m_forkmode == MDB_FM_ASK && mdb.m_term != NULL) { 629*7c478bd9Sstevel@tonic-gate mdb_iob_printf(mdb.m_err, "%s: %s detected: follow (p)arent " 630*7c478bd9Sstevel@tonic-gate "or (c)hild? ", mdb.m_pname, sysname); 631*7c478bd9Sstevel@tonic-gate mdb_iob_flush(mdb.m_err); 632*7c478bd9Sstevel@tonic-gate 633*7c478bd9Sstevel@tonic-gate while (IOP_READ(mdb.m_term, &c, sizeof (c)) == sizeof (c)) { 634*7c478bd9Sstevel@tonic-gate if (c == 'P' || c == 'p') { 635*7c478bd9Sstevel@tonic-gate mdb_iob_printf(mdb.m_err, "%c\n", c); 636*7c478bd9Sstevel@tonic-gate follow_parent = TRUE; 637*7c478bd9Sstevel@tonic-gate break; 638*7c478bd9Sstevel@tonic-gate } else if (c == 'C' || c == 'c') { 639*7c478bd9Sstevel@tonic-gate mdb_iob_printf(mdb.m_err, "%c\n", c); 640*7c478bd9Sstevel@tonic-gate follow_parent = FALSE; 641*7c478bd9Sstevel@tonic-gate break; 642*7c478bd9Sstevel@tonic-gate } 643*7c478bd9Sstevel@tonic-gate } 644*7c478bd9Sstevel@tonic-gate } 645*7c478bd9Sstevel@tonic-gate 646*7c478bd9Sstevel@tonic-gate /* 647*7c478bd9Sstevel@tonic-gate * The parent is now stopped on exit from its fork call. We must now 648*7c478bd9Sstevel@tonic-gate * grab the child on its return from fork in order to manipulate it. 649*7c478bd9Sstevel@tonic-gate */ 650*7c478bd9Sstevel@tonic-gate if ((C = Pgrab(psp->pr_rval1, PGRAB_RETAIN, &gcode)) == NULL) { 651*7c478bd9Sstevel@tonic-gate warn("failed to grab forked child process %ld: %s\n", 652*7c478bd9Sstevel@tonic-gate psp->pr_rval1, Pgrab_error(gcode)); 653*7c478bd9Sstevel@tonic-gate return; /* just stop if we failed to grab the child */ 654*7c478bd9Sstevel@tonic-gate } 655*7c478bd9Sstevel@tonic-gate 656*7c478bd9Sstevel@tonic-gate /* 657*7c478bd9Sstevel@tonic-gate * We may have grabbed the child and stopped it prematurely before it 658*7c478bd9Sstevel@tonic-gate * stopped on exit from fork. If so, wait up to 1 sec for it to settle. 659*7c478bd9Sstevel@tonic-gate */ 660*7c478bd9Sstevel@tonic-gate if (Pstatus(C)->pr_lwp.pr_why != PR_SYSEXIT) 661*7c478bd9Sstevel@tonic-gate (void) Pwait(C, MILLISEC); 662*7c478bd9Sstevel@tonic-gate 663*7c478bd9Sstevel@tonic-gate csp = &Pstatus(C)->pr_lwp; 664*7c478bd9Sstevel@tonic-gate 665*7c478bd9Sstevel@tonic-gate if (csp->pr_why != PR_SYSEXIT || (csp->pr_what != SYS_forkall && 666*7c478bd9Sstevel@tonic-gate csp->pr_what != SYS_fork1 && csp->pr_what != SYS_vfork)) { 667*7c478bd9Sstevel@tonic-gate warn("forked child process %ld did not stop on exit from " 668*7c478bd9Sstevel@tonic-gate "fork as expected\n", psp->pr_rval1); 669*7c478bd9Sstevel@tonic-gate } 670*7c478bd9Sstevel@tonic-gate 671*7c478bd9Sstevel@tonic-gate warn("target forked child process %ld (debugger following %s)\n", 672*7c478bd9Sstevel@tonic-gate psp->pr_rval1, follow_parent ? "parent" : "child"); 673*7c478bd9Sstevel@tonic-gate 674*7c478bd9Sstevel@tonic-gate (void) Punsetflags(C, PR_ASYNC); /* require synchronous mode */ 675*7c478bd9Sstevel@tonic-gate (void) Psetflags(C, PR_BPTADJ); /* always adjust eip on x86 */ 676*7c478bd9Sstevel@tonic-gate (void) Prd_agent(C); /* initialize librtld_db */ 677*7c478bd9Sstevel@tonic-gate 678*7c478bd9Sstevel@tonic-gate /* 679*7c478bd9Sstevel@tonic-gate * At the time pt_fork() is called, the target event engine has already 680*7c478bd9Sstevel@tonic-gate * disarmed the specifiers on the active list, clearing out events in 681*7c478bd9Sstevel@tonic-gate * the parent process. However, this means that events that change 682*7c478bd9Sstevel@tonic-gate * the address space (e.g. breakpoints) have not been effectively 683*7c478bd9Sstevel@tonic-gate * disarmed in the child since its address space reflects the state of 684*7c478bd9Sstevel@tonic-gate * the process at the time of fork when events were armed. We must 685*7c478bd9Sstevel@tonic-gate * therefore handle this as a special case and re-invoke the disarm 686*7c478bd9Sstevel@tonic-gate * callback of each active specifier to clean out the child process. 687*7c478bd9Sstevel@tonic-gate */ 688*7c478bd9Sstevel@tonic-gate if (!is_vfork) { 689*7c478bd9Sstevel@tonic-gate for (t->t_pshandle = C, sep = mdb_list_next(&t->t_active); 690*7c478bd9Sstevel@tonic-gate sep != NULL; sep = mdb_list_next(sep)) { 691*7c478bd9Sstevel@tonic-gate if (sep->se_state == MDB_TGT_SPEC_ACTIVE) 692*7c478bd9Sstevel@tonic-gate (void) sep->se_ops->se_disarm(t, sep); 693*7c478bd9Sstevel@tonic-gate } 694*7c478bd9Sstevel@tonic-gate 695*7c478bd9Sstevel@tonic-gate t->t_pshandle = P; /* restore pshandle to parent */ 696*7c478bd9Sstevel@tonic-gate } 697*7c478bd9Sstevel@tonic-gate 698*7c478bd9Sstevel@tonic-gate /* 699*7c478bd9Sstevel@tonic-gate * If we're following the parent process, we need to temporarily change 700*7c478bd9Sstevel@tonic-gate * t_pshandle to refer to the child handle C so that we can clear out 701*7c478bd9Sstevel@tonic-gate * all the events in the child prior to releasing it below. If we are 702*7c478bd9Sstevel@tonic-gate * tracing a vfork, we also need to explicitly wait for the child to 703*7c478bd9Sstevel@tonic-gate * exec, exit, or die before we can reset and continue the parent. We 704*7c478bd9Sstevel@tonic-gate * avoid having to deal with the vfork child forking again by clearing 705*7c478bd9Sstevel@tonic-gate * PR_FORK and setting PR_RLC; if it does fork it will effectively be 706*7c478bd9Sstevel@tonic-gate * released from our control and we will continue following the parent. 707*7c478bd9Sstevel@tonic-gate */ 708*7c478bd9Sstevel@tonic-gate if (follow_parent) { 709*7c478bd9Sstevel@tonic-gate if (is_vfork) { 710*7c478bd9Sstevel@tonic-gate mdb_tgt_status_t status; 711*7c478bd9Sstevel@tonic-gate 712*7c478bd9Sstevel@tonic-gate ASSERT(psp->pr_flags & PR_VFORKP); 713*7c478bd9Sstevel@tonic-gate mdb_tgt_sespec_idle_all(t, EBUSY, FALSE); 714*7c478bd9Sstevel@tonic-gate t->t_pshandle = C; 715*7c478bd9Sstevel@tonic-gate 716*7c478bd9Sstevel@tonic-gate (void) Psysexit(C, SYS_exec, TRUE); 717*7c478bd9Sstevel@tonic-gate (void) Psysexit(C, SYS_execve, TRUE); 718*7c478bd9Sstevel@tonic-gate 719*7c478bd9Sstevel@tonic-gate (void) Punsetflags(C, PR_FORK | PR_KLC); 720*7c478bd9Sstevel@tonic-gate (void) Psetflags(C, PR_RLC); 721*7c478bd9Sstevel@tonic-gate 722*7c478bd9Sstevel@tonic-gate do { 723*7c478bd9Sstevel@tonic-gate if (pt_setrun(t, &status, 0) == -1 || 724*7c478bd9Sstevel@tonic-gate status.st_state == MDB_TGT_UNDEAD || 725*7c478bd9Sstevel@tonic-gate status.st_state == MDB_TGT_LOST) 726*7c478bd9Sstevel@tonic-gate break; /* failure or process died */ 727*7c478bd9Sstevel@tonic-gate 728*7c478bd9Sstevel@tonic-gate } while (csp->pr_why != PR_SYSEXIT || 729*7c478bd9Sstevel@tonic-gate csp->pr_errno != 0 || (csp->pr_what != SYS_exec && 730*7c478bd9Sstevel@tonic-gate csp->pr_what != SYS_execve)); 731*7c478bd9Sstevel@tonic-gate } else 732*7c478bd9Sstevel@tonic-gate t->t_pshandle = C; 733*7c478bd9Sstevel@tonic-gate } 734*7c478bd9Sstevel@tonic-gate 735*7c478bd9Sstevel@tonic-gate /* 736*7c478bd9Sstevel@tonic-gate * If we are following the child, destroy any active libthread_db 737*7c478bd9Sstevel@tonic-gate * handle before we release the parent process. 738*7c478bd9Sstevel@tonic-gate */ 739*7c478bd9Sstevel@tonic-gate if (!follow_parent) { 740*7c478bd9Sstevel@tonic-gate PTL_DTOR(t); 741*7c478bd9Sstevel@tonic-gate pt->p_tdb_ops = NULL; 742*7c478bd9Sstevel@tonic-gate pt->p_ptl_ops = &proc_lwp_ops; 743*7c478bd9Sstevel@tonic-gate pt->p_ptl_hdl = NULL; 744*7c478bd9Sstevel@tonic-gate } 745*7c478bd9Sstevel@tonic-gate 746*7c478bd9Sstevel@tonic-gate /* 747*7c478bd9Sstevel@tonic-gate * Idle all events to make sure the address space and tracing flags are 748*7c478bd9Sstevel@tonic-gate * restored, and then release the process we are not tracing. If we 749*7c478bd9Sstevel@tonic-gate * are following the child of a vfork, we push the parent's pshandle 750*7c478bd9Sstevel@tonic-gate * on to a list of vfork parents to be released when we exec or exit. 751*7c478bd9Sstevel@tonic-gate */ 752*7c478bd9Sstevel@tonic-gate if (is_vfork && !follow_parent) { 753*7c478bd9Sstevel@tonic-gate pt_vforkp_t *vfp = mdb_alloc(sizeof (pt_vforkp_t), UM_SLEEP); 754*7c478bd9Sstevel@tonic-gate 755*7c478bd9Sstevel@tonic-gate ASSERT(psp->pr_flags & PR_VFORKP); 756*7c478bd9Sstevel@tonic-gate vfp->p_pshandle = P; 757*7c478bd9Sstevel@tonic-gate mdb_list_append(&pt->p_vforkp, vfp); 758*7c478bd9Sstevel@tonic-gate mdb_tgt_sespec_idle_all(t, EBUSY, FALSE); 759*7c478bd9Sstevel@tonic-gate 760*7c478bd9Sstevel@tonic-gate } else { 761*7c478bd9Sstevel@tonic-gate mdb_tgt_sespec_idle_all(t, EBUSY, FALSE); 762*7c478bd9Sstevel@tonic-gate Prelease(t->t_pshandle, PRELEASE_CLEAR); 763*7c478bd9Sstevel@tonic-gate if (!follow_parent) 764*7c478bd9Sstevel@tonic-gate pt_release_parents(t); 765*7c478bd9Sstevel@tonic-gate } 766*7c478bd9Sstevel@tonic-gate 767*7c478bd9Sstevel@tonic-gate /* 768*7c478bd9Sstevel@tonic-gate * Now that all the hard stuff is done, switch t_pshandle back to the 769*7c478bd9Sstevel@tonic-gate * process we are following and reset our events to the ACTIVE state. 770*7c478bd9Sstevel@tonic-gate * If we are following the child, reset the libthread_db handle as well 771*7c478bd9Sstevel@tonic-gate * as the rtld agent. 772*7c478bd9Sstevel@tonic-gate */ 773*7c478bd9Sstevel@tonic-gate if (follow_parent) 774*7c478bd9Sstevel@tonic-gate t->t_pshandle = P; 775*7c478bd9Sstevel@tonic-gate else { 776*7c478bd9Sstevel@tonic-gate t->t_pshandle = C; 777*7c478bd9Sstevel@tonic-gate pt->p_rtld = Prd_agent(C); 778*7c478bd9Sstevel@tonic-gate (void) Pobject_iter(t->t_pshandle, (proc_map_f *)thr_check, t); 779*7c478bd9Sstevel@tonic-gate } 780*7c478bd9Sstevel@tonic-gate 781*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_sespec_activate_all(t); 782*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_continue(t, NULL); 783*7c478bd9Sstevel@tonic-gate } 784*7c478bd9Sstevel@tonic-gate 785*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 786*7c478bd9Sstevel@tonic-gate static void 787*7c478bd9Sstevel@tonic-gate pt_exec(mdb_tgt_t *t, int vid, void *private) 788*7c478bd9Sstevel@tonic-gate { 789*7c478bd9Sstevel@tonic-gate struct ps_prochandle *P = t->t_pshandle; 790*7c478bd9Sstevel@tonic-gate const pstatus_t *psp = Pstatus(P); 791*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 792*7c478bd9Sstevel@tonic-gate int follow_exec = mdb.m_execmode == MDB_EM_FOLLOW; 793*7c478bd9Sstevel@tonic-gate pid_t pid = psp->pr_pid; 794*7c478bd9Sstevel@tonic-gate 795*7c478bd9Sstevel@tonic-gate char execname[MAXPATHLEN]; 796*7c478bd9Sstevel@tonic-gate mdb_sespec_t *sep, *nsep; 797*7c478bd9Sstevel@tonic-gate mdb_io_t *io; 798*7c478bd9Sstevel@tonic-gate char c; 799*7c478bd9Sstevel@tonic-gate 800*7c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_TGT, "exit from %s: errno=%d\n", proc_sysname( 801*7c478bd9Sstevel@tonic-gate psp->pr_lwp.pr_what, execname, sizeof (execname)), 802*7c478bd9Sstevel@tonic-gate psp->pr_lwp.pr_errno); 803*7c478bd9Sstevel@tonic-gate 804*7c478bd9Sstevel@tonic-gate if (psp->pr_lwp.pr_errno != 0) { 805*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_continue(t, NULL); 806*7c478bd9Sstevel@tonic-gate return; /* exec failed */ 807*7c478bd9Sstevel@tonic-gate } 808*7c478bd9Sstevel@tonic-gate 809*7c478bd9Sstevel@tonic-gate /* 810*7c478bd9Sstevel@tonic-gate * If execmode is ASK and stdout is a terminal, then ask the user to 811*7c478bd9Sstevel@tonic-gate * explicitly set the exec behavior for this particular exec. If 812*7c478bd9Sstevel@tonic-gate * Pstate() still shows PS_LOST, we are being called from pt_setrun() 813*7c478bd9Sstevel@tonic-gate * directly and therefore we must resume the terminal since it is still 814*7c478bd9Sstevel@tonic-gate * in the suspended state as far as tgt_continue() is concerned. 815*7c478bd9Sstevel@tonic-gate */ 816*7c478bd9Sstevel@tonic-gate if (mdb.m_execmode == MDB_EM_ASK && mdb.m_term != NULL) { 817*7c478bd9Sstevel@tonic-gate if (Pstate(P) == PS_LOST) 818*7c478bd9Sstevel@tonic-gate IOP_RESUME(mdb.m_term); 819*7c478bd9Sstevel@tonic-gate 820*7c478bd9Sstevel@tonic-gate mdb_iob_printf(mdb.m_err, "%s: %s detected: (f)ollow new " 821*7c478bd9Sstevel@tonic-gate "program or (s)top? ", mdb.m_pname, execname); 822*7c478bd9Sstevel@tonic-gate mdb_iob_flush(mdb.m_err); 823*7c478bd9Sstevel@tonic-gate 824*7c478bd9Sstevel@tonic-gate while (IOP_READ(mdb.m_term, &c, sizeof (c)) == sizeof (c)) { 825*7c478bd9Sstevel@tonic-gate if (c == 'F' || c == 'f') { 826*7c478bd9Sstevel@tonic-gate mdb_iob_printf(mdb.m_err, "%c\n", c); 827*7c478bd9Sstevel@tonic-gate follow_exec = TRUE; 828*7c478bd9Sstevel@tonic-gate break; 829*7c478bd9Sstevel@tonic-gate } else if (c == 'S' || c == 's') { 830*7c478bd9Sstevel@tonic-gate mdb_iob_printf(mdb.m_err, "%c\n", c); 831*7c478bd9Sstevel@tonic-gate follow_exec = FALSE; 832*7c478bd9Sstevel@tonic-gate break; 833*7c478bd9Sstevel@tonic-gate } 834*7c478bd9Sstevel@tonic-gate } 835*7c478bd9Sstevel@tonic-gate 836*7c478bd9Sstevel@tonic-gate if (Pstate(P) == PS_LOST) 837*7c478bd9Sstevel@tonic-gate IOP_SUSPEND(mdb.m_term); 838*7c478bd9Sstevel@tonic-gate } 839*7c478bd9Sstevel@tonic-gate 840*7c478bd9Sstevel@tonic-gate pt_release_parents(t); /* release any waiting vfork parents */ 841*7c478bd9Sstevel@tonic-gate pt_pre_detach(t, FALSE); /* remove our breakpoints and idle events */ 842*7c478bd9Sstevel@tonic-gate Preset_maps(P); /* libproc must delete mappings and symtabs */ 843*7c478bd9Sstevel@tonic-gate pt_close_aout(t); /* free pt symbol tables and GElf file data */ 844*7c478bd9Sstevel@tonic-gate 845*7c478bd9Sstevel@tonic-gate /* 846*7c478bd9Sstevel@tonic-gate * If we lost control of the process across the exec and are not able 847*7c478bd9Sstevel@tonic-gate * to reopen it, we have no choice but to clear the matched event list 848*7c478bd9Sstevel@tonic-gate * and wait for the user to quit or otherwise release the process. 849*7c478bd9Sstevel@tonic-gate */ 850*7c478bd9Sstevel@tonic-gate if (Pstate(P) == PS_LOST && Preopen(P) == -1) { 851*7c478bd9Sstevel@tonic-gate int error = errno; 852*7c478bd9Sstevel@tonic-gate 853*7c478bd9Sstevel@tonic-gate warn("lost control of PID %d due to exec of %s executable\n", 854*7c478bd9Sstevel@tonic-gate (int)pid, error == EOVERFLOW ? "64-bit" : "set-id"); 855*7c478bd9Sstevel@tonic-gate 856*7c478bd9Sstevel@tonic-gate for (sep = t->t_matched; sep != T_SE_END; sep = nsep) { 857*7c478bd9Sstevel@tonic-gate nsep = sep->se_matched; 858*7c478bd9Sstevel@tonic-gate sep->se_matched = NULL; 859*7c478bd9Sstevel@tonic-gate mdb_tgt_sespec_rele(t, sep); 860*7c478bd9Sstevel@tonic-gate } 861*7c478bd9Sstevel@tonic-gate 862*7c478bd9Sstevel@tonic-gate if (error != EOVERFLOW) 863*7c478bd9Sstevel@tonic-gate return; /* just stop if we exec'd a set-id executable */ 864*7c478bd9Sstevel@tonic-gate } 865*7c478bd9Sstevel@tonic-gate 866*7c478bd9Sstevel@tonic-gate if (Pstate(P) != PS_LOST) { 867*7c478bd9Sstevel@tonic-gate if (Pexecname(P, execname, sizeof (execname)) == NULL) { 868*7c478bd9Sstevel@tonic-gate (void) mdb_iob_snprintf(execname, sizeof (execname), 869*7c478bd9Sstevel@tonic-gate "/proc/%d/object/a.out", (int)pid); 870*7c478bd9Sstevel@tonic-gate } 871*7c478bd9Sstevel@tonic-gate 872*7c478bd9Sstevel@tonic-gate if (follow_exec == FALSE || psp->pr_dmodel == PR_MODEL_NATIVE) 873*7c478bd9Sstevel@tonic-gate warn("target performed exec of %s\n", execname); 874*7c478bd9Sstevel@tonic-gate 875*7c478bd9Sstevel@tonic-gate io = mdb_fdio_create_path(NULL, execname, pt->p_oflags, 0); 876*7c478bd9Sstevel@tonic-gate if (io == NULL) { 877*7c478bd9Sstevel@tonic-gate warn("failed to open %s", execname); 878*7c478bd9Sstevel@tonic-gate warn("a.out symbol tables will not be available\n"); 879*7c478bd9Sstevel@tonic-gate } else if (pt_open_aout(t, io) == NULL) { 880*7c478bd9Sstevel@tonic-gate (void) mdb_dis_select(pt_disasm(NULL)); 881*7c478bd9Sstevel@tonic-gate mdb_io_destroy(io); 882*7c478bd9Sstevel@tonic-gate } else 883*7c478bd9Sstevel@tonic-gate (void) mdb_dis_select(pt_disasm(&pt->p_file->gf_ehdr)); 884*7c478bd9Sstevel@tonic-gate } 885*7c478bd9Sstevel@tonic-gate 886*7c478bd9Sstevel@tonic-gate /* 887*7c478bd9Sstevel@tonic-gate * We reset our libthread_db state here, but deliberately do NOT call 888*7c478bd9Sstevel@tonic-gate * PTL_DTOR because we do not want to call libthread_db's td_ta_delete. 889*7c478bd9Sstevel@tonic-gate * This interface is hopelessly broken in that it writes to the process 890*7c478bd9Sstevel@tonic-gate * address space (which we do not want it to do after an exec) and it 891*7c478bd9Sstevel@tonic-gate * doesn't bother deallocating any of its storage anyway. 892*7c478bd9Sstevel@tonic-gate */ 893*7c478bd9Sstevel@tonic-gate pt->p_tdb_ops = NULL; 894*7c478bd9Sstevel@tonic-gate pt->p_ptl_ops = &proc_lwp_ops; 895*7c478bd9Sstevel@tonic-gate pt->p_ptl_hdl = NULL; 896*7c478bd9Sstevel@tonic-gate 897*7c478bd9Sstevel@tonic-gate if (follow_exec && psp->pr_dmodel != PR_MODEL_NATIVE) { 898*7c478bd9Sstevel@tonic-gate const char *argv[3]; 899*7c478bd9Sstevel@tonic-gate char *state, *env; 900*7c478bd9Sstevel@tonic-gate char pidarg[16]; 901*7c478bd9Sstevel@tonic-gate size_t envlen; 902*7c478bd9Sstevel@tonic-gate 903*7c478bd9Sstevel@tonic-gate if (realpath(getexecname(), execname) == NULL) { 904*7c478bd9Sstevel@tonic-gate warn("cannot follow PID %d -- failed to resolve " 905*7c478bd9Sstevel@tonic-gate "debugger pathname for re-exec", (int)pid); 906*7c478bd9Sstevel@tonic-gate return; 907*7c478bd9Sstevel@tonic-gate } 908*7c478bd9Sstevel@tonic-gate 909*7c478bd9Sstevel@tonic-gate warn("restarting debugger to follow PID %d ...\n", (int)pid); 910*7c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_TGT, "re-exec'ing %s\n", execname); 911*7c478bd9Sstevel@tonic-gate 912*7c478bd9Sstevel@tonic-gate (void) mdb_snprintf(pidarg, sizeof (pidarg), "-p%d", (int)pid); 913*7c478bd9Sstevel@tonic-gate 914*7c478bd9Sstevel@tonic-gate state = mdb_get_config(); 915*7c478bd9Sstevel@tonic-gate envlen = strlen(MDB_CONFIG_ENV_VAR) + 1 + strlen(state) + 1; 916*7c478bd9Sstevel@tonic-gate env = mdb_alloc(envlen, UM_SLEEP); 917*7c478bd9Sstevel@tonic-gate snprintf(env, envlen, "%s=%s", MDB_CONFIG_ENV_VAR, state); 918*7c478bd9Sstevel@tonic-gate 919*7c478bd9Sstevel@tonic-gate (void) putenv(env); 920*7c478bd9Sstevel@tonic-gate 921*7c478bd9Sstevel@tonic-gate argv[0] = mdb.m_pname; 922*7c478bd9Sstevel@tonic-gate argv[1] = pidarg; 923*7c478bd9Sstevel@tonic-gate argv[2] = NULL; 924*7c478bd9Sstevel@tonic-gate 925*7c478bd9Sstevel@tonic-gate if (mdb.m_term != NULL) 926*7c478bd9Sstevel@tonic-gate IOP_SUSPEND(mdb.m_term); 927*7c478bd9Sstevel@tonic-gate 928*7c478bd9Sstevel@tonic-gate Prelease(P, PRELEASE_CLEAR | PRELEASE_HANG); 929*7c478bd9Sstevel@tonic-gate (void) execv(execname, (char *const *)argv); 930*7c478bd9Sstevel@tonic-gate warn("failed to re-exec debugger"); 931*7c478bd9Sstevel@tonic-gate 932*7c478bd9Sstevel@tonic-gate if (mdb.m_term != NULL) 933*7c478bd9Sstevel@tonic-gate IOP_RESUME(mdb.m_term); 934*7c478bd9Sstevel@tonic-gate 935*7c478bd9Sstevel@tonic-gate t->t_pshandle = pt->p_idlehandle; 936*7c478bd9Sstevel@tonic-gate return; 937*7c478bd9Sstevel@tonic-gate } 938*7c478bd9Sstevel@tonic-gate 939*7c478bd9Sstevel@tonic-gate pt_post_attach(t); /* install tracing flags and activate events */ 940*7c478bd9Sstevel@tonic-gate pt_activate_common(t); /* initialize librtld_db and libthread_db */ 941*7c478bd9Sstevel@tonic-gate 942*7c478bd9Sstevel@tonic-gate if (psp->pr_dmodel != PR_MODEL_NATIVE && mdb.m_term != NULL) { 943*7c478bd9Sstevel@tonic-gate warn("loadable dcmds will not operate on non-native %d-bit " 944*7c478bd9Sstevel@tonic-gate "data model\n", psp->pr_dmodel == PR_MODEL_ILP32 ? 32 : 64); 945*7c478bd9Sstevel@tonic-gate warn("use ::release -a and then run mdb -p %d to restart " 946*7c478bd9Sstevel@tonic-gate "debugger\n", (int)pid); 947*7c478bd9Sstevel@tonic-gate } 948*7c478bd9Sstevel@tonic-gate 949*7c478bd9Sstevel@tonic-gate if (follow_exec) 950*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_continue(t, NULL); 951*7c478bd9Sstevel@tonic-gate } 952*7c478bd9Sstevel@tonic-gate 953*7c478bd9Sstevel@tonic-gate static int 954*7c478bd9Sstevel@tonic-gate pt_setflags(mdb_tgt_t *t, int flags) 955*7c478bd9Sstevel@tonic-gate { 956*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 957*7c478bd9Sstevel@tonic-gate 958*7c478bd9Sstevel@tonic-gate if ((flags ^ t->t_flags) & MDB_TGT_F_RDWR) { 959*7c478bd9Sstevel@tonic-gate int mode = (flags & MDB_TGT_F_RDWR) ? O_RDWR : O_RDONLY; 960*7c478bd9Sstevel@tonic-gate mdb_io_t *io; 961*7c478bd9Sstevel@tonic-gate 962*7c478bd9Sstevel@tonic-gate if (pt->p_fio == NULL) 963*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOEXEC)); 964*7c478bd9Sstevel@tonic-gate 965*7c478bd9Sstevel@tonic-gate io = mdb_fdio_create_path(NULL, IOP_NAME(pt->p_fio), mode, 0); 966*7c478bd9Sstevel@tonic-gate 967*7c478bd9Sstevel@tonic-gate if (io == NULL) 968*7c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 969*7c478bd9Sstevel@tonic-gate 970*7c478bd9Sstevel@tonic-gate t->t_flags = (t->t_flags & ~MDB_TGT_F_RDWR) | 971*7c478bd9Sstevel@tonic-gate (flags & MDB_TGT_F_RDWR); 972*7c478bd9Sstevel@tonic-gate 973*7c478bd9Sstevel@tonic-gate pt->p_fio = mdb_io_hold(io); 974*7c478bd9Sstevel@tonic-gate mdb_io_rele(pt->p_file->gf_io); 975*7c478bd9Sstevel@tonic-gate pt->p_file->gf_io = pt->p_fio; 976*7c478bd9Sstevel@tonic-gate } 977*7c478bd9Sstevel@tonic-gate 978*7c478bd9Sstevel@tonic-gate if (flags & MDB_TGT_F_FORCE) { 979*7c478bd9Sstevel@tonic-gate t->t_flags |= MDB_TGT_F_FORCE; 980*7c478bd9Sstevel@tonic-gate pt->p_gflags |= PGRAB_FORCE; 981*7c478bd9Sstevel@tonic-gate } 982*7c478bd9Sstevel@tonic-gate 983*7c478bd9Sstevel@tonic-gate return (0); 984*7c478bd9Sstevel@tonic-gate } 985*7c478bd9Sstevel@tonic-gate 986*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 987*7c478bd9Sstevel@tonic-gate static int 988*7c478bd9Sstevel@tonic-gate pt_frame(void *arglim, uintptr_t pc, uint_t argc, const long *argv, 989*7c478bd9Sstevel@tonic-gate const mdb_tgt_gregset_t *gregs) 990*7c478bd9Sstevel@tonic-gate { 991*7c478bd9Sstevel@tonic-gate argc = MIN(argc, (uint_t)(uintptr_t)arglim); 992*7c478bd9Sstevel@tonic-gate mdb_printf("%a(", pc); 993*7c478bd9Sstevel@tonic-gate 994*7c478bd9Sstevel@tonic-gate if (argc != 0) { 995*7c478bd9Sstevel@tonic-gate mdb_printf("%lr", *argv++); 996*7c478bd9Sstevel@tonic-gate for (argc--; argc != 0; argc--) 997*7c478bd9Sstevel@tonic-gate mdb_printf(", %lr", *argv++); 998*7c478bd9Sstevel@tonic-gate } 999*7c478bd9Sstevel@tonic-gate 1000*7c478bd9Sstevel@tonic-gate mdb_printf(")\n"); 1001*7c478bd9Sstevel@tonic-gate return (0); 1002*7c478bd9Sstevel@tonic-gate } 1003*7c478bd9Sstevel@tonic-gate 1004*7c478bd9Sstevel@tonic-gate static int 1005*7c478bd9Sstevel@tonic-gate pt_framev(void *arglim, uintptr_t pc, uint_t argc, const long *argv, 1006*7c478bd9Sstevel@tonic-gate const mdb_tgt_gregset_t *gregs) 1007*7c478bd9Sstevel@tonic-gate { 1008*7c478bd9Sstevel@tonic-gate argc = MIN(argc, (uint_t)(uintptr_t)arglim); 1009*7c478bd9Sstevel@tonic-gate #if defined(__i386) || defined(__amd64) 1010*7c478bd9Sstevel@tonic-gate mdb_printf("%0?lr %a(", gregs->gregs[R_FP], pc); 1011*7c478bd9Sstevel@tonic-gate #else 1012*7c478bd9Sstevel@tonic-gate mdb_printf("%0?lr %a(", gregs->gregs[R_SP], pc); 1013*7c478bd9Sstevel@tonic-gate #endif 1014*7c478bd9Sstevel@tonic-gate if (argc != 0) { 1015*7c478bd9Sstevel@tonic-gate mdb_printf("%lr", *argv++); 1016*7c478bd9Sstevel@tonic-gate for (argc--; argc != 0; argc--) 1017*7c478bd9Sstevel@tonic-gate mdb_printf(", %lr", *argv++); 1018*7c478bd9Sstevel@tonic-gate } 1019*7c478bd9Sstevel@tonic-gate 1020*7c478bd9Sstevel@tonic-gate mdb_printf(")\n"); 1021*7c478bd9Sstevel@tonic-gate return (0); 1022*7c478bd9Sstevel@tonic-gate } 1023*7c478bd9Sstevel@tonic-gate 1024*7c478bd9Sstevel@tonic-gate static int 1025*7c478bd9Sstevel@tonic-gate pt_framer(void *arglim, uintptr_t pc, uint_t argc, const long *argv, 1026*7c478bd9Sstevel@tonic-gate const mdb_tgt_gregset_t *gregs) 1027*7c478bd9Sstevel@tonic-gate { 1028*7c478bd9Sstevel@tonic-gate if (pt_frameregs(arglim, pc, argc, argv, gregs, pc == PC_FAKE) == -1) { 1029*7c478bd9Sstevel@tonic-gate /* 1030*7c478bd9Sstevel@tonic-gate * Use verbose format if register format is not supported. 1031*7c478bd9Sstevel@tonic-gate */ 1032*7c478bd9Sstevel@tonic-gate return (pt_framev(arglim, pc, argc, argv, gregs)); 1033*7c478bd9Sstevel@tonic-gate } 1034*7c478bd9Sstevel@tonic-gate 1035*7c478bd9Sstevel@tonic-gate return (0); 1036*7c478bd9Sstevel@tonic-gate } 1037*7c478bd9Sstevel@tonic-gate 1038*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1039*7c478bd9Sstevel@tonic-gate static int 1040*7c478bd9Sstevel@tonic-gate pt_stack_common(uintptr_t addr, uint_t flags, int argc, 1041*7c478bd9Sstevel@tonic-gate const mdb_arg_t *argv, mdb_tgt_stack_f *func, prgreg_t saved_pc) 1042*7c478bd9Sstevel@tonic-gate { 1043*7c478bd9Sstevel@tonic-gate void *arg = (void *)(uintptr_t)mdb.m_nargs; 1044*7c478bd9Sstevel@tonic-gate mdb_tgt_t *t = mdb.m_target; 1045*7c478bd9Sstevel@tonic-gate mdb_tgt_gregset_t gregs; 1046*7c478bd9Sstevel@tonic-gate 1047*7c478bd9Sstevel@tonic-gate if (argc != 0) { 1048*7c478bd9Sstevel@tonic-gate if (argv->a_type == MDB_TYPE_CHAR || argc > 1) 1049*7c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 1050*7c478bd9Sstevel@tonic-gate 1051*7c478bd9Sstevel@tonic-gate if (argv->a_type == MDB_TYPE_STRING) 1052*7c478bd9Sstevel@tonic-gate arg = (void *)(uintptr_t)mdb_strtoull(argv->a_un.a_str); 1053*7c478bd9Sstevel@tonic-gate else 1054*7c478bd9Sstevel@tonic-gate arg = (void *)(uintptr_t)argv->a_un.a_val; 1055*7c478bd9Sstevel@tonic-gate } 1056*7c478bd9Sstevel@tonic-gate 1057*7c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL || Pstate(t->t_pshandle) == PS_IDLE) { 1058*7c478bd9Sstevel@tonic-gate mdb_warn("no process active\n"); 1059*7c478bd9Sstevel@tonic-gate return (DCMD_ERR); 1060*7c478bd9Sstevel@tonic-gate } 1061*7c478bd9Sstevel@tonic-gate 1062*7c478bd9Sstevel@tonic-gate /* 1063*7c478bd9Sstevel@tonic-gate * In the universe of sparcv7, sparcv9, ia32, and amd64 this code can be 1064*7c478bd9Sstevel@tonic-gate * common: <sys/procfs_isa.h> conveniently #defines R_FP to be the 1065*7c478bd9Sstevel@tonic-gate * appropriate register we need to set in order to perform a stack 1066*7c478bd9Sstevel@tonic-gate * traceback from a given frame address. 1067*7c478bd9Sstevel@tonic-gate */ 1068*7c478bd9Sstevel@tonic-gate if (flags & DCMD_ADDRSPEC) { 1069*7c478bd9Sstevel@tonic-gate bzero(&gregs, sizeof (gregs)); 1070*7c478bd9Sstevel@tonic-gate gregs.gregs[R_FP] = addr; 1071*7c478bd9Sstevel@tonic-gate #ifdef __sparc 1072*7c478bd9Sstevel@tonic-gate gregs.gregs[R_I7] = saved_pc; 1073*7c478bd9Sstevel@tonic-gate #endif /* __sparc */ 1074*7c478bd9Sstevel@tonic-gate } else if (PTL_GETREGS(t, PTL_TID(t), gregs.gregs) != 0) { 1075*7c478bd9Sstevel@tonic-gate mdb_warn("failed to get current register set"); 1076*7c478bd9Sstevel@tonic-gate return (DCMD_ERR); 1077*7c478bd9Sstevel@tonic-gate } 1078*7c478bd9Sstevel@tonic-gate 1079*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_stack_iter(t, &gregs, func, arg); 1080*7c478bd9Sstevel@tonic-gate return (DCMD_OK); 1081*7c478bd9Sstevel@tonic-gate } 1082*7c478bd9Sstevel@tonic-gate 1083*7c478bd9Sstevel@tonic-gate static int 1084*7c478bd9Sstevel@tonic-gate pt_stack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1085*7c478bd9Sstevel@tonic-gate { 1086*7c478bd9Sstevel@tonic-gate return (pt_stack_common(addr, flags, argc, argv, pt_frame, 0)); 1087*7c478bd9Sstevel@tonic-gate } 1088*7c478bd9Sstevel@tonic-gate 1089*7c478bd9Sstevel@tonic-gate static int 1090*7c478bd9Sstevel@tonic-gate pt_stackv(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1091*7c478bd9Sstevel@tonic-gate { 1092*7c478bd9Sstevel@tonic-gate return (pt_stack_common(addr, flags, argc, argv, pt_framev, 0)); 1093*7c478bd9Sstevel@tonic-gate } 1094*7c478bd9Sstevel@tonic-gate 1095*7c478bd9Sstevel@tonic-gate static int 1096*7c478bd9Sstevel@tonic-gate pt_stackr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1097*7c478bd9Sstevel@tonic-gate { 1098*7c478bd9Sstevel@tonic-gate /* 1099*7c478bd9Sstevel@tonic-gate * Force printing of first register window, by setting the 1100*7c478bd9Sstevel@tonic-gate * saved pc (%i7) to PC_FAKE. 1101*7c478bd9Sstevel@tonic-gate */ 1102*7c478bd9Sstevel@tonic-gate return (pt_stack_common(addr, flags, argc, argv, pt_framer, PC_FAKE)); 1103*7c478bd9Sstevel@tonic-gate } 1104*7c478bd9Sstevel@tonic-gate 1105*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1106*7c478bd9Sstevel@tonic-gate static int 1107*7c478bd9Sstevel@tonic-gate pt_ignored(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1108*7c478bd9Sstevel@tonic-gate { 1109*7c478bd9Sstevel@tonic-gate struct ps_prochandle *P = mdb.m_target->t_pshandle; 1110*7c478bd9Sstevel@tonic-gate char buf[PRSIGBUFSZ]; 1111*7c478bd9Sstevel@tonic-gate 1112*7c478bd9Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) || argc != 0) 1113*7c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 1114*7c478bd9Sstevel@tonic-gate 1115*7c478bd9Sstevel@tonic-gate if (P == NULL) { 1116*7c478bd9Sstevel@tonic-gate mdb_warn("no process is currently active\n"); 1117*7c478bd9Sstevel@tonic-gate return (DCMD_ERR); 1118*7c478bd9Sstevel@tonic-gate } 1119*7c478bd9Sstevel@tonic-gate 1120*7c478bd9Sstevel@tonic-gate mdb_printf("%s\n", proc_sigset2str(&Pstatus(P)->pr_sigtrace, " ", 1121*7c478bd9Sstevel@tonic-gate FALSE, buf, sizeof (buf))); 1122*7c478bd9Sstevel@tonic-gate 1123*7c478bd9Sstevel@tonic-gate return (DCMD_OK); 1124*7c478bd9Sstevel@tonic-gate } 1125*7c478bd9Sstevel@tonic-gate 1126*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1127*7c478bd9Sstevel@tonic-gate static int 1128*7c478bd9Sstevel@tonic-gate pt_lwpid(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1129*7c478bd9Sstevel@tonic-gate { 1130*7c478bd9Sstevel@tonic-gate struct ps_prochandle *P = mdb.m_target->t_pshandle; 1131*7c478bd9Sstevel@tonic-gate 1132*7c478bd9Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) || argc != 0) 1133*7c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 1134*7c478bd9Sstevel@tonic-gate 1135*7c478bd9Sstevel@tonic-gate if (P == NULL) { 1136*7c478bd9Sstevel@tonic-gate mdb_warn("no process is currently active\n"); 1137*7c478bd9Sstevel@tonic-gate return (DCMD_ERR); 1138*7c478bd9Sstevel@tonic-gate } 1139*7c478bd9Sstevel@tonic-gate 1140*7c478bd9Sstevel@tonic-gate mdb_printf("%d\n", Pstatus(P)->pr_lwp.pr_lwpid); 1141*7c478bd9Sstevel@tonic-gate return (DCMD_OK); 1142*7c478bd9Sstevel@tonic-gate } 1143*7c478bd9Sstevel@tonic-gate 1144*7c478bd9Sstevel@tonic-gate static int 1145*7c478bd9Sstevel@tonic-gate pt_print_lwpid(int *n, const lwpstatus_t *psp) 1146*7c478bd9Sstevel@tonic-gate { 1147*7c478bd9Sstevel@tonic-gate struct ps_prochandle *P = mdb.m_target->t_pshandle; 1148*7c478bd9Sstevel@tonic-gate int nlwp = Pstatus(P)->pr_nlwp; 1149*7c478bd9Sstevel@tonic-gate 1150*7c478bd9Sstevel@tonic-gate if (*n == nlwp - 2) 1151*7c478bd9Sstevel@tonic-gate mdb_printf("%d and ", (int)psp->pr_lwpid); 1152*7c478bd9Sstevel@tonic-gate else if (*n == nlwp - 1) 1153*7c478bd9Sstevel@tonic-gate mdb_printf("%d are", (int)psp->pr_lwpid); 1154*7c478bd9Sstevel@tonic-gate else 1155*7c478bd9Sstevel@tonic-gate mdb_printf("%d, ", (int)psp->pr_lwpid); 1156*7c478bd9Sstevel@tonic-gate 1157*7c478bd9Sstevel@tonic-gate (*n)++; 1158*7c478bd9Sstevel@tonic-gate return (0); 1159*7c478bd9Sstevel@tonic-gate } 1160*7c478bd9Sstevel@tonic-gate 1161*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1162*7c478bd9Sstevel@tonic-gate static int 1163*7c478bd9Sstevel@tonic-gate pt_lwpids(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1164*7c478bd9Sstevel@tonic-gate { 1165*7c478bd9Sstevel@tonic-gate struct ps_prochandle *P = mdb.m_target->t_pshandle; 1166*7c478bd9Sstevel@tonic-gate int n = 0; 1167*7c478bd9Sstevel@tonic-gate 1168*7c478bd9Sstevel@tonic-gate if (P == NULL) { 1169*7c478bd9Sstevel@tonic-gate mdb_warn("no process is currently active\n"); 1170*7c478bd9Sstevel@tonic-gate return (DCMD_ERR); 1171*7c478bd9Sstevel@tonic-gate } 1172*7c478bd9Sstevel@tonic-gate 1173*7c478bd9Sstevel@tonic-gate switch (Pstatus(P)->pr_nlwp) { 1174*7c478bd9Sstevel@tonic-gate case 0: 1175*7c478bd9Sstevel@tonic-gate mdb_printf("no lwps are"); 1176*7c478bd9Sstevel@tonic-gate break; 1177*7c478bd9Sstevel@tonic-gate case 1: 1178*7c478bd9Sstevel@tonic-gate mdb_printf("lwpid %d is the only lwp", 1179*7c478bd9Sstevel@tonic-gate Pstatus(P)->pr_lwp.pr_lwpid); 1180*7c478bd9Sstevel@tonic-gate break; 1181*7c478bd9Sstevel@tonic-gate default: 1182*7c478bd9Sstevel@tonic-gate mdb_printf("lwpids "); 1183*7c478bd9Sstevel@tonic-gate (void) Plwp_iter(P, (proc_lwp_f *)pt_print_lwpid, &n); 1184*7c478bd9Sstevel@tonic-gate } 1185*7c478bd9Sstevel@tonic-gate 1186*7c478bd9Sstevel@tonic-gate switch (Pstate(P)) { 1187*7c478bd9Sstevel@tonic-gate case PS_DEAD: 1188*7c478bd9Sstevel@tonic-gate mdb_printf(" in core of process %d.\n", Pstatus(P)->pr_pid); 1189*7c478bd9Sstevel@tonic-gate break; 1190*7c478bd9Sstevel@tonic-gate case PS_IDLE: 1191*7c478bd9Sstevel@tonic-gate mdb_printf(" in idle target.\n"); 1192*7c478bd9Sstevel@tonic-gate break; 1193*7c478bd9Sstevel@tonic-gate default: 1194*7c478bd9Sstevel@tonic-gate mdb_printf(" in process %d.\n", (int)Pstatus(P)->pr_pid); 1195*7c478bd9Sstevel@tonic-gate break; 1196*7c478bd9Sstevel@tonic-gate } 1197*7c478bd9Sstevel@tonic-gate 1198*7c478bd9Sstevel@tonic-gate return (DCMD_OK); 1199*7c478bd9Sstevel@tonic-gate } 1200*7c478bd9Sstevel@tonic-gate 1201*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1202*7c478bd9Sstevel@tonic-gate static int 1203*7c478bd9Sstevel@tonic-gate pt_ignore(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1204*7c478bd9Sstevel@tonic-gate { 1205*7c478bd9Sstevel@tonic-gate pt_data_t *pt = mdb.m_target->t_data; 1206*7c478bd9Sstevel@tonic-gate 1207*7c478bd9Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC) || argc != 0) 1208*7c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 1209*7c478bd9Sstevel@tonic-gate 1210*7c478bd9Sstevel@tonic-gate if (addr < 1 || addr > pt->p_maxsig) { 1211*7c478bd9Sstevel@tonic-gate mdb_warn("invalid signal number -- 0t%lu\n", addr); 1212*7c478bd9Sstevel@tonic-gate return (DCMD_ERR); 1213*7c478bd9Sstevel@tonic-gate } 1214*7c478bd9Sstevel@tonic-gate 1215*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_vespec_iter(mdb.m_target, pt_ignore_sig, (void *)addr); 1216*7c478bd9Sstevel@tonic-gate return (DCMD_OK); 1217*7c478bd9Sstevel@tonic-gate } 1218*7c478bd9Sstevel@tonic-gate 1219*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1220*7c478bd9Sstevel@tonic-gate static int 1221*7c478bd9Sstevel@tonic-gate pt_attach(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1222*7c478bd9Sstevel@tonic-gate { 1223*7c478bd9Sstevel@tonic-gate mdb_tgt_t *t = mdb.m_target; 1224*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 1225*7c478bd9Sstevel@tonic-gate int state, perr; 1226*7c478bd9Sstevel@tonic-gate 1227*7c478bd9Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC) && argc == 0) 1228*7c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 1229*7c478bd9Sstevel@tonic-gate 1230*7c478bd9Sstevel@tonic-gate if (((flags & DCMD_ADDRSPEC) && argc != 0) || argc > 1 || 1231*7c478bd9Sstevel@tonic-gate (argc != 0 && argv->a_type != MDB_TYPE_STRING)) 1232*7c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 1233*7c478bd9Sstevel@tonic-gate 1234*7c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL && Pstate(t->t_pshandle) != PS_IDLE) { 1235*7c478bd9Sstevel@tonic-gate mdb_warn("debugger is already attached to a %s\n", 1236*7c478bd9Sstevel@tonic-gate (Pstate(t->t_pshandle) == PS_DEAD) ? "core" : "process"); 1237*7c478bd9Sstevel@tonic-gate return (DCMD_ERR); 1238*7c478bd9Sstevel@tonic-gate } 1239*7c478bd9Sstevel@tonic-gate 1240*7c478bd9Sstevel@tonic-gate if (pt->p_fio == NULL) { 1241*7c478bd9Sstevel@tonic-gate mdb_warn("attach requires executable to be specified on " 1242*7c478bd9Sstevel@tonic-gate "command-line (or use -p)\n"); 1243*7c478bd9Sstevel@tonic-gate return (DCMD_ERR); 1244*7c478bd9Sstevel@tonic-gate } 1245*7c478bd9Sstevel@tonic-gate 1246*7c478bd9Sstevel@tonic-gate if (flags & DCMD_ADDRSPEC) 1247*7c478bd9Sstevel@tonic-gate t->t_pshandle = Pgrab((pid_t)addr, pt->p_gflags, &perr); 1248*7c478bd9Sstevel@tonic-gate else 1249*7c478bd9Sstevel@tonic-gate t->t_pshandle = proc_arg_grab(argv->a_un.a_str, 1250*7c478bd9Sstevel@tonic-gate PR_ARG_ANY, pt->p_gflags, &perr); 1251*7c478bd9Sstevel@tonic-gate 1252*7c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) { 1253*7c478bd9Sstevel@tonic-gate t->t_pshandle = pt->p_idlehandle; 1254*7c478bd9Sstevel@tonic-gate mdb_warn("cannot attach: %s\n", Pgrab_error(perr)); 1255*7c478bd9Sstevel@tonic-gate return (DCMD_ERR); 1256*7c478bd9Sstevel@tonic-gate } 1257*7c478bd9Sstevel@tonic-gate 1258*7c478bd9Sstevel@tonic-gate state = Pstate(t->t_pshandle); 1259*7c478bd9Sstevel@tonic-gate if (state != PS_DEAD && state != PS_IDLE) { 1260*7c478bd9Sstevel@tonic-gate (void) Punsetflags(t->t_pshandle, PR_KLC); 1261*7c478bd9Sstevel@tonic-gate (void) Psetflags(t->t_pshandle, PR_RLC); 1262*7c478bd9Sstevel@tonic-gate pt_post_attach(t); 1263*7c478bd9Sstevel@tonic-gate pt_activate_common(t); 1264*7c478bd9Sstevel@tonic-gate } 1265*7c478bd9Sstevel@tonic-gate 1266*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_status(t, &t->t_status); 1267*7c478bd9Sstevel@tonic-gate mdb_module_load_all(0); 1268*7c478bd9Sstevel@tonic-gate return (DCMD_OK); 1269*7c478bd9Sstevel@tonic-gate } 1270*7c478bd9Sstevel@tonic-gate 1271*7c478bd9Sstevel@tonic-gate static int 1272*7c478bd9Sstevel@tonic-gate pt_regstatus(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1273*7c478bd9Sstevel@tonic-gate { 1274*7c478bd9Sstevel@tonic-gate mdb_tgt_t *t = mdb.m_target; 1275*7c478bd9Sstevel@tonic-gate 1276*7c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL) { 1277*7c478bd9Sstevel@tonic-gate const pstatus_t *psp = Pstatus(t->t_pshandle); 1278*7c478bd9Sstevel@tonic-gate int cursig = psp->pr_lwp.pr_cursig; 1279*7c478bd9Sstevel@tonic-gate char signame[SIG2STR_MAX]; 1280*7c478bd9Sstevel@tonic-gate int state = Pstate(t->t_pshandle); 1281*7c478bd9Sstevel@tonic-gate 1282*7c478bd9Sstevel@tonic-gate if (state != PS_DEAD && state != PS_IDLE) 1283*7c478bd9Sstevel@tonic-gate mdb_printf("process id = %d\n", psp->pr_pid); 1284*7c478bd9Sstevel@tonic-gate else 1285*7c478bd9Sstevel@tonic-gate mdb_printf("no process\n"); 1286*7c478bd9Sstevel@tonic-gate 1287*7c478bd9Sstevel@tonic-gate if (cursig != 0 && sig2str(cursig, signame) == 0) 1288*7c478bd9Sstevel@tonic-gate mdb_printf("SIG%s: %s\n", signame, strsignal(cursig)); 1289*7c478bd9Sstevel@tonic-gate } 1290*7c478bd9Sstevel@tonic-gate 1291*7c478bd9Sstevel@tonic-gate return (pt_regs(addr, flags, argc, argv)); 1292*7c478bd9Sstevel@tonic-gate } 1293*7c478bd9Sstevel@tonic-gate 1294*7c478bd9Sstevel@tonic-gate static int 1295*7c478bd9Sstevel@tonic-gate pt_findstack(uintptr_t tid, uint_t flags, int argc, const mdb_arg_t *argv) 1296*7c478bd9Sstevel@tonic-gate { 1297*7c478bd9Sstevel@tonic-gate mdb_tgt_t *t = mdb.m_target; 1298*7c478bd9Sstevel@tonic-gate mdb_tgt_gregset_t gregs; 1299*7c478bd9Sstevel@tonic-gate int showargs = 0; 1300*7c478bd9Sstevel@tonic-gate int count; 1301*7c478bd9Sstevel@tonic-gate uintptr_t pc, sp; 1302*7c478bd9Sstevel@tonic-gate 1303*7c478bd9Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC)) 1304*7c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 1305*7c478bd9Sstevel@tonic-gate 1306*7c478bd9Sstevel@tonic-gate count = mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &showargs, 1307*7c478bd9Sstevel@tonic-gate NULL); 1308*7c478bd9Sstevel@tonic-gate argc -= count; 1309*7c478bd9Sstevel@tonic-gate argv += count; 1310*7c478bd9Sstevel@tonic-gate 1311*7c478bd9Sstevel@tonic-gate if (argc > 1 || (argc == 1 && argv->a_type != MDB_TYPE_STRING)) 1312*7c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 1313*7c478bd9Sstevel@tonic-gate 1314*7c478bd9Sstevel@tonic-gate if (PTL_GETREGS(t, tid, gregs.gregs) != 0) { 1315*7c478bd9Sstevel@tonic-gate mdb_warn("failed to get register set for thread %p", tid); 1316*7c478bd9Sstevel@tonic-gate return (DCMD_ERR); 1317*7c478bd9Sstevel@tonic-gate } 1318*7c478bd9Sstevel@tonic-gate 1319*7c478bd9Sstevel@tonic-gate pc = gregs.gregs[R_PC]; 1320*7c478bd9Sstevel@tonic-gate #if defined(__i386) || defined(__amd64) 1321*7c478bd9Sstevel@tonic-gate sp = gregs.gregs[R_FP]; 1322*7c478bd9Sstevel@tonic-gate #else 1323*7c478bd9Sstevel@tonic-gate sp = gregs.gregs[R_SP]; 1324*7c478bd9Sstevel@tonic-gate #endif 1325*7c478bd9Sstevel@tonic-gate mdb_printf("stack pointer for thread %p: %p\n", tid, sp); 1326*7c478bd9Sstevel@tonic-gate if (pc != 0) 1327*7c478bd9Sstevel@tonic-gate mdb_printf("[ %0?lr %a() ]\n", sp, pc); 1328*7c478bd9Sstevel@tonic-gate 1329*7c478bd9Sstevel@tonic-gate (void) mdb_inc_indent(2); 1330*7c478bd9Sstevel@tonic-gate mdb_set_dot(sp); 1331*7c478bd9Sstevel@tonic-gate 1332*7c478bd9Sstevel@tonic-gate if (argc == 1) 1333*7c478bd9Sstevel@tonic-gate (void) mdb_eval(argv->a_un.a_str); 1334*7c478bd9Sstevel@tonic-gate else if (showargs) 1335*7c478bd9Sstevel@tonic-gate (void) mdb_eval("<.$C"); 1336*7c478bd9Sstevel@tonic-gate else 1337*7c478bd9Sstevel@tonic-gate (void) mdb_eval("<.$C0"); 1338*7c478bd9Sstevel@tonic-gate 1339*7c478bd9Sstevel@tonic-gate (void) mdb_dec_indent(2); 1340*7c478bd9Sstevel@tonic-gate return (DCMD_OK); 1341*7c478bd9Sstevel@tonic-gate } 1342*7c478bd9Sstevel@tonic-gate 1343*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1344*7c478bd9Sstevel@tonic-gate static int 1345*7c478bd9Sstevel@tonic-gate pt_gcore(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1346*7c478bd9Sstevel@tonic-gate { 1347*7c478bd9Sstevel@tonic-gate mdb_tgt_t *t = mdb.m_target; 1348*7c478bd9Sstevel@tonic-gate char *prefix = "core"; 1349*7c478bd9Sstevel@tonic-gate char *content_str = NULL; 1350*7c478bd9Sstevel@tonic-gate core_content_t content = CC_CONTENT_DEFAULT; 1351*7c478bd9Sstevel@tonic-gate size_t size; 1352*7c478bd9Sstevel@tonic-gate char *fname; 1353*7c478bd9Sstevel@tonic-gate pid_t pid; 1354*7c478bd9Sstevel@tonic-gate 1355*7c478bd9Sstevel@tonic-gate if (flags & DCMD_ADDRSPEC) 1356*7c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 1357*7c478bd9Sstevel@tonic-gate 1358*7c478bd9Sstevel@tonic-gate if (mdb_getopts(argc, argv, 1359*7c478bd9Sstevel@tonic-gate 'o', MDB_OPT_STR, &prefix, 1360*7c478bd9Sstevel@tonic-gate 'c', MDB_OPT_STR, &content_str, NULL) != argc) 1361*7c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 1362*7c478bd9Sstevel@tonic-gate 1363*7c478bd9Sstevel@tonic-gate if (content_str != NULL && 1364*7c478bd9Sstevel@tonic-gate (proc_str2content(content_str, &content) != 0 || 1365*7c478bd9Sstevel@tonic-gate content == CC_CONTENT_INVALID)) { 1366*7c478bd9Sstevel@tonic-gate mdb_warn("invalid content string '%s'\n", content_str); 1367*7c478bd9Sstevel@tonic-gate return (DCMD_ERR); 1368*7c478bd9Sstevel@tonic-gate } 1369*7c478bd9Sstevel@tonic-gate 1370*7c478bd9Sstevel@tonic-gate pid = Pstatus(t->t_pshandle)->pr_pid; 1371*7c478bd9Sstevel@tonic-gate size = 1 + mdb_snprintf(NULL, 0, "%s.%d", prefix, (int)pid); 1372*7c478bd9Sstevel@tonic-gate fname = mdb_alloc(size, UM_SLEEP | UM_GC); 1373*7c478bd9Sstevel@tonic-gate (void) mdb_snprintf(fname, size, "%s.%d", prefix, (int)pid); 1374*7c478bd9Sstevel@tonic-gate 1375*7c478bd9Sstevel@tonic-gate if (Pgcore(t->t_pshandle, fname, content) != 0) { 1376*7c478bd9Sstevel@tonic-gate mdb_warn("couldn't dump core"); 1377*7c478bd9Sstevel@tonic-gate return (DCMD_ERR); 1378*7c478bd9Sstevel@tonic-gate } 1379*7c478bd9Sstevel@tonic-gate 1380*7c478bd9Sstevel@tonic-gate mdb_warn("%s dumped\n", fname); 1381*7c478bd9Sstevel@tonic-gate 1382*7c478bd9Sstevel@tonic-gate return (DCMD_OK); 1383*7c478bd9Sstevel@tonic-gate } 1384*7c478bd9Sstevel@tonic-gate 1385*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1386*7c478bd9Sstevel@tonic-gate static int 1387*7c478bd9Sstevel@tonic-gate pt_kill(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1388*7c478bd9Sstevel@tonic-gate { 1389*7c478bd9Sstevel@tonic-gate mdb_tgt_t *t = mdb.m_target; 1390*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 1391*7c478bd9Sstevel@tonic-gate int state; 1392*7c478bd9Sstevel@tonic-gate 1393*7c478bd9Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) || argc != 0) 1394*7c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 1395*7c478bd9Sstevel@tonic-gate 1396*7c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL && 1397*7c478bd9Sstevel@tonic-gate (state = Pstate(t->t_pshandle)) != PS_DEAD && state != PS_IDLE) { 1398*7c478bd9Sstevel@tonic-gate mdb_warn("victim process PID %d forcibly terminated\n", 1399*7c478bd9Sstevel@tonic-gate (int)Pstatus(t->t_pshandle)->pr_pid); 1400*7c478bd9Sstevel@tonic-gate pt_pre_detach(t, TRUE); 1401*7c478bd9Sstevel@tonic-gate pt_release_parents(t); 1402*7c478bd9Sstevel@tonic-gate Prelease(t->t_pshandle, PRELEASE_KILL); 1403*7c478bd9Sstevel@tonic-gate t->t_pshandle = pt->p_idlehandle; 1404*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_status(t, &t->t_status); 1405*7c478bd9Sstevel@tonic-gate mdb.m_flags &= ~(MDB_FL_VCREATE | MDB_FL_JOBCTL); 1406*7c478bd9Sstevel@tonic-gate } else 1407*7c478bd9Sstevel@tonic-gate mdb_warn("no victim process is currently under control\n"); 1408*7c478bd9Sstevel@tonic-gate 1409*7c478bd9Sstevel@tonic-gate return (DCMD_OK); 1410*7c478bd9Sstevel@tonic-gate } 1411*7c478bd9Sstevel@tonic-gate 1412*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1413*7c478bd9Sstevel@tonic-gate static int 1414*7c478bd9Sstevel@tonic-gate pt_detach(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1415*7c478bd9Sstevel@tonic-gate { 1416*7c478bd9Sstevel@tonic-gate mdb_tgt_t *t = mdb.m_target; 1417*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 1418*7c478bd9Sstevel@tonic-gate int rflags = pt->p_rflags; 1419*7c478bd9Sstevel@tonic-gate 1420*7c478bd9Sstevel@tonic-gate if (argc != 0 && argv->a_type == MDB_TYPE_STRING && 1421*7c478bd9Sstevel@tonic-gate strcmp(argv->a_un.a_str, "-a") == 0) { 1422*7c478bd9Sstevel@tonic-gate rflags = PRELEASE_HANG | PRELEASE_CLEAR; 1423*7c478bd9Sstevel@tonic-gate argv++; 1424*7c478bd9Sstevel@tonic-gate argc--; 1425*7c478bd9Sstevel@tonic-gate } 1426*7c478bd9Sstevel@tonic-gate 1427*7c478bd9Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) || argc != 0) 1428*7c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 1429*7c478bd9Sstevel@tonic-gate 1430*7c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL || Pstate(t->t_pshandle) == PS_IDLE) { 1431*7c478bd9Sstevel@tonic-gate mdb_warn("debugger is not currently attached to a process " 1432*7c478bd9Sstevel@tonic-gate "or core file\n"); 1433*7c478bd9Sstevel@tonic-gate return (DCMD_ERR); 1434*7c478bd9Sstevel@tonic-gate } 1435*7c478bd9Sstevel@tonic-gate 1436*7c478bd9Sstevel@tonic-gate pt_pre_detach(t, TRUE); 1437*7c478bd9Sstevel@tonic-gate pt_release_parents(t); 1438*7c478bd9Sstevel@tonic-gate Prelease(t->t_pshandle, rflags); 1439*7c478bd9Sstevel@tonic-gate t->t_pshandle = pt->p_idlehandle; 1440*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_status(t, &t->t_status); 1441*7c478bd9Sstevel@tonic-gate mdb.m_flags &= ~(MDB_FL_VCREATE | MDB_FL_JOBCTL); 1442*7c478bd9Sstevel@tonic-gate 1443*7c478bd9Sstevel@tonic-gate return (DCMD_OK); 1444*7c478bd9Sstevel@tonic-gate } 1445*7c478bd9Sstevel@tonic-gate 1446*7c478bd9Sstevel@tonic-gate static uintmax_t 1447*7c478bd9Sstevel@tonic-gate reg_disc_get(const mdb_var_t *v) 1448*7c478bd9Sstevel@tonic-gate { 1449*7c478bd9Sstevel@tonic-gate mdb_tgt_t *t = MDB_NV_COOKIE(v); 1450*7c478bd9Sstevel@tonic-gate mdb_tgt_tid_t tid = PTL_TID(t); 1451*7c478bd9Sstevel@tonic-gate mdb_tgt_reg_t r = 0; 1452*7c478bd9Sstevel@tonic-gate 1453*7c478bd9Sstevel@tonic-gate if (tid != (mdb_tgt_tid_t)-1L) 1454*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_getareg(t, tid, mdb_nv_get_name(v), &r); 1455*7c478bd9Sstevel@tonic-gate 1456*7c478bd9Sstevel@tonic-gate return (r); 1457*7c478bd9Sstevel@tonic-gate } 1458*7c478bd9Sstevel@tonic-gate 1459*7c478bd9Sstevel@tonic-gate static void 1460*7c478bd9Sstevel@tonic-gate reg_disc_set(mdb_var_t *v, uintmax_t r) 1461*7c478bd9Sstevel@tonic-gate { 1462*7c478bd9Sstevel@tonic-gate mdb_tgt_t *t = MDB_NV_COOKIE(v); 1463*7c478bd9Sstevel@tonic-gate mdb_tgt_tid_t tid = PTL_TID(t); 1464*7c478bd9Sstevel@tonic-gate 1465*7c478bd9Sstevel@tonic-gate if (tid != (mdb_tgt_tid_t)-1L && mdb_tgt_putareg(t, tid, 1466*7c478bd9Sstevel@tonic-gate mdb_nv_get_name(v), r) == -1) 1467*7c478bd9Sstevel@tonic-gate mdb_warn("failed to modify %%%s register", mdb_nv_get_name(v)); 1468*7c478bd9Sstevel@tonic-gate } 1469*7c478bd9Sstevel@tonic-gate 1470*7c478bd9Sstevel@tonic-gate static void 1471*7c478bd9Sstevel@tonic-gate pt_print_reason(const lwpstatus_t *psp) 1472*7c478bd9Sstevel@tonic-gate { 1473*7c478bd9Sstevel@tonic-gate char name[SIG2STR_MAX + 4]; /* enough for SIG+name+\0, syscall or flt */ 1474*7c478bd9Sstevel@tonic-gate const char *desc; 1475*7c478bd9Sstevel@tonic-gate 1476*7c478bd9Sstevel@tonic-gate switch (psp->pr_why) { 1477*7c478bd9Sstevel@tonic-gate case PR_REQUESTED: 1478*7c478bd9Sstevel@tonic-gate mdb_printf("stopped by debugger"); 1479*7c478bd9Sstevel@tonic-gate break; 1480*7c478bd9Sstevel@tonic-gate case PR_SIGNALLED: 1481*7c478bd9Sstevel@tonic-gate mdb_printf("stopped on %s (%s)", proc_signame(psp->pr_what, 1482*7c478bd9Sstevel@tonic-gate name, sizeof (name)), strsignal(psp->pr_what)); 1483*7c478bd9Sstevel@tonic-gate break; 1484*7c478bd9Sstevel@tonic-gate case PR_SYSENTRY: 1485*7c478bd9Sstevel@tonic-gate mdb_printf("stopped on entry to %s system call", 1486*7c478bd9Sstevel@tonic-gate proc_sysname(psp->pr_what, name, sizeof (name))); 1487*7c478bd9Sstevel@tonic-gate break; 1488*7c478bd9Sstevel@tonic-gate case PR_SYSEXIT: 1489*7c478bd9Sstevel@tonic-gate mdb_printf("stopped on exit from %s system call", 1490*7c478bd9Sstevel@tonic-gate proc_sysname(psp->pr_what, name, sizeof (name))); 1491*7c478bd9Sstevel@tonic-gate break; 1492*7c478bd9Sstevel@tonic-gate case PR_JOBCONTROL: 1493*7c478bd9Sstevel@tonic-gate mdb_printf("stopped by job control"); 1494*7c478bd9Sstevel@tonic-gate break; 1495*7c478bd9Sstevel@tonic-gate case PR_FAULTED: 1496*7c478bd9Sstevel@tonic-gate if (psp->pr_what == FLTBPT) { 1497*7c478bd9Sstevel@tonic-gate mdb_printf("stopped on a breakpoint"); 1498*7c478bd9Sstevel@tonic-gate } else if (psp->pr_what == FLTWATCH) { 1499*7c478bd9Sstevel@tonic-gate switch (psp->pr_info.si_code) { 1500*7c478bd9Sstevel@tonic-gate case TRAP_RWATCH: 1501*7c478bd9Sstevel@tonic-gate desc = "read"; 1502*7c478bd9Sstevel@tonic-gate break; 1503*7c478bd9Sstevel@tonic-gate case TRAP_WWATCH: 1504*7c478bd9Sstevel@tonic-gate desc = "write"; 1505*7c478bd9Sstevel@tonic-gate break; 1506*7c478bd9Sstevel@tonic-gate case TRAP_XWATCH: 1507*7c478bd9Sstevel@tonic-gate desc = "execute"; 1508*7c478bd9Sstevel@tonic-gate break; 1509*7c478bd9Sstevel@tonic-gate default: 1510*7c478bd9Sstevel@tonic-gate desc = "unknown"; 1511*7c478bd9Sstevel@tonic-gate } 1512*7c478bd9Sstevel@tonic-gate mdb_printf("stopped %s a watchpoint (%s access to %p)", 1513*7c478bd9Sstevel@tonic-gate psp->pr_info.si_trapafter ? "after" : "on", 1514*7c478bd9Sstevel@tonic-gate desc, psp->pr_info.si_addr); 1515*7c478bd9Sstevel@tonic-gate } else if (psp->pr_what == FLTTRACE) { 1516*7c478bd9Sstevel@tonic-gate mdb_printf("stopped after a single-step"); 1517*7c478bd9Sstevel@tonic-gate } else { 1518*7c478bd9Sstevel@tonic-gate mdb_printf("stopped on a %s fault", 1519*7c478bd9Sstevel@tonic-gate proc_fltname(psp->pr_what, name, sizeof (name))); 1520*7c478bd9Sstevel@tonic-gate } 1521*7c478bd9Sstevel@tonic-gate break; 1522*7c478bd9Sstevel@tonic-gate case PR_SUSPENDED: 1523*7c478bd9Sstevel@tonic-gate case PR_CHECKPOINT: 1524*7c478bd9Sstevel@tonic-gate mdb_printf("suspended by the kernel"); 1525*7c478bd9Sstevel@tonic-gate break; 1526*7c478bd9Sstevel@tonic-gate default: 1527*7c478bd9Sstevel@tonic-gate mdb_printf("stopped for unknown reason (%d/%d)", 1528*7c478bd9Sstevel@tonic-gate psp->pr_why, psp->pr_what); 1529*7c478bd9Sstevel@tonic-gate } 1530*7c478bd9Sstevel@tonic-gate } 1531*7c478bd9Sstevel@tonic-gate 1532*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1533*7c478bd9Sstevel@tonic-gate static int 1534*7c478bd9Sstevel@tonic-gate pt_status_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1535*7c478bd9Sstevel@tonic-gate { 1536*7c478bd9Sstevel@tonic-gate mdb_tgt_t *t = mdb.m_target; 1537*7c478bd9Sstevel@tonic-gate struct ps_prochandle *P = t->t_pshandle; 1538*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 1539*7c478bd9Sstevel@tonic-gate 1540*7c478bd9Sstevel@tonic-gate if (P != NULL) { 1541*7c478bd9Sstevel@tonic-gate const psinfo_t *pip = Ppsinfo(P); 1542*7c478bd9Sstevel@tonic-gate const pstatus_t *psp = Pstatus(P); 1543*7c478bd9Sstevel@tonic-gate int cursig = 0, bits = 0, coredump = 0; 1544*7c478bd9Sstevel@tonic-gate int state; 1545*7c478bd9Sstevel@tonic-gate GElf_Sym sym; 1546*7c478bd9Sstevel@tonic-gate uintptr_t panicstr; 1547*7c478bd9Sstevel@tonic-gate char panicbuf[128]; 1548*7c478bd9Sstevel@tonic-gate 1549*7c478bd9Sstevel@tonic-gate char execname[MAXPATHLEN], buf[BUFSIZ]; 1550*7c478bd9Sstevel@tonic-gate char signame[SIG2STR_MAX + 4]; /* enough for SIG+name+\0 */ 1551*7c478bd9Sstevel@tonic-gate 1552*7c478bd9Sstevel@tonic-gate mdb_tgt_spec_desc_t desc; 1553*7c478bd9Sstevel@tonic-gate mdb_sespec_t *sep; 1554*7c478bd9Sstevel@tonic-gate 1555*7c478bd9Sstevel@tonic-gate struct utsname uts; 1556*7c478bd9Sstevel@tonic-gate prcred_t cred; 1557*7c478bd9Sstevel@tonic-gate psinfo_t pi; 1558*7c478bd9Sstevel@tonic-gate 1559*7c478bd9Sstevel@tonic-gate (void) strcpy(uts.nodename, "unknown machine"); 1560*7c478bd9Sstevel@tonic-gate (void) Puname(P, &uts); 1561*7c478bd9Sstevel@tonic-gate 1562*7c478bd9Sstevel@tonic-gate if (pip != NULL) { 1563*7c478bd9Sstevel@tonic-gate bcopy(pip, &pi, sizeof (psinfo_t)); 1564*7c478bd9Sstevel@tonic-gate proc_unctrl_psinfo(&pi); 1565*7c478bd9Sstevel@tonic-gate } else 1566*7c478bd9Sstevel@tonic-gate bzero(&pi, sizeof (psinfo_t)); 1567*7c478bd9Sstevel@tonic-gate 1568*7c478bd9Sstevel@tonic-gate bits = pi.pr_dmodel == PR_MODEL_ILP32 ? 32 : 64; 1569*7c478bd9Sstevel@tonic-gate 1570*7c478bd9Sstevel@tonic-gate state = Pstate(P); 1571*7c478bd9Sstevel@tonic-gate if (psp != NULL && state != PS_UNDEAD && state != PS_IDLE) 1572*7c478bd9Sstevel@tonic-gate cursig = psp->pr_lwp.pr_cursig; 1573*7c478bd9Sstevel@tonic-gate 1574*7c478bd9Sstevel@tonic-gate if (state == PS_DEAD && pip != NULL) { 1575*7c478bd9Sstevel@tonic-gate mdb_printf("debugging core file of %s (%d-bit) " 1576*7c478bd9Sstevel@tonic-gate "from %s\n", pi.pr_fname, bits, uts.nodename); 1577*7c478bd9Sstevel@tonic-gate 1578*7c478bd9Sstevel@tonic-gate } else if (state == PS_DEAD) { 1579*7c478bd9Sstevel@tonic-gate mdb_printf("debugging core file\n"); 1580*7c478bd9Sstevel@tonic-gate 1581*7c478bd9Sstevel@tonic-gate } else if (state == PS_IDLE) { 1582*7c478bd9Sstevel@tonic-gate const GElf_Ehdr *ehp = &pt->p_file->gf_ehdr; 1583*7c478bd9Sstevel@tonic-gate 1584*7c478bd9Sstevel@tonic-gate mdb_printf("debugging %s file (%d-bit)\n", 1585*7c478bd9Sstevel@tonic-gate ehp->e_type == ET_EXEC ? "executable" : "object", 1586*7c478bd9Sstevel@tonic-gate ehp->e_ident[EI_CLASS] == ELFCLASS32 ? 32 : 64); 1587*7c478bd9Sstevel@tonic-gate 1588*7c478bd9Sstevel@tonic-gate } else if (state == PS_UNDEAD && pi.pr_pid == 0) { 1589*7c478bd9Sstevel@tonic-gate mdb_printf("debugging defunct process\n"); 1590*7c478bd9Sstevel@tonic-gate 1591*7c478bd9Sstevel@tonic-gate } else { 1592*7c478bd9Sstevel@tonic-gate mdb_printf("debugging PID %d (%d-bit)\n", 1593*7c478bd9Sstevel@tonic-gate pi.pr_pid, bits); 1594*7c478bd9Sstevel@tonic-gate } 1595*7c478bd9Sstevel@tonic-gate 1596*7c478bd9Sstevel@tonic-gate if (Pexecname(P, execname, sizeof (execname)) != NULL) 1597*7c478bd9Sstevel@tonic-gate mdb_printf("file: %s\n", execname); 1598*7c478bd9Sstevel@tonic-gate 1599*7c478bd9Sstevel@tonic-gate if (pip != NULL && state == PS_DEAD) 1600*7c478bd9Sstevel@tonic-gate mdb_printf("initial argv: %s\n", pi.pr_psargs); 1601*7c478bd9Sstevel@tonic-gate 1602*7c478bd9Sstevel@tonic-gate if (state != PS_UNDEAD && state != PS_IDLE) { 1603*7c478bd9Sstevel@tonic-gate mdb_printf("threading model: "); 1604*7c478bd9Sstevel@tonic-gate if (pt->p_ptl_ops == &proc_lwp_ops) 1605*7c478bd9Sstevel@tonic-gate mdb_printf("raw lwps\n"); 1606*7c478bd9Sstevel@tonic-gate else 1607*7c478bd9Sstevel@tonic-gate mdb_printf("native threads\n"); 1608*7c478bd9Sstevel@tonic-gate } 1609*7c478bd9Sstevel@tonic-gate 1610*7c478bd9Sstevel@tonic-gate mdb_printf("status: "); 1611*7c478bd9Sstevel@tonic-gate switch (state) { 1612*7c478bd9Sstevel@tonic-gate case PS_RUN: 1613*7c478bd9Sstevel@tonic-gate ASSERT(!(psp->pr_flags & PR_STOPPED)); 1614*7c478bd9Sstevel@tonic-gate mdb_printf("process is running"); 1615*7c478bd9Sstevel@tonic-gate if (psp->pr_flags & PR_DSTOP) 1616*7c478bd9Sstevel@tonic-gate mdb_printf(", debugger stop directive pending"); 1617*7c478bd9Sstevel@tonic-gate mdb_printf("\n"); 1618*7c478bd9Sstevel@tonic-gate break; 1619*7c478bd9Sstevel@tonic-gate 1620*7c478bd9Sstevel@tonic-gate case PS_STOP: 1621*7c478bd9Sstevel@tonic-gate ASSERT(psp->pr_flags & PR_STOPPED); 1622*7c478bd9Sstevel@tonic-gate pt_print_reason(&psp->pr_lwp); 1623*7c478bd9Sstevel@tonic-gate 1624*7c478bd9Sstevel@tonic-gate if (psp->pr_flags & PR_DSTOP) 1625*7c478bd9Sstevel@tonic-gate mdb_printf(", debugger stop directive pending"); 1626*7c478bd9Sstevel@tonic-gate if (psp->pr_flags & PR_ASLEEP) 1627*7c478bd9Sstevel@tonic-gate mdb_printf(", sleeping in %s system call", 1628*7c478bd9Sstevel@tonic-gate proc_sysname(psp->pr_lwp.pr_syscall, 1629*7c478bd9Sstevel@tonic-gate signame, sizeof (signame))); 1630*7c478bd9Sstevel@tonic-gate 1631*7c478bd9Sstevel@tonic-gate mdb_printf("\n"); 1632*7c478bd9Sstevel@tonic-gate 1633*7c478bd9Sstevel@tonic-gate for (sep = t->t_matched; sep != T_SE_END; 1634*7c478bd9Sstevel@tonic-gate sep = sep->se_matched) { 1635*7c478bd9Sstevel@tonic-gate mdb_printf("event: %s\n", sep->se_ops->se_info( 1636*7c478bd9Sstevel@tonic-gate t, sep, mdb_list_next(&sep->se_velist), 1637*7c478bd9Sstevel@tonic-gate &desc, buf, sizeof (buf))); 1638*7c478bd9Sstevel@tonic-gate } 1639*7c478bd9Sstevel@tonic-gate break; 1640*7c478bd9Sstevel@tonic-gate 1641*7c478bd9Sstevel@tonic-gate case PS_LOST: 1642*7c478bd9Sstevel@tonic-gate mdb_printf("debugger lost control of process\n"); 1643*7c478bd9Sstevel@tonic-gate break; 1644*7c478bd9Sstevel@tonic-gate 1645*7c478bd9Sstevel@tonic-gate case PS_UNDEAD: 1646*7c478bd9Sstevel@tonic-gate coredump = WIFSIGNALED(pi.pr_wstat) && 1647*7c478bd9Sstevel@tonic-gate WCOREDUMP(pi.pr_wstat); 1648*7c478bd9Sstevel@tonic-gate /*FALLTHRU*/ 1649*7c478bd9Sstevel@tonic-gate 1650*7c478bd9Sstevel@tonic-gate case PS_DEAD: 1651*7c478bd9Sstevel@tonic-gate if (cursig == 0 && WIFSIGNALED(pi.pr_wstat)) 1652*7c478bd9Sstevel@tonic-gate cursig = WTERMSIG(pi.pr_wstat); 1653*7c478bd9Sstevel@tonic-gate /* 1654*7c478bd9Sstevel@tonic-gate * We can only use pr_wstat == 0 as a test for gcore if 1655*7c478bd9Sstevel@tonic-gate * an NT_PRCRED note is present; these features were 1656*7c478bd9Sstevel@tonic-gate * added at the same time in Solaris 8. 1657*7c478bd9Sstevel@tonic-gate */ 1658*7c478bd9Sstevel@tonic-gate if (pi.pr_wstat == 0 && Pstate(P) == PS_DEAD && 1659*7c478bd9Sstevel@tonic-gate Pcred(P, &cred, 1) == 0) { 1660*7c478bd9Sstevel@tonic-gate mdb_printf("process core file generated " 1661*7c478bd9Sstevel@tonic-gate "with gcore(1)\n"); 1662*7c478bd9Sstevel@tonic-gate } else if (cursig != 0) { 1663*7c478bd9Sstevel@tonic-gate mdb_printf("process terminated by %s (%s)", 1664*7c478bd9Sstevel@tonic-gate proc_signame(cursig, signame, 1665*7c478bd9Sstevel@tonic-gate sizeof (signame)), strsignal(cursig)); 1666*7c478bd9Sstevel@tonic-gate if (coredump) 1667*7c478bd9Sstevel@tonic-gate mdb_printf(" - core file dumped"); 1668*7c478bd9Sstevel@tonic-gate mdb_printf("\n"); 1669*7c478bd9Sstevel@tonic-gate } else { 1670*7c478bd9Sstevel@tonic-gate mdb_printf("process terminated with exit " 1671*7c478bd9Sstevel@tonic-gate "status %d\n", WEXITSTATUS(pi.pr_wstat)); 1672*7c478bd9Sstevel@tonic-gate } 1673*7c478bd9Sstevel@tonic-gate 1674*7c478bd9Sstevel@tonic-gate if (Plookup_by_name(t->t_pshandle, "libc.so", 1675*7c478bd9Sstevel@tonic-gate "panicstr", &sym) == 0 && 1676*7c478bd9Sstevel@tonic-gate Pread(t->t_pshandle, &panicstr, sizeof (panicstr), 1677*7c478bd9Sstevel@tonic-gate sym.st_value) == sizeof (panicstr) && 1678*7c478bd9Sstevel@tonic-gate Pread_string(t->t_pshandle, panicbuf, 1679*7c478bd9Sstevel@tonic-gate sizeof (panicbuf), panicstr) > 0) { 1680*7c478bd9Sstevel@tonic-gate mdb_printf("panic message: %s", 1681*7c478bd9Sstevel@tonic-gate panicbuf); 1682*7c478bd9Sstevel@tonic-gate } 1683*7c478bd9Sstevel@tonic-gate 1684*7c478bd9Sstevel@tonic-gate 1685*7c478bd9Sstevel@tonic-gate break; 1686*7c478bd9Sstevel@tonic-gate 1687*7c478bd9Sstevel@tonic-gate case PS_IDLE: 1688*7c478bd9Sstevel@tonic-gate mdb_printf("idle\n"); 1689*7c478bd9Sstevel@tonic-gate break; 1690*7c478bd9Sstevel@tonic-gate 1691*7c478bd9Sstevel@tonic-gate default: 1692*7c478bd9Sstevel@tonic-gate mdb_printf("unknown libproc Pstate: %d\n", Pstate(P)); 1693*7c478bd9Sstevel@tonic-gate } 1694*7c478bd9Sstevel@tonic-gate 1695*7c478bd9Sstevel@tonic-gate } else if (pt->p_file != NULL) { 1696*7c478bd9Sstevel@tonic-gate const GElf_Ehdr *ehp = &pt->p_file->gf_ehdr; 1697*7c478bd9Sstevel@tonic-gate 1698*7c478bd9Sstevel@tonic-gate mdb_printf("debugging %s file (%d-bit)\n", 1699*7c478bd9Sstevel@tonic-gate ehp->e_type == ET_EXEC ? "executable" : "object", 1700*7c478bd9Sstevel@tonic-gate ehp->e_ident[EI_CLASS] == ELFCLASS32 ? 32 : 64); 1701*7c478bd9Sstevel@tonic-gate mdb_printf("executable file: %s\n", IOP_NAME(pt->p_fio)); 1702*7c478bd9Sstevel@tonic-gate mdb_printf("status: idle\n"); 1703*7c478bd9Sstevel@tonic-gate } 1704*7c478bd9Sstevel@tonic-gate 1705*7c478bd9Sstevel@tonic-gate return (DCMD_OK); 1706*7c478bd9Sstevel@tonic-gate } 1707*7c478bd9Sstevel@tonic-gate 1708*7c478bd9Sstevel@tonic-gate static int 1709*7c478bd9Sstevel@tonic-gate pt_tls(uintptr_t tid, uint_t flags, int argc, const mdb_arg_t *argv) 1710*7c478bd9Sstevel@tonic-gate { 1711*7c478bd9Sstevel@tonic-gate const char *name; 1712*7c478bd9Sstevel@tonic-gate const char *object; 1713*7c478bd9Sstevel@tonic-gate GElf_Sym sym; 1714*7c478bd9Sstevel@tonic-gate mdb_syminfo_t si; 1715*7c478bd9Sstevel@tonic-gate mdb_tgt_t *t = mdb.m_target; 1716*7c478bd9Sstevel@tonic-gate 1717*7c478bd9Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC) || argc > 1) 1718*7c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 1719*7c478bd9Sstevel@tonic-gate 1720*7c478bd9Sstevel@tonic-gate if (argc == 0) { 1721*7c478bd9Sstevel@tonic-gate psaddr_t b; 1722*7c478bd9Sstevel@tonic-gate 1723*7c478bd9Sstevel@tonic-gate if (tlsbase(t, tid, PR_LMID_EVERY, MDB_TGT_OBJ_EXEC, &b) != 0) { 1724*7c478bd9Sstevel@tonic-gate mdb_warn("failed to lookup tlsbase for %r", tid); 1725*7c478bd9Sstevel@tonic-gate return (DCMD_ERR); 1726*7c478bd9Sstevel@tonic-gate } 1727*7c478bd9Sstevel@tonic-gate 1728*7c478bd9Sstevel@tonic-gate mdb_printf("%lr\n", b); 1729*7c478bd9Sstevel@tonic-gate mdb_set_dot(b); 1730*7c478bd9Sstevel@tonic-gate 1731*7c478bd9Sstevel@tonic-gate return (DCMD_OK); 1732*7c478bd9Sstevel@tonic-gate } 1733*7c478bd9Sstevel@tonic-gate 1734*7c478bd9Sstevel@tonic-gate name = argv[0].a_un.a_str; 1735*7c478bd9Sstevel@tonic-gate object = MDB_TGT_OBJ_EVERY; 1736*7c478bd9Sstevel@tonic-gate 1737*7c478bd9Sstevel@tonic-gate if (pt_lookup_by_name_thr(t, object, name, &sym, &si, tid) != 0) { 1738*7c478bd9Sstevel@tonic-gate mdb_warn("failed to lookup %s", name); 1739*7c478bd9Sstevel@tonic-gate return (DCMD_ABORT); /* avoid repeated failure */ 1740*7c478bd9Sstevel@tonic-gate } 1741*7c478bd9Sstevel@tonic-gate 1742*7c478bd9Sstevel@tonic-gate if (GELF_ST_TYPE(sym.st_info) != STT_TLS && DCMD_HDRSPEC(flags)) 1743*7c478bd9Sstevel@tonic-gate mdb_warn("%s does not refer to thread local storage\n", name); 1744*7c478bd9Sstevel@tonic-gate 1745*7c478bd9Sstevel@tonic-gate mdb_printf("%llr\n", sym.st_value); 1746*7c478bd9Sstevel@tonic-gate mdb_set_dot(sym.st_value); 1747*7c478bd9Sstevel@tonic-gate 1748*7c478bd9Sstevel@tonic-gate return (DCMD_OK); 1749*7c478bd9Sstevel@tonic-gate } 1750*7c478bd9Sstevel@tonic-gate 1751*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1752*7c478bd9Sstevel@tonic-gate static int 1753*7c478bd9Sstevel@tonic-gate pt_tmodel(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1754*7c478bd9Sstevel@tonic-gate { 1755*7c478bd9Sstevel@tonic-gate mdb_tgt_t *t = mdb.m_target; 1756*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 1757*7c478bd9Sstevel@tonic-gate const pt_ptl_ops_t *ptl_ops; 1758*7c478bd9Sstevel@tonic-gate 1759*7c478bd9Sstevel@tonic-gate if (argc != 1 || argv->a_type != MDB_TYPE_STRING) 1760*7c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 1761*7c478bd9Sstevel@tonic-gate 1762*7c478bd9Sstevel@tonic-gate if (strcmp(argv->a_un.a_str, "thread") == 0) 1763*7c478bd9Sstevel@tonic-gate ptl_ops = &proc_tdb_ops; 1764*7c478bd9Sstevel@tonic-gate else if (strcmp(argv->a_un.a_str, "lwp") == 0) 1765*7c478bd9Sstevel@tonic-gate ptl_ops = &proc_lwp_ops; 1766*7c478bd9Sstevel@tonic-gate else 1767*7c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 1768*7c478bd9Sstevel@tonic-gate 1769*7c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL && pt->p_ptl_ops != ptl_ops) { 1770*7c478bd9Sstevel@tonic-gate PTL_DTOR(t); 1771*7c478bd9Sstevel@tonic-gate pt->p_tdb_ops = NULL; 1772*7c478bd9Sstevel@tonic-gate pt->p_ptl_ops = &proc_lwp_ops; 1773*7c478bd9Sstevel@tonic-gate pt->p_ptl_hdl = NULL; 1774*7c478bd9Sstevel@tonic-gate 1775*7c478bd9Sstevel@tonic-gate if (ptl_ops == &proc_tdb_ops) { 1776*7c478bd9Sstevel@tonic-gate (void) Pobject_iter(t->t_pshandle, (proc_map_f *) 1777*7c478bd9Sstevel@tonic-gate thr_check, t); 1778*7c478bd9Sstevel@tonic-gate } 1779*7c478bd9Sstevel@tonic-gate } 1780*7c478bd9Sstevel@tonic-gate 1781*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_status(t, &t->t_status); 1782*7c478bd9Sstevel@tonic-gate return (DCMD_OK); 1783*7c478bd9Sstevel@tonic-gate } 1784*7c478bd9Sstevel@tonic-gate 1785*7c478bd9Sstevel@tonic-gate static const char * 1786*7c478bd9Sstevel@tonic-gate env_match(const char *cmp, const char *nameval) 1787*7c478bd9Sstevel@tonic-gate { 1788*7c478bd9Sstevel@tonic-gate const char *loc; 1789*7c478bd9Sstevel@tonic-gate size_t cmplen = strlen(cmp); 1790*7c478bd9Sstevel@tonic-gate 1791*7c478bd9Sstevel@tonic-gate loc = strchr(nameval, '='); 1792*7c478bd9Sstevel@tonic-gate if (loc != NULL && (loc - nameval) == cmplen && 1793*7c478bd9Sstevel@tonic-gate strncmp(nameval, cmp, cmplen) == 0) { 1794*7c478bd9Sstevel@tonic-gate return (loc + 1); 1795*7c478bd9Sstevel@tonic-gate } 1796*7c478bd9Sstevel@tonic-gate 1797*7c478bd9Sstevel@tonic-gate return (NULL); 1798*7c478bd9Sstevel@tonic-gate } 1799*7c478bd9Sstevel@tonic-gate 1800*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1801*7c478bd9Sstevel@tonic-gate static int 1802*7c478bd9Sstevel@tonic-gate print_env(void *data, struct ps_prochandle *P, uintptr_t addr, 1803*7c478bd9Sstevel@tonic-gate const char *nameval) 1804*7c478bd9Sstevel@tonic-gate { 1805*7c478bd9Sstevel@tonic-gate const char *value; 1806*7c478bd9Sstevel@tonic-gate 1807*7c478bd9Sstevel@tonic-gate if (nameval == NULL) { 1808*7c478bd9Sstevel@tonic-gate mdb_printf("<0x%p>\n", addr); 1809*7c478bd9Sstevel@tonic-gate } else { 1810*7c478bd9Sstevel@tonic-gate if (data == NULL) 1811*7c478bd9Sstevel@tonic-gate mdb_printf("%s\n", nameval); 1812*7c478bd9Sstevel@tonic-gate else if ((value = env_match(data, nameval)) != NULL) 1813*7c478bd9Sstevel@tonic-gate mdb_printf("%s\n", value); 1814*7c478bd9Sstevel@tonic-gate } 1815*7c478bd9Sstevel@tonic-gate 1816*7c478bd9Sstevel@tonic-gate return (0); 1817*7c478bd9Sstevel@tonic-gate } 1818*7c478bd9Sstevel@tonic-gate 1819*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1820*7c478bd9Sstevel@tonic-gate static int 1821*7c478bd9Sstevel@tonic-gate pt_getenv(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1822*7c478bd9Sstevel@tonic-gate { 1823*7c478bd9Sstevel@tonic-gate mdb_tgt_t *t = mdb.m_target; 1824*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 1825*7c478bd9Sstevel@tonic-gate int i; 1826*7c478bd9Sstevel@tonic-gate uint_t opt_t = 0; 1827*7c478bd9Sstevel@tonic-gate mdb_var_t *v; 1828*7c478bd9Sstevel@tonic-gate 1829*7c478bd9Sstevel@tonic-gate i = mdb_getopts(argc, argv, 1830*7c478bd9Sstevel@tonic-gate 't', MDB_OPT_SETBITS, TRUE, &opt_t, NULL); 1831*7c478bd9Sstevel@tonic-gate 1832*7c478bd9Sstevel@tonic-gate argc -= i; 1833*7c478bd9Sstevel@tonic-gate argv += i; 1834*7c478bd9Sstevel@tonic-gate 1835*7c478bd9Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) || argc > 1) 1836*7c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 1837*7c478bd9Sstevel@tonic-gate 1838*7c478bd9Sstevel@tonic-gate if (argc == 1 && argv->a_type != MDB_TYPE_STRING) 1839*7c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 1840*7c478bd9Sstevel@tonic-gate 1841*7c478bd9Sstevel@tonic-gate if (opt_t && (Pstate(t->t_pshandle) == PS_IDLE || 1842*7c478bd9Sstevel@tonic-gate Pstate(t->t_pshandle) == PS_UNDEAD)) { 1843*7c478bd9Sstevel@tonic-gate mdb_warn("-t option requires target to be running\n"); 1844*7c478bd9Sstevel@tonic-gate return (DCMD_ERR); 1845*7c478bd9Sstevel@tonic-gate } 1846*7c478bd9Sstevel@tonic-gate 1847*7c478bd9Sstevel@tonic-gate if (opt_t != 0) { 1848*7c478bd9Sstevel@tonic-gate if (Penv_iter(t->t_pshandle, print_env, 1849*7c478bd9Sstevel@tonic-gate argc == 0 ? NULL : (void *)argv->a_un.a_str) != 0) 1850*7c478bd9Sstevel@tonic-gate return (DCMD_ERR); 1851*7c478bd9Sstevel@tonic-gate } else if (argc == 1) { 1852*7c478bd9Sstevel@tonic-gate if ((v = mdb_nv_lookup(&pt->p_env, argv->a_un.a_str)) == NULL) 1853*7c478bd9Sstevel@tonic-gate return (DCMD_ERR); 1854*7c478bd9Sstevel@tonic-gate 1855*7c478bd9Sstevel@tonic-gate ASSERT(strchr(mdb_nv_get_cookie(v), '=') != NULL); 1856*7c478bd9Sstevel@tonic-gate mdb_printf("%s\n", strchr(mdb_nv_get_cookie(v), '=') + 1); 1857*7c478bd9Sstevel@tonic-gate } else { 1858*7c478bd9Sstevel@tonic-gate 1859*7c478bd9Sstevel@tonic-gate mdb_nv_rewind(&pt->p_env); 1860*7c478bd9Sstevel@tonic-gate while ((v = mdb_nv_advance(&pt->p_env)) != NULL) 1861*7c478bd9Sstevel@tonic-gate mdb_printf("%s\n", mdb_nv_get_cookie(v)); 1862*7c478bd9Sstevel@tonic-gate } 1863*7c478bd9Sstevel@tonic-gate 1864*7c478bd9Sstevel@tonic-gate return (DCMD_OK); 1865*7c478bd9Sstevel@tonic-gate } 1866*7c478bd9Sstevel@tonic-gate 1867*7c478bd9Sstevel@tonic-gate /* 1868*7c478bd9Sstevel@tonic-gate * Function to set a variable in the internal environment, which is used when 1869*7c478bd9Sstevel@tonic-gate * creating new processes. Note that it is possible that 'nameval' can refer to 1870*7c478bd9Sstevel@tonic-gate * read-only memory, if mdb calls putenv() on an existing value before calling 1871*7c478bd9Sstevel@tonic-gate * this function. While we should avoid this situation, this function is 1872*7c478bd9Sstevel@tonic-gate * designed to be robust in the face of such changes. 1873*7c478bd9Sstevel@tonic-gate */ 1874*7c478bd9Sstevel@tonic-gate static void 1875*7c478bd9Sstevel@tonic-gate pt_env_set(pt_data_t *pt, const char *nameval) 1876*7c478bd9Sstevel@tonic-gate { 1877*7c478bd9Sstevel@tonic-gate mdb_var_t *v; 1878*7c478bd9Sstevel@tonic-gate char *equals, *val; 1879*7c478bd9Sstevel@tonic-gate const char *name; 1880*7c478bd9Sstevel@tonic-gate size_t len; 1881*7c478bd9Sstevel@tonic-gate 1882*7c478bd9Sstevel@tonic-gate if ((equals = strchr(nameval, '=')) != NULL) { 1883*7c478bd9Sstevel@tonic-gate val = strdup(nameval); 1884*7c478bd9Sstevel@tonic-gate equals = val + (equals - nameval); 1885*7c478bd9Sstevel@tonic-gate } else { 1886*7c478bd9Sstevel@tonic-gate /* 1887*7c478bd9Sstevel@tonic-gate * nameval doesn't contain an equals character. Convert this to 1888*7c478bd9Sstevel@tonic-gate * be 'nameval='. 1889*7c478bd9Sstevel@tonic-gate */ 1890*7c478bd9Sstevel@tonic-gate len = strlen(nameval); 1891*7c478bd9Sstevel@tonic-gate val = mdb_alloc(len + 2, UM_SLEEP); 1892*7c478bd9Sstevel@tonic-gate (void) mdb_snprintf(val, len + 2, "%s=", nameval); 1893*7c478bd9Sstevel@tonic-gate equals = val + len; 1894*7c478bd9Sstevel@tonic-gate } 1895*7c478bd9Sstevel@tonic-gate 1896*7c478bd9Sstevel@tonic-gate /* temporary truncate the string for lookup/insert */ 1897*7c478bd9Sstevel@tonic-gate *equals = '\0'; 1898*7c478bd9Sstevel@tonic-gate v = mdb_nv_lookup(&pt->p_env, val); 1899*7c478bd9Sstevel@tonic-gate 1900*7c478bd9Sstevel@tonic-gate if (v != NULL) { 1901*7c478bd9Sstevel@tonic-gate char *old = mdb_nv_get_cookie(v); 1902*7c478bd9Sstevel@tonic-gate mdb_free(old, strlen(old) + 1); 1903*7c478bd9Sstevel@tonic-gate name = mdb_nv_get_name(v); 1904*7c478bd9Sstevel@tonic-gate } else { 1905*7c478bd9Sstevel@tonic-gate /* 1906*7c478bd9Sstevel@tonic-gate * The environment is created using MDB_NV_EXTNAME, so we must 1907*7c478bd9Sstevel@tonic-gate * provide external storage for the variable names. 1908*7c478bd9Sstevel@tonic-gate */ 1909*7c478bd9Sstevel@tonic-gate name = strdup(val); 1910*7c478bd9Sstevel@tonic-gate } 1911*7c478bd9Sstevel@tonic-gate 1912*7c478bd9Sstevel@tonic-gate *equals = '='; 1913*7c478bd9Sstevel@tonic-gate 1914*7c478bd9Sstevel@tonic-gate (void) mdb_nv_insert(&pt->p_env, name, NULL, (uintptr_t)val, 1915*7c478bd9Sstevel@tonic-gate MDB_NV_EXTNAME); 1916*7c478bd9Sstevel@tonic-gate 1917*7c478bd9Sstevel@tonic-gate if (equals) 1918*7c478bd9Sstevel@tonic-gate *equals = '='; 1919*7c478bd9Sstevel@tonic-gate } 1920*7c478bd9Sstevel@tonic-gate 1921*7c478bd9Sstevel@tonic-gate /* 1922*7c478bd9Sstevel@tonic-gate * Clears the internal environment. 1923*7c478bd9Sstevel@tonic-gate */ 1924*7c478bd9Sstevel@tonic-gate static void 1925*7c478bd9Sstevel@tonic-gate pt_env_clear(pt_data_t *pt) 1926*7c478bd9Sstevel@tonic-gate { 1927*7c478bd9Sstevel@tonic-gate mdb_var_t *v; 1928*7c478bd9Sstevel@tonic-gate char *val, *name; 1929*7c478bd9Sstevel@tonic-gate 1930*7c478bd9Sstevel@tonic-gate mdb_nv_rewind(&pt->p_env); 1931*7c478bd9Sstevel@tonic-gate while ((v = mdb_nv_advance(&pt->p_env)) != NULL) { 1932*7c478bd9Sstevel@tonic-gate 1933*7c478bd9Sstevel@tonic-gate name = (char *)mdb_nv_get_name(v); 1934*7c478bd9Sstevel@tonic-gate val = mdb_nv_get_cookie(v); 1935*7c478bd9Sstevel@tonic-gate 1936*7c478bd9Sstevel@tonic-gate mdb_nv_remove(&pt->p_env, v); 1937*7c478bd9Sstevel@tonic-gate 1938*7c478bd9Sstevel@tonic-gate mdb_free(name, strlen(name) + 1); 1939*7c478bd9Sstevel@tonic-gate mdb_free(val, strlen(val) + 1); 1940*7c478bd9Sstevel@tonic-gate } 1941*7c478bd9Sstevel@tonic-gate } 1942*7c478bd9Sstevel@tonic-gate 1943*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1944*7c478bd9Sstevel@tonic-gate static int 1945*7c478bd9Sstevel@tonic-gate pt_setenv(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1946*7c478bd9Sstevel@tonic-gate { 1947*7c478bd9Sstevel@tonic-gate mdb_tgt_t *t = mdb.m_target; 1948*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 1949*7c478bd9Sstevel@tonic-gate char *nameval; 1950*7c478bd9Sstevel@tonic-gate size_t len; 1951*7c478bd9Sstevel@tonic-gate int alloc; 1952*7c478bd9Sstevel@tonic-gate 1953*7c478bd9Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) || argc == 0 || argc > 2) 1954*7c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 1955*7c478bd9Sstevel@tonic-gate 1956*7c478bd9Sstevel@tonic-gate if ((argc > 0 && argv[0].a_type != MDB_TYPE_STRING) || 1957*7c478bd9Sstevel@tonic-gate (argc > 1 && argv[1].a_type != MDB_TYPE_STRING)) 1958*7c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 1959*7c478bd9Sstevel@tonic-gate 1960*7c478bd9Sstevel@tonic-gate /* 1961*7c478bd9Sstevel@tonic-gate * If the process is in some sort of running state, warn the user that 1962*7c478bd9Sstevel@tonic-gate * changes won't immediately take effect. 1963*7c478bd9Sstevel@tonic-gate */ 1964*7c478bd9Sstevel@tonic-gate if (Pstate(t->t_pshandle) == PS_RUN || 1965*7c478bd9Sstevel@tonic-gate Pstate(t->t_pshandle) == PS_STOP) { 1966*7c478bd9Sstevel@tonic-gate mdb_warn("warning: changes will not take effect until process" 1967*7c478bd9Sstevel@tonic-gate " is restarted\n"); 1968*7c478bd9Sstevel@tonic-gate } 1969*7c478bd9Sstevel@tonic-gate 1970*7c478bd9Sstevel@tonic-gate /* 1971*7c478bd9Sstevel@tonic-gate * We allow two forms of operation. The first is the usual "name=value" 1972*7c478bd9Sstevel@tonic-gate * parameter. We also allow the user to specify two arguments, where 1973*7c478bd9Sstevel@tonic-gate * the first is the name of the variable, and the second is the value. 1974*7c478bd9Sstevel@tonic-gate */ 1975*7c478bd9Sstevel@tonic-gate alloc = 0; 1976*7c478bd9Sstevel@tonic-gate if (argc == 1) { 1977*7c478bd9Sstevel@tonic-gate nameval = (char *)argv->a_un.a_str; 1978*7c478bd9Sstevel@tonic-gate } else { 1979*7c478bd9Sstevel@tonic-gate len = strlen(argv[0].a_un.a_str) + 1980*7c478bd9Sstevel@tonic-gate strlen(argv[1].a_un.a_str) + 2; 1981*7c478bd9Sstevel@tonic-gate nameval = mdb_alloc(len, UM_SLEEP); 1982*7c478bd9Sstevel@tonic-gate (void) mdb_snprintf(nameval, len, "%s=%s", argv[0].a_un.a_str, 1983*7c478bd9Sstevel@tonic-gate argv[1].a_un.a_str); 1984*7c478bd9Sstevel@tonic-gate alloc = 1; 1985*7c478bd9Sstevel@tonic-gate } 1986*7c478bd9Sstevel@tonic-gate 1987*7c478bd9Sstevel@tonic-gate pt_env_set(pt, nameval); 1988*7c478bd9Sstevel@tonic-gate 1989*7c478bd9Sstevel@tonic-gate if (alloc) 1990*7c478bd9Sstevel@tonic-gate mdb_free(nameval, strlen(nameval) + 1); 1991*7c478bd9Sstevel@tonic-gate 1992*7c478bd9Sstevel@tonic-gate return (DCMD_OK); 1993*7c478bd9Sstevel@tonic-gate } 1994*7c478bd9Sstevel@tonic-gate 1995*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1996*7c478bd9Sstevel@tonic-gate static int 1997*7c478bd9Sstevel@tonic-gate pt_unsetenv(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1998*7c478bd9Sstevel@tonic-gate { 1999*7c478bd9Sstevel@tonic-gate mdb_tgt_t *t = mdb.m_target; 2000*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 2001*7c478bd9Sstevel@tonic-gate mdb_var_t *v; 2002*7c478bd9Sstevel@tonic-gate char *value, *name; 2003*7c478bd9Sstevel@tonic-gate 2004*7c478bd9Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) || argc > 1) 2005*7c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 2006*7c478bd9Sstevel@tonic-gate 2007*7c478bd9Sstevel@tonic-gate if (argc == 1 && argv->a_type != MDB_TYPE_STRING) 2008*7c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 2009*7c478bd9Sstevel@tonic-gate 2010*7c478bd9Sstevel@tonic-gate /* 2011*7c478bd9Sstevel@tonic-gate * If the process is in some sort of running state, warn the user that 2012*7c478bd9Sstevel@tonic-gate * changes won't immediately take effect. 2013*7c478bd9Sstevel@tonic-gate */ 2014*7c478bd9Sstevel@tonic-gate if (Pstate(t->t_pshandle) == PS_RUN || 2015*7c478bd9Sstevel@tonic-gate Pstate(t->t_pshandle) == PS_STOP) { 2016*7c478bd9Sstevel@tonic-gate mdb_warn("warning: changes will not take effect until process" 2017*7c478bd9Sstevel@tonic-gate " is restarted\n"); 2018*7c478bd9Sstevel@tonic-gate } 2019*7c478bd9Sstevel@tonic-gate 2020*7c478bd9Sstevel@tonic-gate if (argc == 0) { 2021*7c478bd9Sstevel@tonic-gate pt_env_clear(pt); 2022*7c478bd9Sstevel@tonic-gate } else { 2023*7c478bd9Sstevel@tonic-gate if ((v = mdb_nv_lookup(&pt->p_env, argv->a_un.a_str)) != NULL) { 2024*7c478bd9Sstevel@tonic-gate name = (char *)mdb_nv_get_name(v); 2025*7c478bd9Sstevel@tonic-gate value = mdb_nv_get_cookie(v); 2026*7c478bd9Sstevel@tonic-gate 2027*7c478bd9Sstevel@tonic-gate mdb_nv_remove(&pt->p_env, v); 2028*7c478bd9Sstevel@tonic-gate 2029*7c478bd9Sstevel@tonic-gate mdb_free(name, strlen(name) + 1); 2030*7c478bd9Sstevel@tonic-gate mdb_free(value, strlen(value) + 1); 2031*7c478bd9Sstevel@tonic-gate } 2032*7c478bd9Sstevel@tonic-gate } 2033*7c478bd9Sstevel@tonic-gate 2034*7c478bd9Sstevel@tonic-gate return (DCMD_OK); 2035*7c478bd9Sstevel@tonic-gate } 2036*7c478bd9Sstevel@tonic-gate 2037*7c478bd9Sstevel@tonic-gate static const mdb_dcmd_t pt_dcmds[] = { 2038*7c478bd9Sstevel@tonic-gate { "$c", "?[cnt]", "print stack backtrace", pt_stack }, 2039*7c478bd9Sstevel@tonic-gate { "$C", "?[cnt]", "print stack backtrace", pt_stackv }, 2040*7c478bd9Sstevel@tonic-gate { "$i", NULL, "print signals that are ignored", pt_ignored }, 2041*7c478bd9Sstevel@tonic-gate { "$l", NULL, "print the representative thread's lwp id", pt_lwpid }, 2042*7c478bd9Sstevel@tonic-gate { "$L", NULL, "print list of the active lwp ids", pt_lwpids }, 2043*7c478bd9Sstevel@tonic-gate { "$r", "?", "print general-purpose registers", pt_regs }, 2044*7c478bd9Sstevel@tonic-gate { "$x", "?", "print floating point registers", pt_fpregs }, 2045*7c478bd9Sstevel@tonic-gate { "$X", "?", "print floating point registers", pt_fpregs }, 2046*7c478bd9Sstevel@tonic-gate { "$y", "?", "print floating point registers", pt_fpregs }, 2047*7c478bd9Sstevel@tonic-gate { "$Y", "?", "print floating point registers", pt_fpregs }, 2048*7c478bd9Sstevel@tonic-gate { "$?", "?", "print status and registers", pt_regstatus }, 2049*7c478bd9Sstevel@tonic-gate { ":A", "?[core|pid]", "attach to process or core file", pt_attach }, 2050*7c478bd9Sstevel@tonic-gate { ":i", ":", "ignore signal (delete all matching events)", pt_ignore }, 2051*7c478bd9Sstevel@tonic-gate { ":k", NULL, "forcibly kill and release target", pt_kill }, 2052*7c478bd9Sstevel@tonic-gate { ":R", "[-a]", "release the previously attached process", pt_detach }, 2053*7c478bd9Sstevel@tonic-gate { "attach", "?[core|pid]", 2054*7c478bd9Sstevel@tonic-gate "attach to process or core file", pt_attach }, 2055*7c478bd9Sstevel@tonic-gate { "findstack", ":[-v]", "find user thread stack", pt_findstack }, 2056*7c478bd9Sstevel@tonic-gate { "gcore", "[-o prefix] [-c content]", 2057*7c478bd9Sstevel@tonic-gate "produce a core file for the attached process", pt_gcore }, 2058*7c478bd9Sstevel@tonic-gate { "getenv", "[-t] [name]", "display an environment variable", 2059*7c478bd9Sstevel@tonic-gate pt_getenv, NULL }, 2060*7c478bd9Sstevel@tonic-gate { "kill", NULL, "forcibly kill and release target", pt_kill }, 2061*7c478bd9Sstevel@tonic-gate { "release", "[-a]", 2062*7c478bd9Sstevel@tonic-gate "release the previously attached process", pt_detach }, 2063*7c478bd9Sstevel@tonic-gate { "regs", "?", "print general-purpose registers", pt_regs }, 2064*7c478bd9Sstevel@tonic-gate { "fpregs", "?[-dqs]", "print floating point registers", pt_fpregs }, 2065*7c478bd9Sstevel@tonic-gate { "setenv", "name=value", "set an environment variable", pt_setenv }, 2066*7c478bd9Sstevel@tonic-gate { "stack", "?[cnt]", "print stack backtrace", pt_stack }, 2067*7c478bd9Sstevel@tonic-gate { "stackregs", "?", "print stack backtrace and registers", pt_stackr }, 2068*7c478bd9Sstevel@tonic-gate { "status", NULL, "print summary of current target", pt_status_dcmd }, 2069*7c478bd9Sstevel@tonic-gate { "tls", ":symbol", 2070*7c478bd9Sstevel@tonic-gate "lookup TLS data in the context of a given thread", pt_tls }, 2071*7c478bd9Sstevel@tonic-gate { "tmodel", "{thread|lwp}", NULL, pt_tmodel }, 2072*7c478bd9Sstevel@tonic-gate { "unsetenv", "[name]", "clear an environment variable", pt_unsetenv }, 2073*7c478bd9Sstevel@tonic-gate { NULL } 2074*7c478bd9Sstevel@tonic-gate }; 2075*7c478bd9Sstevel@tonic-gate 2076*7c478bd9Sstevel@tonic-gate static void 2077*7c478bd9Sstevel@tonic-gate pt_thr_walk_fini(mdb_walk_state_t *wsp) 2078*7c478bd9Sstevel@tonic-gate { 2079*7c478bd9Sstevel@tonic-gate mdb_addrvec_destroy(wsp->walk_data); 2080*7c478bd9Sstevel@tonic-gate mdb_free(wsp->walk_data, sizeof (mdb_addrvec_t)); 2081*7c478bd9Sstevel@tonic-gate } 2082*7c478bd9Sstevel@tonic-gate 2083*7c478bd9Sstevel@tonic-gate static int 2084*7c478bd9Sstevel@tonic-gate pt_thr_walk_init(mdb_walk_state_t *wsp) 2085*7c478bd9Sstevel@tonic-gate { 2086*7c478bd9Sstevel@tonic-gate wsp->walk_data = mdb_zalloc(sizeof (mdb_addrvec_t), UM_SLEEP); 2087*7c478bd9Sstevel@tonic-gate mdb_addrvec_create(wsp->walk_data); 2088*7c478bd9Sstevel@tonic-gate 2089*7c478bd9Sstevel@tonic-gate if (PTL_ITER(mdb.m_target, wsp->walk_data) == -1) { 2090*7c478bd9Sstevel@tonic-gate mdb_warn("failed to iterate over threads"); 2091*7c478bd9Sstevel@tonic-gate pt_thr_walk_fini(wsp); 2092*7c478bd9Sstevel@tonic-gate return (WALK_ERR); 2093*7c478bd9Sstevel@tonic-gate } 2094*7c478bd9Sstevel@tonic-gate 2095*7c478bd9Sstevel@tonic-gate return (WALK_NEXT); 2096*7c478bd9Sstevel@tonic-gate } 2097*7c478bd9Sstevel@tonic-gate 2098*7c478bd9Sstevel@tonic-gate static int 2099*7c478bd9Sstevel@tonic-gate pt_thr_walk_step(mdb_walk_state_t *wsp) 2100*7c478bd9Sstevel@tonic-gate { 2101*7c478bd9Sstevel@tonic-gate if (mdb_addrvec_length(wsp->walk_data) != 0) { 2102*7c478bd9Sstevel@tonic-gate return (wsp->walk_callback(mdb_addrvec_shift(wsp->walk_data), 2103*7c478bd9Sstevel@tonic-gate NULL, wsp->walk_cbdata)); 2104*7c478bd9Sstevel@tonic-gate } 2105*7c478bd9Sstevel@tonic-gate return (WALK_DONE); 2106*7c478bd9Sstevel@tonic-gate } 2107*7c478bd9Sstevel@tonic-gate 2108*7c478bd9Sstevel@tonic-gate static const mdb_walker_t pt_walkers[] = { 2109*7c478bd9Sstevel@tonic-gate { "thread", "walk list of valid thread identifiers", 2110*7c478bd9Sstevel@tonic-gate pt_thr_walk_init, pt_thr_walk_step, pt_thr_walk_fini }, 2111*7c478bd9Sstevel@tonic-gate { NULL } 2112*7c478bd9Sstevel@tonic-gate }; 2113*7c478bd9Sstevel@tonic-gate 2114*7c478bd9Sstevel@tonic-gate 2115*7c478bd9Sstevel@tonic-gate static void 2116*7c478bd9Sstevel@tonic-gate pt_activate_common(mdb_tgt_t *t) 2117*7c478bd9Sstevel@tonic-gate { 2118*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 2119*7c478bd9Sstevel@tonic-gate GElf_Sym sym; 2120*7c478bd9Sstevel@tonic-gate 2121*7c478bd9Sstevel@tonic-gate /* 2122*7c478bd9Sstevel@tonic-gate * If we have a libproc handle and AT_BASE is set, the process or core 2123*7c478bd9Sstevel@tonic-gate * is dynamically linked. We call Prd_agent() to force libproc to 2124*7c478bd9Sstevel@tonic-gate * try to initialize librtld_db, and issue a warning if that fails. 2125*7c478bd9Sstevel@tonic-gate */ 2126*7c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL && Pgetauxval(t->t_pshandle, 2127*7c478bd9Sstevel@tonic-gate AT_BASE) != -1L && Prd_agent(t->t_pshandle) == NULL) { 2128*7c478bd9Sstevel@tonic-gate mdb_warn("warning: librtld_db failed to initialize; shared " 2129*7c478bd9Sstevel@tonic-gate "library information will not be available\n"); 2130*7c478bd9Sstevel@tonic-gate } 2131*7c478bd9Sstevel@tonic-gate 2132*7c478bd9Sstevel@tonic-gate /* 2133*7c478bd9Sstevel@tonic-gate * If we have a libproc handle and libthread is loaded, attempt to load 2134*7c478bd9Sstevel@tonic-gate * and initialize the corresponding libthread_db. If this fails, fall 2135*7c478bd9Sstevel@tonic-gate * back to our native LWP implementation and issue a warning. 2136*7c478bd9Sstevel@tonic-gate */ 2137*7c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL && Pstate(t->t_pshandle) != PS_IDLE) 2138*7c478bd9Sstevel@tonic-gate (void) Pobject_iter(t->t_pshandle, (proc_map_f *)thr_check, t); 2139*7c478bd9Sstevel@tonic-gate 2140*7c478bd9Sstevel@tonic-gate /* 2141*7c478bd9Sstevel@tonic-gate * If there's a global object named '_mdb_abort_info', assuming we're 2142*7c478bd9Sstevel@tonic-gate * debugging mdb itself and load the developer support module. 2143*7c478bd9Sstevel@tonic-gate */ 2144*7c478bd9Sstevel@tonic-gate if (mdb_gelf_symtab_lookup_by_name(pt->p_symtab, "_mdb_abort_info", 2145*7c478bd9Sstevel@tonic-gate &sym, NULL) == 0 && GELF_ST_TYPE(sym.st_info) == STT_OBJECT) { 2146*7c478bd9Sstevel@tonic-gate if (mdb_module_load("mdb_ds", MDB_MOD_SILENT) < 0) 2147*7c478bd9Sstevel@tonic-gate mdb_warn("warning: failed to load developer support\n"); 2148*7c478bd9Sstevel@tonic-gate } 2149*7c478bd9Sstevel@tonic-gate 2150*7c478bd9Sstevel@tonic-gate mdb_tgt_elf_export(pt->p_file); 2151*7c478bd9Sstevel@tonic-gate } 2152*7c478bd9Sstevel@tonic-gate 2153*7c478bd9Sstevel@tonic-gate static void 2154*7c478bd9Sstevel@tonic-gate pt_activate(mdb_tgt_t *t) 2155*7c478bd9Sstevel@tonic-gate { 2156*7c478bd9Sstevel@tonic-gate static const mdb_nv_disc_t reg_disc = { reg_disc_set, reg_disc_get }; 2157*7c478bd9Sstevel@tonic-gate 2158*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 2159*7c478bd9Sstevel@tonic-gate struct utsname u1, u2; 2160*7c478bd9Sstevel@tonic-gate mdb_var_t *v; 2161*7c478bd9Sstevel@tonic-gate core_content_t content; 2162*7c478bd9Sstevel@tonic-gate 2163*7c478bd9Sstevel@tonic-gate if (t->t_pshandle) { 2164*7c478bd9Sstevel@tonic-gate mdb_prop_postmortem = (Pstate(t->t_pshandle) == PS_DEAD); 2165*7c478bd9Sstevel@tonic-gate mdb_prop_kernel = FALSE; 2166*7c478bd9Sstevel@tonic-gate } else 2167*7c478bd9Sstevel@tonic-gate mdb_prop_kernel = mdb_prop_postmortem = FALSE; 2168*7c478bd9Sstevel@tonic-gate 2169*7c478bd9Sstevel@tonic-gate mdb_prop_datamodel = MDB_TGT_MODEL_NATIVE; 2170*7c478bd9Sstevel@tonic-gate 2171*7c478bd9Sstevel@tonic-gate /* 2172*7c478bd9Sstevel@tonic-gate * If we're examining a core file that doesn't contain program text, 2173*7c478bd9Sstevel@tonic-gate * and uname(2) doesn't match the NT_UTSNAME note recorded in the 2174*7c478bd9Sstevel@tonic-gate * core file, issue a warning. 2175*7c478bd9Sstevel@tonic-gate */ 2176*7c478bd9Sstevel@tonic-gate if (mdb_prop_postmortem == TRUE && 2177*7c478bd9Sstevel@tonic-gate ((content = Pcontent(t->t_pshandle)) == CC_CONTENT_INVALID || 2178*7c478bd9Sstevel@tonic-gate !(content & CC_CONTENT_TEXT)) && 2179*7c478bd9Sstevel@tonic-gate uname(&u1) >= 0 && Puname(t->t_pshandle, &u2) == 0 && 2180*7c478bd9Sstevel@tonic-gate (strcmp(u1.release, u2.release) != 0 || 2181*7c478bd9Sstevel@tonic-gate strcmp(u1.version, u2.version) != 0)) { 2182*7c478bd9Sstevel@tonic-gate mdb_warn("warning: core file is from %s %s %s; shared text " 2183*7c478bd9Sstevel@tonic-gate "mappings may not match installed libraries\n", 2184*7c478bd9Sstevel@tonic-gate u2.sysname, u2.release, u2.version); 2185*7c478bd9Sstevel@tonic-gate } 2186*7c478bd9Sstevel@tonic-gate 2187*7c478bd9Sstevel@tonic-gate /* 2188*7c478bd9Sstevel@tonic-gate * Perform the common initialization tasks -- these are shared with 2189*7c478bd9Sstevel@tonic-gate * the pt_exec() and pt_run() subroutines. 2190*7c478bd9Sstevel@tonic-gate */ 2191*7c478bd9Sstevel@tonic-gate pt_activate_common(t); 2192*7c478bd9Sstevel@tonic-gate 2193*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_register_dcmds(t, &pt_dcmds[0], MDB_MOD_FORCE); 2194*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_register_walkers(t, &pt_walkers[0], MDB_MOD_FORCE); 2195*7c478bd9Sstevel@tonic-gate 2196*7c478bd9Sstevel@tonic-gate /* 2197*7c478bd9Sstevel@tonic-gate * Iterate through our register description list and export 2198*7c478bd9Sstevel@tonic-gate * each register as a named variable. 2199*7c478bd9Sstevel@tonic-gate */ 2200*7c478bd9Sstevel@tonic-gate mdb_nv_rewind(&pt->p_regs); 2201*7c478bd9Sstevel@tonic-gate while ((v = mdb_nv_advance(&pt->p_regs)) != NULL) { 2202*7c478bd9Sstevel@tonic-gate ushort_t rd_flags = MDB_TGT_R_FLAGS(mdb_nv_get_value(v)); 2203*7c478bd9Sstevel@tonic-gate 2204*7c478bd9Sstevel@tonic-gate if (!(rd_flags & MDB_TGT_R_EXPORT)) 2205*7c478bd9Sstevel@tonic-gate continue; /* Don't export register as a variable */ 2206*7c478bd9Sstevel@tonic-gate 2207*7c478bd9Sstevel@tonic-gate (void) mdb_nv_insert(&mdb.m_nv, mdb_nv_get_name(v), ®_disc, 2208*7c478bd9Sstevel@tonic-gate (uintptr_t)t, MDB_NV_PERSIST); 2209*7c478bd9Sstevel@tonic-gate } 2210*7c478bd9Sstevel@tonic-gate } 2211*7c478bd9Sstevel@tonic-gate 2212*7c478bd9Sstevel@tonic-gate static void 2213*7c478bd9Sstevel@tonic-gate pt_deactivate(mdb_tgt_t *t) 2214*7c478bd9Sstevel@tonic-gate { 2215*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 2216*7c478bd9Sstevel@tonic-gate const mdb_dcmd_t *dcp; 2217*7c478bd9Sstevel@tonic-gate const mdb_walker_t *wp; 2218*7c478bd9Sstevel@tonic-gate mdb_var_t *v, *w; 2219*7c478bd9Sstevel@tonic-gate 2220*7c478bd9Sstevel@tonic-gate mdb_nv_rewind(&pt->p_regs); 2221*7c478bd9Sstevel@tonic-gate while ((v = mdb_nv_advance(&pt->p_regs)) != NULL) { 2222*7c478bd9Sstevel@tonic-gate ushort_t rd_flags = MDB_TGT_R_FLAGS(mdb_nv_get_value(v)); 2223*7c478bd9Sstevel@tonic-gate 2224*7c478bd9Sstevel@tonic-gate if (!(rd_flags & MDB_TGT_R_EXPORT)) 2225*7c478bd9Sstevel@tonic-gate continue; /* Didn't export register as a variable */ 2226*7c478bd9Sstevel@tonic-gate 2227*7c478bd9Sstevel@tonic-gate if (w = mdb_nv_lookup(&mdb.m_nv, mdb_nv_get_name(v))) { 2228*7c478bd9Sstevel@tonic-gate w->v_flags &= ~MDB_NV_PERSIST; 2229*7c478bd9Sstevel@tonic-gate mdb_nv_remove(&mdb.m_nv, w); 2230*7c478bd9Sstevel@tonic-gate } 2231*7c478bd9Sstevel@tonic-gate } 2232*7c478bd9Sstevel@tonic-gate 2233*7c478bd9Sstevel@tonic-gate for (wp = &pt_walkers[0]; wp->walk_name != NULL; wp++) { 2234*7c478bd9Sstevel@tonic-gate if (mdb_module_remove_walker(t->t_module, wp->walk_name) == -1) 2235*7c478bd9Sstevel@tonic-gate warn("failed to remove walk %s", wp->walk_name); 2236*7c478bd9Sstevel@tonic-gate } 2237*7c478bd9Sstevel@tonic-gate 2238*7c478bd9Sstevel@tonic-gate for (dcp = &pt_dcmds[0]; dcp->dc_name != NULL; dcp++) { 2239*7c478bd9Sstevel@tonic-gate if (mdb_module_remove_dcmd(t->t_module, dcp->dc_name) == -1) 2240*7c478bd9Sstevel@tonic-gate warn("failed to remove dcmd %s", dcp->dc_name); 2241*7c478bd9Sstevel@tonic-gate } 2242*7c478bd9Sstevel@tonic-gate 2243*7c478bd9Sstevel@tonic-gate mdb_prop_postmortem = FALSE; 2244*7c478bd9Sstevel@tonic-gate mdb_prop_kernel = FALSE; 2245*7c478bd9Sstevel@tonic-gate mdb_prop_datamodel = MDB_TGT_MODEL_UNKNOWN; 2246*7c478bd9Sstevel@tonic-gate } 2247*7c478bd9Sstevel@tonic-gate 2248*7c478bd9Sstevel@tonic-gate static void 2249*7c478bd9Sstevel@tonic-gate pt_periodic(mdb_tgt_t *t) 2250*7c478bd9Sstevel@tonic-gate { 2251*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 2252*7c478bd9Sstevel@tonic-gate 2253*7c478bd9Sstevel@tonic-gate if (pt->p_rdstate == PT_RD_CONSIST) { 2254*7c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL && Pstate(t->t_pshandle) < PS_LOST && 2255*7c478bd9Sstevel@tonic-gate !(mdb.m_flags & MDB_FL_NOMODS)) { 2256*7c478bd9Sstevel@tonic-gate mdb_printf("%s: You've got symbols!\n", mdb.m_pname); 2257*7c478bd9Sstevel@tonic-gate mdb_module_load_all(0); 2258*7c478bd9Sstevel@tonic-gate } 2259*7c478bd9Sstevel@tonic-gate pt->p_rdstate = PT_RD_NONE; 2260*7c478bd9Sstevel@tonic-gate } 2261*7c478bd9Sstevel@tonic-gate } 2262*7c478bd9Sstevel@tonic-gate 2263*7c478bd9Sstevel@tonic-gate static void 2264*7c478bd9Sstevel@tonic-gate pt_destroy(mdb_tgt_t *t) 2265*7c478bd9Sstevel@tonic-gate { 2266*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 2267*7c478bd9Sstevel@tonic-gate 2268*7c478bd9Sstevel@tonic-gate if (pt->p_idlehandle != NULL && pt->p_idlehandle != t->t_pshandle) 2269*7c478bd9Sstevel@tonic-gate Prelease(pt->p_idlehandle, 0); 2270*7c478bd9Sstevel@tonic-gate 2271*7c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL) { 2272*7c478bd9Sstevel@tonic-gate PTL_DTOR(t); 2273*7c478bd9Sstevel@tonic-gate pt_release_parents(t); 2274*7c478bd9Sstevel@tonic-gate pt_pre_detach(t, TRUE); 2275*7c478bd9Sstevel@tonic-gate Prelease(t->t_pshandle, pt->p_rflags); 2276*7c478bd9Sstevel@tonic-gate } 2277*7c478bd9Sstevel@tonic-gate 2278*7c478bd9Sstevel@tonic-gate mdb.m_flags &= ~(MDB_FL_VCREATE | MDB_FL_JOBCTL); 2279*7c478bd9Sstevel@tonic-gate pt_close_aout(t); 2280*7c478bd9Sstevel@tonic-gate 2281*7c478bd9Sstevel@tonic-gate if (pt->p_aout_fio != NULL) 2282*7c478bd9Sstevel@tonic-gate mdb_io_rele(pt->p_aout_fio); 2283*7c478bd9Sstevel@tonic-gate 2284*7c478bd9Sstevel@tonic-gate pt_env_clear(pt); 2285*7c478bd9Sstevel@tonic-gate mdb_nv_destroy(&pt->p_env); 2286*7c478bd9Sstevel@tonic-gate 2287*7c478bd9Sstevel@tonic-gate mdb_nv_destroy(&pt->p_regs); 2288*7c478bd9Sstevel@tonic-gate mdb_free(pt, sizeof (pt_data_t)); 2289*7c478bd9Sstevel@tonic-gate } 2290*7c478bd9Sstevel@tonic-gate 2291*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2292*7c478bd9Sstevel@tonic-gate static const char * 2293*7c478bd9Sstevel@tonic-gate pt_name(mdb_tgt_t *t) 2294*7c478bd9Sstevel@tonic-gate { 2295*7c478bd9Sstevel@tonic-gate return ("proc"); 2296*7c478bd9Sstevel@tonic-gate } 2297*7c478bd9Sstevel@tonic-gate 2298*7c478bd9Sstevel@tonic-gate static const char * 2299*7c478bd9Sstevel@tonic-gate pt_platform(mdb_tgt_t *t) 2300*7c478bd9Sstevel@tonic-gate { 2301*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 2302*7c478bd9Sstevel@tonic-gate 2303*7c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL && 2304*7c478bd9Sstevel@tonic-gate Pplatform(t->t_pshandle, pt->p_platform, MAXNAMELEN) != NULL) 2305*7c478bd9Sstevel@tonic-gate return (pt->p_platform); 2306*7c478bd9Sstevel@tonic-gate 2307*7c478bd9Sstevel@tonic-gate return (mdb_conf_platform()); 2308*7c478bd9Sstevel@tonic-gate } 2309*7c478bd9Sstevel@tonic-gate 2310*7c478bd9Sstevel@tonic-gate static int 2311*7c478bd9Sstevel@tonic-gate pt_uname(mdb_tgt_t *t, struct utsname *utsp) 2312*7c478bd9Sstevel@tonic-gate { 2313*7c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL) 2314*7c478bd9Sstevel@tonic-gate return (Puname(t->t_pshandle, utsp)); 2315*7c478bd9Sstevel@tonic-gate 2316*7c478bd9Sstevel@tonic-gate return (uname(utsp) >= 0 ? 0 : -1); 2317*7c478bd9Sstevel@tonic-gate } 2318*7c478bd9Sstevel@tonic-gate 2319*7c478bd9Sstevel@tonic-gate static int 2320*7c478bd9Sstevel@tonic-gate pt_dmodel(mdb_tgt_t *t) 2321*7c478bd9Sstevel@tonic-gate { 2322*7c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) 2323*7c478bd9Sstevel@tonic-gate return (MDB_TGT_MODEL_NATIVE); 2324*7c478bd9Sstevel@tonic-gate 2325*7c478bd9Sstevel@tonic-gate switch (Pstatus(t->t_pshandle)->pr_dmodel) { 2326*7c478bd9Sstevel@tonic-gate case PR_MODEL_ILP32: 2327*7c478bd9Sstevel@tonic-gate return (MDB_TGT_MODEL_ILP32); 2328*7c478bd9Sstevel@tonic-gate case PR_MODEL_LP64: 2329*7c478bd9Sstevel@tonic-gate return (MDB_TGT_MODEL_LP64); 2330*7c478bd9Sstevel@tonic-gate } 2331*7c478bd9Sstevel@tonic-gate 2332*7c478bd9Sstevel@tonic-gate return (MDB_TGT_MODEL_UNKNOWN); 2333*7c478bd9Sstevel@tonic-gate } 2334*7c478bd9Sstevel@tonic-gate 2335*7c478bd9Sstevel@tonic-gate static ssize_t 2336*7c478bd9Sstevel@tonic-gate pt_vread(mdb_tgt_t *t, void *buf, size_t nbytes, uintptr_t addr) 2337*7c478bd9Sstevel@tonic-gate { 2338*7c478bd9Sstevel@tonic-gate ssize_t n; 2339*7c478bd9Sstevel@tonic-gate 2340*7c478bd9Sstevel@tonic-gate /* 2341*7c478bd9Sstevel@tonic-gate * If no handle is open yet, reads from virtual addresses are 2342*7c478bd9Sstevel@tonic-gate * allowed to succeed but return zero-filled memory. 2343*7c478bd9Sstevel@tonic-gate */ 2344*7c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) { 2345*7c478bd9Sstevel@tonic-gate bzero(buf, nbytes); 2346*7c478bd9Sstevel@tonic-gate return (nbytes); 2347*7c478bd9Sstevel@tonic-gate } 2348*7c478bd9Sstevel@tonic-gate 2349*7c478bd9Sstevel@tonic-gate if ((n = Pread(t->t_pshandle, buf, nbytes, addr)) <= 0) 2350*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOMAP)); 2351*7c478bd9Sstevel@tonic-gate 2352*7c478bd9Sstevel@tonic-gate return (n); 2353*7c478bd9Sstevel@tonic-gate } 2354*7c478bd9Sstevel@tonic-gate 2355*7c478bd9Sstevel@tonic-gate static ssize_t 2356*7c478bd9Sstevel@tonic-gate pt_vwrite(mdb_tgt_t *t, const void *buf, size_t nbytes, uintptr_t addr) 2357*7c478bd9Sstevel@tonic-gate { 2358*7c478bd9Sstevel@tonic-gate ssize_t n; 2359*7c478bd9Sstevel@tonic-gate 2360*7c478bd9Sstevel@tonic-gate /* 2361*7c478bd9Sstevel@tonic-gate * If no handle is open yet, writes to virtual addresses are 2362*7c478bd9Sstevel@tonic-gate * allowed to succeed but do not actually modify anything. 2363*7c478bd9Sstevel@tonic-gate */ 2364*7c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) 2365*7c478bd9Sstevel@tonic-gate return (nbytes); 2366*7c478bd9Sstevel@tonic-gate 2367*7c478bd9Sstevel@tonic-gate n = Pwrite(t->t_pshandle, buf, nbytes, addr); 2368*7c478bd9Sstevel@tonic-gate 2369*7c478bd9Sstevel@tonic-gate if (n == -1 && errno == EIO) 2370*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOMAP)); 2371*7c478bd9Sstevel@tonic-gate 2372*7c478bd9Sstevel@tonic-gate return (n); 2373*7c478bd9Sstevel@tonic-gate } 2374*7c478bd9Sstevel@tonic-gate 2375*7c478bd9Sstevel@tonic-gate static ssize_t 2376*7c478bd9Sstevel@tonic-gate pt_fread(mdb_tgt_t *t, void *buf, size_t nbytes, uintptr_t addr) 2377*7c478bd9Sstevel@tonic-gate { 2378*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 2379*7c478bd9Sstevel@tonic-gate 2380*7c478bd9Sstevel@tonic-gate if (pt->p_file != NULL) { 2381*7c478bd9Sstevel@tonic-gate return (mdb_gelf_rw(pt->p_file, buf, nbytes, addr, 2382*7c478bd9Sstevel@tonic-gate IOPF_READ(pt->p_fio), GIO_READ)); 2383*7c478bd9Sstevel@tonic-gate } 2384*7c478bd9Sstevel@tonic-gate 2385*7c478bd9Sstevel@tonic-gate bzero(buf, nbytes); 2386*7c478bd9Sstevel@tonic-gate return (nbytes); 2387*7c478bd9Sstevel@tonic-gate } 2388*7c478bd9Sstevel@tonic-gate 2389*7c478bd9Sstevel@tonic-gate static ssize_t 2390*7c478bd9Sstevel@tonic-gate pt_fwrite(mdb_tgt_t *t, const void *buf, size_t nbytes, uintptr_t addr) 2391*7c478bd9Sstevel@tonic-gate { 2392*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 2393*7c478bd9Sstevel@tonic-gate 2394*7c478bd9Sstevel@tonic-gate if (pt->p_file != NULL) { 2395*7c478bd9Sstevel@tonic-gate return (mdb_gelf_rw(pt->p_file, (void *)buf, nbytes, addr, 2396*7c478bd9Sstevel@tonic-gate IOPF_WRITE(pt->p_fio), GIO_WRITE)); 2397*7c478bd9Sstevel@tonic-gate } 2398*7c478bd9Sstevel@tonic-gate 2399*7c478bd9Sstevel@tonic-gate return (nbytes); 2400*7c478bd9Sstevel@tonic-gate } 2401*7c478bd9Sstevel@tonic-gate 2402*7c478bd9Sstevel@tonic-gate static const char * 2403*7c478bd9Sstevel@tonic-gate pt_resolve_lmid(const char *object, Lmid_t *lmidp) 2404*7c478bd9Sstevel@tonic-gate { 2405*7c478bd9Sstevel@tonic-gate Lmid_t lmid = PR_LMID_EVERY; 2406*7c478bd9Sstevel@tonic-gate const char *p; 2407*7c478bd9Sstevel@tonic-gate 2408*7c478bd9Sstevel@tonic-gate if (object == MDB_TGT_OBJ_EVERY || object == MDB_TGT_OBJ_EXEC) 2409*7c478bd9Sstevel@tonic-gate lmid = LM_ID_BASE; /* restrict scope to a.out's link map */ 2410*7c478bd9Sstevel@tonic-gate else if (object != MDB_TGT_OBJ_RTLD && strncmp(object, "LM", 2) == 0 && 2411*7c478bd9Sstevel@tonic-gate (p = strchr(object, '`')) != NULL) { 2412*7c478bd9Sstevel@tonic-gate object += 2; /* skip past initial "LM" prefix */ 2413*7c478bd9Sstevel@tonic-gate lmid = strntoul(object, (size_t)(p - object), mdb.m_radix); 2414*7c478bd9Sstevel@tonic-gate object = p + 1; /* skip past link map specifier */ 2415*7c478bd9Sstevel@tonic-gate } 2416*7c478bd9Sstevel@tonic-gate 2417*7c478bd9Sstevel@tonic-gate *lmidp = lmid; 2418*7c478bd9Sstevel@tonic-gate return (object); 2419*7c478bd9Sstevel@tonic-gate } 2420*7c478bd9Sstevel@tonic-gate 2421*7c478bd9Sstevel@tonic-gate static int 2422*7c478bd9Sstevel@tonic-gate tlsbase(mdb_tgt_t *t, mdb_tgt_tid_t tid, Lmid_t lmid, const char *object, 2423*7c478bd9Sstevel@tonic-gate psaddr_t *basep) 2424*7c478bd9Sstevel@tonic-gate { 2425*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 2426*7c478bd9Sstevel@tonic-gate const rd_loadobj_t *loadobjp; 2427*7c478bd9Sstevel@tonic-gate td_thrhandle_t th; 2428*7c478bd9Sstevel@tonic-gate td_err_e err; 2429*7c478bd9Sstevel@tonic-gate 2430*7c478bd9Sstevel@tonic-gate if (object == MDB_TGT_OBJ_EVERY) 2431*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 2432*7c478bd9Sstevel@tonic-gate 2433*7c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL || Pstate(t->t_pshandle) == PS_IDLE) 2434*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 2435*7c478bd9Sstevel@tonic-gate 2436*7c478bd9Sstevel@tonic-gate if (pt->p_tdb_ops == NULL) 2437*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_TDB)); 2438*7c478bd9Sstevel@tonic-gate 2439*7c478bd9Sstevel@tonic-gate err = pt->p_tdb_ops->td_ta_map_id2thr(pt->p_ptl_hdl, tid, &th); 2440*7c478bd9Sstevel@tonic-gate if (err != TD_OK) 2441*7c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 2442*7c478bd9Sstevel@tonic-gate 2443*7c478bd9Sstevel@tonic-gate /* 2444*7c478bd9Sstevel@tonic-gate * If this fails, rtld_db has failed to initialize properly. 2445*7c478bd9Sstevel@tonic-gate */ 2446*7c478bd9Sstevel@tonic-gate if ((loadobjp = Plmid_to_loadobj(t->t_pshandle, lmid, object)) == NULL) 2447*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NORTLD)); 2448*7c478bd9Sstevel@tonic-gate 2449*7c478bd9Sstevel@tonic-gate /* 2450*7c478bd9Sstevel@tonic-gate * This will fail if the TLS block has not been allocated for the 2451*7c478bd9Sstevel@tonic-gate * object that contains the TLS symbol in question. 2452*7c478bd9Sstevel@tonic-gate */ 2453*7c478bd9Sstevel@tonic-gate err = pt->p_tdb_ops->td_thr_tlsbase(&th, loadobjp->rl_tlsmodid, basep); 2454*7c478bd9Sstevel@tonic-gate if (err != TD_OK) 2455*7c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 2456*7c478bd9Sstevel@tonic-gate 2457*7c478bd9Sstevel@tonic-gate return (0); 2458*7c478bd9Sstevel@tonic-gate } 2459*7c478bd9Sstevel@tonic-gate 2460*7c478bd9Sstevel@tonic-gate typedef struct { 2461*7c478bd9Sstevel@tonic-gate mdb_tgt_t *pl_tgt; 2462*7c478bd9Sstevel@tonic-gate const char *pl_name; 2463*7c478bd9Sstevel@tonic-gate Lmid_t pl_lmid; 2464*7c478bd9Sstevel@tonic-gate GElf_Sym *pl_symp; 2465*7c478bd9Sstevel@tonic-gate mdb_syminfo_t *pl_sip; 2466*7c478bd9Sstevel@tonic-gate mdb_tgt_tid_t pl_tid; 2467*7c478bd9Sstevel@tonic-gate mdb_bool_t pl_found; 2468*7c478bd9Sstevel@tonic-gate } pt_lookup_t; 2469*7c478bd9Sstevel@tonic-gate 2470*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2471*7c478bd9Sstevel@tonic-gate static int 2472*7c478bd9Sstevel@tonic-gate pt_lookup_cb(void *data, const prmap_t *pmp, const char *object) 2473*7c478bd9Sstevel@tonic-gate { 2474*7c478bd9Sstevel@tonic-gate pt_lookup_t *plp = data; 2475*7c478bd9Sstevel@tonic-gate struct ps_prochandle *P = plp->pl_tgt->t_pshandle; 2476*7c478bd9Sstevel@tonic-gate prsyminfo_t si; 2477*7c478bd9Sstevel@tonic-gate GElf_Sym sym; 2478*7c478bd9Sstevel@tonic-gate 2479*7c478bd9Sstevel@tonic-gate if (Pxlookup_by_name(P, plp->pl_lmid, object, plp->pl_name, &sym, 2480*7c478bd9Sstevel@tonic-gate &si) != 0) 2481*7c478bd9Sstevel@tonic-gate return (0); 2482*7c478bd9Sstevel@tonic-gate 2483*7c478bd9Sstevel@tonic-gate /* 2484*7c478bd9Sstevel@tonic-gate * If we encounter a match with SHN_UNDEF, keep looking for a 2485*7c478bd9Sstevel@tonic-gate * better match. Return the first match with SHN_UNDEF set if no 2486*7c478bd9Sstevel@tonic-gate * better match is found. 2487*7c478bd9Sstevel@tonic-gate */ 2488*7c478bd9Sstevel@tonic-gate if (sym.st_shndx == SHN_UNDEF) { 2489*7c478bd9Sstevel@tonic-gate if (!plp->pl_found) { 2490*7c478bd9Sstevel@tonic-gate plp->pl_found = TRUE; 2491*7c478bd9Sstevel@tonic-gate *plp->pl_symp = sym; 2492*7c478bd9Sstevel@tonic-gate plp->pl_sip->sym_table = si.prs_table; 2493*7c478bd9Sstevel@tonic-gate plp->pl_sip->sym_id = si.prs_id; 2494*7c478bd9Sstevel@tonic-gate } 2495*7c478bd9Sstevel@tonic-gate 2496*7c478bd9Sstevel@tonic-gate return (0); 2497*7c478bd9Sstevel@tonic-gate } 2498*7c478bd9Sstevel@tonic-gate 2499*7c478bd9Sstevel@tonic-gate /* 2500*7c478bd9Sstevel@tonic-gate * Note that if the symbol's st_shndx is SHN_UNDEF we don't have the 2501*7c478bd9Sstevel@tonic-gate * TLS offset anyway, so adding in the tlsbase would be worthless. 2502*7c478bd9Sstevel@tonic-gate */ 2503*7c478bd9Sstevel@tonic-gate if (GELF_ST_TYPE(sym.st_info) == STT_TLS && 2504*7c478bd9Sstevel@tonic-gate plp->pl_tid != (mdb_tgt_tid_t)-1) { 2505*7c478bd9Sstevel@tonic-gate psaddr_t base; 2506*7c478bd9Sstevel@tonic-gate 2507*7c478bd9Sstevel@tonic-gate if (tlsbase(plp->pl_tgt, plp->pl_tid, plp->pl_lmid, object, 2508*7c478bd9Sstevel@tonic-gate &base) != 0) 2509*7c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 2510*7c478bd9Sstevel@tonic-gate 2511*7c478bd9Sstevel@tonic-gate sym.st_value += base; 2512*7c478bd9Sstevel@tonic-gate } 2513*7c478bd9Sstevel@tonic-gate 2514*7c478bd9Sstevel@tonic-gate plp->pl_found = TRUE; 2515*7c478bd9Sstevel@tonic-gate *plp->pl_symp = sym; 2516*7c478bd9Sstevel@tonic-gate plp->pl_sip->sym_table = si.prs_table; 2517*7c478bd9Sstevel@tonic-gate plp->pl_sip->sym_id = si.prs_id; 2518*7c478bd9Sstevel@tonic-gate 2519*7c478bd9Sstevel@tonic-gate return (1); 2520*7c478bd9Sstevel@tonic-gate } 2521*7c478bd9Sstevel@tonic-gate 2522*7c478bd9Sstevel@tonic-gate /* 2523*7c478bd9Sstevel@tonic-gate * Lookup the symbol with a thread context so that we can adjust TLS symbols 2524*7c478bd9Sstevel@tonic-gate * to get the values as they would appear in the context of the given thread. 2525*7c478bd9Sstevel@tonic-gate */ 2526*7c478bd9Sstevel@tonic-gate static int 2527*7c478bd9Sstevel@tonic-gate pt_lookup_by_name_thr(mdb_tgt_t *t, const char *object, 2528*7c478bd9Sstevel@tonic-gate const char *name, GElf_Sym *symp, mdb_syminfo_t *sip, mdb_tgt_tid_t tid) 2529*7c478bd9Sstevel@tonic-gate { 2530*7c478bd9Sstevel@tonic-gate struct ps_prochandle *P = t->t_pshandle; 2531*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 2532*7c478bd9Sstevel@tonic-gate Lmid_t lmid; 2533*7c478bd9Sstevel@tonic-gate uint_t i; 2534*7c478bd9Sstevel@tonic-gate const rd_loadobj_t *aout_lop; 2535*7c478bd9Sstevel@tonic-gate 2536*7c478bd9Sstevel@tonic-gate object = pt_resolve_lmid(object, &lmid); 2537*7c478bd9Sstevel@tonic-gate 2538*7c478bd9Sstevel@tonic-gate if (P != NULL) { 2539*7c478bd9Sstevel@tonic-gate pt_lookup_t pl; 2540*7c478bd9Sstevel@tonic-gate 2541*7c478bd9Sstevel@tonic-gate pl.pl_tgt = t; 2542*7c478bd9Sstevel@tonic-gate pl.pl_name = name; 2543*7c478bd9Sstevel@tonic-gate pl.pl_lmid = lmid; 2544*7c478bd9Sstevel@tonic-gate pl.pl_symp = symp; 2545*7c478bd9Sstevel@tonic-gate pl.pl_sip = sip; 2546*7c478bd9Sstevel@tonic-gate pl.pl_tid = tid; 2547*7c478bd9Sstevel@tonic-gate pl.pl_found = FALSE; 2548*7c478bd9Sstevel@tonic-gate 2549*7c478bd9Sstevel@tonic-gate if (object == MDB_TGT_OBJ_EVERY) { 2550*7c478bd9Sstevel@tonic-gate if (Pobject_iter(P, pt_lookup_cb, &pl) == -1) 2551*7c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 2552*7c478bd9Sstevel@tonic-gate } else { 2553*7c478bd9Sstevel@tonic-gate const prmap_t *pmp; 2554*7c478bd9Sstevel@tonic-gate 2555*7c478bd9Sstevel@tonic-gate /* 2556*7c478bd9Sstevel@tonic-gate * This can fail either due to an invalid lmid or 2557*7c478bd9Sstevel@tonic-gate * an invalid object. To determine which is 2558*7c478bd9Sstevel@tonic-gate * faulty, we test the lmid against known valid 2559*7c478bd9Sstevel@tonic-gate * lmids and then see if using a wild-card lmid 2560*7c478bd9Sstevel@tonic-gate * improves ths situation. 2561*7c478bd9Sstevel@tonic-gate */ 2562*7c478bd9Sstevel@tonic-gate if ((pmp = Plmid_to_map(P, lmid, object)) == NULL) { 2563*7c478bd9Sstevel@tonic-gate if (lmid != PR_LMID_EVERY && 2564*7c478bd9Sstevel@tonic-gate lmid != LM_ID_BASE && 2565*7c478bd9Sstevel@tonic-gate lmid != LM_ID_LDSO && 2566*7c478bd9Sstevel@tonic-gate Plmid_to_map(P, PR_LMID_EVERY, object) 2567*7c478bd9Sstevel@tonic-gate != NULL) 2568*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOLMID)); 2569*7c478bd9Sstevel@tonic-gate else 2570*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOOBJ)); 2571*7c478bd9Sstevel@tonic-gate } 2572*7c478bd9Sstevel@tonic-gate 2573*7c478bd9Sstevel@tonic-gate if (pt_lookup_cb(&pl, pmp, object) == -1) 2574*7c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 2575*7c478bd9Sstevel@tonic-gate } 2576*7c478bd9Sstevel@tonic-gate 2577*7c478bd9Sstevel@tonic-gate if (pl.pl_found) 2578*7c478bd9Sstevel@tonic-gate return (0); 2579*7c478bd9Sstevel@tonic-gate } 2580*7c478bd9Sstevel@tonic-gate 2581*7c478bd9Sstevel@tonic-gate /* 2582*7c478bd9Sstevel@tonic-gate * If libproc doesn't have the symbols for rtld, we're cooked -- 2583*7c478bd9Sstevel@tonic-gate * mdb doesn't have those symbols either. 2584*7c478bd9Sstevel@tonic-gate */ 2585*7c478bd9Sstevel@tonic-gate if (object == MDB_TGT_OBJ_RTLD) 2586*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOSYM)); 2587*7c478bd9Sstevel@tonic-gate 2588*7c478bd9Sstevel@tonic-gate if (object != MDB_TGT_OBJ_EXEC && object != MDB_TGT_OBJ_EVERY) { 2589*7c478bd9Sstevel@tonic-gate int status = mdb_gelf_symtab_lookup_by_file(pt->p_symtab, 2590*7c478bd9Sstevel@tonic-gate object, name, symp, &sip->sym_id); 2591*7c478bd9Sstevel@tonic-gate 2592*7c478bd9Sstevel@tonic-gate if (status != 0) { 2593*7c478bd9Sstevel@tonic-gate if (P != NULL && 2594*7c478bd9Sstevel@tonic-gate Plmid_to_map(P, PR_LMID_EVERY, object) != NULL) 2595*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOSYM)); 2596*7c478bd9Sstevel@tonic-gate else 2597*7c478bd9Sstevel@tonic-gate return (-1); /* errno set from lookup_by_file */ 2598*7c478bd9Sstevel@tonic-gate } 2599*7c478bd9Sstevel@tonic-gate 2600*7c478bd9Sstevel@tonic-gate goto found; 2601*7c478bd9Sstevel@tonic-gate } 2602*7c478bd9Sstevel@tonic-gate 2603*7c478bd9Sstevel@tonic-gate if (mdb_gelf_symtab_lookup_by_name(pt->p_symtab, name, symp, &i) == 0) { 2604*7c478bd9Sstevel@tonic-gate sip->sym_table = MDB_TGT_SYMTAB; 2605*7c478bd9Sstevel@tonic-gate sip->sym_id = i; 2606*7c478bd9Sstevel@tonic-gate goto local_found; 2607*7c478bd9Sstevel@tonic-gate } 2608*7c478bd9Sstevel@tonic-gate 2609*7c478bd9Sstevel@tonic-gate if (mdb_gelf_symtab_lookup_by_name(pt->p_dynsym, name, symp, &i) == 0) { 2610*7c478bd9Sstevel@tonic-gate sip->sym_table = MDB_TGT_DYNSYM; 2611*7c478bd9Sstevel@tonic-gate sip->sym_id = i; 2612*7c478bd9Sstevel@tonic-gate goto local_found; 2613*7c478bd9Sstevel@tonic-gate } 2614*7c478bd9Sstevel@tonic-gate 2615*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOSYM)); 2616*7c478bd9Sstevel@tonic-gate 2617*7c478bd9Sstevel@tonic-gate local_found: 2618*7c478bd9Sstevel@tonic-gate if (pt->p_file != NULL && 2619*7c478bd9Sstevel@tonic-gate pt->p_file->gf_ehdr.e_type == ET_DYN && 2620*7c478bd9Sstevel@tonic-gate P != NULL && 2621*7c478bd9Sstevel@tonic-gate (aout_lop = Pname_to_loadobj(P, PR_OBJ_EXEC)) != NULL) 2622*7c478bd9Sstevel@tonic-gate symp->st_value += aout_lop->rl_base; 2623*7c478bd9Sstevel@tonic-gate 2624*7c478bd9Sstevel@tonic-gate found: 2625*7c478bd9Sstevel@tonic-gate /* 2626*7c478bd9Sstevel@tonic-gate * If the symbol has type TLS, libproc should have found the symbol 2627*7c478bd9Sstevel@tonic-gate * if it exists and has been allocated. 2628*7c478bd9Sstevel@tonic-gate */ 2629*7c478bd9Sstevel@tonic-gate if (GELF_ST_TYPE(symp->st_info) == STT_TLS) 2630*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_TLS)); 2631*7c478bd9Sstevel@tonic-gate 2632*7c478bd9Sstevel@tonic-gate return (0); 2633*7c478bd9Sstevel@tonic-gate } 2634*7c478bd9Sstevel@tonic-gate 2635*7c478bd9Sstevel@tonic-gate static int 2636*7c478bd9Sstevel@tonic-gate pt_lookup_by_name(mdb_tgt_t *t, const char *object, 2637*7c478bd9Sstevel@tonic-gate const char *name, GElf_Sym *symp, mdb_syminfo_t *sip) 2638*7c478bd9Sstevel@tonic-gate { 2639*7c478bd9Sstevel@tonic-gate return (pt_lookup_by_name_thr(t, object, name, symp, sip, PTL_TID(t))); 2640*7c478bd9Sstevel@tonic-gate } 2641*7c478bd9Sstevel@tonic-gate 2642*7c478bd9Sstevel@tonic-gate static int 2643*7c478bd9Sstevel@tonic-gate pt_lookup_by_addr(mdb_tgt_t *t, uintptr_t addr, uint_t flags, 2644*7c478bd9Sstevel@tonic-gate char *buf, size_t nbytes, GElf_Sym *symp, mdb_syminfo_t *sip) 2645*7c478bd9Sstevel@tonic-gate { 2646*7c478bd9Sstevel@tonic-gate struct ps_prochandle *P = t->t_pshandle; 2647*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 2648*7c478bd9Sstevel@tonic-gate 2649*7c478bd9Sstevel@tonic-gate rd_plt_info_t rpi = { 0 }; 2650*7c478bd9Sstevel@tonic-gate const char *pltsym; 2651*7c478bd9Sstevel@tonic-gate int match, i; 2652*7c478bd9Sstevel@tonic-gate 2653*7c478bd9Sstevel@tonic-gate mdb_gelf_symtab_t *gsts[3]; /* mdb.m_prsym, .symtab, .dynsym */ 2654*7c478bd9Sstevel@tonic-gate int gstc = 0; /* number of valid gsts[] entries */ 2655*7c478bd9Sstevel@tonic-gate 2656*7c478bd9Sstevel@tonic-gate mdb_gelf_symtab_t *gst = NULL; /* set if 'sym' is from a gst */ 2657*7c478bd9Sstevel@tonic-gate const prmap_t *pmp = NULL; /* set if 'sym' is from libproc */ 2658*7c478bd9Sstevel@tonic-gate GElf_Sym sym; /* best symbol found so far if !exact */ 2659*7c478bd9Sstevel@tonic-gate prsyminfo_t si; 2660*7c478bd9Sstevel@tonic-gate 2661*7c478bd9Sstevel@tonic-gate /* 2662*7c478bd9Sstevel@tonic-gate * Fill in our array of symbol table pointers with the private symbol 2663*7c478bd9Sstevel@tonic-gate * table, static symbol table, and dynamic symbol table if applicable. 2664*7c478bd9Sstevel@tonic-gate * These are done in order of precedence so that if we match and 2665*7c478bd9Sstevel@tonic-gate * MDB_TGT_SYM_EXACT is set, we need not look any further. 2666*7c478bd9Sstevel@tonic-gate */ 2667*7c478bd9Sstevel@tonic-gate if (mdb.m_prsym != NULL) 2668*7c478bd9Sstevel@tonic-gate gsts[gstc++] = mdb.m_prsym; 2669*7c478bd9Sstevel@tonic-gate if (P == NULL && pt->p_symtab != NULL) 2670*7c478bd9Sstevel@tonic-gate gsts[gstc++] = pt->p_symtab; 2671*7c478bd9Sstevel@tonic-gate if (P == NULL && pt->p_dynsym != NULL) 2672*7c478bd9Sstevel@tonic-gate gsts[gstc++] = pt->p_dynsym; 2673*7c478bd9Sstevel@tonic-gate 2674*7c478bd9Sstevel@tonic-gate /* 2675*7c478bd9Sstevel@tonic-gate * Loop through our array attempting to match the address. If we match 2676*7c478bd9Sstevel@tonic-gate * and we're in exact mode, we're done. Otherwise save the symbol in 2677*7c478bd9Sstevel@tonic-gate * the local sym variable if it is closer than our previous match. 2678*7c478bd9Sstevel@tonic-gate * We explicitly watch for zero-valued symbols since DevPro insists 2679*7c478bd9Sstevel@tonic-gate * on storing __fsr_init_value's value as the symbol value instead 2680*7c478bd9Sstevel@tonic-gate * of storing it in a constant integer. 2681*7c478bd9Sstevel@tonic-gate */ 2682*7c478bd9Sstevel@tonic-gate for (i = 0; i < gstc; i++) { 2683*7c478bd9Sstevel@tonic-gate if (mdb_gelf_symtab_lookup_by_addr(gsts[i], addr, flags, buf, 2684*7c478bd9Sstevel@tonic-gate nbytes, symp, &sip->sym_id) != 0 || symp->st_value == 0) 2685*7c478bd9Sstevel@tonic-gate continue; 2686*7c478bd9Sstevel@tonic-gate 2687*7c478bd9Sstevel@tonic-gate if (flags & MDB_TGT_SYM_EXACT) { 2688*7c478bd9Sstevel@tonic-gate gst = gsts[i]; 2689*7c478bd9Sstevel@tonic-gate goto found; 2690*7c478bd9Sstevel@tonic-gate } 2691*7c478bd9Sstevel@tonic-gate 2692*7c478bd9Sstevel@tonic-gate if (gst == NULL || mdb_gelf_sym_closer(symp, &sym, addr)) { 2693*7c478bd9Sstevel@tonic-gate gst = gsts[i]; 2694*7c478bd9Sstevel@tonic-gate sym = *symp; 2695*7c478bd9Sstevel@tonic-gate } 2696*7c478bd9Sstevel@tonic-gate } 2697*7c478bd9Sstevel@tonic-gate 2698*7c478bd9Sstevel@tonic-gate /* 2699*7c478bd9Sstevel@tonic-gate * If we have no libproc handle active, we're done: fail if gst is 2700*7c478bd9Sstevel@tonic-gate * NULL; otherwise copy out our best symbol and skip to the end. 2701*7c478bd9Sstevel@tonic-gate * We also skip to found if gst is the private symbol table: we 2702*7c478bd9Sstevel@tonic-gate * want this to always take precedence over PLT re-vectoring. 2703*7c478bd9Sstevel@tonic-gate */ 2704*7c478bd9Sstevel@tonic-gate if (P == NULL || (gst != NULL && gst == mdb.m_prsym)) { 2705*7c478bd9Sstevel@tonic-gate if (gst == NULL) 2706*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOSYMADDR)); 2707*7c478bd9Sstevel@tonic-gate *symp = sym; 2708*7c478bd9Sstevel@tonic-gate goto found; 2709*7c478bd9Sstevel@tonic-gate } 2710*7c478bd9Sstevel@tonic-gate 2711*7c478bd9Sstevel@tonic-gate /* 2712*7c478bd9Sstevel@tonic-gate * Check to see if the address is in a PLT: if it is, use librtld_db to 2713*7c478bd9Sstevel@tonic-gate * attempt to resolve the PLT entry. If the entry is bound, reset addr 2714*7c478bd9Sstevel@tonic-gate * to the bound address, add a special prefix to the caller's buf, 2715*7c478bd9Sstevel@tonic-gate * forget our previous guess, and then continue using the new addr. 2716*7c478bd9Sstevel@tonic-gate * If the entry is not bound, copy the corresponding symbol name into 2717*7c478bd9Sstevel@tonic-gate * buf and return a fake symbol for the given address. 2718*7c478bd9Sstevel@tonic-gate */ 2719*7c478bd9Sstevel@tonic-gate if ((pltsym = Ppltdest(P, addr)) != NULL) { 2720*7c478bd9Sstevel@tonic-gate const rd_loadobj_t *rlp; 2721*7c478bd9Sstevel@tonic-gate rd_agent_t *rap; 2722*7c478bd9Sstevel@tonic-gate 2723*7c478bd9Sstevel@tonic-gate if ((rap = Prd_agent(P)) != NULL && 2724*7c478bd9Sstevel@tonic-gate (rlp = Paddr_to_loadobj(P, addr)) != NULL && 2725*7c478bd9Sstevel@tonic-gate rd_plt_resolution(rap, addr, Pstatus(P)->pr_lwp.pr_lwpid, 2726*7c478bd9Sstevel@tonic-gate rlp->rl_plt_base, &rpi) == RD_OK && 2727*7c478bd9Sstevel@tonic-gate (rpi.pi_flags & RD_FLG_PI_PLTBOUND)) { 2728*7c478bd9Sstevel@tonic-gate size_t n; 2729*7c478bd9Sstevel@tonic-gate n = mdb_iob_snprintf(buf, nbytes, "PLT="); 2730*7c478bd9Sstevel@tonic-gate addr = rpi.pi_baddr; 2731*7c478bd9Sstevel@tonic-gate if (n > nbytes) { 2732*7c478bd9Sstevel@tonic-gate buf += nbytes; 2733*7c478bd9Sstevel@tonic-gate nbytes = 0; 2734*7c478bd9Sstevel@tonic-gate } else { 2735*7c478bd9Sstevel@tonic-gate buf += n; 2736*7c478bd9Sstevel@tonic-gate nbytes -= n; 2737*7c478bd9Sstevel@tonic-gate } 2738*7c478bd9Sstevel@tonic-gate gst = NULL; 2739*7c478bd9Sstevel@tonic-gate } else { 2740*7c478bd9Sstevel@tonic-gate (void) mdb_iob_snprintf(buf, nbytes, "PLT:%s", pltsym); 2741*7c478bd9Sstevel@tonic-gate bzero(symp, sizeof (GElf_Sym)); 2742*7c478bd9Sstevel@tonic-gate symp->st_value = addr; 2743*7c478bd9Sstevel@tonic-gate symp->st_info = GELF_ST_INFO(STB_GLOBAL, STT_FUNC); 2744*7c478bd9Sstevel@tonic-gate return (0); 2745*7c478bd9Sstevel@tonic-gate } 2746*7c478bd9Sstevel@tonic-gate } 2747*7c478bd9Sstevel@tonic-gate 2748*7c478bd9Sstevel@tonic-gate /* 2749*7c478bd9Sstevel@tonic-gate * Ask libproc to convert the address to the closest symbol for us. 2750*7c478bd9Sstevel@tonic-gate * Once we get the closest symbol, we perform the EXACT match or 2751*7c478bd9Sstevel@tonic-gate * smart-mode or absolute distance check ourself: 2752*7c478bd9Sstevel@tonic-gate */ 2753*7c478bd9Sstevel@tonic-gate if (Pxlookup_by_addr(P, addr, buf, nbytes, symp, &si) == 0 && 2754*7c478bd9Sstevel@tonic-gate symp->st_value != 0 && (gst == NULL || 2755*7c478bd9Sstevel@tonic-gate mdb_gelf_sym_closer(symp, &sym, addr))) { 2756*7c478bd9Sstevel@tonic-gate 2757*7c478bd9Sstevel@tonic-gate if (flags & MDB_TGT_SYM_EXACT) 2758*7c478bd9Sstevel@tonic-gate match = (addr == symp->st_value); 2759*7c478bd9Sstevel@tonic-gate else if (mdb.m_symdist == 0) 2760*7c478bd9Sstevel@tonic-gate match = (addr >= symp->st_value && 2761*7c478bd9Sstevel@tonic-gate addr < symp->st_value + symp->st_size); 2762*7c478bd9Sstevel@tonic-gate else 2763*7c478bd9Sstevel@tonic-gate match = (addr >= symp->st_value && 2764*7c478bd9Sstevel@tonic-gate addr < symp->st_value + mdb.m_symdist); 2765*7c478bd9Sstevel@tonic-gate 2766*7c478bd9Sstevel@tonic-gate if (match) { 2767*7c478bd9Sstevel@tonic-gate pmp = Paddr_to_map(P, addr); 2768*7c478bd9Sstevel@tonic-gate gst = NULL; 2769*7c478bd9Sstevel@tonic-gate sip->sym_table = si.prs_table; 2770*7c478bd9Sstevel@tonic-gate sip->sym_id = si.prs_id; 2771*7c478bd9Sstevel@tonic-gate goto found; 2772*7c478bd9Sstevel@tonic-gate } 2773*7c478bd9Sstevel@tonic-gate } 2774*7c478bd9Sstevel@tonic-gate 2775*7c478bd9Sstevel@tonic-gate /* 2776*7c478bd9Sstevel@tonic-gate * If we get here, Plookup_by_addr has failed us. If we have no 2777*7c478bd9Sstevel@tonic-gate * previous best symbol (gst == NULL), we've failed completely. 2778*7c478bd9Sstevel@tonic-gate * Otherwise we copy out that symbol and continue on to 'found'. 2779*7c478bd9Sstevel@tonic-gate */ 2780*7c478bd9Sstevel@tonic-gate if (gst == NULL) 2781*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOSYMADDR)); 2782*7c478bd9Sstevel@tonic-gate *symp = sym; 2783*7c478bd9Sstevel@tonic-gate found: 2784*7c478bd9Sstevel@tonic-gate /* 2785*7c478bd9Sstevel@tonic-gate * Once we've found something, copy the final name into the caller's 2786*7c478bd9Sstevel@tonic-gate * buffer and prefix it with the mapping name if appropriate. 2787*7c478bd9Sstevel@tonic-gate */ 2788*7c478bd9Sstevel@tonic-gate if (pmp != NULL && pmp != Pname_to_map(P, PR_OBJ_EXEC)) { 2789*7c478bd9Sstevel@tonic-gate const char *prefix = pmp->pr_mapname; 2790*7c478bd9Sstevel@tonic-gate Lmid_t lmid; 2791*7c478bd9Sstevel@tonic-gate 2792*7c478bd9Sstevel@tonic-gate if (Pobjname(P, addr, pt->p_objname, MDB_TGT_MAPSZ)) 2793*7c478bd9Sstevel@tonic-gate prefix = pt->p_objname; 2794*7c478bd9Sstevel@tonic-gate 2795*7c478bd9Sstevel@tonic-gate if (buf != NULL && nbytes > 1) { 2796*7c478bd9Sstevel@tonic-gate (void) strncpy(pt->p_symname, buf, MDB_TGT_SYM_NAMLEN); 2797*7c478bd9Sstevel@tonic-gate pt->p_symname[MDB_TGT_SYM_NAMLEN - 1] = '\0'; 2798*7c478bd9Sstevel@tonic-gate } else { 2799*7c478bd9Sstevel@tonic-gate pt->p_symname[0] = '\0'; 2800*7c478bd9Sstevel@tonic-gate } 2801*7c478bd9Sstevel@tonic-gate 2802*7c478bd9Sstevel@tonic-gate if (prefix == pt->p_objname && Plmid(P, addr, &lmid) == 0 && ( 2803*7c478bd9Sstevel@tonic-gate (lmid != LM_ID_BASE && lmid != LM_ID_LDSO) || 2804*7c478bd9Sstevel@tonic-gate (mdb.m_flags & MDB_FL_SHOWLMID))) { 2805*7c478bd9Sstevel@tonic-gate (void) mdb_iob_snprintf(buf, nbytes, "LM%lr`%s`%s", 2806*7c478bd9Sstevel@tonic-gate lmid, strbasename(prefix), pt->p_symname); 2807*7c478bd9Sstevel@tonic-gate } else { 2808*7c478bd9Sstevel@tonic-gate (void) mdb_iob_snprintf(buf, nbytes, "%s`%s", 2809*7c478bd9Sstevel@tonic-gate strbasename(prefix), pt->p_symname); 2810*7c478bd9Sstevel@tonic-gate } 2811*7c478bd9Sstevel@tonic-gate 2812*7c478bd9Sstevel@tonic-gate } else if (gst != NULL && buf != NULL && nbytes > 0) { 2813*7c478bd9Sstevel@tonic-gate (void) strncpy(buf, mdb_gelf_sym_name(gst, symp), nbytes); 2814*7c478bd9Sstevel@tonic-gate buf[nbytes - 1] = '\0'; 2815*7c478bd9Sstevel@tonic-gate } 2816*7c478bd9Sstevel@tonic-gate 2817*7c478bd9Sstevel@tonic-gate return (0); 2818*7c478bd9Sstevel@tonic-gate } 2819*7c478bd9Sstevel@tonic-gate 2820*7c478bd9Sstevel@tonic-gate 2821*7c478bd9Sstevel@tonic-gate static int 2822*7c478bd9Sstevel@tonic-gate pt_symbol_iter_cb(void *arg, const GElf_Sym *sym, const char *name, 2823*7c478bd9Sstevel@tonic-gate const prsyminfo_t *sip) 2824*7c478bd9Sstevel@tonic-gate { 2825*7c478bd9Sstevel@tonic-gate pt_symarg_t *psp = arg; 2826*7c478bd9Sstevel@tonic-gate 2827*7c478bd9Sstevel@tonic-gate psp->psym_info.sym_id = sip->prs_id; 2828*7c478bd9Sstevel@tonic-gate 2829*7c478bd9Sstevel@tonic-gate return (psp->psym_func(psp->psym_private, sym, name, &psp->psym_info, 2830*7c478bd9Sstevel@tonic-gate psp->psym_obj)); 2831*7c478bd9Sstevel@tonic-gate } 2832*7c478bd9Sstevel@tonic-gate 2833*7c478bd9Sstevel@tonic-gate static int 2834*7c478bd9Sstevel@tonic-gate pt_objsym_iter(void *arg, const prmap_t *pmp, const char *object) 2835*7c478bd9Sstevel@tonic-gate { 2836*7c478bd9Sstevel@tonic-gate Lmid_t lmid = PR_LMID_EVERY; 2837*7c478bd9Sstevel@tonic-gate pt_symarg_t *psp = arg; 2838*7c478bd9Sstevel@tonic-gate 2839*7c478bd9Sstevel@tonic-gate psp->psym_obj = object; 2840*7c478bd9Sstevel@tonic-gate 2841*7c478bd9Sstevel@tonic-gate (void) Plmid(psp->psym_targ->t_pshandle, pmp->pr_vaddr, &lmid); 2842*7c478bd9Sstevel@tonic-gate (void) Pxsymbol_iter(psp->psym_targ->t_pshandle, lmid, object, 2843*7c478bd9Sstevel@tonic-gate psp->psym_which, psp->psym_type, pt_symbol_iter_cb, arg); 2844*7c478bd9Sstevel@tonic-gate 2845*7c478bd9Sstevel@tonic-gate return (0); 2846*7c478bd9Sstevel@tonic-gate } 2847*7c478bd9Sstevel@tonic-gate 2848*7c478bd9Sstevel@tonic-gate static int 2849*7c478bd9Sstevel@tonic-gate pt_symbol_filt(void *arg, const GElf_Sym *sym, const char *name, uint_t id) 2850*7c478bd9Sstevel@tonic-gate { 2851*7c478bd9Sstevel@tonic-gate pt_symarg_t *psp = arg; 2852*7c478bd9Sstevel@tonic-gate 2853*7c478bd9Sstevel@tonic-gate if (mdb_tgt_sym_match(sym, psp->psym_type)) { 2854*7c478bd9Sstevel@tonic-gate psp->psym_info.sym_id = id; 2855*7c478bd9Sstevel@tonic-gate return (psp->psym_func(psp->psym_private, sym, name, 2856*7c478bd9Sstevel@tonic-gate &psp->psym_info, psp->psym_obj)); 2857*7c478bd9Sstevel@tonic-gate } 2858*7c478bd9Sstevel@tonic-gate 2859*7c478bd9Sstevel@tonic-gate return (0); 2860*7c478bd9Sstevel@tonic-gate } 2861*7c478bd9Sstevel@tonic-gate 2862*7c478bd9Sstevel@tonic-gate static int 2863*7c478bd9Sstevel@tonic-gate pt_symbol_iter(mdb_tgt_t *t, const char *object, uint_t which, 2864*7c478bd9Sstevel@tonic-gate uint_t type, mdb_tgt_sym_f *func, void *private) 2865*7c478bd9Sstevel@tonic-gate { 2866*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 2867*7c478bd9Sstevel@tonic-gate mdb_gelf_symtab_t *gst; 2868*7c478bd9Sstevel@tonic-gate pt_symarg_t ps; 2869*7c478bd9Sstevel@tonic-gate Lmid_t lmid; 2870*7c478bd9Sstevel@tonic-gate 2871*7c478bd9Sstevel@tonic-gate object = pt_resolve_lmid(object, &lmid); 2872*7c478bd9Sstevel@tonic-gate 2873*7c478bd9Sstevel@tonic-gate ps.psym_targ = t; 2874*7c478bd9Sstevel@tonic-gate ps.psym_which = which; 2875*7c478bd9Sstevel@tonic-gate ps.psym_type = type; 2876*7c478bd9Sstevel@tonic-gate ps.psym_func = func; 2877*7c478bd9Sstevel@tonic-gate ps.psym_private = private; 2878*7c478bd9Sstevel@tonic-gate ps.psym_obj = object; 2879*7c478bd9Sstevel@tonic-gate 2880*7c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL) { 2881*7c478bd9Sstevel@tonic-gate if (object != MDB_TGT_OBJ_EVERY) { 2882*7c478bd9Sstevel@tonic-gate if (Plmid_to_map(t->t_pshandle, lmid, object) == NULL) 2883*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOOBJ)); 2884*7c478bd9Sstevel@tonic-gate (void) Pxsymbol_iter(t->t_pshandle, lmid, object, 2885*7c478bd9Sstevel@tonic-gate which, type, pt_symbol_iter_cb, &ps); 2886*7c478bd9Sstevel@tonic-gate return (0); 2887*7c478bd9Sstevel@tonic-gate } else if (Prd_agent(t->t_pshandle) != NULL) { 2888*7c478bd9Sstevel@tonic-gate (void) Pobject_iter(t->t_pshandle, pt_objsym_iter, &ps); 2889*7c478bd9Sstevel@tonic-gate return (0); 2890*7c478bd9Sstevel@tonic-gate } 2891*7c478bd9Sstevel@tonic-gate } 2892*7c478bd9Sstevel@tonic-gate 2893*7c478bd9Sstevel@tonic-gate if (lmid != LM_ID_BASE && lmid != PR_LMID_EVERY) 2894*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOLMID)); 2895*7c478bd9Sstevel@tonic-gate 2896*7c478bd9Sstevel@tonic-gate if (object != MDB_TGT_OBJ_EXEC && object != MDB_TGT_OBJ_EVERY && 2897*7c478bd9Sstevel@tonic-gate pt->p_fio != NULL && 2898*7c478bd9Sstevel@tonic-gate strcmp(object, IOP_NAME(pt->p_fio)) != 0) 2899*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOOBJ)); 2900*7c478bd9Sstevel@tonic-gate 2901*7c478bd9Sstevel@tonic-gate if (which == MDB_TGT_SYMTAB) 2902*7c478bd9Sstevel@tonic-gate gst = pt->p_symtab; 2903*7c478bd9Sstevel@tonic-gate else 2904*7c478bd9Sstevel@tonic-gate gst = pt->p_dynsym; 2905*7c478bd9Sstevel@tonic-gate 2906*7c478bd9Sstevel@tonic-gate if (gst != NULL) { 2907*7c478bd9Sstevel@tonic-gate ps.psym_info.sym_table = gst->gst_tabid; 2908*7c478bd9Sstevel@tonic-gate mdb_gelf_symtab_iter(gst, pt_symbol_filt, &ps); 2909*7c478bd9Sstevel@tonic-gate } 2910*7c478bd9Sstevel@tonic-gate 2911*7c478bd9Sstevel@tonic-gate return (0); 2912*7c478bd9Sstevel@tonic-gate } 2913*7c478bd9Sstevel@tonic-gate 2914*7c478bd9Sstevel@tonic-gate static const mdb_map_t * 2915*7c478bd9Sstevel@tonic-gate pt_prmap_to_mdbmap(mdb_tgt_t *t, const prmap_t *prp, mdb_map_t *mp) 2916*7c478bd9Sstevel@tonic-gate { 2917*7c478bd9Sstevel@tonic-gate struct ps_prochandle *P = t->t_pshandle; 2918*7c478bd9Sstevel@tonic-gate char name[MAXPATHLEN]; 2919*7c478bd9Sstevel@tonic-gate Lmid_t lmid; 2920*7c478bd9Sstevel@tonic-gate 2921*7c478bd9Sstevel@tonic-gate if (Pobjname(P, prp->pr_vaddr, name, sizeof (name)) != NULL) { 2922*7c478bd9Sstevel@tonic-gate if (Plmid(P, prp->pr_vaddr, &lmid) == 0 && ( 2923*7c478bd9Sstevel@tonic-gate (lmid != LM_ID_BASE && lmid != LM_ID_LDSO) || 2924*7c478bd9Sstevel@tonic-gate (mdb.m_flags & MDB_FL_SHOWLMID))) { 2925*7c478bd9Sstevel@tonic-gate (void) mdb_iob_snprintf(mp->map_name, MDB_TGT_MAPSZ, 2926*7c478bd9Sstevel@tonic-gate "LM%lr`%s", lmid, name); 2927*7c478bd9Sstevel@tonic-gate } else { 2928*7c478bd9Sstevel@tonic-gate (void) strncpy(mp->map_name, name, MDB_TGT_MAPSZ - 1); 2929*7c478bd9Sstevel@tonic-gate mp->map_name[MDB_TGT_MAPSZ - 1] = '\0'; 2930*7c478bd9Sstevel@tonic-gate } 2931*7c478bd9Sstevel@tonic-gate } else { 2932*7c478bd9Sstevel@tonic-gate (void) strncpy(mp->map_name, prp->pr_mapname, 2933*7c478bd9Sstevel@tonic-gate MDB_TGT_MAPSZ - 1); 2934*7c478bd9Sstevel@tonic-gate mp->map_name[MDB_TGT_MAPSZ - 1] = '\0'; 2935*7c478bd9Sstevel@tonic-gate } 2936*7c478bd9Sstevel@tonic-gate 2937*7c478bd9Sstevel@tonic-gate mp->map_base = prp->pr_vaddr; 2938*7c478bd9Sstevel@tonic-gate mp->map_size = prp->pr_size; 2939*7c478bd9Sstevel@tonic-gate mp->map_flags = 0; 2940*7c478bd9Sstevel@tonic-gate 2941*7c478bd9Sstevel@tonic-gate if (prp->pr_mflags & MA_READ) 2942*7c478bd9Sstevel@tonic-gate mp->map_flags |= MDB_TGT_MAP_R; 2943*7c478bd9Sstevel@tonic-gate if (prp->pr_mflags & MA_WRITE) 2944*7c478bd9Sstevel@tonic-gate mp->map_flags |= MDB_TGT_MAP_W; 2945*7c478bd9Sstevel@tonic-gate if (prp->pr_mflags & MA_EXEC) 2946*7c478bd9Sstevel@tonic-gate mp->map_flags |= MDB_TGT_MAP_X; 2947*7c478bd9Sstevel@tonic-gate 2948*7c478bd9Sstevel@tonic-gate if (prp->pr_mflags & MA_SHM) 2949*7c478bd9Sstevel@tonic-gate mp->map_flags |= MDB_TGT_MAP_SHMEM; 2950*7c478bd9Sstevel@tonic-gate if (prp->pr_mflags & MA_BREAK) 2951*7c478bd9Sstevel@tonic-gate mp->map_flags |= MDB_TGT_MAP_HEAP; 2952*7c478bd9Sstevel@tonic-gate if (prp->pr_mflags & MA_STACK) 2953*7c478bd9Sstevel@tonic-gate mp->map_flags |= MDB_TGT_MAP_STACK; 2954*7c478bd9Sstevel@tonic-gate if (prp->pr_mflags & MA_ANON) 2955*7c478bd9Sstevel@tonic-gate mp->map_flags |= MDB_TGT_MAP_ANON; 2956*7c478bd9Sstevel@tonic-gate 2957*7c478bd9Sstevel@tonic-gate return (mp); 2958*7c478bd9Sstevel@tonic-gate } 2959*7c478bd9Sstevel@tonic-gate 2960*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2961*7c478bd9Sstevel@tonic-gate static int 2962*7c478bd9Sstevel@tonic-gate pt_map_apply(void *arg, const prmap_t *prp, const char *name) 2963*7c478bd9Sstevel@tonic-gate { 2964*7c478bd9Sstevel@tonic-gate pt_maparg_t *pmp = arg; 2965*7c478bd9Sstevel@tonic-gate mdb_map_t map; 2966*7c478bd9Sstevel@tonic-gate 2967*7c478bd9Sstevel@tonic-gate return (pmp->pmap_func(pmp->pmap_private, 2968*7c478bd9Sstevel@tonic-gate pt_prmap_to_mdbmap(pmp->pmap_targ, prp, &map), map.map_name)); 2969*7c478bd9Sstevel@tonic-gate } 2970*7c478bd9Sstevel@tonic-gate 2971*7c478bd9Sstevel@tonic-gate static int 2972*7c478bd9Sstevel@tonic-gate pt_mapping_iter(mdb_tgt_t *t, mdb_tgt_map_f *func, void *private) 2973*7c478bd9Sstevel@tonic-gate { 2974*7c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL) { 2975*7c478bd9Sstevel@tonic-gate pt_maparg_t pm; 2976*7c478bd9Sstevel@tonic-gate 2977*7c478bd9Sstevel@tonic-gate pm.pmap_targ = t; 2978*7c478bd9Sstevel@tonic-gate pm.pmap_func = func; 2979*7c478bd9Sstevel@tonic-gate pm.pmap_private = private; 2980*7c478bd9Sstevel@tonic-gate 2981*7c478bd9Sstevel@tonic-gate (void) Pmapping_iter(t->t_pshandle, pt_map_apply, &pm); 2982*7c478bd9Sstevel@tonic-gate return (0); 2983*7c478bd9Sstevel@tonic-gate } 2984*7c478bd9Sstevel@tonic-gate 2985*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 2986*7c478bd9Sstevel@tonic-gate } 2987*7c478bd9Sstevel@tonic-gate 2988*7c478bd9Sstevel@tonic-gate static int 2989*7c478bd9Sstevel@tonic-gate pt_object_iter(mdb_tgt_t *t, mdb_tgt_map_f *func, void *private) 2990*7c478bd9Sstevel@tonic-gate { 2991*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 2992*7c478bd9Sstevel@tonic-gate 2993*7c478bd9Sstevel@tonic-gate /* 2994*7c478bd9Sstevel@tonic-gate * If we have a libproc handle, we can just call Pobject_iter to 2995*7c478bd9Sstevel@tonic-gate * iterate over its list of load object information. 2996*7c478bd9Sstevel@tonic-gate */ 2997*7c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL) { 2998*7c478bd9Sstevel@tonic-gate pt_maparg_t pm; 2999*7c478bd9Sstevel@tonic-gate 3000*7c478bd9Sstevel@tonic-gate pm.pmap_targ = t; 3001*7c478bd9Sstevel@tonic-gate pm.pmap_func = func; 3002*7c478bd9Sstevel@tonic-gate pm.pmap_private = private; 3003*7c478bd9Sstevel@tonic-gate 3004*7c478bd9Sstevel@tonic-gate (void) Pobject_iter(t->t_pshandle, pt_map_apply, &pm); 3005*7c478bd9Sstevel@tonic-gate return (0); 3006*7c478bd9Sstevel@tonic-gate } 3007*7c478bd9Sstevel@tonic-gate 3008*7c478bd9Sstevel@tonic-gate /* 3009*7c478bd9Sstevel@tonic-gate * If we're examining an executable or other ELF file but we have no 3010*7c478bd9Sstevel@tonic-gate * libproc handle, fake up some information based on DT_NEEDED entries. 3011*7c478bd9Sstevel@tonic-gate */ 3012*7c478bd9Sstevel@tonic-gate if (pt->p_dynsym != NULL && pt->p_file->gf_dyns != NULL && 3013*7c478bd9Sstevel@tonic-gate pt->p_fio != NULL) { 3014*7c478bd9Sstevel@tonic-gate mdb_gelf_sect_t *gsp = pt->p_dynsym->gst_ssect; 3015*7c478bd9Sstevel@tonic-gate GElf_Dyn *dynp = pt->p_file->gf_dyns; 3016*7c478bd9Sstevel@tonic-gate mdb_map_t *mp = &pt->p_map; 3017*7c478bd9Sstevel@tonic-gate const char *s = IOP_NAME(pt->p_fio); 3018*7c478bd9Sstevel@tonic-gate size_t i; 3019*7c478bd9Sstevel@tonic-gate 3020*7c478bd9Sstevel@tonic-gate (void) strncpy(mp->map_name, s, MDB_TGT_MAPSZ); 3021*7c478bd9Sstevel@tonic-gate mp->map_name[MDB_TGT_MAPSZ - 1] = '\0'; 3022*7c478bd9Sstevel@tonic-gate mp->map_flags = MDB_TGT_MAP_R | MDB_TGT_MAP_X; 3023*7c478bd9Sstevel@tonic-gate mp->map_base = NULL; 3024*7c478bd9Sstevel@tonic-gate mp->map_size = 0; 3025*7c478bd9Sstevel@tonic-gate 3026*7c478bd9Sstevel@tonic-gate if (func(private, mp, s) != 0) 3027*7c478bd9Sstevel@tonic-gate return (0); 3028*7c478bd9Sstevel@tonic-gate 3029*7c478bd9Sstevel@tonic-gate for (i = 0; i < pt->p_file->gf_ndyns; i++, dynp++) { 3030*7c478bd9Sstevel@tonic-gate if (dynp->d_tag == DT_NEEDED) { 3031*7c478bd9Sstevel@tonic-gate s = (char *)gsp->gs_data + dynp->d_un.d_val; 3032*7c478bd9Sstevel@tonic-gate (void) strncpy(mp->map_name, s, MDB_TGT_MAPSZ); 3033*7c478bd9Sstevel@tonic-gate mp->map_name[MDB_TGT_MAPSZ - 1] = '\0'; 3034*7c478bd9Sstevel@tonic-gate if (func(private, mp, s) != 0) 3035*7c478bd9Sstevel@tonic-gate return (0); 3036*7c478bd9Sstevel@tonic-gate } 3037*7c478bd9Sstevel@tonic-gate } 3038*7c478bd9Sstevel@tonic-gate 3039*7c478bd9Sstevel@tonic-gate return (0); 3040*7c478bd9Sstevel@tonic-gate } 3041*7c478bd9Sstevel@tonic-gate 3042*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 3043*7c478bd9Sstevel@tonic-gate } 3044*7c478bd9Sstevel@tonic-gate 3045*7c478bd9Sstevel@tonic-gate static const mdb_map_t * 3046*7c478bd9Sstevel@tonic-gate pt_addr_to_map(mdb_tgt_t *t, uintptr_t addr) 3047*7c478bd9Sstevel@tonic-gate { 3048*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 3049*7c478bd9Sstevel@tonic-gate const prmap_t *pmp; 3050*7c478bd9Sstevel@tonic-gate 3051*7c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) { 3052*7c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_NOPROC); 3053*7c478bd9Sstevel@tonic-gate return (NULL); 3054*7c478bd9Sstevel@tonic-gate } 3055*7c478bd9Sstevel@tonic-gate 3056*7c478bd9Sstevel@tonic-gate if ((pmp = Paddr_to_map(t->t_pshandle, addr)) == NULL) { 3057*7c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_NOMAP); 3058*7c478bd9Sstevel@tonic-gate return (NULL); 3059*7c478bd9Sstevel@tonic-gate } 3060*7c478bd9Sstevel@tonic-gate 3061*7c478bd9Sstevel@tonic-gate return (pt_prmap_to_mdbmap(t, pmp, &pt->p_map)); 3062*7c478bd9Sstevel@tonic-gate } 3063*7c478bd9Sstevel@tonic-gate 3064*7c478bd9Sstevel@tonic-gate static const mdb_map_t * 3065*7c478bd9Sstevel@tonic-gate pt_name_to_map(mdb_tgt_t *t, const char *object) 3066*7c478bd9Sstevel@tonic-gate { 3067*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 3068*7c478bd9Sstevel@tonic-gate const prmap_t *pmp; 3069*7c478bd9Sstevel@tonic-gate Lmid_t lmid; 3070*7c478bd9Sstevel@tonic-gate 3071*7c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) { 3072*7c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_NOPROC); 3073*7c478bd9Sstevel@tonic-gate return (NULL); 3074*7c478bd9Sstevel@tonic-gate } 3075*7c478bd9Sstevel@tonic-gate 3076*7c478bd9Sstevel@tonic-gate object = pt_resolve_lmid(object, &lmid); 3077*7c478bd9Sstevel@tonic-gate 3078*7c478bd9Sstevel@tonic-gate if ((pmp = Plmid_to_map(t->t_pshandle, lmid, object)) == NULL) { 3079*7c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_NOOBJ); 3080*7c478bd9Sstevel@tonic-gate return (NULL); 3081*7c478bd9Sstevel@tonic-gate } 3082*7c478bd9Sstevel@tonic-gate 3083*7c478bd9Sstevel@tonic-gate return (pt_prmap_to_mdbmap(t, pmp, &pt->p_map)); 3084*7c478bd9Sstevel@tonic-gate } 3085*7c478bd9Sstevel@tonic-gate 3086*7c478bd9Sstevel@tonic-gate static ctf_file_t * 3087*7c478bd9Sstevel@tonic-gate pt_addr_to_ctf(mdb_tgt_t *t, uintptr_t addr) 3088*7c478bd9Sstevel@tonic-gate { 3089*7c478bd9Sstevel@tonic-gate ctf_file_t *ret; 3090*7c478bd9Sstevel@tonic-gate 3091*7c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) { 3092*7c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_NOPROC); 3093*7c478bd9Sstevel@tonic-gate return (NULL); 3094*7c478bd9Sstevel@tonic-gate } 3095*7c478bd9Sstevel@tonic-gate 3096*7c478bd9Sstevel@tonic-gate if ((ret = Paddr_to_ctf(t->t_pshandle, addr)) == NULL) { 3097*7c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_NOOBJ); 3098*7c478bd9Sstevel@tonic-gate return (NULL); 3099*7c478bd9Sstevel@tonic-gate } 3100*7c478bd9Sstevel@tonic-gate 3101*7c478bd9Sstevel@tonic-gate return (ret); 3102*7c478bd9Sstevel@tonic-gate } 3103*7c478bd9Sstevel@tonic-gate 3104*7c478bd9Sstevel@tonic-gate static ctf_file_t * 3105*7c478bd9Sstevel@tonic-gate pt_name_to_ctf(mdb_tgt_t *t, const char *name) 3106*7c478bd9Sstevel@tonic-gate { 3107*7c478bd9Sstevel@tonic-gate ctf_file_t *ret; 3108*7c478bd9Sstevel@tonic-gate 3109*7c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) { 3110*7c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_NOPROC); 3111*7c478bd9Sstevel@tonic-gate return (NULL); 3112*7c478bd9Sstevel@tonic-gate } 3113*7c478bd9Sstevel@tonic-gate 3114*7c478bd9Sstevel@tonic-gate if ((ret = Pname_to_ctf(t->t_pshandle, name)) == NULL) { 3115*7c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_NOOBJ); 3116*7c478bd9Sstevel@tonic-gate return (NULL); 3117*7c478bd9Sstevel@tonic-gate } 3118*7c478bd9Sstevel@tonic-gate 3119*7c478bd9Sstevel@tonic-gate return (ret); 3120*7c478bd9Sstevel@tonic-gate } 3121*7c478bd9Sstevel@tonic-gate 3122*7c478bd9Sstevel@tonic-gate static int 3123*7c478bd9Sstevel@tonic-gate pt_status(mdb_tgt_t *t, mdb_tgt_status_t *tsp) 3124*7c478bd9Sstevel@tonic-gate { 3125*7c478bd9Sstevel@tonic-gate const pstatus_t *psp; 3126*7c478bd9Sstevel@tonic-gate prgregset_t gregs; 3127*7c478bd9Sstevel@tonic-gate int state; 3128*7c478bd9Sstevel@tonic-gate 3129*7c478bd9Sstevel@tonic-gate bzero(tsp, sizeof (mdb_tgt_status_t)); 3130*7c478bd9Sstevel@tonic-gate 3131*7c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) { 3132*7c478bd9Sstevel@tonic-gate tsp->st_state = MDB_TGT_IDLE; 3133*7c478bd9Sstevel@tonic-gate return (0); 3134*7c478bd9Sstevel@tonic-gate } 3135*7c478bd9Sstevel@tonic-gate 3136*7c478bd9Sstevel@tonic-gate switch (state = Pstate(t->t_pshandle)) { 3137*7c478bd9Sstevel@tonic-gate case PS_RUN: 3138*7c478bd9Sstevel@tonic-gate tsp->st_state = MDB_TGT_RUNNING; 3139*7c478bd9Sstevel@tonic-gate break; 3140*7c478bd9Sstevel@tonic-gate 3141*7c478bd9Sstevel@tonic-gate case PS_STOP: 3142*7c478bd9Sstevel@tonic-gate tsp->st_state = MDB_TGT_STOPPED; 3143*7c478bd9Sstevel@tonic-gate psp = Pstatus(t->t_pshandle); 3144*7c478bd9Sstevel@tonic-gate 3145*7c478bd9Sstevel@tonic-gate tsp->st_tid = PTL_TID(t); 3146*7c478bd9Sstevel@tonic-gate if (PTL_GETREGS(t, tsp->st_tid, gregs) == 0) 3147*7c478bd9Sstevel@tonic-gate tsp->st_pc = gregs[R_PC]; 3148*7c478bd9Sstevel@tonic-gate 3149*7c478bd9Sstevel@tonic-gate if (psp->pr_flags & PR_ISTOP) 3150*7c478bd9Sstevel@tonic-gate tsp->st_flags |= MDB_TGT_ISTOP; 3151*7c478bd9Sstevel@tonic-gate if (psp->pr_flags & PR_DSTOP) 3152*7c478bd9Sstevel@tonic-gate tsp->st_flags |= MDB_TGT_DSTOP; 3153*7c478bd9Sstevel@tonic-gate 3154*7c478bd9Sstevel@tonic-gate break; 3155*7c478bd9Sstevel@tonic-gate 3156*7c478bd9Sstevel@tonic-gate case PS_LOST: 3157*7c478bd9Sstevel@tonic-gate tsp->st_state = MDB_TGT_LOST; 3158*7c478bd9Sstevel@tonic-gate break; 3159*7c478bd9Sstevel@tonic-gate case PS_UNDEAD: 3160*7c478bd9Sstevel@tonic-gate tsp->st_state = MDB_TGT_UNDEAD; 3161*7c478bd9Sstevel@tonic-gate break; 3162*7c478bd9Sstevel@tonic-gate case PS_DEAD: 3163*7c478bd9Sstevel@tonic-gate tsp->st_state = MDB_TGT_DEAD; 3164*7c478bd9Sstevel@tonic-gate break; 3165*7c478bd9Sstevel@tonic-gate case PS_IDLE: 3166*7c478bd9Sstevel@tonic-gate tsp->st_state = MDB_TGT_IDLE; 3167*7c478bd9Sstevel@tonic-gate break; 3168*7c478bd9Sstevel@tonic-gate default: 3169*7c478bd9Sstevel@tonic-gate fail("unknown libproc state (%d)\n", state); 3170*7c478bd9Sstevel@tonic-gate } 3171*7c478bd9Sstevel@tonic-gate 3172*7c478bd9Sstevel@tonic-gate if (t->t_flags & MDB_TGT_F_BUSY) 3173*7c478bd9Sstevel@tonic-gate tsp->st_flags |= MDB_TGT_BUSY; 3174*7c478bd9Sstevel@tonic-gate 3175*7c478bd9Sstevel@tonic-gate return (0); 3176*7c478bd9Sstevel@tonic-gate } 3177*7c478bd9Sstevel@tonic-gate 3178*7c478bd9Sstevel@tonic-gate static void 3179*7c478bd9Sstevel@tonic-gate pt_dupfd(const char *file, int oflags, mode_t mode, int dfd) 3180*7c478bd9Sstevel@tonic-gate { 3181*7c478bd9Sstevel@tonic-gate int fd; 3182*7c478bd9Sstevel@tonic-gate 3183*7c478bd9Sstevel@tonic-gate if ((fd = open(file, oflags, mode)) >= 0) { 3184*7c478bd9Sstevel@tonic-gate (void) fcntl(fd, F_DUP2FD, dfd); 3185*7c478bd9Sstevel@tonic-gate (void) close(fd); 3186*7c478bd9Sstevel@tonic-gate } else 3187*7c478bd9Sstevel@tonic-gate warn("failed to open %s as descriptor %d", file, dfd); 3188*7c478bd9Sstevel@tonic-gate } 3189*7c478bd9Sstevel@tonic-gate 3190*7c478bd9Sstevel@tonic-gate /* 3191*7c478bd9Sstevel@tonic-gate * The Pcreate_callback() function interposes on the default, empty libproc 3192*7c478bd9Sstevel@tonic-gate * definition. It will be called following a fork of a new child process by 3193*7c478bd9Sstevel@tonic-gate * Pcreate() below, but before the exec of the new process image. We use this 3194*7c478bd9Sstevel@tonic-gate * callback to optionally redirect stdin and stdout and reset the dispositions 3195*7c478bd9Sstevel@tonic-gate * of SIGPIPE and SIGQUIT from SIG_IGN back to SIG_DFL. 3196*7c478bd9Sstevel@tonic-gate */ 3197*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3198*7c478bd9Sstevel@tonic-gate void 3199*7c478bd9Sstevel@tonic-gate Pcreate_callback(struct ps_prochandle *P) 3200*7c478bd9Sstevel@tonic-gate { 3201*7c478bd9Sstevel@tonic-gate pt_data_t *pt = mdb.m_target->t_data; 3202*7c478bd9Sstevel@tonic-gate 3203*7c478bd9Sstevel@tonic-gate if (pt->p_stdin != NULL) 3204*7c478bd9Sstevel@tonic-gate pt_dupfd(pt->p_stdin, O_RDWR, 0, STDIN_FILENO); 3205*7c478bd9Sstevel@tonic-gate if (pt->p_stdout != NULL) 3206*7c478bd9Sstevel@tonic-gate pt_dupfd(pt->p_stdout, O_CREAT | O_WRONLY, 0666, STDOUT_FILENO); 3207*7c478bd9Sstevel@tonic-gate 3208*7c478bd9Sstevel@tonic-gate (void) mdb_signal_sethandler(SIGPIPE, SIG_DFL, NULL); 3209*7c478bd9Sstevel@tonic-gate (void) mdb_signal_sethandler(SIGQUIT, SIG_DFL, NULL); 3210*7c478bd9Sstevel@tonic-gate } 3211*7c478bd9Sstevel@tonic-gate 3212*7c478bd9Sstevel@tonic-gate static int 3213*7c478bd9Sstevel@tonic-gate pt_run(mdb_tgt_t *t, int argc, const mdb_arg_t *argv) 3214*7c478bd9Sstevel@tonic-gate { 3215*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 3216*7c478bd9Sstevel@tonic-gate struct ps_prochandle *P; 3217*7c478bd9Sstevel@tonic-gate char execname[MAXPATHLEN]; 3218*7c478bd9Sstevel@tonic-gate const char **pargv; 3219*7c478bd9Sstevel@tonic-gate int pargc = 0; 3220*7c478bd9Sstevel@tonic-gate int i, perr; 3221*7c478bd9Sstevel@tonic-gate char **penv; 3222*7c478bd9Sstevel@tonic-gate mdb_var_t *v; 3223*7c478bd9Sstevel@tonic-gate 3224*7c478bd9Sstevel@tonic-gate if (pt->p_aout_fio == NULL) { 3225*7c478bd9Sstevel@tonic-gate warn("run requires executable to be specified on " 3226*7c478bd9Sstevel@tonic-gate "command-line\n"); 3227*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_TGT)); 3228*7c478bd9Sstevel@tonic-gate } 3229*7c478bd9Sstevel@tonic-gate 3230*7c478bd9Sstevel@tonic-gate pargv = mdb_alloc(sizeof (char *) * (argc + 2), UM_SLEEP); 3231*7c478bd9Sstevel@tonic-gate pargv[pargc++] = strbasename(IOP_NAME(pt->p_aout_fio)); 3232*7c478bd9Sstevel@tonic-gate 3233*7c478bd9Sstevel@tonic-gate for (i = 0; i < argc; i++) { 3234*7c478bd9Sstevel@tonic-gate if (argv[i].a_type != MDB_TYPE_STRING) { 3235*7c478bd9Sstevel@tonic-gate mdb_free(pargv, sizeof (char *) * (argc + 2)); 3236*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 3237*7c478bd9Sstevel@tonic-gate } 3238*7c478bd9Sstevel@tonic-gate if (argv[i].a_un.a_str[0] == '<') 3239*7c478bd9Sstevel@tonic-gate pt->p_stdin = argv[i].a_un.a_str + 1; 3240*7c478bd9Sstevel@tonic-gate else if (argv[i].a_un.a_str[0] == '>') 3241*7c478bd9Sstevel@tonic-gate pt->p_stdout = argv[i].a_un.a_str + 1; 3242*7c478bd9Sstevel@tonic-gate else 3243*7c478bd9Sstevel@tonic-gate pargv[pargc++] = argv[i].a_un.a_str; 3244*7c478bd9Sstevel@tonic-gate } 3245*7c478bd9Sstevel@tonic-gate pargv[pargc] = NULL; 3246*7c478bd9Sstevel@tonic-gate 3247*7c478bd9Sstevel@tonic-gate /* 3248*7c478bd9Sstevel@tonic-gate * Since Pcreate() uses execvp() and "." may not be present in $PATH, 3249*7c478bd9Sstevel@tonic-gate * we must manually prepend "./" when the executable is a simple name. 3250*7c478bd9Sstevel@tonic-gate */ 3251*7c478bd9Sstevel@tonic-gate if (strchr(IOP_NAME(pt->p_aout_fio), '/') == NULL) { 3252*7c478bd9Sstevel@tonic-gate (void) snprintf(execname, sizeof (execname), "./%s", 3253*7c478bd9Sstevel@tonic-gate IOP_NAME(pt->p_aout_fio)); 3254*7c478bd9Sstevel@tonic-gate } else { 3255*7c478bd9Sstevel@tonic-gate (void) snprintf(execname, sizeof (execname), "%s", 3256*7c478bd9Sstevel@tonic-gate IOP_NAME(pt->p_aout_fio)); 3257*7c478bd9Sstevel@tonic-gate } 3258*7c478bd9Sstevel@tonic-gate 3259*7c478bd9Sstevel@tonic-gate penv = mdb_alloc((mdb_nv_size(&pt->p_env)+ 1) * sizeof (char *), 3260*7c478bd9Sstevel@tonic-gate UM_SLEEP); 3261*7c478bd9Sstevel@tonic-gate for (mdb_nv_rewind(&pt->p_env), i = 0; 3262*7c478bd9Sstevel@tonic-gate (v = mdb_nv_advance(&pt->p_env)) != NULL; i++) 3263*7c478bd9Sstevel@tonic-gate penv[i] = mdb_nv_get_cookie(v); 3264*7c478bd9Sstevel@tonic-gate penv[i] = NULL; 3265*7c478bd9Sstevel@tonic-gate 3266*7c478bd9Sstevel@tonic-gate P = Pxcreate(execname, (char **)pargv, penv, &perr, NULL, 0); 3267*7c478bd9Sstevel@tonic-gate mdb_free(pargv, sizeof (char *) * (argc + 2)); 3268*7c478bd9Sstevel@tonic-gate pt->p_stdin = pt->p_stdout = NULL; 3269*7c478bd9Sstevel@tonic-gate 3270*7c478bd9Sstevel@tonic-gate mdb_free(penv, i * sizeof (char *)); 3271*7c478bd9Sstevel@tonic-gate 3272*7c478bd9Sstevel@tonic-gate if (P == NULL) { 3273*7c478bd9Sstevel@tonic-gate warn("failed to create process: %s\n", Pcreate_error(perr)); 3274*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_TGT)); 3275*7c478bd9Sstevel@tonic-gate } 3276*7c478bd9Sstevel@tonic-gate 3277*7c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL) { 3278*7c478bd9Sstevel@tonic-gate pt_pre_detach(t, TRUE); 3279*7c478bd9Sstevel@tonic-gate if (t->t_pshandle != pt->p_idlehandle) 3280*7c478bd9Sstevel@tonic-gate Prelease(t->t_pshandle, pt->p_rflags); 3281*7c478bd9Sstevel@tonic-gate } 3282*7c478bd9Sstevel@tonic-gate 3283*7c478bd9Sstevel@tonic-gate (void) Punsetflags(P, PR_RLC); /* make sure run-on-last-close is off */ 3284*7c478bd9Sstevel@tonic-gate (void) Psetflags(P, PR_KLC); /* kill on last close by debugger */ 3285*7c478bd9Sstevel@tonic-gate pt->p_rflags = PRELEASE_KILL; /* kill on debugger Prelease */ 3286*7c478bd9Sstevel@tonic-gate t->t_pshandle = P; 3287*7c478bd9Sstevel@tonic-gate 3288*7c478bd9Sstevel@tonic-gate pt_post_attach(t); 3289*7c478bd9Sstevel@tonic-gate pt_activate_common(t); 3290*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_status(t, &t->t_status); 3291*7c478bd9Sstevel@tonic-gate mdb.m_flags |= MDB_FL_VCREATE; 3292*7c478bd9Sstevel@tonic-gate 3293*7c478bd9Sstevel@tonic-gate return (0); 3294*7c478bd9Sstevel@tonic-gate } 3295*7c478bd9Sstevel@tonic-gate 3296*7c478bd9Sstevel@tonic-gate /* 3297*7c478bd9Sstevel@tonic-gate * Forward a signal to the victim process in order to force it to stop or die. 3298*7c478bd9Sstevel@tonic-gate * Refer to the comments above pt_setrun(), below, for more info. 3299*7c478bd9Sstevel@tonic-gate */ 3300*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3301*7c478bd9Sstevel@tonic-gate static void 3302*7c478bd9Sstevel@tonic-gate pt_sigfwd(int sig, siginfo_t *sip, ucontext_t *ucp, mdb_tgt_t *t) 3303*7c478bd9Sstevel@tonic-gate { 3304*7c478bd9Sstevel@tonic-gate struct ps_prochandle *P = t->t_pshandle; 3305*7c478bd9Sstevel@tonic-gate const lwpstatus_t *psp = &Pstatus(P)->pr_lwp; 3306*7c478bd9Sstevel@tonic-gate pid_t pid = Pstatus(P)->pr_pid; 3307*7c478bd9Sstevel@tonic-gate long ctl[2]; 3308*7c478bd9Sstevel@tonic-gate 3309*7c478bd9Sstevel@tonic-gate if (getpgid(pid) != mdb.m_pgid) { 3310*7c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_TGT, "fwd SIG#%d to %d\n", sig, (int)pid); 3311*7c478bd9Sstevel@tonic-gate (void) kill(pid, sig); 3312*7c478bd9Sstevel@tonic-gate } 3313*7c478bd9Sstevel@tonic-gate 3314*7c478bd9Sstevel@tonic-gate if (Pwait(P, 1) == 0 && (psp->pr_flags & PR_STOPPED) && 3315*7c478bd9Sstevel@tonic-gate psp->pr_why == PR_JOBCONTROL && Pdstop(P) == 0) { 3316*7c478bd9Sstevel@tonic-gate /* 3317*7c478bd9Sstevel@tonic-gate * If we're job control stopped and our DSTOP is pending, the 3318*7c478bd9Sstevel@tonic-gate * victim will never see our signal, so undo the kill() and 3319*7c478bd9Sstevel@tonic-gate * then send SIGCONT the victim to kick it out of the job 3320*7c478bd9Sstevel@tonic-gate * control stop and force our DSTOP to take effect. 3321*7c478bd9Sstevel@tonic-gate */ 3322*7c478bd9Sstevel@tonic-gate if ((psp->pr_flags & PR_DSTOP) && 3323*7c478bd9Sstevel@tonic-gate prismember(&Pstatus(P)->pr_sigpend, sig)) { 3324*7c478bd9Sstevel@tonic-gate ctl[0] = PCUNKILL; 3325*7c478bd9Sstevel@tonic-gate ctl[1] = sig; 3326*7c478bd9Sstevel@tonic-gate (void) write(Pctlfd(P), ctl, sizeof (ctl)); 3327*7c478bd9Sstevel@tonic-gate } 3328*7c478bd9Sstevel@tonic-gate 3329*7c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_TGT, "fwd SIGCONT to %d\n", (int)pid); 3330*7c478bd9Sstevel@tonic-gate (void) kill(pid, SIGCONT); 3331*7c478bd9Sstevel@tonic-gate } 3332*7c478bd9Sstevel@tonic-gate } 3333*7c478bd9Sstevel@tonic-gate 3334*7c478bd9Sstevel@tonic-gate /* 3335*7c478bd9Sstevel@tonic-gate * Common code for step and continue: if no victim process has been created, 3336*7c478bd9Sstevel@tonic-gate * call pt_run() to create one. Then set the victim running, clearing any 3337*7c478bd9Sstevel@tonic-gate * pending fault. One special case is that if the victim was previously 3338*7c478bd9Sstevel@tonic-gate * stopped on reception of SIGINT, we know that SIGINT was traced and the user 3339*7c478bd9Sstevel@tonic-gate * requested the victim to stop, so clear this signal before continuing. 3340*7c478bd9Sstevel@tonic-gate * For all other traced signals, the signal will be delivered on continue. 3341*7c478bd9Sstevel@tonic-gate * 3342*7c478bd9Sstevel@tonic-gate * Once the victim process is running, we wait for it to stop on an event of 3343*7c478bd9Sstevel@tonic-gate * interest. Although libproc provides the basic primitive to wait for the 3344*7c478bd9Sstevel@tonic-gate * victim, we must be careful in our handling of signals. We want to allow the 3345*7c478bd9Sstevel@tonic-gate * user to issue a SIGINT or SIGQUIT using the designated terminal control 3346*7c478bd9Sstevel@tonic-gate * character (typically ^C and ^\), and have these signals stop the target and 3347*7c478bd9Sstevel@tonic-gate * return control to the debugger if the signals are traced. There are three 3348*7c478bd9Sstevel@tonic-gate * cases to be considered in our implementation: 3349*7c478bd9Sstevel@tonic-gate * 3350*7c478bd9Sstevel@tonic-gate * (1) If the debugger and victim are in the same process group, both receive 3351*7c478bd9Sstevel@tonic-gate * the signal from the terminal driver. The debugger returns from Pwait() with 3352*7c478bd9Sstevel@tonic-gate * errno = EINTR, so we want to loop back and continue waiting until the victim 3353*7c478bd9Sstevel@tonic-gate * stops on receipt of its SIGINT or SIGQUIT. 3354*7c478bd9Sstevel@tonic-gate * 3355*7c478bd9Sstevel@tonic-gate * (2) If the debugger and victim are in different process groups, and the 3356*7c478bd9Sstevel@tonic-gate * victim is a member of the foreground process group, it will receive the 3357*7c478bd9Sstevel@tonic-gate * signal from the terminal driver and the debugger will not. As such, we 3358*7c478bd9Sstevel@tonic-gate * will remain blocked in Pwait() until the victim stops on its signal. 3359*7c478bd9Sstevel@tonic-gate * 3360*7c478bd9Sstevel@tonic-gate * (3) If the debugger and victim are in different process groups, and the 3361*7c478bd9Sstevel@tonic-gate * debugger is a member of the foreground process group, it will receive the 3362*7c478bd9Sstevel@tonic-gate * signal from the terminal driver, and the victim will not. The debugger 3363*7c478bd9Sstevel@tonic-gate * returns from Pwait() with errno = EINTR, so we need to forward the signal 3364*7c478bd9Sstevel@tonic-gate * to the victim process directly and then Pwait() again for it to stop. 3365*7c478bd9Sstevel@tonic-gate * 3366*7c478bd9Sstevel@tonic-gate * We can observe that all three cases are handled by simply calling Pwait() 3367*7c478bd9Sstevel@tonic-gate * repeatedly if it fails with EINTR, and forwarding SIGINT and SIGQUIT to 3368*7c478bd9Sstevel@tonic-gate * the victim if it is in a different process group, using pt_sigfwd() above. 3369*7c478bd9Sstevel@tonic-gate * 3370*7c478bd9Sstevel@tonic-gate * An additional complication is that the process may not be able to field 3371*7c478bd9Sstevel@tonic-gate * the signal if it is currently stopped by job control. In this case, we 3372*7c478bd9Sstevel@tonic-gate * also DSTOP the process, and then send it a SIGCONT to wake it up from 3373*7c478bd9Sstevel@tonic-gate * job control and force it to re-enter stop() under the control of /proc. 3374*7c478bd9Sstevel@tonic-gate * 3375*7c478bd9Sstevel@tonic-gate * Finally, we would like to allow the user to suspend the process using the 3376*7c478bd9Sstevel@tonic-gate * terminal suspend character (typically ^Z) if both are in the same session. 3377*7c478bd9Sstevel@tonic-gate * We again employ pt_sigfwd() to forward SIGTSTP to the victim, wait for it to 3378*7c478bd9Sstevel@tonic-gate * stop from job control, and then capture it using /proc. Once the process 3379*7c478bd9Sstevel@tonic-gate * has stopped, normal SIGTSTP processing is restored and the user can issue 3380*7c478bd9Sstevel@tonic-gate * another ^Z in order to suspend the debugger and return to the parent shell. 3381*7c478bd9Sstevel@tonic-gate */ 3382*7c478bd9Sstevel@tonic-gate static int 3383*7c478bd9Sstevel@tonic-gate pt_setrun(mdb_tgt_t *t, mdb_tgt_status_t *tsp, int flags) 3384*7c478bd9Sstevel@tonic-gate { 3385*7c478bd9Sstevel@tonic-gate struct ps_prochandle *P = t->t_pshandle; 3386*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 3387*7c478bd9Sstevel@tonic-gate pid_t old_pgid = -1; 3388*7c478bd9Sstevel@tonic-gate 3389*7c478bd9Sstevel@tonic-gate mdb_signal_f *intf, *quitf, *tstpf; 3390*7c478bd9Sstevel@tonic-gate const lwpstatus_t *psp; 3391*7c478bd9Sstevel@tonic-gate void *intd, *quitd, *tstpd; 3392*7c478bd9Sstevel@tonic-gate 3393*7c478bd9Sstevel@tonic-gate int sig = pt->p_signal; 3394*7c478bd9Sstevel@tonic-gate int error = 0; 3395*7c478bd9Sstevel@tonic-gate int pgid = -1; 3396*7c478bd9Sstevel@tonic-gate 3397*7c478bd9Sstevel@tonic-gate pt->p_signal = 0; /* clear pending signal */ 3398*7c478bd9Sstevel@tonic-gate 3399*7c478bd9Sstevel@tonic-gate if (P == NULL && pt_run(t, 0, NULL) == -1) 3400*7c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 3401*7c478bd9Sstevel@tonic-gate 3402*7c478bd9Sstevel@tonic-gate P = t->t_pshandle; 3403*7c478bd9Sstevel@tonic-gate psp = &Pstatus(P)->pr_lwp; 3404*7c478bd9Sstevel@tonic-gate 3405*7c478bd9Sstevel@tonic-gate if (sig == 0 && psp->pr_why == PR_SIGNALLED && psp->pr_what == SIGINT) 3406*7c478bd9Sstevel@tonic-gate flags |= PRCSIG; /* clear pending SIGINT */ 3407*7c478bd9Sstevel@tonic-gate else 3408*7c478bd9Sstevel@tonic-gate flags |= PRCFAULT; /* clear any pending fault (e.g. BPT) */ 3409*7c478bd9Sstevel@tonic-gate 3410*7c478bd9Sstevel@tonic-gate intf = mdb_signal_gethandler(SIGINT, &intd); 3411*7c478bd9Sstevel@tonic-gate quitf = mdb_signal_gethandler(SIGQUIT, &quitd); 3412*7c478bd9Sstevel@tonic-gate tstpf = mdb_signal_gethandler(SIGTSTP, &tstpd); 3413*7c478bd9Sstevel@tonic-gate 3414*7c478bd9Sstevel@tonic-gate (void) mdb_signal_sethandler(SIGINT, (mdb_signal_f *)pt_sigfwd, t); 3415*7c478bd9Sstevel@tonic-gate (void) mdb_signal_sethandler(SIGQUIT, (mdb_signal_f *)pt_sigfwd, t); 3416*7c478bd9Sstevel@tonic-gate (void) mdb_signal_sethandler(SIGTSTP, (mdb_signal_f *)pt_sigfwd, t); 3417*7c478bd9Sstevel@tonic-gate 3418*7c478bd9Sstevel@tonic-gate if (sig != 0 && Pstate(P) == PS_RUN && 3419*7c478bd9Sstevel@tonic-gate kill(Pstatus(P)->pr_pid, sig) == -1) { 3420*7c478bd9Sstevel@tonic-gate error = errno; 3421*7c478bd9Sstevel@tonic-gate goto out; 3422*7c478bd9Sstevel@tonic-gate } 3423*7c478bd9Sstevel@tonic-gate 3424*7c478bd9Sstevel@tonic-gate /* 3425*7c478bd9Sstevel@tonic-gate * If we attached to a job stopped background process in the same 3426*7c478bd9Sstevel@tonic-gate * session, make its pgid the foreground process group before running 3427*7c478bd9Sstevel@tonic-gate * it. Ignore SIGTTOU while doing this to avoid being suspended. 3428*7c478bd9Sstevel@tonic-gate */ 3429*7c478bd9Sstevel@tonic-gate if (mdb.m_flags & MDB_FL_JOBCTL) { 3430*7c478bd9Sstevel@tonic-gate (void) mdb_signal_sethandler(SIGTTOU, SIG_IGN, NULL); 3431*7c478bd9Sstevel@tonic-gate (void) IOP_CTL(mdb.m_term, TIOCGPGRP, &old_pgid); 3432*7c478bd9Sstevel@tonic-gate (void) IOP_CTL(mdb.m_term, TIOCSPGRP, 3433*7c478bd9Sstevel@tonic-gate (void *)&Pstatus(P)->pr_pgid); 3434*7c478bd9Sstevel@tonic-gate (void) mdb_signal_sethandler(SIGTTOU, SIG_DFL, NULL); 3435*7c478bd9Sstevel@tonic-gate } 3436*7c478bd9Sstevel@tonic-gate 3437*7c478bd9Sstevel@tonic-gate if (Pstate(P) != PS_RUN && Psetrun(P, sig, flags) == -1) { 3438*7c478bd9Sstevel@tonic-gate error = errno; 3439*7c478bd9Sstevel@tonic-gate goto out; 3440*7c478bd9Sstevel@tonic-gate } 3441*7c478bd9Sstevel@tonic-gate 3442*7c478bd9Sstevel@tonic-gate /* 3443*7c478bd9Sstevel@tonic-gate * If the process is stopped on job control, resume its process group 3444*7c478bd9Sstevel@tonic-gate * by sending it a SIGCONT if we are in the same session. Otherwise 3445*7c478bd9Sstevel@tonic-gate * we have no choice but to wait for someone else to foreground it. 3446*7c478bd9Sstevel@tonic-gate */ 3447*7c478bd9Sstevel@tonic-gate if (psp->pr_why == PR_JOBCONTROL) { 3448*7c478bd9Sstevel@tonic-gate if (mdb.m_flags & MDB_FL_JOBCTL) 3449*7c478bd9Sstevel@tonic-gate (void) kill(-Pstatus(P)->pr_pgid, SIGCONT); 3450*7c478bd9Sstevel@tonic-gate else if (mdb.m_term != NULL) 3451*7c478bd9Sstevel@tonic-gate warn("process is still suspended by job control ...\n"); 3452*7c478bd9Sstevel@tonic-gate } 3453*7c478bd9Sstevel@tonic-gate 3454*7c478bd9Sstevel@tonic-gate /* 3455*7c478bd9Sstevel@tonic-gate * Wait for the process to stop. As described above, we loop around if 3456*7c478bd9Sstevel@tonic-gate * we are interrupted (EINTR). If we lose control, attempt to re-open 3457*7c478bd9Sstevel@tonic-gate * the process, or call pt_exec() if that fails to handle a re-exec. 3458*7c478bd9Sstevel@tonic-gate * If the process dies (ENOENT) or Pwait() fails, break out of the loop. 3459*7c478bd9Sstevel@tonic-gate */ 3460*7c478bd9Sstevel@tonic-gate while (Pwait(P, 0) == -1) { 3461*7c478bd9Sstevel@tonic-gate if (errno != EINTR) { 3462*7c478bd9Sstevel@tonic-gate if (Pstate(P) == PS_LOST) { 3463*7c478bd9Sstevel@tonic-gate if (Preopen(P) == 0) 3464*7c478bd9Sstevel@tonic-gate continue; /* Pwait() again */ 3465*7c478bd9Sstevel@tonic-gate else 3466*7c478bd9Sstevel@tonic-gate pt_exec(t, 0, NULL); 3467*7c478bd9Sstevel@tonic-gate } else if (errno != ENOENT) 3468*7c478bd9Sstevel@tonic-gate warn("failed to wait for event"); 3469*7c478bd9Sstevel@tonic-gate break; 3470*7c478bd9Sstevel@tonic-gate } 3471*7c478bd9Sstevel@tonic-gate } 3472*7c478bd9Sstevel@tonic-gate 3473*7c478bd9Sstevel@tonic-gate /* 3474*7c478bd9Sstevel@tonic-gate * If we changed the foreground process group, restore the old pgid 3475*7c478bd9Sstevel@tonic-gate * while ignoring SIGTTOU so we are not accidentally suspended. 3476*7c478bd9Sstevel@tonic-gate */ 3477*7c478bd9Sstevel@tonic-gate if (old_pgid != -1) { 3478*7c478bd9Sstevel@tonic-gate (void) mdb_signal_sethandler(SIGTTOU, SIG_IGN, NULL); 3479*7c478bd9Sstevel@tonic-gate (void) IOP_CTL(mdb.m_term, TIOCSPGRP, &pgid); 3480*7c478bd9Sstevel@tonic-gate (void) mdb_signal_sethandler(SIGTTOU, SIG_DFL, NULL); 3481*7c478bd9Sstevel@tonic-gate } 3482*7c478bd9Sstevel@tonic-gate 3483*7c478bd9Sstevel@tonic-gate /* 3484*7c478bd9Sstevel@tonic-gate * If we're now stopped on exit from a successful exec, release any 3485*7c478bd9Sstevel@tonic-gate * vfork parents and clean out their address space before returning 3486*7c478bd9Sstevel@tonic-gate * to tgt_continue() and perturbing the list of armed event specs. 3487*7c478bd9Sstevel@tonic-gate * If we're stopped for any other reason, just update the mappings. 3488*7c478bd9Sstevel@tonic-gate */ 3489*7c478bd9Sstevel@tonic-gate switch (Pstate(P)) { 3490*7c478bd9Sstevel@tonic-gate case PS_STOP: 3491*7c478bd9Sstevel@tonic-gate if (psp->pr_why == PR_SYSEXIT && psp->pr_errno == 0 && 3492*7c478bd9Sstevel@tonic-gate (psp->pr_what == SYS_exec || psp->pr_what == SYS_execve)) 3493*7c478bd9Sstevel@tonic-gate pt_release_parents(t); 3494*7c478bd9Sstevel@tonic-gate else 3495*7c478bd9Sstevel@tonic-gate Pupdate_maps(P); 3496*7c478bd9Sstevel@tonic-gate break; 3497*7c478bd9Sstevel@tonic-gate 3498*7c478bd9Sstevel@tonic-gate case PS_UNDEAD: 3499*7c478bd9Sstevel@tonic-gate case PS_LOST: 3500*7c478bd9Sstevel@tonic-gate pt_release_parents(t); 3501*7c478bd9Sstevel@tonic-gate break; 3502*7c478bd9Sstevel@tonic-gate } 3503*7c478bd9Sstevel@tonic-gate 3504*7c478bd9Sstevel@tonic-gate out: 3505*7c478bd9Sstevel@tonic-gate (void) mdb_signal_sethandler(SIGINT, intf, intd); 3506*7c478bd9Sstevel@tonic-gate (void) mdb_signal_sethandler(SIGQUIT, quitf, quitd); 3507*7c478bd9Sstevel@tonic-gate (void) mdb_signal_sethandler(SIGTSTP, tstpf, tstpd); 3508*7c478bd9Sstevel@tonic-gate (void) pt_status(t, tsp); 3509*7c478bd9Sstevel@tonic-gate 3510*7c478bd9Sstevel@tonic-gate return (error ? set_errno(error) : 0); 3511*7c478bd9Sstevel@tonic-gate } 3512*7c478bd9Sstevel@tonic-gate 3513*7c478bd9Sstevel@tonic-gate static int 3514*7c478bd9Sstevel@tonic-gate pt_step(mdb_tgt_t *t, mdb_tgt_status_t *tsp) 3515*7c478bd9Sstevel@tonic-gate { 3516*7c478bd9Sstevel@tonic-gate return (pt_setrun(t, tsp, PRSTEP)); 3517*7c478bd9Sstevel@tonic-gate } 3518*7c478bd9Sstevel@tonic-gate 3519*7c478bd9Sstevel@tonic-gate static int 3520*7c478bd9Sstevel@tonic-gate pt_continue(mdb_tgt_t *t, mdb_tgt_status_t *tsp) 3521*7c478bd9Sstevel@tonic-gate { 3522*7c478bd9Sstevel@tonic-gate return (pt_setrun(t, tsp, 0)); 3523*7c478bd9Sstevel@tonic-gate } 3524*7c478bd9Sstevel@tonic-gate 3525*7c478bd9Sstevel@tonic-gate static int 3526*7c478bd9Sstevel@tonic-gate pt_signal(mdb_tgt_t *t, int sig) 3527*7c478bd9Sstevel@tonic-gate { 3528*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 3529*7c478bd9Sstevel@tonic-gate 3530*7c478bd9Sstevel@tonic-gate if (sig > 0 && sig <= pt->p_maxsig) { 3531*7c478bd9Sstevel@tonic-gate pt->p_signal = sig; /* pending until next pt_setrun */ 3532*7c478bd9Sstevel@tonic-gate return (0); 3533*7c478bd9Sstevel@tonic-gate } 3534*7c478bd9Sstevel@tonic-gate 3535*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_BADSIGNUM)); 3536*7c478bd9Sstevel@tonic-gate } 3537*7c478bd9Sstevel@tonic-gate 3538*7c478bd9Sstevel@tonic-gate static int 3539*7c478bd9Sstevel@tonic-gate pt_sysenter_ctor(mdb_tgt_t *t, mdb_sespec_t *sep, void *args) 3540*7c478bd9Sstevel@tonic-gate { 3541*7c478bd9Sstevel@tonic-gate struct ps_prochandle *P = t->t_pshandle; 3542*7c478bd9Sstevel@tonic-gate 3543*7c478bd9Sstevel@tonic-gate if (P != NULL && Pstate(P) < PS_LOST) { 3544*7c478bd9Sstevel@tonic-gate sep->se_data = args; /* data is raw system call number */ 3545*7c478bd9Sstevel@tonic-gate return (Psysentry(P, (intptr_t)args, TRUE) < 0 ? -1 : 0); 3546*7c478bd9Sstevel@tonic-gate } 3547*7c478bd9Sstevel@tonic-gate 3548*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 3549*7c478bd9Sstevel@tonic-gate } 3550*7c478bd9Sstevel@tonic-gate 3551*7c478bd9Sstevel@tonic-gate static void 3552*7c478bd9Sstevel@tonic-gate pt_sysenter_dtor(mdb_tgt_t *t, mdb_sespec_t *sep) 3553*7c478bd9Sstevel@tonic-gate { 3554*7c478bd9Sstevel@tonic-gate (void) Psysentry(t->t_pshandle, (intptr_t)sep->se_data, FALSE); 3555*7c478bd9Sstevel@tonic-gate } 3556*7c478bd9Sstevel@tonic-gate 3557*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3558*7c478bd9Sstevel@tonic-gate static char * 3559*7c478bd9Sstevel@tonic-gate pt_sysenter_info(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_vespec_t *vep, 3560*7c478bd9Sstevel@tonic-gate mdb_tgt_spec_desc_t *sp, char *buf, size_t nbytes) 3561*7c478bd9Sstevel@tonic-gate { 3562*7c478bd9Sstevel@tonic-gate char name[32]; 3563*7c478bd9Sstevel@tonic-gate int sysnum; 3564*7c478bd9Sstevel@tonic-gate 3565*7c478bd9Sstevel@tonic-gate if (vep != NULL) 3566*7c478bd9Sstevel@tonic-gate sysnum = (intptr_t)vep->ve_args; 3567*7c478bd9Sstevel@tonic-gate else 3568*7c478bd9Sstevel@tonic-gate sysnum = (intptr_t)sep->se_data; 3569*7c478bd9Sstevel@tonic-gate 3570*7c478bd9Sstevel@tonic-gate (void) proc_sysname(sysnum, name, sizeof (name)); 3571*7c478bd9Sstevel@tonic-gate (void) mdb_iob_snprintf(buf, nbytes, "stop on entry to %s", name); 3572*7c478bd9Sstevel@tonic-gate 3573*7c478bd9Sstevel@tonic-gate return (buf); 3574*7c478bd9Sstevel@tonic-gate } 3575*7c478bd9Sstevel@tonic-gate 3576*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3577*7c478bd9Sstevel@tonic-gate static int 3578*7c478bd9Sstevel@tonic-gate pt_sysenter_match(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_tgt_status_t *tsp) 3579*7c478bd9Sstevel@tonic-gate { 3580*7c478bd9Sstevel@tonic-gate const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp; 3581*7c478bd9Sstevel@tonic-gate int sysnum = (intptr_t)sep->se_data; 3582*7c478bd9Sstevel@tonic-gate 3583*7c478bd9Sstevel@tonic-gate return (psp->pr_why == PR_SYSENTRY && psp->pr_what == sysnum); 3584*7c478bd9Sstevel@tonic-gate } 3585*7c478bd9Sstevel@tonic-gate 3586*7c478bd9Sstevel@tonic-gate static const mdb_se_ops_t proc_sysenter_ops = { 3587*7c478bd9Sstevel@tonic-gate pt_sysenter_ctor, /* se_ctor */ 3588*7c478bd9Sstevel@tonic-gate pt_sysenter_dtor, /* se_dtor */ 3589*7c478bd9Sstevel@tonic-gate pt_sysenter_info, /* se_info */ 3590*7c478bd9Sstevel@tonic-gate no_se_secmp, /* se_secmp */ 3591*7c478bd9Sstevel@tonic-gate no_se_vecmp, /* se_vecmp */ 3592*7c478bd9Sstevel@tonic-gate no_se_arm, /* se_arm */ 3593*7c478bd9Sstevel@tonic-gate no_se_disarm, /* se_disarm */ 3594*7c478bd9Sstevel@tonic-gate no_se_cont, /* se_cont */ 3595*7c478bd9Sstevel@tonic-gate pt_sysenter_match /* se_match */ 3596*7c478bd9Sstevel@tonic-gate }; 3597*7c478bd9Sstevel@tonic-gate 3598*7c478bd9Sstevel@tonic-gate static int 3599*7c478bd9Sstevel@tonic-gate pt_sysexit_ctor(mdb_tgt_t *t, mdb_sespec_t *sep, void *args) 3600*7c478bd9Sstevel@tonic-gate { 3601*7c478bd9Sstevel@tonic-gate struct ps_prochandle *P = t->t_pshandle; 3602*7c478bd9Sstevel@tonic-gate 3603*7c478bd9Sstevel@tonic-gate if (P != NULL && Pstate(P) < PS_LOST) { 3604*7c478bd9Sstevel@tonic-gate sep->se_data = args; /* data is raw system call number */ 3605*7c478bd9Sstevel@tonic-gate return (Psysexit(P, (intptr_t)args, TRUE) < 0 ? -1 : 0); 3606*7c478bd9Sstevel@tonic-gate } 3607*7c478bd9Sstevel@tonic-gate 3608*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 3609*7c478bd9Sstevel@tonic-gate } 3610*7c478bd9Sstevel@tonic-gate 3611*7c478bd9Sstevel@tonic-gate static void 3612*7c478bd9Sstevel@tonic-gate pt_sysexit_dtor(mdb_tgt_t *t, mdb_sespec_t *sep) 3613*7c478bd9Sstevel@tonic-gate { 3614*7c478bd9Sstevel@tonic-gate (void) Psysexit(t->t_pshandle, (intptr_t)sep->se_data, FALSE); 3615*7c478bd9Sstevel@tonic-gate } 3616*7c478bd9Sstevel@tonic-gate 3617*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3618*7c478bd9Sstevel@tonic-gate static char * 3619*7c478bd9Sstevel@tonic-gate pt_sysexit_info(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_vespec_t *vep, 3620*7c478bd9Sstevel@tonic-gate mdb_tgt_spec_desc_t *sp, char *buf, size_t nbytes) 3621*7c478bd9Sstevel@tonic-gate { 3622*7c478bd9Sstevel@tonic-gate char name[32]; 3623*7c478bd9Sstevel@tonic-gate int sysnum; 3624*7c478bd9Sstevel@tonic-gate 3625*7c478bd9Sstevel@tonic-gate if (vep != NULL) 3626*7c478bd9Sstevel@tonic-gate sysnum = (intptr_t)vep->ve_args; 3627*7c478bd9Sstevel@tonic-gate else 3628*7c478bd9Sstevel@tonic-gate sysnum = (intptr_t)sep->se_data; 3629*7c478bd9Sstevel@tonic-gate 3630*7c478bd9Sstevel@tonic-gate (void) proc_sysname(sysnum, name, sizeof (name)); 3631*7c478bd9Sstevel@tonic-gate (void) mdb_iob_snprintf(buf, nbytes, "stop on exit from %s", name); 3632*7c478bd9Sstevel@tonic-gate 3633*7c478bd9Sstevel@tonic-gate return (buf); 3634*7c478bd9Sstevel@tonic-gate } 3635*7c478bd9Sstevel@tonic-gate 3636*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3637*7c478bd9Sstevel@tonic-gate static int 3638*7c478bd9Sstevel@tonic-gate pt_sysexit_match(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_tgt_status_t *tsp) 3639*7c478bd9Sstevel@tonic-gate { 3640*7c478bd9Sstevel@tonic-gate const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp; 3641*7c478bd9Sstevel@tonic-gate int sysnum = (intptr_t)sep->se_data; 3642*7c478bd9Sstevel@tonic-gate 3643*7c478bd9Sstevel@tonic-gate return (psp->pr_why == PR_SYSEXIT && psp->pr_what == sysnum); 3644*7c478bd9Sstevel@tonic-gate } 3645*7c478bd9Sstevel@tonic-gate 3646*7c478bd9Sstevel@tonic-gate static const mdb_se_ops_t proc_sysexit_ops = { 3647*7c478bd9Sstevel@tonic-gate pt_sysexit_ctor, /* se_ctor */ 3648*7c478bd9Sstevel@tonic-gate pt_sysexit_dtor, /* se_dtor */ 3649*7c478bd9Sstevel@tonic-gate pt_sysexit_info, /* se_info */ 3650*7c478bd9Sstevel@tonic-gate no_se_secmp, /* se_secmp */ 3651*7c478bd9Sstevel@tonic-gate no_se_vecmp, /* se_vecmp */ 3652*7c478bd9Sstevel@tonic-gate no_se_arm, /* se_arm */ 3653*7c478bd9Sstevel@tonic-gate no_se_disarm, /* se_disarm */ 3654*7c478bd9Sstevel@tonic-gate no_se_cont, /* se_cont */ 3655*7c478bd9Sstevel@tonic-gate pt_sysexit_match /* se_match */ 3656*7c478bd9Sstevel@tonic-gate }; 3657*7c478bd9Sstevel@tonic-gate 3658*7c478bd9Sstevel@tonic-gate static int 3659*7c478bd9Sstevel@tonic-gate pt_signal_ctor(mdb_tgt_t *t, mdb_sespec_t *sep, void *args) 3660*7c478bd9Sstevel@tonic-gate { 3661*7c478bd9Sstevel@tonic-gate struct ps_prochandle *P = t->t_pshandle; 3662*7c478bd9Sstevel@tonic-gate 3663*7c478bd9Sstevel@tonic-gate if (P != NULL && Pstate(P) < PS_LOST) { 3664*7c478bd9Sstevel@tonic-gate sep->se_data = args; /* data is raw signal number */ 3665*7c478bd9Sstevel@tonic-gate return (Psignal(P, (intptr_t)args, TRUE) < 0 ? -1 : 0); 3666*7c478bd9Sstevel@tonic-gate } 3667*7c478bd9Sstevel@tonic-gate 3668*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 3669*7c478bd9Sstevel@tonic-gate } 3670*7c478bd9Sstevel@tonic-gate 3671*7c478bd9Sstevel@tonic-gate static void 3672*7c478bd9Sstevel@tonic-gate pt_signal_dtor(mdb_tgt_t *t, mdb_sespec_t *sep) 3673*7c478bd9Sstevel@tonic-gate { 3674*7c478bd9Sstevel@tonic-gate (void) Psignal(t->t_pshandle, (intptr_t)sep->se_data, FALSE); 3675*7c478bd9Sstevel@tonic-gate } 3676*7c478bd9Sstevel@tonic-gate 3677*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3678*7c478bd9Sstevel@tonic-gate static char * 3679*7c478bd9Sstevel@tonic-gate pt_signal_info(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_vespec_t *vep, 3680*7c478bd9Sstevel@tonic-gate mdb_tgt_spec_desc_t *sp, char *buf, size_t nbytes) 3681*7c478bd9Sstevel@tonic-gate { 3682*7c478bd9Sstevel@tonic-gate char name[SIG2STR_MAX]; 3683*7c478bd9Sstevel@tonic-gate int signum; 3684*7c478bd9Sstevel@tonic-gate 3685*7c478bd9Sstevel@tonic-gate if (vep != NULL) 3686*7c478bd9Sstevel@tonic-gate signum = (intptr_t)vep->ve_args; 3687*7c478bd9Sstevel@tonic-gate else 3688*7c478bd9Sstevel@tonic-gate signum = (intptr_t)sep->se_data; 3689*7c478bd9Sstevel@tonic-gate 3690*7c478bd9Sstevel@tonic-gate (void) proc_signame(signum, name, sizeof (name)); 3691*7c478bd9Sstevel@tonic-gate (void) mdb_iob_snprintf(buf, nbytes, "stop on %s", name); 3692*7c478bd9Sstevel@tonic-gate 3693*7c478bd9Sstevel@tonic-gate return (buf); 3694*7c478bd9Sstevel@tonic-gate } 3695*7c478bd9Sstevel@tonic-gate 3696*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3697*7c478bd9Sstevel@tonic-gate static int 3698*7c478bd9Sstevel@tonic-gate pt_signal_match(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_tgt_status_t *tsp) 3699*7c478bd9Sstevel@tonic-gate { 3700*7c478bd9Sstevel@tonic-gate const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp; 3701*7c478bd9Sstevel@tonic-gate int signum = (intptr_t)sep->se_data; 3702*7c478bd9Sstevel@tonic-gate 3703*7c478bd9Sstevel@tonic-gate return (psp->pr_why == PR_SIGNALLED && psp->pr_what == signum); 3704*7c478bd9Sstevel@tonic-gate } 3705*7c478bd9Sstevel@tonic-gate 3706*7c478bd9Sstevel@tonic-gate static const mdb_se_ops_t proc_signal_ops = { 3707*7c478bd9Sstevel@tonic-gate pt_signal_ctor, /* se_ctor */ 3708*7c478bd9Sstevel@tonic-gate pt_signal_dtor, /* se_dtor */ 3709*7c478bd9Sstevel@tonic-gate pt_signal_info, /* se_info */ 3710*7c478bd9Sstevel@tonic-gate no_se_secmp, /* se_secmp */ 3711*7c478bd9Sstevel@tonic-gate no_se_vecmp, /* se_vecmp */ 3712*7c478bd9Sstevel@tonic-gate no_se_arm, /* se_arm */ 3713*7c478bd9Sstevel@tonic-gate no_se_disarm, /* se_disarm */ 3714*7c478bd9Sstevel@tonic-gate no_se_cont, /* se_cont */ 3715*7c478bd9Sstevel@tonic-gate pt_signal_match /* se_match */ 3716*7c478bd9Sstevel@tonic-gate }; 3717*7c478bd9Sstevel@tonic-gate 3718*7c478bd9Sstevel@tonic-gate static int 3719*7c478bd9Sstevel@tonic-gate pt_fault_ctor(mdb_tgt_t *t, mdb_sespec_t *sep, void *args) 3720*7c478bd9Sstevel@tonic-gate { 3721*7c478bd9Sstevel@tonic-gate struct ps_prochandle *P = t->t_pshandle; 3722*7c478bd9Sstevel@tonic-gate 3723*7c478bd9Sstevel@tonic-gate if (P != NULL && Pstate(P) < PS_LOST) { 3724*7c478bd9Sstevel@tonic-gate sep->se_data = args; /* data is raw fault number */ 3725*7c478bd9Sstevel@tonic-gate return (Pfault(P, (intptr_t)args, TRUE) < 0 ? -1 : 0); 3726*7c478bd9Sstevel@tonic-gate } 3727*7c478bd9Sstevel@tonic-gate 3728*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 3729*7c478bd9Sstevel@tonic-gate } 3730*7c478bd9Sstevel@tonic-gate 3731*7c478bd9Sstevel@tonic-gate static void 3732*7c478bd9Sstevel@tonic-gate pt_fault_dtor(mdb_tgt_t *t, mdb_sespec_t *sep) 3733*7c478bd9Sstevel@tonic-gate { 3734*7c478bd9Sstevel@tonic-gate int fault = (intptr_t)sep->se_data; 3735*7c478bd9Sstevel@tonic-gate 3736*7c478bd9Sstevel@tonic-gate if (fault != FLTBPT && fault != FLTTRACE && fault != FLTWATCH) 3737*7c478bd9Sstevel@tonic-gate (void) Pfault(t->t_pshandle, fault, FALSE); 3738*7c478bd9Sstevel@tonic-gate } 3739*7c478bd9Sstevel@tonic-gate 3740*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3741*7c478bd9Sstevel@tonic-gate static char * 3742*7c478bd9Sstevel@tonic-gate pt_fault_info(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_vespec_t *vep, 3743*7c478bd9Sstevel@tonic-gate mdb_tgt_spec_desc_t *sp, char *buf, size_t nbytes) 3744*7c478bd9Sstevel@tonic-gate { 3745*7c478bd9Sstevel@tonic-gate char name[32]; 3746*7c478bd9Sstevel@tonic-gate int fltnum; 3747*7c478bd9Sstevel@tonic-gate 3748*7c478bd9Sstevel@tonic-gate if (vep != NULL) 3749*7c478bd9Sstevel@tonic-gate fltnum = (intptr_t)vep->ve_args; 3750*7c478bd9Sstevel@tonic-gate else 3751*7c478bd9Sstevel@tonic-gate fltnum = (intptr_t)sep->se_data; 3752*7c478bd9Sstevel@tonic-gate 3753*7c478bd9Sstevel@tonic-gate (void) proc_fltname(fltnum, name, sizeof (name)); 3754*7c478bd9Sstevel@tonic-gate (void) mdb_iob_snprintf(buf, nbytes, "stop on %s", name); 3755*7c478bd9Sstevel@tonic-gate 3756*7c478bd9Sstevel@tonic-gate return (buf); 3757*7c478bd9Sstevel@tonic-gate } 3758*7c478bd9Sstevel@tonic-gate 3759*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3760*7c478bd9Sstevel@tonic-gate static int 3761*7c478bd9Sstevel@tonic-gate pt_fault_match(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_tgt_status_t *tsp) 3762*7c478bd9Sstevel@tonic-gate { 3763*7c478bd9Sstevel@tonic-gate const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp; 3764*7c478bd9Sstevel@tonic-gate int fltnum = (intptr_t)sep->se_data; 3765*7c478bd9Sstevel@tonic-gate 3766*7c478bd9Sstevel@tonic-gate return (psp->pr_why == PR_FAULTED && psp->pr_what == fltnum); 3767*7c478bd9Sstevel@tonic-gate } 3768*7c478bd9Sstevel@tonic-gate 3769*7c478bd9Sstevel@tonic-gate static const mdb_se_ops_t proc_fault_ops = { 3770*7c478bd9Sstevel@tonic-gate pt_fault_ctor, /* se_ctor */ 3771*7c478bd9Sstevel@tonic-gate pt_fault_dtor, /* se_dtor */ 3772*7c478bd9Sstevel@tonic-gate pt_fault_info, /* se_info */ 3773*7c478bd9Sstevel@tonic-gate no_se_secmp, /* se_secmp */ 3774*7c478bd9Sstevel@tonic-gate no_se_vecmp, /* se_vecmp */ 3775*7c478bd9Sstevel@tonic-gate no_se_arm, /* se_arm */ 3776*7c478bd9Sstevel@tonic-gate no_se_disarm, /* se_disarm */ 3777*7c478bd9Sstevel@tonic-gate no_se_cont, /* se_cont */ 3778*7c478bd9Sstevel@tonic-gate pt_fault_match /* se_match */ 3779*7c478bd9Sstevel@tonic-gate }; 3780*7c478bd9Sstevel@tonic-gate 3781*7c478bd9Sstevel@tonic-gate /* 3782*7c478bd9Sstevel@tonic-gate * Callback for pt_ignore() dcmd above: for each VID, determine if it 3783*7c478bd9Sstevel@tonic-gate * corresponds to a vespec that traces the specified signal, and delete it. 3784*7c478bd9Sstevel@tonic-gate */ 3785*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3786*7c478bd9Sstevel@tonic-gate static int 3787*7c478bd9Sstevel@tonic-gate pt_ignore_sig(mdb_tgt_t *t, void *sig, int vid, void *data) 3788*7c478bd9Sstevel@tonic-gate { 3789*7c478bd9Sstevel@tonic-gate mdb_vespec_t *vep = mdb_tgt_vespec_lookup(t, vid); 3790*7c478bd9Sstevel@tonic-gate 3791*7c478bd9Sstevel@tonic-gate if (vep->ve_se->se_ops == &proc_signal_ops && vep->ve_args == sig) 3792*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_vespec_delete(t, vid); 3793*7c478bd9Sstevel@tonic-gate 3794*7c478bd9Sstevel@tonic-gate return (0); 3795*7c478bd9Sstevel@tonic-gate } 3796*7c478bd9Sstevel@tonic-gate 3797*7c478bd9Sstevel@tonic-gate static int 3798*7c478bd9Sstevel@tonic-gate pt_brkpt_ctor(mdb_tgt_t *t, mdb_sespec_t *sep, void *args) 3799*7c478bd9Sstevel@tonic-gate { 3800*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 3801*7c478bd9Sstevel@tonic-gate pt_bparg_t *pta = args; 3802*7c478bd9Sstevel@tonic-gate pt_brkpt_t *ptb; 3803*7c478bd9Sstevel@tonic-gate GElf_Sym s; 3804*7c478bd9Sstevel@tonic-gate 3805*7c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL || Pstate(t->t_pshandle) >= PS_LOST) 3806*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 3807*7c478bd9Sstevel@tonic-gate 3808*7c478bd9Sstevel@tonic-gate if (pta->pta_symbol != NULL) { 3809*7c478bd9Sstevel@tonic-gate if (!pt->p_rtld_finished && 3810*7c478bd9Sstevel@tonic-gate strchr(pta->pta_symbol, '`') == NULL) 3811*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOSYM)); 3812*7c478bd9Sstevel@tonic-gate if (mdb_tgt_lookup_by_scope(t, pta->pta_symbol, &s, 3813*7c478bd9Sstevel@tonic-gate NULL) == -1) { 3814*7c478bd9Sstevel@tonic-gate if (errno != EMDB_NOOBJ && !(errno == EMDB_NOSYM && 3815*7c478bd9Sstevel@tonic-gate (!(mdb.m_flags & MDB_FL_BPTNOSYMSTOP) || 3816*7c478bd9Sstevel@tonic-gate !pt->p_rtld_finished))) { 3817*7c478bd9Sstevel@tonic-gate warn("breakpoint %s activation failed", 3818*7c478bd9Sstevel@tonic-gate pta->pta_symbol); 3819*7c478bd9Sstevel@tonic-gate } 3820*7c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 3821*7c478bd9Sstevel@tonic-gate } 3822*7c478bd9Sstevel@tonic-gate 3823*7c478bd9Sstevel@tonic-gate pta->pta_addr = (uintptr_t)s.st_value; 3824*7c478bd9Sstevel@tonic-gate } 3825*7c478bd9Sstevel@tonic-gate 3826*7c478bd9Sstevel@tonic-gate #ifdef __sparc 3827*7c478bd9Sstevel@tonic-gate if (pta->pta_addr & 3) 3828*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_BPALIGN)); 3829*7c478bd9Sstevel@tonic-gate #endif 3830*7c478bd9Sstevel@tonic-gate 3831*7c478bd9Sstevel@tonic-gate if (Paddr_to_map(t->t_pshandle, pta->pta_addr) == NULL) 3832*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOMAP)); 3833*7c478bd9Sstevel@tonic-gate 3834*7c478bd9Sstevel@tonic-gate ptb = mdb_alloc(sizeof (pt_brkpt_t), UM_SLEEP); 3835*7c478bd9Sstevel@tonic-gate ptb->ptb_addr = pta->pta_addr; 3836*7c478bd9Sstevel@tonic-gate ptb->ptb_instr = NULL; 3837*7c478bd9Sstevel@tonic-gate sep->se_data = ptb; 3838*7c478bd9Sstevel@tonic-gate 3839*7c478bd9Sstevel@tonic-gate return (0); 3840*7c478bd9Sstevel@tonic-gate } 3841*7c478bd9Sstevel@tonic-gate 3842*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3843*7c478bd9Sstevel@tonic-gate static void 3844*7c478bd9Sstevel@tonic-gate pt_brkpt_dtor(mdb_tgt_t *t, mdb_sespec_t *sep) 3845*7c478bd9Sstevel@tonic-gate { 3846*7c478bd9Sstevel@tonic-gate mdb_free(sep->se_data, sizeof (pt_brkpt_t)); 3847*7c478bd9Sstevel@tonic-gate } 3848*7c478bd9Sstevel@tonic-gate 3849*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3850*7c478bd9Sstevel@tonic-gate static char * 3851*7c478bd9Sstevel@tonic-gate pt_brkpt_info(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_vespec_t *vep, 3852*7c478bd9Sstevel@tonic-gate mdb_tgt_spec_desc_t *sp, char *buf, size_t nbytes) 3853*7c478bd9Sstevel@tonic-gate { 3854*7c478bd9Sstevel@tonic-gate uintptr_t addr = NULL; 3855*7c478bd9Sstevel@tonic-gate 3856*7c478bd9Sstevel@tonic-gate if (vep != NULL) { 3857*7c478bd9Sstevel@tonic-gate pt_bparg_t *pta = vep->ve_args; 3858*7c478bd9Sstevel@tonic-gate 3859*7c478bd9Sstevel@tonic-gate if (pta->pta_symbol != NULL) { 3860*7c478bd9Sstevel@tonic-gate (void) mdb_iob_snprintf(buf, nbytes, "stop at %s", 3861*7c478bd9Sstevel@tonic-gate pta->pta_symbol); 3862*7c478bd9Sstevel@tonic-gate } else { 3863*7c478bd9Sstevel@tonic-gate (void) mdb_iob_snprintf(buf, nbytes, "stop at %a", 3864*7c478bd9Sstevel@tonic-gate pta->pta_addr); 3865*7c478bd9Sstevel@tonic-gate addr = pta->pta_addr; 3866*7c478bd9Sstevel@tonic-gate } 3867*7c478bd9Sstevel@tonic-gate 3868*7c478bd9Sstevel@tonic-gate } else { 3869*7c478bd9Sstevel@tonic-gate addr = ((pt_brkpt_t *)sep->se_data)->ptb_addr; 3870*7c478bd9Sstevel@tonic-gate (void) mdb_iob_snprintf(buf, nbytes, "stop at %a", addr); 3871*7c478bd9Sstevel@tonic-gate } 3872*7c478bd9Sstevel@tonic-gate 3873*7c478bd9Sstevel@tonic-gate sp->spec_base = addr; 3874*7c478bd9Sstevel@tonic-gate sp->spec_size = sizeof (instr_t); 3875*7c478bd9Sstevel@tonic-gate 3876*7c478bd9Sstevel@tonic-gate return (buf); 3877*7c478bd9Sstevel@tonic-gate } 3878*7c478bd9Sstevel@tonic-gate 3879*7c478bd9Sstevel@tonic-gate static int 3880*7c478bd9Sstevel@tonic-gate pt_brkpt_secmp(mdb_tgt_t *t, mdb_sespec_t *sep, void *args) 3881*7c478bd9Sstevel@tonic-gate { 3882*7c478bd9Sstevel@tonic-gate pt_brkpt_t *ptb = sep->se_data; 3883*7c478bd9Sstevel@tonic-gate pt_bparg_t *pta = args; 3884*7c478bd9Sstevel@tonic-gate GElf_Sym sym; 3885*7c478bd9Sstevel@tonic-gate 3886*7c478bd9Sstevel@tonic-gate if (pta->pta_symbol != NULL) { 3887*7c478bd9Sstevel@tonic-gate return (mdb_tgt_lookup_by_scope(t, pta->pta_symbol, 3888*7c478bd9Sstevel@tonic-gate &sym, NULL) == 0 && sym.st_value == ptb->ptb_addr); 3889*7c478bd9Sstevel@tonic-gate } 3890*7c478bd9Sstevel@tonic-gate 3891*7c478bd9Sstevel@tonic-gate return (pta->pta_addr == ptb->ptb_addr); 3892*7c478bd9Sstevel@tonic-gate } 3893*7c478bd9Sstevel@tonic-gate 3894*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3895*7c478bd9Sstevel@tonic-gate static int 3896*7c478bd9Sstevel@tonic-gate pt_brkpt_vecmp(mdb_tgt_t *t, mdb_vespec_t *vep, void *args) 3897*7c478bd9Sstevel@tonic-gate { 3898*7c478bd9Sstevel@tonic-gate pt_bparg_t *pta1 = vep->ve_args; 3899*7c478bd9Sstevel@tonic-gate pt_bparg_t *pta2 = args; 3900*7c478bd9Sstevel@tonic-gate 3901*7c478bd9Sstevel@tonic-gate if (pta1->pta_symbol != NULL && pta2->pta_symbol != NULL) 3902*7c478bd9Sstevel@tonic-gate return (strcmp(pta1->pta_symbol, pta2->pta_symbol) == 0); 3903*7c478bd9Sstevel@tonic-gate 3904*7c478bd9Sstevel@tonic-gate if (pta1->pta_symbol == NULL && pta2->pta_symbol == NULL) 3905*7c478bd9Sstevel@tonic-gate return (pta1->pta_addr == pta2->pta_addr); 3906*7c478bd9Sstevel@tonic-gate 3907*7c478bd9Sstevel@tonic-gate return (0); /* fail if one is symbolic, other is an explicit address */ 3908*7c478bd9Sstevel@tonic-gate } 3909*7c478bd9Sstevel@tonic-gate 3910*7c478bd9Sstevel@tonic-gate static int 3911*7c478bd9Sstevel@tonic-gate pt_brkpt_arm(mdb_tgt_t *t, mdb_sespec_t *sep) 3912*7c478bd9Sstevel@tonic-gate { 3913*7c478bd9Sstevel@tonic-gate pt_brkpt_t *ptb = sep->se_data; 3914*7c478bd9Sstevel@tonic-gate return (Psetbkpt(t->t_pshandle, ptb->ptb_addr, &ptb->ptb_instr)); 3915*7c478bd9Sstevel@tonic-gate } 3916*7c478bd9Sstevel@tonic-gate 3917*7c478bd9Sstevel@tonic-gate /* 3918*7c478bd9Sstevel@tonic-gate * In order to disarm a breakpoint, we replace the trap instruction at ptb_addr 3919*7c478bd9Sstevel@tonic-gate * with the saved instruction. However, if we have stopped after a successful 3920*7c478bd9Sstevel@tonic-gate * exec(2), we do not want to restore ptb_instr because the address space has 3921*7c478bd9Sstevel@tonic-gate * now been replaced with the text of a different executable, and so restoring 3922*7c478bd9Sstevel@tonic-gate * the saved instruction would be incorrect. The exec itself has effectively 3923*7c478bd9Sstevel@tonic-gate * removed all breakpoint trap instructions for us, so we can just return. 3924*7c478bd9Sstevel@tonic-gate */ 3925*7c478bd9Sstevel@tonic-gate static int 3926*7c478bd9Sstevel@tonic-gate pt_brkpt_disarm(mdb_tgt_t *t, mdb_sespec_t *sep) 3927*7c478bd9Sstevel@tonic-gate { 3928*7c478bd9Sstevel@tonic-gate const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp; 3929*7c478bd9Sstevel@tonic-gate pt_brkpt_t *ptb = sep->se_data; 3930*7c478bd9Sstevel@tonic-gate 3931*7c478bd9Sstevel@tonic-gate if ((psp->pr_why == PR_SYSEXIT && psp->pr_errno == 0) && 3932*7c478bd9Sstevel@tonic-gate (psp->pr_what == SYS_exec || psp->pr_what == SYS_execve)) 3933*7c478bd9Sstevel@tonic-gate return (0); /* do not restore saved instruction */ 3934*7c478bd9Sstevel@tonic-gate 3935*7c478bd9Sstevel@tonic-gate return (Pdelbkpt(t->t_pshandle, ptb->ptb_addr, ptb->ptb_instr)); 3936*7c478bd9Sstevel@tonic-gate } 3937*7c478bd9Sstevel@tonic-gate 3938*7c478bd9Sstevel@tonic-gate /* 3939*7c478bd9Sstevel@tonic-gate * Determine whether the specified sespec is an armed watchpoint that overlaps 3940*7c478bd9Sstevel@tonic-gate * with the given breakpoint and has the given flags set. We use this to find 3941*7c478bd9Sstevel@tonic-gate * conflicts with breakpoints, below. 3942*7c478bd9Sstevel@tonic-gate */ 3943*7c478bd9Sstevel@tonic-gate static int 3944*7c478bd9Sstevel@tonic-gate pt_wp_overlap(mdb_sespec_t *sep, pt_brkpt_t *ptb, int flags) 3945*7c478bd9Sstevel@tonic-gate { 3946*7c478bd9Sstevel@tonic-gate const prwatch_t *wp = sep->se_data; 3947*7c478bd9Sstevel@tonic-gate 3948*7c478bd9Sstevel@tonic-gate return (sep->se_state == MDB_TGT_SPEC_ARMED && 3949*7c478bd9Sstevel@tonic-gate sep->se_ops == &proc_wapt_ops && (wp->pr_wflags & flags) && 3950*7c478bd9Sstevel@tonic-gate ptb->ptb_addr - wp->pr_vaddr < wp->pr_size); 3951*7c478bd9Sstevel@tonic-gate } 3952*7c478bd9Sstevel@tonic-gate 3953*7c478bd9Sstevel@tonic-gate /* 3954*7c478bd9Sstevel@tonic-gate * We step over breakpoints using Pxecbkpt() in libproc. If a conflicting 3955*7c478bd9Sstevel@tonic-gate * watchpoint is present, we must temporarily remove it before stepping over 3956*7c478bd9Sstevel@tonic-gate * the breakpoint so we do not immediately re-trigger the watchpoint. We know 3957*7c478bd9Sstevel@tonic-gate * the watchpoint has already triggered on our trap instruction as part of 3958*7c478bd9Sstevel@tonic-gate * fetching it. Before we return, we must re-install any disabled watchpoints. 3959*7c478bd9Sstevel@tonic-gate */ 3960*7c478bd9Sstevel@tonic-gate static int 3961*7c478bd9Sstevel@tonic-gate pt_brkpt_cont(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_tgt_status_t *tsp) 3962*7c478bd9Sstevel@tonic-gate { 3963*7c478bd9Sstevel@tonic-gate pt_brkpt_t *ptb = sep->se_data; 3964*7c478bd9Sstevel@tonic-gate int status = -1; 3965*7c478bd9Sstevel@tonic-gate int error; 3966*7c478bd9Sstevel@tonic-gate const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp; 3967*7c478bd9Sstevel@tonic-gate 3968*7c478bd9Sstevel@tonic-gate /* 3969*7c478bd9Sstevel@tonic-gate * If the PC no longer matches our original address, then the user has 3970*7c478bd9Sstevel@tonic-gate * changed it while we have been stopped. In this case, it no longer 3971*7c478bd9Sstevel@tonic-gate * makes any sense to continue over this breakpoint. We return as if we 3972*7c478bd9Sstevel@tonic-gate * continued normally. 3973*7c478bd9Sstevel@tonic-gate */ 3974*7c478bd9Sstevel@tonic-gate if ((uintptr_t)psp->pr_info.si_addr != psp->pr_reg[R_PC]) 3975*7c478bd9Sstevel@tonic-gate return (pt_status(t, tsp)); 3976*7c478bd9Sstevel@tonic-gate 3977*7c478bd9Sstevel@tonic-gate for (sep = mdb_list_next(&t->t_active); sep; sep = mdb_list_next(sep)) { 3978*7c478bd9Sstevel@tonic-gate if (pt_wp_overlap(sep, ptb, WA_EXEC)) 3979*7c478bd9Sstevel@tonic-gate (void) Pdelwapt(t->t_pshandle, sep->se_data); 3980*7c478bd9Sstevel@tonic-gate } 3981*7c478bd9Sstevel@tonic-gate 3982*7c478bd9Sstevel@tonic-gate if (Pxecbkpt(t->t_pshandle, ptb->ptb_instr) == 0 && 3983*7c478bd9Sstevel@tonic-gate Pdelbkpt(t->t_pshandle, ptb->ptb_addr, ptb->ptb_instr) == 0) 3984*7c478bd9Sstevel@tonic-gate status = pt_status(t, tsp); 3985*7c478bd9Sstevel@tonic-gate 3986*7c478bd9Sstevel@tonic-gate error = errno; /* save errno from Pxecbkpt, Pdelbkpt, or pt_status */ 3987*7c478bd9Sstevel@tonic-gate 3988*7c478bd9Sstevel@tonic-gate for (sep = mdb_list_next(&t->t_active); sep; sep = mdb_list_next(sep)) { 3989*7c478bd9Sstevel@tonic-gate if (pt_wp_overlap(sep, ptb, WA_EXEC) && 3990*7c478bd9Sstevel@tonic-gate Psetwapt(t->t_pshandle, sep->se_data) == -1) { 3991*7c478bd9Sstevel@tonic-gate sep->se_state = MDB_TGT_SPEC_ERROR; 3992*7c478bd9Sstevel@tonic-gate sep->se_errno = errno; 3993*7c478bd9Sstevel@tonic-gate } 3994*7c478bd9Sstevel@tonic-gate } 3995*7c478bd9Sstevel@tonic-gate 3996*7c478bd9Sstevel@tonic-gate (void) set_errno(error); 3997*7c478bd9Sstevel@tonic-gate return (status); 3998*7c478bd9Sstevel@tonic-gate } 3999*7c478bd9Sstevel@tonic-gate 4000*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4001*7c478bd9Sstevel@tonic-gate static int 4002*7c478bd9Sstevel@tonic-gate pt_brkpt_match(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_tgt_status_t *tsp) 4003*7c478bd9Sstevel@tonic-gate { 4004*7c478bd9Sstevel@tonic-gate const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp; 4005*7c478bd9Sstevel@tonic-gate pt_brkpt_t *ptb = sep->se_data; 4006*7c478bd9Sstevel@tonic-gate 4007*7c478bd9Sstevel@tonic-gate return (psp->pr_why == PR_FAULTED && psp->pr_what == FLTBPT && 4008*7c478bd9Sstevel@tonic-gate psp->pr_reg[R_PC] == ptb->ptb_addr); 4009*7c478bd9Sstevel@tonic-gate } 4010*7c478bd9Sstevel@tonic-gate 4011*7c478bd9Sstevel@tonic-gate static const mdb_se_ops_t proc_brkpt_ops = { 4012*7c478bd9Sstevel@tonic-gate pt_brkpt_ctor, /* se_ctor */ 4013*7c478bd9Sstevel@tonic-gate pt_brkpt_dtor, /* se_dtor */ 4014*7c478bd9Sstevel@tonic-gate pt_brkpt_info, /* se_info */ 4015*7c478bd9Sstevel@tonic-gate pt_brkpt_secmp, /* se_secmp */ 4016*7c478bd9Sstevel@tonic-gate pt_brkpt_vecmp, /* se_vecmp */ 4017*7c478bd9Sstevel@tonic-gate pt_brkpt_arm, /* se_arm */ 4018*7c478bd9Sstevel@tonic-gate pt_brkpt_disarm, /* se_disarm */ 4019*7c478bd9Sstevel@tonic-gate pt_brkpt_cont, /* se_cont */ 4020*7c478bd9Sstevel@tonic-gate pt_brkpt_match /* se_match */ 4021*7c478bd9Sstevel@tonic-gate }; 4022*7c478bd9Sstevel@tonic-gate 4023*7c478bd9Sstevel@tonic-gate static int 4024*7c478bd9Sstevel@tonic-gate pt_wapt_ctor(mdb_tgt_t *t, mdb_sespec_t *sep, void *args) 4025*7c478bd9Sstevel@tonic-gate { 4026*7c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL || Pstate(t->t_pshandle) >= PS_LOST) 4027*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 4028*7c478bd9Sstevel@tonic-gate 4029*7c478bd9Sstevel@tonic-gate sep->se_data = mdb_alloc(sizeof (prwatch_t), UM_SLEEP); 4030*7c478bd9Sstevel@tonic-gate bcopy(args, sep->se_data, sizeof (prwatch_t)); 4031*7c478bd9Sstevel@tonic-gate return (0); 4032*7c478bd9Sstevel@tonic-gate } 4033*7c478bd9Sstevel@tonic-gate 4034*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4035*7c478bd9Sstevel@tonic-gate static void 4036*7c478bd9Sstevel@tonic-gate pt_wapt_dtor(mdb_tgt_t *t, mdb_sespec_t *sep) 4037*7c478bd9Sstevel@tonic-gate { 4038*7c478bd9Sstevel@tonic-gate mdb_free(sep->se_data, sizeof (prwatch_t)); 4039*7c478bd9Sstevel@tonic-gate } 4040*7c478bd9Sstevel@tonic-gate 4041*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4042*7c478bd9Sstevel@tonic-gate static char * 4043*7c478bd9Sstevel@tonic-gate pt_wapt_info(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_vespec_t *vep, 4044*7c478bd9Sstevel@tonic-gate mdb_tgt_spec_desc_t *sp, char *buf, size_t nbytes) 4045*7c478bd9Sstevel@tonic-gate { 4046*7c478bd9Sstevel@tonic-gate prwatch_t *wp = vep != NULL ? vep->ve_args : sep->se_data; 4047*7c478bd9Sstevel@tonic-gate char desc[24]; 4048*7c478bd9Sstevel@tonic-gate 4049*7c478bd9Sstevel@tonic-gate ASSERT(wp->pr_wflags != 0); 4050*7c478bd9Sstevel@tonic-gate desc[0] = '\0'; 4051*7c478bd9Sstevel@tonic-gate 4052*7c478bd9Sstevel@tonic-gate switch (wp->pr_wflags) { 4053*7c478bd9Sstevel@tonic-gate case WA_READ: 4054*7c478bd9Sstevel@tonic-gate (void) strcat(desc, "/read"); 4055*7c478bd9Sstevel@tonic-gate break; 4056*7c478bd9Sstevel@tonic-gate case WA_WRITE: 4057*7c478bd9Sstevel@tonic-gate (void) strcat(desc, "/write"); 4058*7c478bd9Sstevel@tonic-gate break; 4059*7c478bd9Sstevel@tonic-gate case WA_EXEC: 4060*7c478bd9Sstevel@tonic-gate (void) strcat(desc, "/exec"); 4061*7c478bd9Sstevel@tonic-gate break; 4062*7c478bd9Sstevel@tonic-gate default: 4063*7c478bd9Sstevel@tonic-gate if (wp->pr_wflags & WA_READ) 4064*7c478bd9Sstevel@tonic-gate (void) strcat(desc, "/r"); 4065*7c478bd9Sstevel@tonic-gate if (wp->pr_wflags & WA_WRITE) 4066*7c478bd9Sstevel@tonic-gate (void) strcat(desc, "/w"); 4067*7c478bd9Sstevel@tonic-gate if (wp->pr_wflags & WA_EXEC) 4068*7c478bd9Sstevel@tonic-gate (void) strcat(desc, "/x"); 4069*7c478bd9Sstevel@tonic-gate } 4070*7c478bd9Sstevel@tonic-gate 4071*7c478bd9Sstevel@tonic-gate (void) mdb_iob_snprintf(buf, nbytes, "stop on %s of [%la, %la)", 4072*7c478bd9Sstevel@tonic-gate desc + 1, wp->pr_vaddr, wp->pr_vaddr + wp->pr_size); 4073*7c478bd9Sstevel@tonic-gate 4074*7c478bd9Sstevel@tonic-gate sp->spec_base = wp->pr_vaddr; 4075*7c478bd9Sstevel@tonic-gate sp->spec_size = wp->pr_size; 4076*7c478bd9Sstevel@tonic-gate 4077*7c478bd9Sstevel@tonic-gate return (buf); 4078*7c478bd9Sstevel@tonic-gate } 4079*7c478bd9Sstevel@tonic-gate 4080*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4081*7c478bd9Sstevel@tonic-gate static int 4082*7c478bd9Sstevel@tonic-gate pt_wapt_secmp(mdb_tgt_t *t, mdb_sespec_t *sep, void *args) 4083*7c478bd9Sstevel@tonic-gate { 4084*7c478bd9Sstevel@tonic-gate prwatch_t *wp1 = sep->se_data; 4085*7c478bd9Sstevel@tonic-gate prwatch_t *wp2 = args; 4086*7c478bd9Sstevel@tonic-gate 4087*7c478bd9Sstevel@tonic-gate return (wp1->pr_vaddr == wp2->pr_vaddr && 4088*7c478bd9Sstevel@tonic-gate wp1->pr_size == wp2->pr_size && wp1->pr_wflags == wp2->pr_wflags); 4089*7c478bd9Sstevel@tonic-gate } 4090*7c478bd9Sstevel@tonic-gate 4091*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4092*7c478bd9Sstevel@tonic-gate static int 4093*7c478bd9Sstevel@tonic-gate pt_wapt_vecmp(mdb_tgt_t *t, mdb_vespec_t *vep, void *args) 4094*7c478bd9Sstevel@tonic-gate { 4095*7c478bd9Sstevel@tonic-gate prwatch_t *wp1 = vep->ve_args; 4096*7c478bd9Sstevel@tonic-gate prwatch_t *wp2 = args; 4097*7c478bd9Sstevel@tonic-gate 4098*7c478bd9Sstevel@tonic-gate return (wp1->pr_vaddr == wp2->pr_vaddr && 4099*7c478bd9Sstevel@tonic-gate wp1->pr_size == wp2->pr_size && wp1->pr_wflags == wp2->pr_wflags); 4100*7c478bd9Sstevel@tonic-gate } 4101*7c478bd9Sstevel@tonic-gate 4102*7c478bd9Sstevel@tonic-gate static int 4103*7c478bd9Sstevel@tonic-gate pt_wapt_arm(mdb_tgt_t *t, mdb_sespec_t *sep) 4104*7c478bd9Sstevel@tonic-gate { 4105*7c478bd9Sstevel@tonic-gate return (Psetwapt(t->t_pshandle, sep->se_data)); 4106*7c478bd9Sstevel@tonic-gate } 4107*7c478bd9Sstevel@tonic-gate 4108*7c478bd9Sstevel@tonic-gate static int 4109*7c478bd9Sstevel@tonic-gate pt_wapt_disarm(mdb_tgt_t *t, mdb_sespec_t *sep) 4110*7c478bd9Sstevel@tonic-gate { 4111*7c478bd9Sstevel@tonic-gate return (Pdelwapt(t->t_pshandle, sep->se_data)); 4112*7c478bd9Sstevel@tonic-gate } 4113*7c478bd9Sstevel@tonic-gate 4114*7c478bd9Sstevel@tonic-gate /* 4115*7c478bd9Sstevel@tonic-gate * Determine whether the specified sespec is an armed breakpoint at the 4116*7c478bd9Sstevel@tonic-gate * given %pc. We use this to find conflicts with watchpoints below. 4117*7c478bd9Sstevel@tonic-gate */ 4118*7c478bd9Sstevel@tonic-gate static int 4119*7c478bd9Sstevel@tonic-gate pt_bp_overlap(mdb_sespec_t *sep, uintptr_t pc) 4120*7c478bd9Sstevel@tonic-gate { 4121*7c478bd9Sstevel@tonic-gate pt_brkpt_t *ptb = sep->se_data; 4122*7c478bd9Sstevel@tonic-gate 4123*7c478bd9Sstevel@tonic-gate return (sep->se_state == MDB_TGT_SPEC_ARMED && 4124*7c478bd9Sstevel@tonic-gate sep->se_ops == &proc_brkpt_ops && ptb->ptb_addr == pc); 4125*7c478bd9Sstevel@tonic-gate } 4126*7c478bd9Sstevel@tonic-gate 4127*7c478bd9Sstevel@tonic-gate /* 4128*7c478bd9Sstevel@tonic-gate * We step over watchpoints using Pxecwapt() in libproc. If a conflicting 4129*7c478bd9Sstevel@tonic-gate * breakpoint is present, we must temporarily disarm it before stepping 4130*7c478bd9Sstevel@tonic-gate * over the watchpoint so we do not immediately re-trigger the breakpoint. 4131*7c478bd9Sstevel@tonic-gate * This is similar to the case handled in pt_brkpt_cont(), above. 4132*7c478bd9Sstevel@tonic-gate */ 4133*7c478bd9Sstevel@tonic-gate static int 4134*7c478bd9Sstevel@tonic-gate pt_wapt_cont(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_tgt_status_t *tsp) 4135*7c478bd9Sstevel@tonic-gate { 4136*7c478bd9Sstevel@tonic-gate const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp; 4137*7c478bd9Sstevel@tonic-gate mdb_sespec_t *bep = NULL; 4138*7c478bd9Sstevel@tonic-gate int status = -1; 4139*7c478bd9Sstevel@tonic-gate int error; 4140*7c478bd9Sstevel@tonic-gate 4141*7c478bd9Sstevel@tonic-gate /* 4142*7c478bd9Sstevel@tonic-gate * If the PC no longer matches our original address, then the user has 4143*7c478bd9Sstevel@tonic-gate * changed it while we have been stopped. In this case, it no longer 4144*7c478bd9Sstevel@tonic-gate * makes any sense to continue over this instruction. We return as if 4145*7c478bd9Sstevel@tonic-gate * we continued normally. 4146*7c478bd9Sstevel@tonic-gate */ 4147*7c478bd9Sstevel@tonic-gate if ((uintptr_t)psp->pr_info.si_pc != psp->pr_reg[R_PC]) 4148*7c478bd9Sstevel@tonic-gate return (pt_status(t, tsp)); 4149*7c478bd9Sstevel@tonic-gate 4150*7c478bd9Sstevel@tonic-gate if (psp->pr_info.si_code != TRAP_XWATCH) { 4151*7c478bd9Sstevel@tonic-gate for (bep = mdb_list_next(&t->t_active); bep != NULL; 4152*7c478bd9Sstevel@tonic-gate bep = mdb_list_next(bep)) { 4153*7c478bd9Sstevel@tonic-gate if (pt_bp_overlap(bep, psp->pr_reg[R_PC])) { 4154*7c478bd9Sstevel@tonic-gate (void) bep->se_ops->se_disarm(t, bep); 4155*7c478bd9Sstevel@tonic-gate bep->se_state = MDB_TGT_SPEC_ACTIVE; 4156*7c478bd9Sstevel@tonic-gate break; 4157*7c478bd9Sstevel@tonic-gate } 4158*7c478bd9Sstevel@tonic-gate } 4159*7c478bd9Sstevel@tonic-gate } 4160*7c478bd9Sstevel@tonic-gate 4161*7c478bd9Sstevel@tonic-gate if (Pxecwapt(t->t_pshandle, sep->se_data) == 0) 4162*7c478bd9Sstevel@tonic-gate status = pt_status(t, tsp); 4163*7c478bd9Sstevel@tonic-gate 4164*7c478bd9Sstevel@tonic-gate error = errno; /* save errno from Pxecwapt or pt_status */ 4165*7c478bd9Sstevel@tonic-gate 4166*7c478bd9Sstevel@tonic-gate if (bep != NULL) 4167*7c478bd9Sstevel@tonic-gate mdb_tgt_sespec_arm_one(t, bep); 4168*7c478bd9Sstevel@tonic-gate 4169*7c478bd9Sstevel@tonic-gate (void) set_errno(error); 4170*7c478bd9Sstevel@tonic-gate return (status); 4171*7c478bd9Sstevel@tonic-gate } 4172*7c478bd9Sstevel@tonic-gate 4173*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4174*7c478bd9Sstevel@tonic-gate static int 4175*7c478bd9Sstevel@tonic-gate pt_wapt_match(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_tgt_status_t *tsp) 4176*7c478bd9Sstevel@tonic-gate { 4177*7c478bd9Sstevel@tonic-gate const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp; 4178*7c478bd9Sstevel@tonic-gate prwatch_t *wp = sep->se_data; 4179*7c478bd9Sstevel@tonic-gate 4180*7c478bd9Sstevel@tonic-gate return (psp->pr_why == PR_FAULTED && psp->pr_what == FLTWATCH && 4181*7c478bd9Sstevel@tonic-gate (uintptr_t)psp->pr_info.si_addr - wp->pr_vaddr < wp->pr_size); 4182*7c478bd9Sstevel@tonic-gate } 4183*7c478bd9Sstevel@tonic-gate 4184*7c478bd9Sstevel@tonic-gate static const mdb_se_ops_t proc_wapt_ops = { 4185*7c478bd9Sstevel@tonic-gate pt_wapt_ctor, /* se_ctor */ 4186*7c478bd9Sstevel@tonic-gate pt_wapt_dtor, /* se_dtor */ 4187*7c478bd9Sstevel@tonic-gate pt_wapt_info, /* se_info */ 4188*7c478bd9Sstevel@tonic-gate pt_wapt_secmp, /* se_secmp */ 4189*7c478bd9Sstevel@tonic-gate pt_wapt_vecmp, /* se_vecmp */ 4190*7c478bd9Sstevel@tonic-gate pt_wapt_arm, /* se_arm */ 4191*7c478bd9Sstevel@tonic-gate pt_wapt_disarm, /* se_disarm */ 4192*7c478bd9Sstevel@tonic-gate pt_wapt_cont, /* se_cont */ 4193*7c478bd9Sstevel@tonic-gate pt_wapt_match /* se_match */ 4194*7c478bd9Sstevel@tonic-gate }; 4195*7c478bd9Sstevel@tonic-gate 4196*7c478bd9Sstevel@tonic-gate static void 4197*7c478bd9Sstevel@tonic-gate pt_bparg_dtor(mdb_vespec_t *vep) 4198*7c478bd9Sstevel@tonic-gate { 4199*7c478bd9Sstevel@tonic-gate pt_bparg_t *pta = vep->ve_args; 4200*7c478bd9Sstevel@tonic-gate 4201*7c478bd9Sstevel@tonic-gate if (pta->pta_symbol != NULL) 4202*7c478bd9Sstevel@tonic-gate strfree(pta->pta_symbol); 4203*7c478bd9Sstevel@tonic-gate 4204*7c478bd9Sstevel@tonic-gate mdb_free(pta, sizeof (pt_bparg_t)); 4205*7c478bd9Sstevel@tonic-gate } 4206*7c478bd9Sstevel@tonic-gate 4207*7c478bd9Sstevel@tonic-gate static int 4208*7c478bd9Sstevel@tonic-gate pt_add_vbrkpt(mdb_tgt_t *t, uintptr_t addr, 4209*7c478bd9Sstevel@tonic-gate int spec_flags, mdb_tgt_se_f *func, void *data) 4210*7c478bd9Sstevel@tonic-gate { 4211*7c478bd9Sstevel@tonic-gate pt_bparg_t *pta = mdb_alloc(sizeof (pt_bparg_t), UM_SLEEP); 4212*7c478bd9Sstevel@tonic-gate 4213*7c478bd9Sstevel@tonic-gate pta->pta_symbol = NULL; 4214*7c478bd9Sstevel@tonic-gate pta->pta_addr = addr; 4215*7c478bd9Sstevel@tonic-gate 4216*7c478bd9Sstevel@tonic-gate return (mdb_tgt_vespec_insert(t, &proc_brkpt_ops, spec_flags, 4217*7c478bd9Sstevel@tonic-gate func, data, pta, pt_bparg_dtor)); 4218*7c478bd9Sstevel@tonic-gate } 4219*7c478bd9Sstevel@tonic-gate 4220*7c478bd9Sstevel@tonic-gate static int 4221*7c478bd9Sstevel@tonic-gate pt_add_sbrkpt(mdb_tgt_t *t, const char *sym, 4222*7c478bd9Sstevel@tonic-gate int spec_flags, mdb_tgt_se_f *func, void *data) 4223*7c478bd9Sstevel@tonic-gate { 4224*7c478bd9Sstevel@tonic-gate pt_bparg_t *pta; 4225*7c478bd9Sstevel@tonic-gate 4226*7c478bd9Sstevel@tonic-gate if (sym[0] == '`') { 4227*7c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_NOOBJ); 4228*7c478bd9Sstevel@tonic-gate return (0); 4229*7c478bd9Sstevel@tonic-gate } 4230*7c478bd9Sstevel@tonic-gate 4231*7c478bd9Sstevel@tonic-gate if (sym[strlen(sym) - 1] == '`') { 4232*7c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_NOSYM); 4233*7c478bd9Sstevel@tonic-gate return (0); 4234*7c478bd9Sstevel@tonic-gate } 4235*7c478bd9Sstevel@tonic-gate 4236*7c478bd9Sstevel@tonic-gate pta = mdb_alloc(sizeof (pt_bparg_t), UM_SLEEP); 4237*7c478bd9Sstevel@tonic-gate pta->pta_symbol = strdup(sym); 4238*7c478bd9Sstevel@tonic-gate pta->pta_addr = NULL; 4239*7c478bd9Sstevel@tonic-gate 4240*7c478bd9Sstevel@tonic-gate return (mdb_tgt_vespec_insert(t, &proc_brkpt_ops, spec_flags, 4241*7c478bd9Sstevel@tonic-gate func, data, pta, pt_bparg_dtor)); 4242*7c478bd9Sstevel@tonic-gate } 4243*7c478bd9Sstevel@tonic-gate 4244*7c478bd9Sstevel@tonic-gate static int 4245*7c478bd9Sstevel@tonic-gate pt_wparg_overlap(const prwatch_t *wp1, const prwatch_t *wp2) 4246*7c478bd9Sstevel@tonic-gate { 4247*7c478bd9Sstevel@tonic-gate if (wp2->pr_vaddr + wp2->pr_size <= wp1->pr_vaddr) 4248*7c478bd9Sstevel@tonic-gate return (0); /* no range overlap */ 4249*7c478bd9Sstevel@tonic-gate 4250*7c478bd9Sstevel@tonic-gate if (wp1->pr_vaddr + wp1->pr_size <= wp2->pr_vaddr) 4251*7c478bd9Sstevel@tonic-gate return (0); /* no range overlap */ 4252*7c478bd9Sstevel@tonic-gate 4253*7c478bd9Sstevel@tonic-gate return (wp1->pr_vaddr != wp2->pr_vaddr || 4254*7c478bd9Sstevel@tonic-gate wp1->pr_size != wp2->pr_size || wp1->pr_wflags != wp2->pr_wflags); 4255*7c478bd9Sstevel@tonic-gate } 4256*7c478bd9Sstevel@tonic-gate 4257*7c478bd9Sstevel@tonic-gate static void 4258*7c478bd9Sstevel@tonic-gate pt_wparg_dtor(mdb_vespec_t *vep) 4259*7c478bd9Sstevel@tonic-gate { 4260*7c478bd9Sstevel@tonic-gate mdb_free(vep->ve_args, sizeof (prwatch_t)); 4261*7c478bd9Sstevel@tonic-gate } 4262*7c478bd9Sstevel@tonic-gate 4263*7c478bd9Sstevel@tonic-gate static int 4264*7c478bd9Sstevel@tonic-gate pt_add_vwapt(mdb_tgt_t *t, uintptr_t addr, size_t len, uint_t wflags, 4265*7c478bd9Sstevel@tonic-gate int spec_flags, mdb_tgt_se_f *func, void *data) 4266*7c478bd9Sstevel@tonic-gate { 4267*7c478bd9Sstevel@tonic-gate prwatch_t *wp = mdb_alloc(sizeof (prwatch_t), UM_SLEEP); 4268*7c478bd9Sstevel@tonic-gate mdb_sespec_t *sep; 4269*7c478bd9Sstevel@tonic-gate 4270*7c478bd9Sstevel@tonic-gate wp->pr_vaddr = addr; 4271*7c478bd9Sstevel@tonic-gate wp->pr_size = len; 4272*7c478bd9Sstevel@tonic-gate wp->pr_wflags = 0; 4273*7c478bd9Sstevel@tonic-gate 4274*7c478bd9Sstevel@tonic-gate if (wflags & MDB_TGT_WA_R) 4275*7c478bd9Sstevel@tonic-gate wp->pr_wflags |= WA_READ; 4276*7c478bd9Sstevel@tonic-gate if (wflags & MDB_TGT_WA_W) 4277*7c478bd9Sstevel@tonic-gate wp->pr_wflags |= WA_WRITE; 4278*7c478bd9Sstevel@tonic-gate if (wflags & MDB_TGT_WA_X) 4279*7c478bd9Sstevel@tonic-gate wp->pr_wflags |= WA_EXEC; 4280*7c478bd9Sstevel@tonic-gate 4281*7c478bd9Sstevel@tonic-gate for (sep = mdb_list_next(&t->t_active); sep; sep = mdb_list_next(sep)) { 4282*7c478bd9Sstevel@tonic-gate if (sep->se_ops == &proc_wapt_ops && 4283*7c478bd9Sstevel@tonic-gate mdb_list_next(&sep->se_velist) != NULL && 4284*7c478bd9Sstevel@tonic-gate pt_wparg_overlap(wp, sep->se_data)) 4285*7c478bd9Sstevel@tonic-gate goto dup; 4286*7c478bd9Sstevel@tonic-gate } 4287*7c478bd9Sstevel@tonic-gate 4288*7c478bd9Sstevel@tonic-gate for (sep = mdb_list_next(&t->t_idle); sep; sep = mdb_list_next(sep)) { 4289*7c478bd9Sstevel@tonic-gate if (sep->se_ops == &proc_wapt_ops && pt_wparg_overlap(wp, 4290*7c478bd9Sstevel@tonic-gate ((mdb_vespec_t *)mdb_list_next(&sep->se_velist))->ve_args)) 4291*7c478bd9Sstevel@tonic-gate goto dup; 4292*7c478bd9Sstevel@tonic-gate } 4293*7c478bd9Sstevel@tonic-gate 4294*7c478bd9Sstevel@tonic-gate return (mdb_tgt_vespec_insert(t, &proc_wapt_ops, spec_flags, 4295*7c478bd9Sstevel@tonic-gate func, data, wp, pt_wparg_dtor)); 4296*7c478bd9Sstevel@tonic-gate 4297*7c478bd9Sstevel@tonic-gate dup: 4298*7c478bd9Sstevel@tonic-gate mdb_free(wp, sizeof (prwatch_t)); 4299*7c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_WPDUP); 4300*7c478bd9Sstevel@tonic-gate return (0); 4301*7c478bd9Sstevel@tonic-gate } 4302*7c478bd9Sstevel@tonic-gate 4303*7c478bd9Sstevel@tonic-gate static int 4304*7c478bd9Sstevel@tonic-gate pt_add_sysenter(mdb_tgt_t *t, int sysnum, 4305*7c478bd9Sstevel@tonic-gate int spec_flags, mdb_tgt_se_f *func, void *data) 4306*7c478bd9Sstevel@tonic-gate { 4307*7c478bd9Sstevel@tonic-gate if (sysnum <= 0 || sysnum > PRMAXSYS) { 4308*7c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_BADSYSNUM); 4309*7c478bd9Sstevel@tonic-gate return (0); 4310*7c478bd9Sstevel@tonic-gate } 4311*7c478bd9Sstevel@tonic-gate 4312*7c478bd9Sstevel@tonic-gate return (mdb_tgt_vespec_insert(t, &proc_sysenter_ops, spec_flags, 4313*7c478bd9Sstevel@tonic-gate func, data, (void *)(uintptr_t)sysnum, no_ve_dtor)); 4314*7c478bd9Sstevel@tonic-gate } 4315*7c478bd9Sstevel@tonic-gate 4316*7c478bd9Sstevel@tonic-gate static int 4317*7c478bd9Sstevel@tonic-gate pt_add_sysexit(mdb_tgt_t *t, int sysnum, 4318*7c478bd9Sstevel@tonic-gate int spec_flags, mdb_tgt_se_f *func, void *data) 4319*7c478bd9Sstevel@tonic-gate { 4320*7c478bd9Sstevel@tonic-gate if (sysnum <= 0 || sysnum > PRMAXSYS) { 4321*7c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_BADSYSNUM); 4322*7c478bd9Sstevel@tonic-gate return (0); 4323*7c478bd9Sstevel@tonic-gate } 4324*7c478bd9Sstevel@tonic-gate 4325*7c478bd9Sstevel@tonic-gate return (mdb_tgt_vespec_insert(t, &proc_sysexit_ops, spec_flags, 4326*7c478bd9Sstevel@tonic-gate func, data, (void *)(uintptr_t)sysnum, no_ve_dtor)); 4327*7c478bd9Sstevel@tonic-gate } 4328*7c478bd9Sstevel@tonic-gate 4329*7c478bd9Sstevel@tonic-gate static int 4330*7c478bd9Sstevel@tonic-gate pt_add_signal(mdb_tgt_t *t, int signum, 4331*7c478bd9Sstevel@tonic-gate int spec_flags, mdb_tgt_se_f *func, void *data) 4332*7c478bd9Sstevel@tonic-gate { 4333*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 4334*7c478bd9Sstevel@tonic-gate 4335*7c478bd9Sstevel@tonic-gate if (signum <= 0 || signum > pt->p_maxsig) { 4336*7c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_BADSIGNUM); 4337*7c478bd9Sstevel@tonic-gate return (0); 4338*7c478bd9Sstevel@tonic-gate } 4339*7c478bd9Sstevel@tonic-gate 4340*7c478bd9Sstevel@tonic-gate return (mdb_tgt_vespec_insert(t, &proc_signal_ops, spec_flags, 4341*7c478bd9Sstevel@tonic-gate func, data, (void *)(uintptr_t)signum, no_ve_dtor)); 4342*7c478bd9Sstevel@tonic-gate } 4343*7c478bd9Sstevel@tonic-gate 4344*7c478bd9Sstevel@tonic-gate static int 4345*7c478bd9Sstevel@tonic-gate pt_add_fault(mdb_tgt_t *t, int fltnum, 4346*7c478bd9Sstevel@tonic-gate int spec_flags, mdb_tgt_se_f *func, void *data) 4347*7c478bd9Sstevel@tonic-gate { 4348*7c478bd9Sstevel@tonic-gate if (fltnum <= 0 || fltnum > PRMAXFAULT) { 4349*7c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_BADFLTNUM); 4350*7c478bd9Sstevel@tonic-gate return (0); 4351*7c478bd9Sstevel@tonic-gate } 4352*7c478bd9Sstevel@tonic-gate 4353*7c478bd9Sstevel@tonic-gate return (mdb_tgt_vespec_insert(t, &proc_fault_ops, spec_flags, 4354*7c478bd9Sstevel@tonic-gate func, data, (void *)(uintptr_t)fltnum, no_ve_dtor)); 4355*7c478bd9Sstevel@tonic-gate } 4356*7c478bd9Sstevel@tonic-gate 4357*7c478bd9Sstevel@tonic-gate static int 4358*7c478bd9Sstevel@tonic-gate pt_getareg(mdb_tgt_t *t, mdb_tgt_tid_t tid, 4359*7c478bd9Sstevel@tonic-gate const char *rname, mdb_tgt_reg_t *rp) 4360*7c478bd9Sstevel@tonic-gate { 4361*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 4362*7c478bd9Sstevel@tonic-gate prgregset_t grs; 4363*7c478bd9Sstevel@tonic-gate mdb_var_t *v; 4364*7c478bd9Sstevel@tonic-gate 4365*7c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) 4366*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 4367*7c478bd9Sstevel@tonic-gate 4368*7c478bd9Sstevel@tonic-gate if ((v = mdb_nv_lookup(&pt->p_regs, rname)) != NULL) { 4369*7c478bd9Sstevel@tonic-gate uintmax_t rd_nval = mdb_nv_get_value(v); 4370*7c478bd9Sstevel@tonic-gate ushort_t rd_num = MDB_TGT_R_NUM(rd_nval); 4371*7c478bd9Sstevel@tonic-gate ushort_t rd_flags = MDB_TGT_R_FLAGS(rd_nval); 4372*7c478bd9Sstevel@tonic-gate 4373*7c478bd9Sstevel@tonic-gate if (!MDB_TGT_R_IS_FP(rd_flags)) { 4374*7c478bd9Sstevel@tonic-gate mdb_tgt_reg_t r = 0; 4375*7c478bd9Sstevel@tonic-gate 4376*7c478bd9Sstevel@tonic-gate #if defined(__sparc) && defined(_ILP32) 4377*7c478bd9Sstevel@tonic-gate /* 4378*7c478bd9Sstevel@tonic-gate * If we are debugging on 32-bit SPARC, the globals and 4379*7c478bd9Sstevel@tonic-gate * outs can have 32 upper bits hiding in the xregs. 4380*7c478bd9Sstevel@tonic-gate */ 4381*7c478bd9Sstevel@tonic-gate /* LINTED */ 4382*7c478bd9Sstevel@tonic-gate int is_g = (rd_num >= R_G0 && rd_num <= R_G7); 4383*7c478bd9Sstevel@tonic-gate int is_o = (rd_num >= R_O0 && rd_num <= R_O7); 4384*7c478bd9Sstevel@tonic-gate prxregset_t xrs; 4385*7c478bd9Sstevel@tonic-gate 4386*7c478bd9Sstevel@tonic-gate if (is_g && PTL_GETXREGS(t, tid, &xrs) == 0 && 4387*7c478bd9Sstevel@tonic-gate xrs.pr_type == XR_TYPE_V8P) { 4388*7c478bd9Sstevel@tonic-gate r |= (uint64_t)xrs.pr_un.pr_v8p.pr_xg[ 4389*7c478bd9Sstevel@tonic-gate rd_num - R_G0 + XR_G0] << 32; 4390*7c478bd9Sstevel@tonic-gate } 4391*7c478bd9Sstevel@tonic-gate 4392*7c478bd9Sstevel@tonic-gate if (is_o && PTL_GETXREGS(t, tid, &xrs) == 0 && 4393*7c478bd9Sstevel@tonic-gate xrs.pr_type == XR_TYPE_V8P) { 4394*7c478bd9Sstevel@tonic-gate r |= (uint64_t)xrs.pr_un.pr_v8p.pr_xo[ 4395*7c478bd9Sstevel@tonic-gate rd_num - R_O0 + XR_O0] << 32; 4396*7c478bd9Sstevel@tonic-gate } 4397*7c478bd9Sstevel@tonic-gate #endif /* __sparc && _ILP32 */ 4398*7c478bd9Sstevel@tonic-gate 4399*7c478bd9Sstevel@tonic-gate /* 4400*7c478bd9Sstevel@tonic-gate * Avoid sign-extension by casting: recall that procfs 4401*7c478bd9Sstevel@tonic-gate * defines prgreg_t as a long or int and our native 4402*7c478bd9Sstevel@tonic-gate * register handling uses uint64_t's. 4403*7c478bd9Sstevel@tonic-gate */ 4404*7c478bd9Sstevel@tonic-gate if (PTL_GETREGS(t, tid, grs) == 0) { 4405*7c478bd9Sstevel@tonic-gate *rp = r | (ulong_t)grs[rd_num]; 4406*7c478bd9Sstevel@tonic-gate return (0); 4407*7c478bd9Sstevel@tonic-gate } 4408*7c478bd9Sstevel@tonic-gate return (-1); 4409*7c478bd9Sstevel@tonic-gate } else 4410*7c478bd9Sstevel@tonic-gate return (pt_getfpreg(t, tid, rd_num, rd_flags, rp)); 4411*7c478bd9Sstevel@tonic-gate } 4412*7c478bd9Sstevel@tonic-gate 4413*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_BADREG)); 4414*7c478bd9Sstevel@tonic-gate } 4415*7c478bd9Sstevel@tonic-gate 4416*7c478bd9Sstevel@tonic-gate static int 4417*7c478bd9Sstevel@tonic-gate pt_putareg(mdb_tgt_t *t, mdb_tgt_tid_t tid, const char *rname, mdb_tgt_reg_t r) 4418*7c478bd9Sstevel@tonic-gate { 4419*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 4420*7c478bd9Sstevel@tonic-gate prgregset_t grs; 4421*7c478bd9Sstevel@tonic-gate mdb_var_t *v; 4422*7c478bd9Sstevel@tonic-gate 4423*7c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) 4424*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 4425*7c478bd9Sstevel@tonic-gate 4426*7c478bd9Sstevel@tonic-gate if ((v = mdb_nv_lookup(&pt->p_regs, rname)) != NULL) { 4427*7c478bd9Sstevel@tonic-gate uintmax_t rd_nval = mdb_nv_get_value(v); 4428*7c478bd9Sstevel@tonic-gate ushort_t rd_num = MDB_TGT_R_NUM(rd_nval); 4429*7c478bd9Sstevel@tonic-gate ushort_t rd_flags = MDB_TGT_R_FLAGS(rd_nval); 4430*7c478bd9Sstevel@tonic-gate 4431*7c478bd9Sstevel@tonic-gate if (!MDB_TGT_R_IS_FP(rd_flags)) { 4432*7c478bd9Sstevel@tonic-gate #if defined(__sparc) && defined(_ILP32) 4433*7c478bd9Sstevel@tonic-gate /* 4434*7c478bd9Sstevel@tonic-gate * If we are debugging on 32-bit SPARC, the globals and 4435*7c478bd9Sstevel@tonic-gate * outs can have 32 upper bits stored in the xregs. 4436*7c478bd9Sstevel@tonic-gate */ 4437*7c478bd9Sstevel@tonic-gate /* LINTED */ 4438*7c478bd9Sstevel@tonic-gate int is_g = (rd_num >= R_G0 && rd_num <= R_G7); 4439*7c478bd9Sstevel@tonic-gate int is_o = (rd_num >= R_O0 && rd_num <= R_O7); 4440*7c478bd9Sstevel@tonic-gate prxregset_t xrs; 4441*7c478bd9Sstevel@tonic-gate 4442*7c478bd9Sstevel@tonic-gate if ((is_g || is_o) && PTL_GETXREGS(t, tid, &xrs) == 0 && 4443*7c478bd9Sstevel@tonic-gate xrs.pr_type == XR_TYPE_V8P) { 4444*7c478bd9Sstevel@tonic-gate if (is_g) { 4445*7c478bd9Sstevel@tonic-gate xrs.pr_un.pr_v8p.pr_xg[rd_num - 4446*7c478bd9Sstevel@tonic-gate R_G0 + XR_G0] = (uint32_t)(r >> 32); 4447*7c478bd9Sstevel@tonic-gate } else if (is_o) { 4448*7c478bd9Sstevel@tonic-gate xrs.pr_un.pr_v8p.pr_xo[rd_num - 4449*7c478bd9Sstevel@tonic-gate R_O0 + XR_O0] = (uint32_t)(r >> 32); 4450*7c478bd9Sstevel@tonic-gate } 4451*7c478bd9Sstevel@tonic-gate 4452*7c478bd9Sstevel@tonic-gate if (PTL_SETXREGS(t, tid, &xrs) == -1) 4453*7c478bd9Sstevel@tonic-gate return (-1); 4454*7c478bd9Sstevel@tonic-gate } 4455*7c478bd9Sstevel@tonic-gate #endif /* __sparc && _ILP32 */ 4456*7c478bd9Sstevel@tonic-gate 4457*7c478bd9Sstevel@tonic-gate if (PTL_GETREGS(t, tid, grs) == 0) { 4458*7c478bd9Sstevel@tonic-gate grs[rd_num] = (prgreg_t)r; 4459*7c478bd9Sstevel@tonic-gate return (PTL_SETREGS(t, tid, grs)); 4460*7c478bd9Sstevel@tonic-gate } 4461*7c478bd9Sstevel@tonic-gate return (-1); 4462*7c478bd9Sstevel@tonic-gate } else 4463*7c478bd9Sstevel@tonic-gate return (pt_putfpreg(t, tid, rd_num, rd_flags, r)); 4464*7c478bd9Sstevel@tonic-gate } 4465*7c478bd9Sstevel@tonic-gate 4466*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_BADREG)); 4467*7c478bd9Sstevel@tonic-gate } 4468*7c478bd9Sstevel@tonic-gate 4469*7c478bd9Sstevel@tonic-gate static int 4470*7c478bd9Sstevel@tonic-gate pt_stack_call(pt_stkarg_t *psp, const prgregset_t grs, uint_t argc, long *argv) 4471*7c478bd9Sstevel@tonic-gate { 4472*7c478bd9Sstevel@tonic-gate psp->pstk_gotpc |= (grs[R_PC] != 0); 4473*7c478bd9Sstevel@tonic-gate 4474*7c478bd9Sstevel@tonic-gate if (!psp->pstk_gotpc) 4475*7c478bd9Sstevel@tonic-gate return (0); /* skip initial zeroed frames */ 4476*7c478bd9Sstevel@tonic-gate 4477*7c478bd9Sstevel@tonic-gate return (psp->pstk_func(psp->pstk_private, grs[R_PC], 4478*7c478bd9Sstevel@tonic-gate argc, argv, (const struct mdb_tgt_gregset *)grs)); 4479*7c478bd9Sstevel@tonic-gate } 4480*7c478bd9Sstevel@tonic-gate 4481*7c478bd9Sstevel@tonic-gate static int 4482*7c478bd9Sstevel@tonic-gate pt_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp, 4483*7c478bd9Sstevel@tonic-gate mdb_tgt_stack_f *func, void *arg) 4484*7c478bd9Sstevel@tonic-gate { 4485*7c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL) { 4486*7c478bd9Sstevel@tonic-gate pt_stkarg_t pstk; 4487*7c478bd9Sstevel@tonic-gate 4488*7c478bd9Sstevel@tonic-gate pstk.pstk_func = func; 4489*7c478bd9Sstevel@tonic-gate pstk.pstk_private = arg; 4490*7c478bd9Sstevel@tonic-gate pstk.pstk_gotpc = FALSE; 4491*7c478bd9Sstevel@tonic-gate 4492*7c478bd9Sstevel@tonic-gate (void) Pstack_iter(t->t_pshandle, gsp->gregs, 4493*7c478bd9Sstevel@tonic-gate (proc_stack_f *)pt_stack_call, &pstk); 4494*7c478bd9Sstevel@tonic-gate 4495*7c478bd9Sstevel@tonic-gate return (0); 4496*7c478bd9Sstevel@tonic-gate } 4497*7c478bd9Sstevel@tonic-gate 4498*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 4499*7c478bd9Sstevel@tonic-gate } 4500*7c478bd9Sstevel@tonic-gate 4501*7c478bd9Sstevel@tonic-gate static const mdb_tgt_ops_t proc_ops = { 4502*7c478bd9Sstevel@tonic-gate pt_setflags, /* t_setflags */ 4503*7c478bd9Sstevel@tonic-gate (int (*)()) mdb_tgt_notsup, /* t_setcontext */ 4504*7c478bd9Sstevel@tonic-gate pt_activate, /* t_activate */ 4505*7c478bd9Sstevel@tonic-gate pt_deactivate, /* t_deactivate */ 4506*7c478bd9Sstevel@tonic-gate pt_periodic, /* t_periodic */ 4507*7c478bd9Sstevel@tonic-gate pt_destroy, /* t_destroy */ 4508*7c478bd9Sstevel@tonic-gate pt_name, /* t_name */ 4509*7c478bd9Sstevel@tonic-gate (const char *(*)()) mdb_conf_isa, /* t_isa */ 4510*7c478bd9Sstevel@tonic-gate pt_platform, /* t_platform */ 4511*7c478bd9Sstevel@tonic-gate pt_uname, /* t_uname */ 4512*7c478bd9Sstevel@tonic-gate pt_dmodel, /* t_dmodel */ 4513*7c478bd9Sstevel@tonic-gate (ssize_t (*)()) mdb_tgt_notsup, /* t_aread */ 4514*7c478bd9Sstevel@tonic-gate (ssize_t (*)()) mdb_tgt_notsup, /* t_awrite */ 4515*7c478bd9Sstevel@tonic-gate pt_vread, /* t_vread */ 4516*7c478bd9Sstevel@tonic-gate pt_vwrite, /* t_vwrite */ 4517*7c478bd9Sstevel@tonic-gate (ssize_t (*)()) mdb_tgt_notsup, /* t_pread */ 4518*7c478bd9Sstevel@tonic-gate (ssize_t (*)()) mdb_tgt_notsup, /* t_pwrite */ 4519*7c478bd9Sstevel@tonic-gate pt_fread, /* t_fread */ 4520*7c478bd9Sstevel@tonic-gate pt_fwrite, /* t_fwrite */ 4521*7c478bd9Sstevel@tonic-gate (ssize_t (*)()) mdb_tgt_notsup, /* t_ioread */ 4522*7c478bd9Sstevel@tonic-gate (ssize_t (*)()) mdb_tgt_notsup, /* t_iowrite */ 4523*7c478bd9Sstevel@tonic-gate (int (*)()) mdb_tgt_notsup, /* t_vtop */ 4524*7c478bd9Sstevel@tonic-gate pt_lookup_by_name, /* t_lookup_by_name */ 4525*7c478bd9Sstevel@tonic-gate pt_lookup_by_addr, /* t_lookup_by_addr */ 4526*7c478bd9Sstevel@tonic-gate pt_symbol_iter, /* t_symbol_iter */ 4527*7c478bd9Sstevel@tonic-gate pt_mapping_iter, /* t_mapping_iter */ 4528*7c478bd9Sstevel@tonic-gate pt_object_iter, /* t_object_iter */ 4529*7c478bd9Sstevel@tonic-gate pt_addr_to_map, /* t_addr_to_map */ 4530*7c478bd9Sstevel@tonic-gate pt_name_to_map, /* t_name_to_map */ 4531*7c478bd9Sstevel@tonic-gate pt_addr_to_ctf, /* t_addr_to_ctf */ 4532*7c478bd9Sstevel@tonic-gate pt_name_to_ctf, /* t_name_to_ctf */ 4533*7c478bd9Sstevel@tonic-gate pt_status, /* t_status */ 4534*7c478bd9Sstevel@tonic-gate pt_run, /* t_run */ 4535*7c478bd9Sstevel@tonic-gate pt_step, /* t_step */ 4536*7c478bd9Sstevel@tonic-gate pt_step_out, /* t_step_out */ 4537*7c478bd9Sstevel@tonic-gate (int (*)()) mdb_tgt_notsup, /* t_step_branch */ 4538*7c478bd9Sstevel@tonic-gate pt_next, /* t_next */ 4539*7c478bd9Sstevel@tonic-gate pt_continue, /* t_cont */ 4540*7c478bd9Sstevel@tonic-gate pt_signal, /* t_signal */ 4541*7c478bd9Sstevel@tonic-gate pt_add_vbrkpt, /* t_add_vbrkpt */ 4542*7c478bd9Sstevel@tonic-gate pt_add_sbrkpt, /* t_add_sbrkpt */ 4543*7c478bd9Sstevel@tonic-gate (int (*)()) mdb_tgt_null, /* t_add_pwapt */ 4544*7c478bd9Sstevel@tonic-gate pt_add_vwapt, /* t_add_vwapt */ 4545*7c478bd9Sstevel@tonic-gate (int (*)()) mdb_tgt_null, /* t_add_iowapt */ 4546*7c478bd9Sstevel@tonic-gate pt_add_sysenter, /* t_add_sysenter */ 4547*7c478bd9Sstevel@tonic-gate pt_add_sysexit, /* t_add_sysexit */ 4548*7c478bd9Sstevel@tonic-gate pt_add_signal, /* t_add_signal */ 4549*7c478bd9Sstevel@tonic-gate pt_add_fault, /* t_add_fault */ 4550*7c478bd9Sstevel@tonic-gate pt_getareg, /* t_getareg */ 4551*7c478bd9Sstevel@tonic-gate pt_putareg, /* t_putareg */ 4552*7c478bd9Sstevel@tonic-gate pt_stack_iter /* t_stack_iter */ 4553*7c478bd9Sstevel@tonic-gate }; 4554*7c478bd9Sstevel@tonic-gate 4555*7c478bd9Sstevel@tonic-gate /* 4556*7c478bd9Sstevel@tonic-gate * Utility function for converting libproc errno values to mdb error values 4557*7c478bd9Sstevel@tonic-gate * for the ptl calls below. Currently, we only need to convert ENOENT to 4558*7c478bd9Sstevel@tonic-gate * EMDB_NOTHREAD to produce a more useful error message for the user. 4559*7c478bd9Sstevel@tonic-gate */ 4560*7c478bd9Sstevel@tonic-gate static int 4561*7c478bd9Sstevel@tonic-gate ptl_err(int error) 4562*7c478bd9Sstevel@tonic-gate { 4563*7c478bd9Sstevel@tonic-gate if (error != 0 && errno == ENOENT) 4564*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOTHREAD)); 4565*7c478bd9Sstevel@tonic-gate 4566*7c478bd9Sstevel@tonic-gate return (error); 4567*7c478bd9Sstevel@tonic-gate } 4568*7c478bd9Sstevel@tonic-gate 4569*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4570*7c478bd9Sstevel@tonic-gate static mdb_tgt_tid_t 4571*7c478bd9Sstevel@tonic-gate pt_lwp_tid(mdb_tgt_t *t, void *tap) 4572*7c478bd9Sstevel@tonic-gate { 4573*7c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL) 4574*7c478bd9Sstevel@tonic-gate return (Pstatus(t->t_pshandle)->pr_lwp.pr_lwpid); 4575*7c478bd9Sstevel@tonic-gate 4576*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 4577*7c478bd9Sstevel@tonic-gate } 4578*7c478bd9Sstevel@tonic-gate 4579*7c478bd9Sstevel@tonic-gate static int 4580*7c478bd9Sstevel@tonic-gate pt_lwp_add(mdb_addrvec_t *ap, const lwpstatus_t *psp) 4581*7c478bd9Sstevel@tonic-gate { 4582*7c478bd9Sstevel@tonic-gate mdb_addrvec_unshift(ap, psp->pr_lwpid); 4583*7c478bd9Sstevel@tonic-gate return (0); 4584*7c478bd9Sstevel@tonic-gate } 4585*7c478bd9Sstevel@tonic-gate 4586*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4587*7c478bd9Sstevel@tonic-gate static int 4588*7c478bd9Sstevel@tonic-gate pt_lwp_iter(mdb_tgt_t *t, void *tap, mdb_addrvec_t *ap) 4589*7c478bd9Sstevel@tonic-gate { 4590*7c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL) 4591*7c478bd9Sstevel@tonic-gate return (Plwp_iter(t->t_pshandle, (proc_lwp_f *)pt_lwp_add, ap)); 4592*7c478bd9Sstevel@tonic-gate 4593*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 4594*7c478bd9Sstevel@tonic-gate } 4595*7c478bd9Sstevel@tonic-gate 4596*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4597*7c478bd9Sstevel@tonic-gate static int 4598*7c478bd9Sstevel@tonic-gate pt_lwp_getregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid, prgregset_t gregs) 4599*7c478bd9Sstevel@tonic-gate { 4600*7c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL) { 4601*7c478bd9Sstevel@tonic-gate return (ptl_err(Plwp_getregs(t->t_pshandle, 4602*7c478bd9Sstevel@tonic-gate (lwpid_t)tid, gregs))); 4603*7c478bd9Sstevel@tonic-gate } 4604*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 4605*7c478bd9Sstevel@tonic-gate } 4606*7c478bd9Sstevel@tonic-gate 4607*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4608*7c478bd9Sstevel@tonic-gate static int 4609*7c478bd9Sstevel@tonic-gate pt_lwp_setregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid, prgregset_t gregs) 4610*7c478bd9Sstevel@tonic-gate { 4611*7c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL) { 4612*7c478bd9Sstevel@tonic-gate return (ptl_err(Plwp_setregs(t->t_pshandle, 4613*7c478bd9Sstevel@tonic-gate (lwpid_t)tid, gregs))); 4614*7c478bd9Sstevel@tonic-gate } 4615*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 4616*7c478bd9Sstevel@tonic-gate } 4617*7c478bd9Sstevel@tonic-gate 4618*7c478bd9Sstevel@tonic-gate #ifdef __sparc 4619*7c478bd9Sstevel@tonic-gate 4620*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4621*7c478bd9Sstevel@tonic-gate static int 4622*7c478bd9Sstevel@tonic-gate pt_lwp_getxregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid, prxregset_t *xregs) 4623*7c478bd9Sstevel@tonic-gate { 4624*7c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL) { 4625*7c478bd9Sstevel@tonic-gate return (ptl_err(Plwp_getxregs(t->t_pshandle, 4626*7c478bd9Sstevel@tonic-gate (lwpid_t)tid, xregs))); 4627*7c478bd9Sstevel@tonic-gate } 4628*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 4629*7c478bd9Sstevel@tonic-gate } 4630*7c478bd9Sstevel@tonic-gate 4631*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4632*7c478bd9Sstevel@tonic-gate static int 4633*7c478bd9Sstevel@tonic-gate pt_lwp_setxregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid, 4634*7c478bd9Sstevel@tonic-gate const prxregset_t *xregs) 4635*7c478bd9Sstevel@tonic-gate { 4636*7c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL) { 4637*7c478bd9Sstevel@tonic-gate return (ptl_err(Plwp_setxregs(t->t_pshandle, 4638*7c478bd9Sstevel@tonic-gate (lwpid_t)tid, xregs))); 4639*7c478bd9Sstevel@tonic-gate } 4640*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 4641*7c478bd9Sstevel@tonic-gate } 4642*7c478bd9Sstevel@tonic-gate 4643*7c478bd9Sstevel@tonic-gate #endif /* __sparc */ 4644*7c478bd9Sstevel@tonic-gate 4645*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4646*7c478bd9Sstevel@tonic-gate static int 4647*7c478bd9Sstevel@tonic-gate pt_lwp_getfpregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid, 4648*7c478bd9Sstevel@tonic-gate prfpregset_t *fpregs) 4649*7c478bd9Sstevel@tonic-gate { 4650*7c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL) { 4651*7c478bd9Sstevel@tonic-gate return (ptl_err(Plwp_getfpregs(t->t_pshandle, 4652*7c478bd9Sstevel@tonic-gate (lwpid_t)tid, fpregs))); 4653*7c478bd9Sstevel@tonic-gate } 4654*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 4655*7c478bd9Sstevel@tonic-gate } 4656*7c478bd9Sstevel@tonic-gate 4657*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4658*7c478bd9Sstevel@tonic-gate static int 4659*7c478bd9Sstevel@tonic-gate pt_lwp_setfpregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid, 4660*7c478bd9Sstevel@tonic-gate const prfpregset_t *fpregs) 4661*7c478bd9Sstevel@tonic-gate { 4662*7c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL) { 4663*7c478bd9Sstevel@tonic-gate return (ptl_err(Plwp_setfpregs(t->t_pshandle, 4664*7c478bd9Sstevel@tonic-gate (lwpid_t)tid, fpregs))); 4665*7c478bd9Sstevel@tonic-gate } 4666*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 4667*7c478bd9Sstevel@tonic-gate } 4668*7c478bd9Sstevel@tonic-gate 4669*7c478bd9Sstevel@tonic-gate static const pt_ptl_ops_t proc_lwp_ops = { 4670*7c478bd9Sstevel@tonic-gate (int (*)()) mdb_tgt_nop, 4671*7c478bd9Sstevel@tonic-gate (void (*)()) mdb_tgt_nop, 4672*7c478bd9Sstevel@tonic-gate pt_lwp_tid, 4673*7c478bd9Sstevel@tonic-gate pt_lwp_iter, 4674*7c478bd9Sstevel@tonic-gate pt_lwp_getregs, 4675*7c478bd9Sstevel@tonic-gate pt_lwp_setregs, 4676*7c478bd9Sstevel@tonic-gate #ifdef __sparc 4677*7c478bd9Sstevel@tonic-gate pt_lwp_getxregs, 4678*7c478bd9Sstevel@tonic-gate pt_lwp_setxregs, 4679*7c478bd9Sstevel@tonic-gate #endif 4680*7c478bd9Sstevel@tonic-gate pt_lwp_getfpregs, 4681*7c478bd9Sstevel@tonic-gate pt_lwp_setfpregs 4682*7c478bd9Sstevel@tonic-gate }; 4683*7c478bd9Sstevel@tonic-gate 4684*7c478bd9Sstevel@tonic-gate static int 4685*7c478bd9Sstevel@tonic-gate pt_tdb_ctor(mdb_tgt_t *t) 4686*7c478bd9Sstevel@tonic-gate { 4687*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 4688*7c478bd9Sstevel@tonic-gate td_thragent_t *tap; 4689*7c478bd9Sstevel@tonic-gate td_err_e err; 4690*7c478bd9Sstevel@tonic-gate 4691*7c478bd9Sstevel@tonic-gate if ((err = pt->p_tdb_ops->td_ta_new(t->t_pshandle, &tap)) != TD_OK) 4692*7c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 4693*7c478bd9Sstevel@tonic-gate 4694*7c478bd9Sstevel@tonic-gate pt->p_ptl_hdl = tap; 4695*7c478bd9Sstevel@tonic-gate return (0); 4696*7c478bd9Sstevel@tonic-gate } 4697*7c478bd9Sstevel@tonic-gate 4698*7c478bd9Sstevel@tonic-gate static void 4699*7c478bd9Sstevel@tonic-gate pt_tdb_dtor(mdb_tgt_t *t, void *tap) 4700*7c478bd9Sstevel@tonic-gate { 4701*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 4702*7c478bd9Sstevel@tonic-gate 4703*7c478bd9Sstevel@tonic-gate ASSERT(tap == pt->p_ptl_hdl); 4704*7c478bd9Sstevel@tonic-gate (void) pt->p_tdb_ops->td_ta_delete(tap); 4705*7c478bd9Sstevel@tonic-gate pt->p_ptl_hdl = NULL; 4706*7c478bd9Sstevel@tonic-gate } 4707*7c478bd9Sstevel@tonic-gate 4708*7c478bd9Sstevel@tonic-gate static mdb_tgt_tid_t 4709*7c478bd9Sstevel@tonic-gate pt_tdb_tid(mdb_tgt_t *t, void *tap) 4710*7c478bd9Sstevel@tonic-gate { 4711*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 4712*7c478bd9Sstevel@tonic-gate 4713*7c478bd9Sstevel@tonic-gate td_thrhandle_t th; 4714*7c478bd9Sstevel@tonic-gate td_thrinfo_t ti; 4715*7c478bd9Sstevel@tonic-gate td_err_e err; 4716*7c478bd9Sstevel@tonic-gate 4717*7c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) 4718*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 4719*7c478bd9Sstevel@tonic-gate 4720*7c478bd9Sstevel@tonic-gate if ((err = pt->p_tdb_ops->td_ta_map_lwp2thr(tap, 4721*7c478bd9Sstevel@tonic-gate Pstatus(t->t_pshandle)->pr_lwp.pr_lwpid, &th)) != TD_OK) 4722*7c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 4723*7c478bd9Sstevel@tonic-gate 4724*7c478bd9Sstevel@tonic-gate if ((err = pt->p_tdb_ops->td_thr_get_info(&th, &ti)) != TD_OK) 4725*7c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 4726*7c478bd9Sstevel@tonic-gate 4727*7c478bd9Sstevel@tonic-gate return (ti.ti_tid); 4728*7c478bd9Sstevel@tonic-gate } 4729*7c478bd9Sstevel@tonic-gate 4730*7c478bd9Sstevel@tonic-gate static int 4731*7c478bd9Sstevel@tonic-gate pt_tdb_add(const td_thrhandle_t *thp, pt_addarg_t *pap) 4732*7c478bd9Sstevel@tonic-gate { 4733*7c478bd9Sstevel@tonic-gate td_thrinfo_t ti; 4734*7c478bd9Sstevel@tonic-gate 4735*7c478bd9Sstevel@tonic-gate if (pap->pa_pt->p_tdb_ops->td_thr_get_info(thp, &ti) == TD_OK && 4736*7c478bd9Sstevel@tonic-gate ti.ti_state != TD_THR_ZOMBIE) 4737*7c478bd9Sstevel@tonic-gate mdb_addrvec_unshift(pap->pa_ap, ti.ti_tid); 4738*7c478bd9Sstevel@tonic-gate 4739*7c478bd9Sstevel@tonic-gate return (0); 4740*7c478bd9Sstevel@tonic-gate } 4741*7c478bd9Sstevel@tonic-gate 4742*7c478bd9Sstevel@tonic-gate static int 4743*7c478bd9Sstevel@tonic-gate pt_tdb_iter(mdb_tgt_t *t, void *tap, mdb_addrvec_t *ap) 4744*7c478bd9Sstevel@tonic-gate { 4745*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 4746*7c478bd9Sstevel@tonic-gate pt_addarg_t arg; 4747*7c478bd9Sstevel@tonic-gate int err; 4748*7c478bd9Sstevel@tonic-gate 4749*7c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) 4750*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 4751*7c478bd9Sstevel@tonic-gate 4752*7c478bd9Sstevel@tonic-gate arg.pa_pt = pt; 4753*7c478bd9Sstevel@tonic-gate arg.pa_ap = ap; 4754*7c478bd9Sstevel@tonic-gate 4755*7c478bd9Sstevel@tonic-gate if ((err = pt->p_tdb_ops->td_ta_thr_iter(tap, (td_thr_iter_f *) 4756*7c478bd9Sstevel@tonic-gate pt_tdb_add, &arg, TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY, 4757*7c478bd9Sstevel@tonic-gate TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS)) != TD_OK) 4758*7c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 4759*7c478bd9Sstevel@tonic-gate 4760*7c478bd9Sstevel@tonic-gate return (0); 4761*7c478bd9Sstevel@tonic-gate } 4762*7c478bd9Sstevel@tonic-gate 4763*7c478bd9Sstevel@tonic-gate static int 4764*7c478bd9Sstevel@tonic-gate pt_tdb_getregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid, prgregset_t gregs) 4765*7c478bd9Sstevel@tonic-gate { 4766*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 4767*7c478bd9Sstevel@tonic-gate 4768*7c478bd9Sstevel@tonic-gate td_thrhandle_t th; 4769*7c478bd9Sstevel@tonic-gate td_err_e err; 4770*7c478bd9Sstevel@tonic-gate 4771*7c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) 4772*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 4773*7c478bd9Sstevel@tonic-gate 4774*7c478bd9Sstevel@tonic-gate if ((err = pt->p_tdb_ops->td_ta_map_id2thr(tap, tid, &th)) != TD_OK) 4775*7c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 4776*7c478bd9Sstevel@tonic-gate 4777*7c478bd9Sstevel@tonic-gate err = pt->p_tdb_ops->td_thr_getgregs(&th, gregs); 4778*7c478bd9Sstevel@tonic-gate if (err != TD_OK && err != TD_PARTIALREG) 4779*7c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 4780*7c478bd9Sstevel@tonic-gate 4781*7c478bd9Sstevel@tonic-gate return (0); 4782*7c478bd9Sstevel@tonic-gate } 4783*7c478bd9Sstevel@tonic-gate 4784*7c478bd9Sstevel@tonic-gate static int 4785*7c478bd9Sstevel@tonic-gate pt_tdb_setregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid, prgregset_t gregs) 4786*7c478bd9Sstevel@tonic-gate { 4787*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 4788*7c478bd9Sstevel@tonic-gate 4789*7c478bd9Sstevel@tonic-gate td_thrhandle_t th; 4790*7c478bd9Sstevel@tonic-gate td_err_e err; 4791*7c478bd9Sstevel@tonic-gate 4792*7c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) 4793*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 4794*7c478bd9Sstevel@tonic-gate 4795*7c478bd9Sstevel@tonic-gate if ((err = pt->p_tdb_ops->td_ta_map_id2thr(tap, tid, &th)) != TD_OK) 4796*7c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 4797*7c478bd9Sstevel@tonic-gate 4798*7c478bd9Sstevel@tonic-gate err = pt->p_tdb_ops->td_thr_setgregs(&th, gregs); 4799*7c478bd9Sstevel@tonic-gate if (err != TD_OK && err != TD_PARTIALREG) 4800*7c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 4801*7c478bd9Sstevel@tonic-gate 4802*7c478bd9Sstevel@tonic-gate return (0); 4803*7c478bd9Sstevel@tonic-gate } 4804*7c478bd9Sstevel@tonic-gate 4805*7c478bd9Sstevel@tonic-gate #ifdef __sparc 4806*7c478bd9Sstevel@tonic-gate 4807*7c478bd9Sstevel@tonic-gate static int 4808*7c478bd9Sstevel@tonic-gate pt_tdb_getxregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid, prxregset_t *xregs) 4809*7c478bd9Sstevel@tonic-gate { 4810*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 4811*7c478bd9Sstevel@tonic-gate 4812*7c478bd9Sstevel@tonic-gate td_thrhandle_t th; 4813*7c478bd9Sstevel@tonic-gate td_err_e err; 4814*7c478bd9Sstevel@tonic-gate 4815*7c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) 4816*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 4817*7c478bd9Sstevel@tonic-gate 4818*7c478bd9Sstevel@tonic-gate if ((err = pt->p_tdb_ops->td_ta_map_id2thr(tap, tid, &th)) != TD_OK) 4819*7c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 4820*7c478bd9Sstevel@tonic-gate 4821*7c478bd9Sstevel@tonic-gate err = pt->p_tdb_ops->td_thr_getxregs(&th, xregs); 4822*7c478bd9Sstevel@tonic-gate if (err != TD_OK && err != TD_PARTIALREG) 4823*7c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 4824*7c478bd9Sstevel@tonic-gate 4825*7c478bd9Sstevel@tonic-gate return (0); 4826*7c478bd9Sstevel@tonic-gate } 4827*7c478bd9Sstevel@tonic-gate 4828*7c478bd9Sstevel@tonic-gate static int 4829*7c478bd9Sstevel@tonic-gate pt_tdb_setxregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid, 4830*7c478bd9Sstevel@tonic-gate const prxregset_t *xregs) 4831*7c478bd9Sstevel@tonic-gate { 4832*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 4833*7c478bd9Sstevel@tonic-gate 4834*7c478bd9Sstevel@tonic-gate td_thrhandle_t th; 4835*7c478bd9Sstevel@tonic-gate td_err_e err; 4836*7c478bd9Sstevel@tonic-gate 4837*7c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) 4838*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 4839*7c478bd9Sstevel@tonic-gate 4840*7c478bd9Sstevel@tonic-gate if ((err = pt->p_tdb_ops->td_ta_map_id2thr(tap, tid, &th)) != TD_OK) 4841*7c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 4842*7c478bd9Sstevel@tonic-gate 4843*7c478bd9Sstevel@tonic-gate err = pt->p_tdb_ops->td_thr_setxregs(&th, xregs); 4844*7c478bd9Sstevel@tonic-gate if (err != TD_OK && err != TD_PARTIALREG) 4845*7c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 4846*7c478bd9Sstevel@tonic-gate 4847*7c478bd9Sstevel@tonic-gate return (0); 4848*7c478bd9Sstevel@tonic-gate } 4849*7c478bd9Sstevel@tonic-gate 4850*7c478bd9Sstevel@tonic-gate #endif /* __sparc */ 4851*7c478bd9Sstevel@tonic-gate 4852*7c478bd9Sstevel@tonic-gate static int 4853*7c478bd9Sstevel@tonic-gate pt_tdb_getfpregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid, 4854*7c478bd9Sstevel@tonic-gate prfpregset_t *fpregs) 4855*7c478bd9Sstevel@tonic-gate { 4856*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 4857*7c478bd9Sstevel@tonic-gate 4858*7c478bd9Sstevel@tonic-gate td_thrhandle_t th; 4859*7c478bd9Sstevel@tonic-gate td_err_e err; 4860*7c478bd9Sstevel@tonic-gate 4861*7c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) 4862*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 4863*7c478bd9Sstevel@tonic-gate 4864*7c478bd9Sstevel@tonic-gate if ((err = pt->p_tdb_ops->td_ta_map_id2thr(tap, tid, &th)) != TD_OK) 4865*7c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 4866*7c478bd9Sstevel@tonic-gate 4867*7c478bd9Sstevel@tonic-gate err = pt->p_tdb_ops->td_thr_getfpregs(&th, fpregs); 4868*7c478bd9Sstevel@tonic-gate if (err != TD_OK && err != TD_PARTIALREG) 4869*7c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 4870*7c478bd9Sstevel@tonic-gate 4871*7c478bd9Sstevel@tonic-gate return (0); 4872*7c478bd9Sstevel@tonic-gate } 4873*7c478bd9Sstevel@tonic-gate 4874*7c478bd9Sstevel@tonic-gate static int 4875*7c478bd9Sstevel@tonic-gate pt_tdb_setfpregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid, 4876*7c478bd9Sstevel@tonic-gate const prfpregset_t *fpregs) 4877*7c478bd9Sstevel@tonic-gate { 4878*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 4879*7c478bd9Sstevel@tonic-gate 4880*7c478bd9Sstevel@tonic-gate td_thrhandle_t th; 4881*7c478bd9Sstevel@tonic-gate td_err_e err; 4882*7c478bd9Sstevel@tonic-gate 4883*7c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) 4884*7c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 4885*7c478bd9Sstevel@tonic-gate 4886*7c478bd9Sstevel@tonic-gate if ((err = pt->p_tdb_ops->td_ta_map_id2thr(tap, tid, &th)) != TD_OK) 4887*7c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 4888*7c478bd9Sstevel@tonic-gate 4889*7c478bd9Sstevel@tonic-gate err = pt->p_tdb_ops->td_thr_setfpregs(&th, fpregs); 4890*7c478bd9Sstevel@tonic-gate if (err != TD_OK && err != TD_PARTIALREG) 4891*7c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 4892*7c478bd9Sstevel@tonic-gate 4893*7c478bd9Sstevel@tonic-gate return (0); 4894*7c478bd9Sstevel@tonic-gate } 4895*7c478bd9Sstevel@tonic-gate 4896*7c478bd9Sstevel@tonic-gate static const pt_ptl_ops_t proc_tdb_ops = { 4897*7c478bd9Sstevel@tonic-gate pt_tdb_ctor, 4898*7c478bd9Sstevel@tonic-gate pt_tdb_dtor, 4899*7c478bd9Sstevel@tonic-gate pt_tdb_tid, 4900*7c478bd9Sstevel@tonic-gate pt_tdb_iter, 4901*7c478bd9Sstevel@tonic-gate pt_tdb_getregs, 4902*7c478bd9Sstevel@tonic-gate pt_tdb_setregs, 4903*7c478bd9Sstevel@tonic-gate #ifdef __sparc 4904*7c478bd9Sstevel@tonic-gate pt_tdb_getxregs, 4905*7c478bd9Sstevel@tonic-gate pt_tdb_setxregs, 4906*7c478bd9Sstevel@tonic-gate #endif 4907*7c478bd9Sstevel@tonic-gate pt_tdb_getfpregs, 4908*7c478bd9Sstevel@tonic-gate pt_tdb_setfpregs 4909*7c478bd9Sstevel@tonic-gate }; 4910*7c478bd9Sstevel@tonic-gate 4911*7c478bd9Sstevel@tonic-gate static ssize_t 4912*7c478bd9Sstevel@tonic-gate pt_xd_auxv(mdb_tgt_t *t, void *buf, size_t nbytes) 4913*7c478bd9Sstevel@tonic-gate { 4914*7c478bd9Sstevel@tonic-gate struct ps_prochandle *P = t->t_pshandle; 4915*7c478bd9Sstevel@tonic-gate const auxv_t *auxp, *auxv = NULL; 4916*7c478bd9Sstevel@tonic-gate int auxn = 0; 4917*7c478bd9Sstevel@tonic-gate 4918*7c478bd9Sstevel@tonic-gate if (P != NULL && (auxv = Pgetauxvec(P)) != NULL && 4919*7c478bd9Sstevel@tonic-gate auxv->a_type != AT_NULL) { 4920*7c478bd9Sstevel@tonic-gate for (auxp = auxv, auxn = 1; auxp->a_type != NULL; auxp++) 4921*7c478bd9Sstevel@tonic-gate auxn++; 4922*7c478bd9Sstevel@tonic-gate } 4923*7c478bd9Sstevel@tonic-gate 4924*7c478bd9Sstevel@tonic-gate if (buf == NULL && nbytes == 0) 4925*7c478bd9Sstevel@tonic-gate return (sizeof (auxv_t) * auxn); 4926*7c478bd9Sstevel@tonic-gate 4927*7c478bd9Sstevel@tonic-gate if (auxn == 0) 4928*7c478bd9Sstevel@tonic-gate return (set_errno(ENODATA)); 4929*7c478bd9Sstevel@tonic-gate 4930*7c478bd9Sstevel@tonic-gate nbytes = MIN(nbytes, sizeof (auxv_t) * auxn); 4931*7c478bd9Sstevel@tonic-gate bcopy(auxv, buf, nbytes); 4932*7c478bd9Sstevel@tonic-gate return (nbytes); 4933*7c478bd9Sstevel@tonic-gate } 4934*7c478bd9Sstevel@tonic-gate 4935*7c478bd9Sstevel@tonic-gate static ssize_t 4936*7c478bd9Sstevel@tonic-gate pt_xd_cred(mdb_tgt_t *t, void *buf, size_t nbytes) 4937*7c478bd9Sstevel@tonic-gate { 4938*7c478bd9Sstevel@tonic-gate prcred_t cr, *crp; 4939*7c478bd9Sstevel@tonic-gate size_t cbytes = 0; 4940*7c478bd9Sstevel@tonic-gate 4941*7c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL && Pcred(t->t_pshandle, &cr, 1) == 0) { 4942*7c478bd9Sstevel@tonic-gate cbytes = (cr.pr_ngroups <= 1) ? sizeof (prcred_t) : 4943*7c478bd9Sstevel@tonic-gate (sizeof (prcred_t) + (cr.pr_ngroups - 1) * sizeof (gid_t)); 4944*7c478bd9Sstevel@tonic-gate } 4945*7c478bd9Sstevel@tonic-gate 4946*7c478bd9Sstevel@tonic-gate if (buf == NULL && nbytes == 0) 4947*7c478bd9Sstevel@tonic-gate return (cbytes); 4948*7c478bd9Sstevel@tonic-gate 4949*7c478bd9Sstevel@tonic-gate if (cbytes == 0) 4950*7c478bd9Sstevel@tonic-gate return (set_errno(ENODATA)); 4951*7c478bd9Sstevel@tonic-gate 4952*7c478bd9Sstevel@tonic-gate crp = mdb_alloc(cbytes, UM_SLEEP); 4953*7c478bd9Sstevel@tonic-gate 4954*7c478bd9Sstevel@tonic-gate if (Pcred(t->t_pshandle, crp, cr.pr_ngroups) == -1) 4955*7c478bd9Sstevel@tonic-gate return (set_errno(ENODATA)); 4956*7c478bd9Sstevel@tonic-gate 4957*7c478bd9Sstevel@tonic-gate nbytes = MIN(nbytes, cbytes); 4958*7c478bd9Sstevel@tonic-gate bcopy(crp, buf, nbytes); 4959*7c478bd9Sstevel@tonic-gate mdb_free(crp, cbytes); 4960*7c478bd9Sstevel@tonic-gate return (nbytes); 4961*7c478bd9Sstevel@tonic-gate } 4962*7c478bd9Sstevel@tonic-gate 4963*7c478bd9Sstevel@tonic-gate static ssize_t 4964*7c478bd9Sstevel@tonic-gate pt_xd_ehdr(mdb_tgt_t *t, void *buf, size_t nbytes) 4965*7c478bd9Sstevel@tonic-gate { 4966*7c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 4967*7c478bd9Sstevel@tonic-gate 4968*7c478bd9Sstevel@tonic-gate if (buf == NULL && nbytes == 0) 4969*7c478bd9Sstevel@tonic-gate return (sizeof (GElf_Ehdr)); 4970*7c478bd9Sstevel@tonic-gate 4971*7c478bd9Sstevel@tonic-gate if (pt->p_file == NULL) 4972*7c478bd9Sstevel@tonic-gate return (set_errno(ENODATA)); 4973*7c478bd9Sstevel@tonic-gate 4974*7c478bd9Sstevel@tonic-gate nbytes = MIN(nbytes, sizeof (GElf_Ehdr)); 4975*7c478bd9Sstevel@tonic-gate bcopy(&pt->p_file->gf_ehdr, buf, nbytes); 4976*7c478bd9Sstevel@tonic-gate return (nbytes); 4977*7c478bd9Sstevel@tonic-gate } 4978*7c478bd9Sstevel@tonic-gate 4979*7c478bd9Sstevel@tonic-gate static int 4980*7c478bd9Sstevel@tonic-gate pt_copy_lwp(lwpstatus_t **lspp, const lwpstatus_t *lsp) 4981*7c478bd9Sstevel@tonic-gate { 4982*7c478bd9Sstevel@tonic-gate bcopy(lsp, *lspp, sizeof (lwpstatus_t)); 4983*7c478bd9Sstevel@tonic-gate (*lspp)++; 4984*7c478bd9Sstevel@tonic-gate return (0); 4985*7c478bd9Sstevel@tonic-gate } 4986*7c478bd9Sstevel@tonic-gate 4987*7c478bd9Sstevel@tonic-gate static ssize_t 4988*7c478bd9Sstevel@tonic-gate pt_xd_lwpstatus(mdb_tgt_t *t, void *buf, size_t nbytes) 4989*7c478bd9Sstevel@tonic-gate { 4990*7c478bd9Sstevel@tonic-gate lwpstatus_t *lsp, *lbuf; 4991*7c478bd9Sstevel@tonic-gate const pstatus_t *psp; 4992*7c478bd9Sstevel@tonic-gate int nlwp = 0; 4993*7c478bd9Sstevel@tonic-gate 4994*7c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL && (psp = Pstatus(t->t_pshandle)) != NULL) 4995*7c478bd9Sstevel@tonic-gate nlwp = psp->pr_nlwp; 4996*7c478bd9Sstevel@tonic-gate 4997*7c478bd9Sstevel@tonic-gate if (buf == NULL && nbytes == 0) 4998*7c478bd9Sstevel@tonic-gate return (sizeof (lwpstatus_t) * nlwp); 4999*7c478bd9Sstevel@tonic-gate 5000*7c478bd9Sstevel@tonic-gate if (nlwp == 0) 5001*7c478bd9Sstevel@tonic-gate return (set_errno(ENODATA)); 5002*7c478bd9Sstevel@tonic-gate 5003*7c478bd9Sstevel@tonic-gate lsp = lbuf = mdb_alloc(sizeof (lwpstatus_t) * nlwp, UM_SLEEP); 5004*7c478bd9Sstevel@tonic-gate nbytes = MIN(nbytes, sizeof (lwpstatus_t) * nlwp); 5005*7c478bd9Sstevel@tonic-gate 5006*7c478bd9Sstevel@tonic-gate (void) Plwp_iter(t->t_pshandle, (proc_lwp_f *)pt_copy_lwp, &lsp); 5007*7c478bd9Sstevel@tonic-gate bcopy(lbuf, buf, nbytes); 5008*7c478bd9Sstevel@tonic-gate 5009*7c478bd9Sstevel@tonic-gate mdb_free(lbuf, sizeof (lwpstatus_t) * nlwp); 5010*7c478bd9Sstevel@tonic-gate return (nbytes); 5011*7c478bd9Sstevel@tonic-gate } 5012*7c478bd9Sstevel@tonic-gate 5013*7c478bd9Sstevel@tonic-gate static ssize_t 5014*7c478bd9Sstevel@tonic-gate pt_xd_pshandle(mdb_tgt_t *t, void *buf, size_t nbytes) 5015*7c478bd9Sstevel@tonic-gate { 5016*7c478bd9Sstevel@tonic-gate if (buf == NULL && nbytes == 0) 5017*7c478bd9Sstevel@tonic-gate return (sizeof (struct ps_prochandle *)); 5018*7c478bd9Sstevel@tonic-gate 5019*7c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL || nbytes != sizeof (struct ps_prochandle *)) 5020*7c478bd9Sstevel@tonic-gate return (set_errno(ENODATA)); 5021*7c478bd9Sstevel@tonic-gate 5022*7c478bd9Sstevel@tonic-gate bcopy(&t->t_pshandle, buf, nbytes); 5023*7c478bd9Sstevel@tonic-gate return (nbytes); 5024*7c478bd9Sstevel@tonic-gate } 5025*7c478bd9Sstevel@tonic-gate 5026*7c478bd9Sstevel@tonic-gate static ssize_t 5027*7c478bd9Sstevel@tonic-gate pt_xd_psinfo(mdb_tgt_t *t, void *buf, size_t nbytes) 5028*7c478bd9Sstevel@tonic-gate { 5029*7c478bd9Sstevel@tonic-gate const psinfo_t *psp; 5030*7c478bd9Sstevel@tonic-gate 5031*7c478bd9Sstevel@tonic-gate if (buf == NULL && nbytes == 0) 5032*7c478bd9Sstevel@tonic-gate return (sizeof (psinfo_t)); 5033*7c478bd9Sstevel@tonic-gate 5034*7c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL || (psp = Ppsinfo(t->t_pshandle)) == NULL) 5035*7c478bd9Sstevel@tonic-gate return (set_errno(ENODATA)); 5036*7c478bd9Sstevel@tonic-gate 5037*7c478bd9Sstevel@tonic-gate nbytes = MIN(nbytes, sizeof (psinfo_t)); 5038*7c478bd9Sstevel@tonic-gate bcopy(psp, buf, nbytes); 5039*7c478bd9Sstevel@tonic-gate return (nbytes); 5040*7c478bd9Sstevel@tonic-gate } 5041*7c478bd9Sstevel@tonic-gate 5042*7c478bd9Sstevel@tonic-gate static ssize_t 5043*7c478bd9Sstevel@tonic-gate pt_xd_pstatus(mdb_tgt_t *t, void *buf, size_t nbytes) 5044*7c478bd9Sstevel@tonic-gate { 5045*7c478bd9Sstevel@tonic-gate const pstatus_t *psp; 5046*7c478bd9Sstevel@tonic-gate 5047*7c478bd9Sstevel@tonic-gate if (buf == NULL && nbytes == 0) 5048*7c478bd9Sstevel@tonic-gate return (sizeof (pstatus_t)); 5049*7c478bd9Sstevel@tonic-gate 5050*7c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL || (psp = Pstatus(t->t_pshandle)) == NULL) 5051*7c478bd9Sstevel@tonic-gate return (set_errno(ENODATA)); 5052*7c478bd9Sstevel@tonic-gate 5053*7c478bd9Sstevel@tonic-gate nbytes = MIN(nbytes, sizeof (pstatus_t)); 5054*7c478bd9Sstevel@tonic-gate bcopy(psp, buf, nbytes); 5055*7c478bd9Sstevel@tonic-gate return (nbytes); 5056*7c478bd9Sstevel@tonic-gate } 5057*7c478bd9Sstevel@tonic-gate 5058*7c478bd9Sstevel@tonic-gate static ssize_t 5059*7c478bd9Sstevel@tonic-gate pt_xd_utsname(mdb_tgt_t *t, void *buf, size_t nbytes) 5060*7c478bd9Sstevel@tonic-gate { 5061*7c478bd9Sstevel@tonic-gate struct utsname uts; 5062*7c478bd9Sstevel@tonic-gate 5063*7c478bd9Sstevel@tonic-gate if (buf == NULL && nbytes == 0) 5064*7c478bd9Sstevel@tonic-gate return (sizeof (struct utsname)); 5065*7c478bd9Sstevel@tonic-gate 5066*7c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL || Puname(t->t_pshandle, &uts) != 0) 5067*7c478bd9Sstevel@tonic-gate return (set_errno(ENODATA)); 5068*7c478bd9Sstevel@tonic-gate 5069*7c478bd9Sstevel@tonic-gate nbytes = MIN(nbytes, sizeof (struct utsname)); 5070*7c478bd9Sstevel@tonic-gate bcopy(&uts, buf, nbytes); 5071*7c478bd9Sstevel@tonic-gate return (nbytes); 5072*7c478bd9Sstevel@tonic-gate } 5073*7c478bd9Sstevel@tonic-gate 5074*7c478bd9Sstevel@tonic-gate int 5075*7c478bd9Sstevel@tonic-gate mdb_proc_tgt_create(mdb_tgt_t *t, int argc, const char *argv[]) 5076*7c478bd9Sstevel@tonic-gate { 5077*7c478bd9Sstevel@tonic-gate pt_data_t *pt = mdb_zalloc(sizeof (pt_data_t), UM_SLEEP); 5078*7c478bd9Sstevel@tonic-gate 5079*7c478bd9Sstevel@tonic-gate const char *aout_path = argc > 0 ? argv[0] : PT_EXEC_PATH; 5080*7c478bd9Sstevel@tonic-gate const char *core_path = argc > 1 ? argv[1] : NULL; 5081*7c478bd9Sstevel@tonic-gate 5082*7c478bd9Sstevel@tonic-gate const mdb_tgt_regdesc_t *rdp; 5083*7c478bd9Sstevel@tonic-gate char execname[MAXPATHLEN]; 5084*7c478bd9Sstevel@tonic-gate struct stat64 st; 5085*7c478bd9Sstevel@tonic-gate int perr; 5086*7c478bd9Sstevel@tonic-gate int state; 5087*7c478bd9Sstevel@tonic-gate struct rlimit rlim; 5088*7c478bd9Sstevel@tonic-gate int i; 5089*7c478bd9Sstevel@tonic-gate 5090*7c478bd9Sstevel@tonic-gate if (argc > 2) { 5091*7c478bd9Sstevel@tonic-gate mdb_free(pt, sizeof (pt_data_t)); 5092*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 5093*7c478bd9Sstevel@tonic-gate } 5094*7c478bd9Sstevel@tonic-gate 5095*7c478bd9Sstevel@tonic-gate if (t->t_flags & MDB_TGT_F_RDWR) 5096*7c478bd9Sstevel@tonic-gate pt->p_oflags = O_RDWR; 5097*7c478bd9Sstevel@tonic-gate else 5098*7c478bd9Sstevel@tonic-gate pt->p_oflags = O_RDONLY; 5099*7c478bd9Sstevel@tonic-gate 5100*7c478bd9Sstevel@tonic-gate if (t->t_flags & MDB_TGT_F_FORCE) 5101*7c478bd9Sstevel@tonic-gate pt->p_gflags |= PGRAB_FORCE; 5102*7c478bd9Sstevel@tonic-gate if (t->t_flags & MDB_TGT_F_NOSTOP) 5103*7c478bd9Sstevel@tonic-gate pt->p_gflags |= PGRAB_NOSTOP; 5104*7c478bd9Sstevel@tonic-gate 5105*7c478bd9Sstevel@tonic-gate pt->p_ptl_ops = &proc_lwp_ops; 5106*7c478bd9Sstevel@tonic-gate pt->p_maxsig = sysconf(_SC_SIGRT_MAX); 5107*7c478bd9Sstevel@tonic-gate 5108*7c478bd9Sstevel@tonic-gate (void) mdb_nv_create(&pt->p_regs, UM_SLEEP); 5109*7c478bd9Sstevel@tonic-gate (void) mdb_nv_create(&pt->p_env, UM_SLEEP); 5110*7c478bd9Sstevel@tonic-gate 5111*7c478bd9Sstevel@tonic-gate t->t_ops = &proc_ops; 5112*7c478bd9Sstevel@tonic-gate t->t_data = pt; 5113*7c478bd9Sstevel@tonic-gate 5114*7c478bd9Sstevel@tonic-gate /* 5115*7c478bd9Sstevel@tonic-gate * If no core file name was specified, but the file ./core is present, 5116*7c478bd9Sstevel@tonic-gate * infer that we want to debug it. I find this behavior confusing, 5117*7c478bd9Sstevel@tonic-gate * so we only do this when precise adb(1) compatibility is required. 5118*7c478bd9Sstevel@tonic-gate */ 5119*7c478bd9Sstevel@tonic-gate if (core_path == NULL && (mdb.m_flags & MDB_FL_ADB) && 5120*7c478bd9Sstevel@tonic-gate access(PT_CORE_PATH, F_OK) == 0) 5121*7c478bd9Sstevel@tonic-gate core_path = PT_CORE_PATH; 5122*7c478bd9Sstevel@tonic-gate 5123*7c478bd9Sstevel@tonic-gate /* 5124*7c478bd9Sstevel@tonic-gate * For compatibility with adb(1), the special name "-" may be used 5125*7c478bd9Sstevel@tonic-gate * to suppress the loading of the executable or core file. 5126*7c478bd9Sstevel@tonic-gate */ 5127*7c478bd9Sstevel@tonic-gate if (aout_path != NULL && strcmp(aout_path, "-") == 0) 5128*7c478bd9Sstevel@tonic-gate aout_path = NULL; 5129*7c478bd9Sstevel@tonic-gate if (core_path != NULL && strcmp(core_path, "-") == 0) 5130*7c478bd9Sstevel@tonic-gate core_path = NULL; 5131*7c478bd9Sstevel@tonic-gate 5132*7c478bd9Sstevel@tonic-gate /* 5133*7c478bd9Sstevel@tonic-gate * If a core file or pid was specified, attempt to grab it now using 5134*7c478bd9Sstevel@tonic-gate * proc_arg_grab(); otherwise we'll create a fresh process later. 5135*7c478bd9Sstevel@tonic-gate */ 5136*7c478bd9Sstevel@tonic-gate if (core_path != NULL && (t->t_pshandle = proc_arg_xgrab(core_path, 5137*7c478bd9Sstevel@tonic-gate aout_path == PT_EXEC_PATH ? NULL : aout_path, PR_ARG_ANY, 5138*7c478bd9Sstevel@tonic-gate pt->p_gflags, &perr, NULL)) == NULL) { 5139*7c478bd9Sstevel@tonic-gate mdb_warn("cannot debug %s: %s\n", core_path, Pgrab_error(perr)); 5140*7c478bd9Sstevel@tonic-gate goto err; 5141*7c478bd9Sstevel@tonic-gate } 5142*7c478bd9Sstevel@tonic-gate 5143*7c478bd9Sstevel@tonic-gate if (aout_path != NULL && 5144*7c478bd9Sstevel@tonic-gate (pt->p_idlehandle = Pgrab_file(aout_path, &perr)) != NULL && 5145*7c478bd9Sstevel@tonic-gate t->t_pshandle == NULL) 5146*7c478bd9Sstevel@tonic-gate t->t_pshandle = pt->p_idlehandle; 5147*7c478bd9Sstevel@tonic-gate 5148*7c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL) 5149*7c478bd9Sstevel@tonic-gate state = Pstate(t->t_pshandle); 5150*7c478bd9Sstevel@tonic-gate 5151*7c478bd9Sstevel@tonic-gate /* 5152*7c478bd9Sstevel@tonic-gate * Make sure we'll have enough file descriptors to handle a target 5153*7c478bd9Sstevel@tonic-gate * has many many mappings. 5154*7c478bd9Sstevel@tonic-gate */ 5155*7c478bd9Sstevel@tonic-gate if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) { 5156*7c478bd9Sstevel@tonic-gate rlim.rlim_cur = rlim.rlim_max; 5157*7c478bd9Sstevel@tonic-gate (void) setrlimit(RLIMIT_NOFILE, &rlim); 5158*7c478bd9Sstevel@tonic-gate } 5159*7c478bd9Sstevel@tonic-gate 5160*7c478bd9Sstevel@tonic-gate /* 5161*7c478bd9Sstevel@tonic-gate * If we don't have an executable path or the executable path is the 5162*7c478bd9Sstevel@tonic-gate * /proc/<pid>/object/a.out path, but we now have a libproc handle, 5163*7c478bd9Sstevel@tonic-gate * attempt to derive the executable path using Pexecname(). We need 5164*7c478bd9Sstevel@tonic-gate * to do this in the /proc case in order to open the executable for 5165*7c478bd9Sstevel@tonic-gate * writing because /proc/object/<file> permission are masked with 0555. 5166*7c478bd9Sstevel@tonic-gate * If Pexecname() fails us, fall back to /proc/<pid>/object/a.out. 5167*7c478bd9Sstevel@tonic-gate */ 5168*7c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL && (aout_path == NULL || (stat64(aout_path, 5169*7c478bd9Sstevel@tonic-gate &st) == 0 && strcmp(st.st_fstype, "proc") == 0))) { 5170*7c478bd9Sstevel@tonic-gate GElf_Sym s; 5171*7c478bd9Sstevel@tonic-gate aout_path = Pexecname(t->t_pshandle, execname, MAXPATHLEN); 5172*7c478bd9Sstevel@tonic-gate if (aout_path == NULL && state != PS_DEAD && state != PS_IDLE) { 5173*7c478bd9Sstevel@tonic-gate (void) mdb_iob_snprintf(execname, sizeof (execname), 5174*7c478bd9Sstevel@tonic-gate "/proc/%d/object/a.out", 5175*7c478bd9Sstevel@tonic-gate (int)Pstatus(t->t_pshandle)->pr_pid); 5176*7c478bd9Sstevel@tonic-gate aout_path = execname; 5177*7c478bd9Sstevel@tonic-gate } 5178*7c478bd9Sstevel@tonic-gate if (aout_path == NULL && 5179*7c478bd9Sstevel@tonic-gate Plookup_by_name(t->t_pshandle, "a.out", "_start", &s) != 0) 5180*7c478bd9Sstevel@tonic-gate mdb_warn("warning: failed to infer pathname to " 5181*7c478bd9Sstevel@tonic-gate "executable; symbol table will not be available\n"); 5182*7c478bd9Sstevel@tonic-gate 5183*7c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_TGT, "a.out is %s\n", aout_path); 5184*7c478bd9Sstevel@tonic-gate } 5185*7c478bd9Sstevel@tonic-gate 5186*7c478bd9Sstevel@tonic-gate /* 5187*7c478bd9Sstevel@tonic-gate * Attempt to open the executable file. We only want this operation 5188*7c478bd9Sstevel@tonic-gate * to actually cause the constructor to abort if the executable file 5189*7c478bd9Sstevel@tonic-gate * name was given explicitly. If we defaulted to PT_EXEC_PATH or 5190*7c478bd9Sstevel@tonic-gate * derived the executable using Pexecname, then we want to continue 5191*7c478bd9Sstevel@tonic-gate * along with p_fio and p_file set to NULL. 5192*7c478bd9Sstevel@tonic-gate */ 5193*7c478bd9Sstevel@tonic-gate if (aout_path != NULL && (pt->p_aout_fio = mdb_fdio_create_path(NULL, 5194*7c478bd9Sstevel@tonic-gate aout_path, pt->p_oflags, 0)) == NULL && argc > 0) { 5195*7c478bd9Sstevel@tonic-gate mdb_warn("failed to open %s", aout_path); 5196*7c478bd9Sstevel@tonic-gate goto err; 5197*7c478bd9Sstevel@tonic-gate } 5198*7c478bd9Sstevel@tonic-gate 5199*7c478bd9Sstevel@tonic-gate /* 5200*7c478bd9Sstevel@tonic-gate * Now create an ELF file from the input file, if we have one. Again, 5201*7c478bd9Sstevel@tonic-gate * only abort the constructor if the name was given explicitly. 5202*7c478bd9Sstevel@tonic-gate */ 5203*7c478bd9Sstevel@tonic-gate if (pt->p_aout_fio != NULL && pt_open_aout(t, 5204*7c478bd9Sstevel@tonic-gate mdb_io_hold(pt->p_aout_fio)) == NULL && argc > 0) 5205*7c478bd9Sstevel@tonic-gate goto err; 5206*7c478bd9Sstevel@tonic-gate 5207*7c478bd9Sstevel@tonic-gate /* 5208*7c478bd9Sstevel@tonic-gate * If we've successfully opened an ELF file, select the appropriate 5209*7c478bd9Sstevel@tonic-gate * disassembler based on the ELF header. 5210*7c478bd9Sstevel@tonic-gate */ 5211*7c478bd9Sstevel@tonic-gate if (pt->p_file != NULL) 5212*7c478bd9Sstevel@tonic-gate (void) mdb_dis_select(pt_disasm(&pt->p_file->gf_ehdr)); 5213*7c478bd9Sstevel@tonic-gate else 5214*7c478bd9Sstevel@tonic-gate (void) mdb_dis_select(pt_disasm(NULL)); 5215*7c478bd9Sstevel@tonic-gate 5216*7c478bd9Sstevel@tonic-gate /* 5217*7c478bd9Sstevel@tonic-gate * Add each register described in the target ISA register description 5218*7c478bd9Sstevel@tonic-gate * list to our hash table of register descriptions and then add any 5219*7c478bd9Sstevel@tonic-gate * appropriate ISA-specific floating-point register descriptions. 5220*7c478bd9Sstevel@tonic-gate */ 5221*7c478bd9Sstevel@tonic-gate for (rdp = pt_regdesc; rdp->rd_name != NULL; rdp++) { 5222*7c478bd9Sstevel@tonic-gate (void) mdb_nv_insert(&pt->p_regs, rdp->rd_name, NULL, 5223*7c478bd9Sstevel@tonic-gate MDB_TGT_R_NVAL(rdp->rd_num, rdp->rd_flags), MDB_NV_RDONLY); 5224*7c478bd9Sstevel@tonic-gate } 5225*7c478bd9Sstevel@tonic-gate pt_addfpregs(t); 5226*7c478bd9Sstevel@tonic-gate 5227*7c478bd9Sstevel@tonic-gate /* 5228*7c478bd9Sstevel@tonic-gate * Certain important /proc structures may be of interest to mdb 5229*7c478bd9Sstevel@tonic-gate * modules and their dcmds. Export these using the xdata interface: 5230*7c478bd9Sstevel@tonic-gate */ 5231*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_xdata_insert(t, "auxv", 5232*7c478bd9Sstevel@tonic-gate "procfs auxv_t array", pt_xd_auxv); 5233*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_xdata_insert(t, "cred", 5234*7c478bd9Sstevel@tonic-gate "procfs prcred_t structure", pt_xd_cred); 5235*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_xdata_insert(t, "ehdr", 5236*7c478bd9Sstevel@tonic-gate "executable file GElf_Ehdr structure", pt_xd_ehdr); 5237*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_xdata_insert(t, "lwpstatus", 5238*7c478bd9Sstevel@tonic-gate "procfs lwpstatus_t array", pt_xd_lwpstatus); 5239*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_xdata_insert(t, "pshandle", 5240*7c478bd9Sstevel@tonic-gate "libproc proc service API handle", pt_xd_pshandle); 5241*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_xdata_insert(t, "psinfo", 5242*7c478bd9Sstevel@tonic-gate "procfs psinfo_t structure", pt_xd_psinfo); 5243*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_xdata_insert(t, "pstatus", 5244*7c478bd9Sstevel@tonic-gate "procfs pstatus_t structure", pt_xd_pstatus); 5245*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_xdata_insert(t, "utsname", 5246*7c478bd9Sstevel@tonic-gate "utsname structure", pt_xd_utsname); 5247*7c478bd9Sstevel@tonic-gate 5248*7c478bd9Sstevel@tonic-gate /* 5249*7c478bd9Sstevel@tonic-gate * Force a status update now so that we fill in t_status with the 5250*7c478bd9Sstevel@tonic-gate * latest information based on any successful grab. 5251*7c478bd9Sstevel@tonic-gate */ 5252*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_status(t, &t->t_status); 5253*7c478bd9Sstevel@tonic-gate 5254*7c478bd9Sstevel@tonic-gate /* 5255*7c478bd9Sstevel@tonic-gate * If we're not examining a core file, trace SIGINT and all signals 5256*7c478bd9Sstevel@tonic-gate * that cause the process to dump core as part of our initialization. 5257*7c478bd9Sstevel@tonic-gate */ 5258*7c478bd9Sstevel@tonic-gate if ((t->t_pshandle != NULL && state != PS_DEAD && state != PS_IDLE) || 5259*7c478bd9Sstevel@tonic-gate (pt->p_file != NULL && pt->p_file->gf_ehdr.e_type == ET_EXEC)) { 5260*7c478bd9Sstevel@tonic-gate 5261*7c478bd9Sstevel@tonic-gate int tflag = MDB_TGT_SPEC_STICKY; /* default sigs are sticky */ 5262*7c478bd9Sstevel@tonic-gate 5263*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_signal(t, SIGINT, tflag, no_se_f, NULL); 5264*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_signal(t, SIGQUIT, tflag, no_se_f, NULL); 5265*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_signal(t, SIGILL, tflag, no_se_f, NULL); 5266*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_signal(t, SIGTRAP, tflag, no_se_f, NULL); 5267*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_signal(t, SIGABRT, tflag, no_se_f, NULL); 5268*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_signal(t, SIGEMT, tflag, no_se_f, NULL); 5269*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_signal(t, SIGFPE, tflag, no_se_f, NULL); 5270*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_signal(t, SIGBUS, tflag, no_se_f, NULL); 5271*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_signal(t, SIGSEGV, tflag, no_se_f, NULL); 5272*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_signal(t, SIGSYS, tflag, no_se_f, NULL); 5273*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_signal(t, SIGXCPU, tflag, no_se_f, NULL); 5274*7c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_signal(t, SIGXFSZ, tflag, no_se_f, NULL); 5275*7c478bd9Sstevel@tonic-gate } 5276*7c478bd9Sstevel@tonic-gate 5277*7c478bd9Sstevel@tonic-gate /* 5278*7c478bd9Sstevel@tonic-gate * If we've grabbed a live process, establish our initial breakpoints 5279*7c478bd9Sstevel@tonic-gate * and librtld_db agent so we can track rtld activity. If FL_VCREATE 5280*7c478bd9Sstevel@tonic-gate * is set, this process was created by a previous instantiation of 5281*7c478bd9Sstevel@tonic-gate * the debugger, so reset pr_flags to kill it; otherwise we attached 5282*7c478bd9Sstevel@tonic-gate * to an already running process. Pgrab() has already set the PR_RLC 5283*7c478bd9Sstevel@tonic-gate * flag appropriately based on whether the process was stopped when we 5284*7c478bd9Sstevel@tonic-gate * attached. 5285*7c478bd9Sstevel@tonic-gate */ 5286*7c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL && state != PS_DEAD && state != PS_IDLE) { 5287*7c478bd9Sstevel@tonic-gate if (mdb.m_flags & MDB_FL_VCREATE) { 5288*7c478bd9Sstevel@tonic-gate (void) Punsetflags(t->t_pshandle, PR_RLC); 5289*7c478bd9Sstevel@tonic-gate (void) Psetflags(t->t_pshandle, PR_KLC); 5290*7c478bd9Sstevel@tonic-gate pt->p_rflags = PRELEASE_KILL; 5291*7c478bd9Sstevel@tonic-gate } else { 5292*7c478bd9Sstevel@tonic-gate (void) Punsetflags(t->t_pshandle, PR_KLC); 5293*7c478bd9Sstevel@tonic-gate } 5294*7c478bd9Sstevel@tonic-gate pt_post_attach(t); 5295*7c478bd9Sstevel@tonic-gate } 5296*7c478bd9Sstevel@tonic-gate 5297*7c478bd9Sstevel@tonic-gate /* 5298*7c478bd9Sstevel@tonic-gate * Initialize a local copy of the environment, which can be modified 5299*7c478bd9Sstevel@tonic-gate * before running the program. 5300*7c478bd9Sstevel@tonic-gate */ 5301*7c478bd9Sstevel@tonic-gate for (i = 0; mdb.m_env[i] != NULL; i++) 5302*7c478bd9Sstevel@tonic-gate pt_env_set(pt, mdb.m_env[i]); 5303*7c478bd9Sstevel@tonic-gate 5304*7c478bd9Sstevel@tonic-gate /* 5305*7c478bd9Sstevel@tonic-gate * If adb(1) compatibility mode is on, then print the appropriate 5306*7c478bd9Sstevel@tonic-gate * greeting message if we have grabbed a core file. 5307*7c478bd9Sstevel@tonic-gate */ 5308*7c478bd9Sstevel@tonic-gate if ((mdb.m_flags & MDB_FL_ADB) && t->t_pshandle != NULL && 5309*7c478bd9Sstevel@tonic-gate state == PS_DEAD) { 5310*7c478bd9Sstevel@tonic-gate const pstatus_t *psp = Pstatus(t->t_pshandle); 5311*7c478bd9Sstevel@tonic-gate int cursig = psp->pr_lwp.pr_cursig; 5312*7c478bd9Sstevel@tonic-gate char signame[SIG2STR_MAX]; 5313*7c478bd9Sstevel@tonic-gate 5314*7c478bd9Sstevel@tonic-gate mdb_printf("core file = %s -- program ``%s'' on platform %s\n", 5315*7c478bd9Sstevel@tonic-gate core_path, aout_path ? aout_path : "?", pt_platform(t)); 5316*7c478bd9Sstevel@tonic-gate 5317*7c478bd9Sstevel@tonic-gate if (cursig != 0 && sig2str(cursig, signame) == 0) 5318*7c478bd9Sstevel@tonic-gate mdb_printf("SIG%s: %s\n", signame, strsignal(cursig)); 5319*7c478bd9Sstevel@tonic-gate } 5320*7c478bd9Sstevel@tonic-gate 5321*7c478bd9Sstevel@tonic-gate return (0); 5322*7c478bd9Sstevel@tonic-gate 5323*7c478bd9Sstevel@tonic-gate err: 5324*7c478bd9Sstevel@tonic-gate pt_destroy(t); 5325*7c478bd9Sstevel@tonic-gate return (-1); 5326*7c478bd9Sstevel@tonic-gate } 5327