17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5004388ebScasper * Common Development and Distribution License (the "License"). 6004388ebScasper * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 218fd04b83SRoger A. Faulkner 227c478bd9Sstevel@tonic-gate /* 238fd04b83SRoger A. Faulkner * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 268f68126cSBryan Cantrill /* 278f88a51fSJoshua M. Clulow * Copyright 2015 Joyent, Inc. 28255ca53cSPrakash Surya * Copyright (c) 2014 by Delphix. All rights reserved. 298f68126cSBryan Cantrill */ 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate /* 327c478bd9Sstevel@tonic-gate * User Process Target 337c478bd9Sstevel@tonic-gate * 347c478bd9Sstevel@tonic-gate * The user process target is invoked when the -u or -p command-line options 357c478bd9Sstevel@tonic-gate * are used, or when an ELF executable file or ELF core file is specified on 367c478bd9Sstevel@tonic-gate * the command-line. This target is also selected by default when no target 377c478bd9Sstevel@tonic-gate * options are present. In this case, it defaults the executable name to 387c478bd9Sstevel@tonic-gate * "a.out". If no process or core file is currently attached, the target 397c478bd9Sstevel@tonic-gate * functions as a kind of virtual /dev/zero (in accordance with adb(1) 407c478bd9Sstevel@tonic-gate * semantics); reads from the virtual address space return zeroes and writes 417c478bd9Sstevel@tonic-gate * fail silently. The proc target itself is designed as a wrapper around the 427c478bd9Sstevel@tonic-gate * services provided by libproc.so: t->t_pshandle is set to the struct 437c478bd9Sstevel@tonic-gate * ps_prochandle pointer returned as a handle by libproc. The target also 447c478bd9Sstevel@tonic-gate * opens the executable file itself using the MDB GElf services, for 457c478bd9Sstevel@tonic-gate * interpreting the .symtab and .dynsym if no libproc handle has been 467c478bd9Sstevel@tonic-gate * initialized, and for handling i/o to and from the object file. Currently, 477c478bd9Sstevel@tonic-gate * the only ISA-dependent portions of the proc target are the $r and ::fpregs 487c478bd9Sstevel@tonic-gate * dcmds, the callbacks for t_next() and t_step_out(), and the list of named 497c478bd9Sstevel@tonic-gate * registers; these are linked in from the proc_isadep.c file for each ISA and 507c478bd9Sstevel@tonic-gate * called from the common code in this file. 517c478bd9Sstevel@tonic-gate * 527c478bd9Sstevel@tonic-gate * The user process target implements complete user process control using the 537c478bd9Sstevel@tonic-gate * facilities provided by libproc.so. The MDB execution control model and 547c478bd9Sstevel@tonic-gate * an overview of software event management is described in mdb_target.c. The 557c478bd9Sstevel@tonic-gate * proc target implements breakpoints by replacing the instruction of interest 567c478bd9Sstevel@tonic-gate * with a trap instruction, and then restoring the original instruction to step 577c478bd9Sstevel@tonic-gate * over the breakpoint. The idea of replacing program text with instructions 587c478bd9Sstevel@tonic-gate * that transfer control to the debugger dates back as far as 1951 [1]. When 597c478bd9Sstevel@tonic-gate * the target stops, we replace each breakpoint with the original instruction 607c478bd9Sstevel@tonic-gate * as part of the disarm operation. This means that no special processing is 617c478bd9Sstevel@tonic-gate * required for t_vread() because the instrumented instructions will never be 627c478bd9Sstevel@tonic-gate * seen by the debugger once the target stops. Some debuggers have improved 637c478bd9Sstevel@tonic-gate * start/stop performance by leaving breakpoint traps in place and then 647c478bd9Sstevel@tonic-gate * handling a read from a breakpoint address as a special case. Although this 657c478bd9Sstevel@tonic-gate * improves efficiency for a source-level debugger, it runs somewhat contrary 667c478bd9Sstevel@tonic-gate * to the philosophy of the low-level debugger. Since we remove the 677c478bd9Sstevel@tonic-gate * instructions, users can apply other external debugging tools to the process 687c478bd9Sstevel@tonic-gate * once it has stopped (e.g. the proc(1) tools) and not be misled by MDB 697c478bd9Sstevel@tonic-gate * instrumentation. The tracing of faults, signals, system calls, and 707c478bd9Sstevel@tonic-gate * watchpoints and general process inspection is implemented directly using 717c478bd9Sstevel@tonic-gate * the mechanisms provided by /proc, as described originally in [2] and [3]. 727c478bd9Sstevel@tonic-gate * 737c478bd9Sstevel@tonic-gate * References 747c478bd9Sstevel@tonic-gate * 757c478bd9Sstevel@tonic-gate * [1] S. Gill, "The Diagnosis Of Mistakes In Programmes on the EDSAC", 767c478bd9Sstevel@tonic-gate * Proceedings of the Royal Society Series A Mathematical and Physical 777c478bd9Sstevel@tonic-gate * Sciences, Cambridge University Press, 206(1087), May 1951, pp. 538-554. 787c478bd9Sstevel@tonic-gate * 797c478bd9Sstevel@tonic-gate * [2] T.J. Killian, "Processes as Files", Proceedings of the USENIX Association 807c478bd9Sstevel@tonic-gate * Summer Conference, Salt Lake City, June 1984, pp. 203-207. 817c478bd9Sstevel@tonic-gate * 827c478bd9Sstevel@tonic-gate * [3] Roger Faulkner and Ron Gomes, "The Process File System and Process 837c478bd9Sstevel@tonic-gate * Model in UNIX System V", Proceedings of the USENIX Association 847c478bd9Sstevel@tonic-gate * Winter Conference, Dallas, January 1991, pp. 243-252. 857c478bd9Sstevel@tonic-gate */ 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate #include <mdb/mdb_proc.h> 887c478bd9Sstevel@tonic-gate #include <mdb/mdb_disasm.h> 897c478bd9Sstevel@tonic-gate #include <mdb/mdb_signal.h> 907c478bd9Sstevel@tonic-gate #include <mdb/mdb_string.h> 917c478bd9Sstevel@tonic-gate #include <mdb/mdb_module.h> 927c478bd9Sstevel@tonic-gate #include <mdb/mdb_debug.h> 937c478bd9Sstevel@tonic-gate #include <mdb/mdb_conf.h> 947c478bd9Sstevel@tonic-gate #include <mdb/mdb_err.h> 957c478bd9Sstevel@tonic-gate #include <mdb/mdb_types.h> 967c478bd9Sstevel@tonic-gate #include <mdb/mdb.h> 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate #include <sys/utsname.h> 997c478bd9Sstevel@tonic-gate #include <sys/wait.h> 1007c478bd9Sstevel@tonic-gate #include <sys/stat.h> 1017c478bd9Sstevel@tonic-gate #include <termio.h> 1027c478bd9Sstevel@tonic-gate #include <signal.h> 103004388ebScasper #include <stdio_ext.h> 1047c478bd9Sstevel@tonic-gate #include <stdlib.h> 1057c478bd9Sstevel@tonic-gate #include <string.h> 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate #define PC_FAKE -1UL /* illegal pc value unequal 0 */ 108*f68770eaSRobert Mustacchi #define PANIC_BUFSIZE 1024 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate static const char PT_EXEC_PATH[] = "a.out"; /* Default executable */ 1117c478bd9Sstevel@tonic-gate static const char PT_CORE_PATH[] = "core"; /* Default core file */ 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate static const pt_ptl_ops_t proc_lwp_ops; 1147c478bd9Sstevel@tonic-gate static const pt_ptl_ops_t proc_tdb_ops; 1157c478bd9Sstevel@tonic-gate static const mdb_se_ops_t proc_brkpt_ops; 1167c478bd9Sstevel@tonic-gate static const mdb_se_ops_t proc_wapt_ops; 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate static int pt_setrun(mdb_tgt_t *, mdb_tgt_status_t *, int); 1197c478bd9Sstevel@tonic-gate static void pt_activate_common(mdb_tgt_t *); 1207c478bd9Sstevel@tonic-gate static mdb_tgt_vespec_f pt_ignore_sig; 1217c478bd9Sstevel@tonic-gate static mdb_tgt_se_f pt_fork; 1227c478bd9Sstevel@tonic-gate static mdb_tgt_se_f pt_exec; 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate static int pt_lookup_by_name_thr(mdb_tgt_t *, const char *, 1257c478bd9Sstevel@tonic-gate const char *, GElf_Sym *, mdb_syminfo_t *, mdb_tgt_tid_t); 1267c478bd9Sstevel@tonic-gate static int tlsbase(mdb_tgt_t *, mdb_tgt_tid_t, Lmid_t, const char *, 1277c478bd9Sstevel@tonic-gate psaddr_t *); 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate /* 1308f68126cSBryan Cantrill * When debugging postmortem, we don't resolve names as we may very well not 1318f68126cSBryan Cantrill * be on a system on which those names resolve. 1328f68126cSBryan Cantrill */ 1338f68126cSBryan Cantrill #define PT_LIBPROC_RESOLVE(P) \ 1348f68126cSBryan Cantrill (!(mdb.m_flags & MDB_FL_LMRAW) && Pstate(P) != PS_DEAD) 1358f68126cSBryan Cantrill 1368f68126cSBryan Cantrill /* 1377c478bd9Sstevel@tonic-gate * The Perror_printf() function interposes on the default, empty libproc 1387c478bd9Sstevel@tonic-gate * definition. It will be called to report additional information on complex 1397c478bd9Sstevel@tonic-gate * errors, such as a corrupt core file. We just pass the args to vwarn. 1407c478bd9Sstevel@tonic-gate */ 1417c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1427c478bd9Sstevel@tonic-gate void 1437c478bd9Sstevel@tonic-gate Perror_printf(struct ps_prochandle *P, const char *format, ...) 1447c478bd9Sstevel@tonic-gate { 1457c478bd9Sstevel@tonic-gate va_list alist; 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate va_start(alist, format); 1487c478bd9Sstevel@tonic-gate vwarn(format, alist); 1497c478bd9Sstevel@tonic-gate va_end(alist); 1507c478bd9Sstevel@tonic-gate } 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate /* 1537c478bd9Sstevel@tonic-gate * Open the specified i/o backend as the a.out executable file, and attempt to 1547c478bd9Sstevel@tonic-gate * load its standard and dynamic symbol tables. Note that if mdb_gelf_create 1557c478bd9Sstevel@tonic-gate * succeeds, io is assigned to p_fio and is automatically held by gelf_create. 1567c478bd9Sstevel@tonic-gate */ 1577c478bd9Sstevel@tonic-gate static mdb_gelf_file_t * 1587c478bd9Sstevel@tonic-gate pt_open_aout(mdb_tgt_t *t, mdb_io_t *io) 1597c478bd9Sstevel@tonic-gate { 1607c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 1617c478bd9Sstevel@tonic-gate GElf_Sym s1, s2; 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate if ((pt->p_file = mdb_gelf_create(io, ET_NONE, GF_FILE)) == NULL) 1647c478bd9Sstevel@tonic-gate return (NULL); 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate pt->p_symtab = mdb_gelf_symtab_create_file(pt->p_file, 1677c478bd9Sstevel@tonic-gate SHT_SYMTAB, MDB_TGT_SYMTAB); 1687c478bd9Sstevel@tonic-gate pt->p_dynsym = mdb_gelf_symtab_create_file(pt->p_file, 1697c478bd9Sstevel@tonic-gate SHT_DYNSYM, MDB_TGT_DYNSYM); 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate /* 1727c478bd9Sstevel@tonic-gate * If we've got an _start symbol with a zero size, prime the private 1737c478bd9Sstevel@tonic-gate * symbol table with a copy of _start with its size set to the distance 1747c478bd9Sstevel@tonic-gate * between _mcount and _start. We do this because DevPro has shipped 1757c478bd9Sstevel@tonic-gate * the Intel crt1.o without proper .size directives for years, which 1767c478bd9Sstevel@tonic-gate * precludes proper identification of _start in stack traces. 1777c478bd9Sstevel@tonic-gate */ 1787c478bd9Sstevel@tonic-gate if (mdb_gelf_symtab_lookup_by_name(pt->p_dynsym, "_start", &s1, 1797c478bd9Sstevel@tonic-gate NULL) == 0 && s1.st_size == 0 && 1807c478bd9Sstevel@tonic-gate GELF_ST_TYPE(s1.st_info) == STT_FUNC) { 1817c478bd9Sstevel@tonic-gate if (mdb_gelf_symtab_lookup_by_name(pt->p_dynsym, "_mcount", 1827c478bd9Sstevel@tonic-gate &s2, NULL) == 0 && GELF_ST_TYPE(s2.st_info) == STT_FUNC) { 1837c478bd9Sstevel@tonic-gate s1.st_size = s2.st_value - s1.st_value; 1847c478bd9Sstevel@tonic-gate mdb_gelf_symtab_insert(mdb.m_prsym, "_start", &s1); 1857c478bd9Sstevel@tonic-gate } 1867c478bd9Sstevel@tonic-gate } 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate pt->p_fio = io; 1897c478bd9Sstevel@tonic-gate return (pt->p_file); 1907c478bd9Sstevel@tonic-gate } 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate /* 1937c478bd9Sstevel@tonic-gate * Destroy the symbol tables and GElf file object associated with p_fio. Note 1947c478bd9Sstevel@tonic-gate * that we do not need to explicitly free p_fio: its reference count is 1957c478bd9Sstevel@tonic-gate * automatically decremented by mdb_gelf_destroy, which will free it if needed. 1967c478bd9Sstevel@tonic-gate */ 1977c478bd9Sstevel@tonic-gate static void 1987c478bd9Sstevel@tonic-gate pt_close_aout(mdb_tgt_t *t) 1997c478bd9Sstevel@tonic-gate { 2007c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 2017c478bd9Sstevel@tonic-gate 2027c478bd9Sstevel@tonic-gate if (pt->p_symtab != NULL) { 2037c478bd9Sstevel@tonic-gate mdb_gelf_symtab_destroy(pt->p_symtab); 2047c478bd9Sstevel@tonic-gate pt->p_symtab = NULL; 2057c478bd9Sstevel@tonic-gate } 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate if (pt->p_dynsym != NULL) { 2087c478bd9Sstevel@tonic-gate mdb_gelf_symtab_destroy(pt->p_dynsym); 2097c478bd9Sstevel@tonic-gate pt->p_dynsym = NULL; 2107c478bd9Sstevel@tonic-gate } 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate if (pt->p_file != NULL) { 2137c478bd9Sstevel@tonic-gate mdb_gelf_destroy(pt->p_file); 2147c478bd9Sstevel@tonic-gate pt->p_file = NULL; 2157c478bd9Sstevel@tonic-gate } 2167c478bd9Sstevel@tonic-gate 2177c478bd9Sstevel@tonic-gate mdb_gelf_symtab_delete(mdb.m_prsym, "_start", NULL); 2187c478bd9Sstevel@tonic-gate pt->p_fio = NULL; 2197c478bd9Sstevel@tonic-gate } 2207c478bd9Sstevel@tonic-gate 22195d62a61SEdward Pilatowicz typedef struct tdb_mapping { 22295d62a61SEdward Pilatowicz const char *tm_thr_lib; 22395d62a61SEdward Pilatowicz const char *tm_db_dir; 22495d62a61SEdward Pilatowicz const char *tm_db_name; 22595d62a61SEdward Pilatowicz } tdb_mapping_t; 22695d62a61SEdward Pilatowicz 22795d62a61SEdward Pilatowicz static const tdb_mapping_t tdb_map[] = { 22895d62a61SEdward Pilatowicz { "/lwp/amd64/libthread.so", "/usr/lib/lwp/", "libthread_db.so" }, 22995d62a61SEdward Pilatowicz { "/lwp/sparcv9/libthread.so", "/usr/lib/lwp/", "libthread_db.so" }, 23095d62a61SEdward Pilatowicz { "/lwp/libthread.so", "/usr/lib/lwp/", "libthread_db.so" }, 23195d62a61SEdward Pilatowicz { "/libthread.so", "/lib/", "libthread_db.so" }, 23295d62a61SEdward Pilatowicz { "/libc_hwcap", "/lib/", "libc_db.so" }, 23395d62a61SEdward Pilatowicz { "/libc.so", "/lib/", "libc_db.so" } 23495d62a61SEdward Pilatowicz }; 23595d62a61SEdward Pilatowicz 2367c478bd9Sstevel@tonic-gate /* 2377c478bd9Sstevel@tonic-gate * Pobject_iter callback that we use to search for the presence of libthread in 2387c478bd9Sstevel@tonic-gate * order to load the corresponding libthread_db support. We derive the 2397c478bd9Sstevel@tonic-gate * libthread_db path dynamically based on the libthread path. If libthread is 2407c478bd9Sstevel@tonic-gate * found, this function returns 1 (and thus Pobject_iter aborts and returns 1) 2417c478bd9Sstevel@tonic-gate * regardless of whether it was successful in loading the libthread_db support. 2427c478bd9Sstevel@tonic-gate * If we iterate over all objects and no libthread is found, 0 is returned. 2437c478bd9Sstevel@tonic-gate * Since libthread_db support was then merged into libc_db, we load either 2447c478bd9Sstevel@tonic-gate * libc_db or libthread_db, depending on which library we see first. 2457c478bd9Sstevel@tonic-gate */ 2467c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2477c478bd9Sstevel@tonic-gate static int 2487c478bd9Sstevel@tonic-gate thr_check(mdb_tgt_t *t, const prmap_t *pmp, const char *name) 2497c478bd9Sstevel@tonic-gate { 2507c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 2517c478bd9Sstevel@tonic-gate const mdb_tdb_ops_t *ops; 25295d62a61SEdward Pilatowicz char *p; 2537c478bd9Sstevel@tonic-gate 25495d62a61SEdward Pilatowicz char path[MAXPATHLEN]; 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate int libn; 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate if (name == NULL) 2597c478bd9Sstevel@tonic-gate return (0); /* no rtld_db object name; keep going */ 2607c478bd9Sstevel@tonic-gate 26195d62a61SEdward Pilatowicz for (libn = 0; libn < sizeof (tdb_map) / sizeof (tdb_map[0]); libn++) { 26295d62a61SEdward Pilatowicz if ((p = strstr(name, tdb_map[libn].tm_thr_lib)) != NULL) 2637c478bd9Sstevel@tonic-gate break; 2647c478bd9Sstevel@tonic-gate } 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate if (p == NULL) 2677c478bd9Sstevel@tonic-gate return (0); /* no match; keep going */ 2687c478bd9Sstevel@tonic-gate 26995d62a61SEdward Pilatowicz path[0] = '\0'; 27095d62a61SEdward Pilatowicz (void) strlcat(path, mdb.m_root, sizeof (path)); 27195d62a61SEdward Pilatowicz (void) strlcat(path, tdb_map[libn].tm_db_dir, sizeof (path)); 27295d62a61SEdward Pilatowicz #if !defined(_ILP32) 27395d62a61SEdward Pilatowicz (void) strlcat(path, "64/", sizeof (path)); 27495d62a61SEdward Pilatowicz #endif /* !_ILP32 */ 27595d62a61SEdward Pilatowicz (void) strlcat(path, tdb_map[libn].tm_db_name, sizeof (path)); 2767c478bd9Sstevel@tonic-gate 27795d62a61SEdward Pilatowicz /* Append the trailing library version number. */ 27895d62a61SEdward Pilatowicz (void) strlcat(path, strrchr(name, '.'), sizeof (path)); 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate if ((ops = mdb_tdb_load(path)) == NULL) { 2817c478bd9Sstevel@tonic-gate if (libn != 0 || errno != ENOENT) 2827c478bd9Sstevel@tonic-gate warn("failed to load %s", path); 2837c478bd9Sstevel@tonic-gate goto err; 2847c478bd9Sstevel@tonic-gate } 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate if (ops == pt->p_tdb_ops) 2877c478bd9Sstevel@tonic-gate return (1); /* no changes needed */ 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate PTL_DTOR(t); 2907c478bd9Sstevel@tonic-gate pt->p_tdb_ops = ops; 2917c478bd9Sstevel@tonic-gate pt->p_ptl_ops = &proc_tdb_ops; 2927c478bd9Sstevel@tonic-gate pt->p_ptl_hdl = NULL; 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate if (PTL_CTOR(t) == -1) { 2957c478bd9Sstevel@tonic-gate warn("failed to initialize %s", path); 2967c478bd9Sstevel@tonic-gate goto err; 2977c478bd9Sstevel@tonic-gate } 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_TGT, "loaded %s for debugging %s\n", path, name); 3007c478bd9Sstevel@tonic-gate (void) mdb_tgt_status(t, &t->t_status); 3017c478bd9Sstevel@tonic-gate return (1); 3027c478bd9Sstevel@tonic-gate err: 3037c478bd9Sstevel@tonic-gate PTL_DTOR(t); 3047c478bd9Sstevel@tonic-gate pt->p_tdb_ops = NULL; 3057c478bd9Sstevel@tonic-gate pt->p_ptl_ops = &proc_lwp_ops; 3067c478bd9Sstevel@tonic-gate pt->p_ptl_hdl = NULL; 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate if (libn != 0 || errno != ENOENT) { 3097c478bd9Sstevel@tonic-gate warn("warning: debugger will only be able to " 3107c478bd9Sstevel@tonic-gate "examine raw LWPs\n"); 3117c478bd9Sstevel@tonic-gate } 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate (void) mdb_tgt_status(t, &t->t_status); 3147c478bd9Sstevel@tonic-gate return (1); 3157c478bd9Sstevel@tonic-gate } 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate /* 3187c478bd9Sstevel@tonic-gate * Whenever the link map is consistent following an add or delete event, we ask 3197c478bd9Sstevel@tonic-gate * libproc to update its mappings, check to see if we need to load libthread_db, 3207c478bd9Sstevel@tonic-gate * and then update breakpoints which have been mapped or unmapped. 3217c478bd9Sstevel@tonic-gate */ 3227c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3237c478bd9Sstevel@tonic-gate static void 3247c478bd9Sstevel@tonic-gate pt_rtld_event(mdb_tgt_t *t, int vid, void *private) 3257c478bd9Sstevel@tonic-gate { 3267c478bd9Sstevel@tonic-gate struct ps_prochandle *P = t->t_pshandle; 3277c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 3287c478bd9Sstevel@tonic-gate rd_event_msg_t rdm; 32995d62a61SEdward Pilatowicz int docontinue = 1; 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate if (rd_event_getmsg(pt->p_rtld, &rdm) == RD_OK) { 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_TGT, "rtld event type 0x%x state 0x%x\n", 3347c478bd9Sstevel@tonic-gate rdm.type, rdm.u.state); 3357c478bd9Sstevel@tonic-gate 3367c478bd9Sstevel@tonic-gate if (rdm.type == RD_DLACTIVITY && rdm.u.state == RD_CONSISTENT) { 3377c478bd9Sstevel@tonic-gate mdb_sespec_t *sep, *nsep = mdb_list_next(&t->t_active); 3387c478bd9Sstevel@tonic-gate pt_brkpt_t *ptb; 3397c478bd9Sstevel@tonic-gate 3407c478bd9Sstevel@tonic-gate Pupdate_maps(P); 3417c478bd9Sstevel@tonic-gate 34295d62a61SEdward Pilatowicz if (Pobject_iter(P, (proc_map_f *)thr_check, t) == 0 && 34395d62a61SEdward Pilatowicz pt->p_ptl_ops != &proc_lwp_ops) { 3447c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_TGT, "unloading thread_db " 3457c478bd9Sstevel@tonic-gate "support after dlclose\n"); 3467c478bd9Sstevel@tonic-gate PTL_DTOR(t); 3477c478bd9Sstevel@tonic-gate pt->p_tdb_ops = NULL; 3487c478bd9Sstevel@tonic-gate pt->p_ptl_ops = &proc_lwp_ops; 3497c478bd9Sstevel@tonic-gate pt->p_ptl_hdl = NULL; 3507c478bd9Sstevel@tonic-gate (void) mdb_tgt_status(t, &t->t_status); 3517c478bd9Sstevel@tonic-gate } 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate for (sep = nsep; sep != NULL; sep = nsep) { 3547c478bd9Sstevel@tonic-gate nsep = mdb_list_next(sep); 3557c478bd9Sstevel@tonic-gate ptb = sep->se_data; 3567c478bd9Sstevel@tonic-gate 3577c478bd9Sstevel@tonic-gate if (sep->se_ops == &proc_brkpt_ops && 3587c478bd9Sstevel@tonic-gate Paddr_to_map(P, ptb->ptb_addr) == NULL) 3597c478bd9Sstevel@tonic-gate mdb_tgt_sespec_idle_one(t, sep, 3607c478bd9Sstevel@tonic-gate EMDB_NOMAP); 3617c478bd9Sstevel@tonic-gate } 3627c478bd9Sstevel@tonic-gate 3637c478bd9Sstevel@tonic-gate if (!mdb_tgt_sespec_activate_all(t) && 3647c478bd9Sstevel@tonic-gate (mdb.m_flags & MDB_FL_BPTNOSYMSTOP) && 3657c478bd9Sstevel@tonic-gate pt->p_rtld_finished) { 3667c478bd9Sstevel@tonic-gate /* 3677c478bd9Sstevel@tonic-gate * We weren't able to activate the breakpoints. 3687c478bd9Sstevel@tonic-gate * If so requested, we'll return without 3697c478bd9Sstevel@tonic-gate * calling continue, thus throwing the user into 3707c478bd9Sstevel@tonic-gate * the debugger. 3717c478bd9Sstevel@tonic-gate */ 3727c478bd9Sstevel@tonic-gate docontinue = 0; 3737c478bd9Sstevel@tonic-gate } 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate if (pt->p_rdstate == PT_RD_ADD) 3767c478bd9Sstevel@tonic-gate pt->p_rdstate = PT_RD_CONSIST; 3777c478bd9Sstevel@tonic-gate } 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate if (rdm.type == RD_PREINIT) 3807c478bd9Sstevel@tonic-gate (void) mdb_tgt_sespec_activate_all(t); 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate if (rdm.type == RD_POSTINIT) { 3837c478bd9Sstevel@tonic-gate pt->p_rtld_finished = TRUE; 3847c478bd9Sstevel@tonic-gate if (!mdb_tgt_sespec_activate_all(t) && 3857c478bd9Sstevel@tonic-gate (mdb.m_flags & MDB_FL_BPTNOSYMSTOP)) { 3867c478bd9Sstevel@tonic-gate /* 3877c478bd9Sstevel@tonic-gate * Now that rtld has been initialized, we 3887c478bd9Sstevel@tonic-gate * should be able to initialize all deferred 3897c478bd9Sstevel@tonic-gate * breakpoints. If we can't, don't let the 3907c478bd9Sstevel@tonic-gate * target continue. 3917c478bd9Sstevel@tonic-gate */ 3927c478bd9Sstevel@tonic-gate docontinue = 0; 3937c478bd9Sstevel@tonic-gate } 3947c478bd9Sstevel@tonic-gate } 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate if (rdm.type == RD_DLACTIVITY && rdm.u.state == RD_ADD && 3977c478bd9Sstevel@tonic-gate pt->p_rtld_finished) 3987c478bd9Sstevel@tonic-gate pt->p_rdstate = MAX(pt->p_rdstate, PT_RD_ADD); 3997c478bd9Sstevel@tonic-gate } 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate if (docontinue) 4027c478bd9Sstevel@tonic-gate (void) mdb_tgt_continue(t, NULL); 4037c478bd9Sstevel@tonic-gate } 4047c478bd9Sstevel@tonic-gate 4057c478bd9Sstevel@tonic-gate static void 4067c478bd9Sstevel@tonic-gate pt_post_attach(mdb_tgt_t *t) 4077c478bd9Sstevel@tonic-gate { 4087c478bd9Sstevel@tonic-gate struct ps_prochandle *P = t->t_pshandle; 4097c478bd9Sstevel@tonic-gate const lwpstatus_t *psp = &Pstatus(P)->pr_lwp; 4107c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 4117c478bd9Sstevel@tonic-gate int hflag = MDB_TGT_SPEC_HIDDEN; 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_TGT, "attach pr_flags=0x%x pr_why=%d pr_what=%d\n", 4147c478bd9Sstevel@tonic-gate psp->pr_flags, psp->pr_why, psp->pr_what); 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate /* 4177c478bd9Sstevel@tonic-gate * When we grab a process, the initial setting of p_rtld_finished 4187c478bd9Sstevel@tonic-gate * should be false if the process was just created by exec; otherwise 4197c478bd9Sstevel@tonic-gate * we permit unscoped references to resolve because we do not know how 4207c478bd9Sstevel@tonic-gate * far the process has proceeded through linker initialization. 4217c478bd9Sstevel@tonic-gate */ 4227c478bd9Sstevel@tonic-gate if ((psp->pr_flags & PR_ISTOP) && psp->pr_why == PR_SYSEXIT && 4238fd04b83SRoger A. Faulkner psp->pr_errno == 0 && psp->pr_what == SYS_execve) { 4247c478bd9Sstevel@tonic-gate if (mdb.m_target == NULL) { 4257c478bd9Sstevel@tonic-gate warn("target performed exec of %s\n", 4267c478bd9Sstevel@tonic-gate IOP_NAME(pt->p_fio)); 4277c478bd9Sstevel@tonic-gate } 4287c478bd9Sstevel@tonic-gate pt->p_rtld_finished = FALSE; 4297c478bd9Sstevel@tonic-gate } else 4307c478bd9Sstevel@tonic-gate pt->p_rtld_finished = TRUE; 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate /* 4337c478bd9Sstevel@tonic-gate * When we grab a process, if it is stopped by job control and part of 4347c478bd9Sstevel@tonic-gate * the same session (i.e. same controlling tty), set MDB_FL_JOBCTL so 4357c478bd9Sstevel@tonic-gate * we will know to bring it to the foreground when we continue it. 4367c478bd9Sstevel@tonic-gate */ 4377c478bd9Sstevel@tonic-gate if (mdb.m_term != NULL && (psp->pr_flags & PR_STOPPED) && 4387c478bd9Sstevel@tonic-gate psp->pr_why == PR_JOBCONTROL && getsid(0) == Pstatus(P)->pr_sid) 4397c478bd9Sstevel@tonic-gate mdb.m_flags |= MDB_FL_JOBCTL; 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate /* 4427c478bd9Sstevel@tonic-gate * When we grab control of a live process, set F_RDWR so that the 4437c478bd9Sstevel@tonic-gate * target layer permits writes to the target's address space. 4447c478bd9Sstevel@tonic-gate */ 4457c478bd9Sstevel@tonic-gate t->t_flags |= MDB_TGT_F_RDWR; 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate (void) Pfault(P, FLTBPT, TRUE); /* always trace breakpoints */ 4487c478bd9Sstevel@tonic-gate (void) Pfault(P, FLTWATCH, TRUE); /* always trace watchpoints */ 4497c478bd9Sstevel@tonic-gate (void) Pfault(P, FLTTRACE, TRUE); /* always trace single-step */ 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate (void) Punsetflags(P, PR_ASYNC); /* require synchronous mode */ 4527c478bd9Sstevel@tonic-gate (void) Psetflags(P, PR_BPTADJ); /* always adjust eip on x86 */ 4537c478bd9Sstevel@tonic-gate (void) Psetflags(P, PR_FORK); /* inherit tracing on fork */ 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate /* 4567c478bd9Sstevel@tonic-gate * Install event specifiers to track fork and exec activities: 4577c478bd9Sstevel@tonic-gate */ 4587c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_sysexit(t, SYS_vfork, hflag, pt_fork, NULL); 459657b1f3dSraf (void) mdb_tgt_add_sysexit(t, SYS_forksys, hflag, pt_fork, NULL); 4607c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_sysexit(t, SYS_execve, hflag, pt_exec, NULL); 4617c478bd9Sstevel@tonic-gate 4627c478bd9Sstevel@tonic-gate /* 4637c478bd9Sstevel@tonic-gate * Attempt to instantiate the librtld_db agent and set breakpoints 4647c478bd9Sstevel@tonic-gate * to track rtld activity. We will legitimately fail to instantiate 4657c478bd9Sstevel@tonic-gate * the rtld_db agent if the target is statically linked. 4667c478bd9Sstevel@tonic-gate */ 4677c478bd9Sstevel@tonic-gate if (pt->p_rtld == NULL && (pt->p_rtld = Prd_agent(P)) != NULL) { 4687c478bd9Sstevel@tonic-gate rd_notify_t rdn; 4697c478bd9Sstevel@tonic-gate rd_err_e err; 4707c478bd9Sstevel@tonic-gate 4717c478bd9Sstevel@tonic-gate if ((err = rd_event_enable(pt->p_rtld, TRUE)) != RD_OK) { 4727c478bd9Sstevel@tonic-gate warn("failed to enable rtld_db event tracing: %s\n", 4737c478bd9Sstevel@tonic-gate rd_errstr(err)); 4747c478bd9Sstevel@tonic-gate goto out; 4757c478bd9Sstevel@tonic-gate } 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate if ((err = rd_event_addr(pt->p_rtld, RD_PREINIT, 4787c478bd9Sstevel@tonic-gate &rdn)) == RD_OK && rdn.type == RD_NOTIFY_BPT) { 4797c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_vbrkpt(t, rdn.u.bptaddr, 4807c478bd9Sstevel@tonic-gate hflag, pt_rtld_event, NULL); 4817c478bd9Sstevel@tonic-gate } else { 4827c478bd9Sstevel@tonic-gate warn("failed to install rtld_db preinit tracing: %s\n", 4837c478bd9Sstevel@tonic-gate rd_errstr(err)); 4847c478bd9Sstevel@tonic-gate } 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate if ((err = rd_event_addr(pt->p_rtld, RD_POSTINIT, 4877c478bd9Sstevel@tonic-gate &rdn)) == RD_OK && rdn.type == RD_NOTIFY_BPT) { 4887c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_vbrkpt(t, rdn.u.bptaddr, 4897c478bd9Sstevel@tonic-gate hflag, pt_rtld_event, NULL); 4907c478bd9Sstevel@tonic-gate } else { 4917c478bd9Sstevel@tonic-gate warn("failed to install rtld_db postinit tracing: %s\n", 4927c478bd9Sstevel@tonic-gate rd_errstr(err)); 4937c478bd9Sstevel@tonic-gate } 4947c478bd9Sstevel@tonic-gate 4957c478bd9Sstevel@tonic-gate if ((err = rd_event_addr(pt->p_rtld, RD_DLACTIVITY, 4967c478bd9Sstevel@tonic-gate &rdn)) == RD_OK && rdn.type == RD_NOTIFY_BPT) { 4977c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_vbrkpt(t, rdn.u.bptaddr, 4987c478bd9Sstevel@tonic-gate hflag, pt_rtld_event, NULL); 4997c478bd9Sstevel@tonic-gate } else { 5007c478bd9Sstevel@tonic-gate warn("failed to install rtld_db activity tracing: %s\n", 5017c478bd9Sstevel@tonic-gate rd_errstr(err)); 5027c478bd9Sstevel@tonic-gate } 5037c478bd9Sstevel@tonic-gate } 5047c478bd9Sstevel@tonic-gate out: 5057c478bd9Sstevel@tonic-gate Pupdate_maps(P); 5067c478bd9Sstevel@tonic-gate Psync(P); 5077c478bd9Sstevel@tonic-gate 5087c478bd9Sstevel@tonic-gate /* 5097c478bd9Sstevel@tonic-gate * If librtld_db failed to initialize due to an error or because we are 5107c478bd9Sstevel@tonic-gate * debugging a statically linked executable, allow unscoped references. 5117c478bd9Sstevel@tonic-gate */ 5127c478bd9Sstevel@tonic-gate if (pt->p_rtld == NULL) 5137c478bd9Sstevel@tonic-gate pt->p_rtld_finished = TRUE; 5147c478bd9Sstevel@tonic-gate 5157c478bd9Sstevel@tonic-gate (void) mdb_tgt_sespec_activate_all(t); 5167c478bd9Sstevel@tonic-gate } 5177c478bd9Sstevel@tonic-gate 5187c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5197c478bd9Sstevel@tonic-gate static int 5207c478bd9Sstevel@tonic-gate pt_vespec_delete(mdb_tgt_t *t, void *private, int id, void *data) 5217c478bd9Sstevel@tonic-gate { 5227c478bd9Sstevel@tonic-gate if (id < 0) { 5237c478bd9Sstevel@tonic-gate ASSERT(data == NULL); /* we don't use any ve_data */ 5247c478bd9Sstevel@tonic-gate (void) mdb_tgt_vespec_delete(t, id); 5257c478bd9Sstevel@tonic-gate } 5267c478bd9Sstevel@tonic-gate return (0); 5277c478bd9Sstevel@tonic-gate } 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate static void 5307c478bd9Sstevel@tonic-gate pt_pre_detach(mdb_tgt_t *t, int clear_matched) 5317c478bd9Sstevel@tonic-gate { 5327c478bd9Sstevel@tonic-gate const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp; 5337c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 5347c478bd9Sstevel@tonic-gate long cmd = 0; 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate /* 5377c478bd9Sstevel@tonic-gate * If we are about to release the process and it is stopped on a traced 5387c478bd9Sstevel@tonic-gate * SIGINT, breakpoint fault, single-step fault, or watchpoint, make 5397c478bd9Sstevel@tonic-gate * sure to clear this event prior to releasing the process so that it 5407c478bd9Sstevel@tonic-gate * does not subsequently reissue the fault and die from SIGTRAP. 5417c478bd9Sstevel@tonic-gate */ 5427c478bd9Sstevel@tonic-gate if (psp->pr_flags & PR_ISTOP) { 5437c478bd9Sstevel@tonic-gate if (psp->pr_why == PR_FAULTED && (psp->pr_what == FLTBPT || 5447c478bd9Sstevel@tonic-gate psp->pr_what == FLTTRACE || psp->pr_what == FLTWATCH)) 5457c478bd9Sstevel@tonic-gate cmd = PCCFAULT; 5467c478bd9Sstevel@tonic-gate else if (psp->pr_why == PR_SIGNALLED && psp->pr_what == SIGINT) 5477c478bd9Sstevel@tonic-gate cmd = PCCSIG; 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate if (cmd != 0) 5507c478bd9Sstevel@tonic-gate (void) write(Pctlfd(t->t_pshandle), &cmd, sizeof (cmd)); 5517c478bd9Sstevel@tonic-gate } 5527c478bd9Sstevel@tonic-gate 5537c478bd9Sstevel@tonic-gate if (Pstate(t->t_pshandle) == PS_UNDEAD) 5547c478bd9Sstevel@tonic-gate (void) waitpid(Pstatus(t->t_pshandle)->pr_pid, NULL, WNOHANG); 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate (void) mdb_tgt_vespec_iter(t, pt_vespec_delete, NULL); 5577c478bd9Sstevel@tonic-gate mdb_tgt_sespec_idle_all(t, EMDB_NOPROC, clear_matched); 5587c478bd9Sstevel@tonic-gate 5597c478bd9Sstevel@tonic-gate if (pt->p_fio != pt->p_aout_fio) { 5607c478bd9Sstevel@tonic-gate pt_close_aout(t); 5617c478bd9Sstevel@tonic-gate (void) pt_open_aout(t, pt->p_aout_fio); 5627c478bd9Sstevel@tonic-gate } 5637c478bd9Sstevel@tonic-gate 5647c478bd9Sstevel@tonic-gate PTL_DTOR(t); 5657c478bd9Sstevel@tonic-gate pt->p_tdb_ops = NULL; 5667c478bd9Sstevel@tonic-gate pt->p_ptl_ops = &proc_lwp_ops; 5677c478bd9Sstevel@tonic-gate pt->p_ptl_hdl = NULL; 5687c478bd9Sstevel@tonic-gate 5697c478bd9Sstevel@tonic-gate pt->p_rtld = NULL; 5707c478bd9Sstevel@tonic-gate pt->p_signal = 0; 5717c478bd9Sstevel@tonic-gate pt->p_rtld_finished = FALSE; 5727c478bd9Sstevel@tonic-gate pt->p_rdstate = PT_RD_NONE; 5737c478bd9Sstevel@tonic-gate } 5747c478bd9Sstevel@tonic-gate 5757c478bd9Sstevel@tonic-gate static void 5767c478bd9Sstevel@tonic-gate pt_release_parents(mdb_tgt_t *t) 5777c478bd9Sstevel@tonic-gate { 5787c478bd9Sstevel@tonic-gate struct ps_prochandle *P = t->t_pshandle; 5797c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate mdb_sespec_t *sep; 5827c478bd9Sstevel@tonic-gate pt_vforkp_t *vfp; 5837c478bd9Sstevel@tonic-gate 5847c478bd9Sstevel@tonic-gate while ((vfp = mdb_list_next(&pt->p_vforkp)) != NULL) { 5857c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_TGT, "releasing vfork parent %d\n", 5867c478bd9Sstevel@tonic-gate (int)Pstatus(vfp->p_pshandle)->pr_pid); 5877c478bd9Sstevel@tonic-gate 5887c478bd9Sstevel@tonic-gate /* 5897c478bd9Sstevel@tonic-gate * To release vfork parents, we must also wipe out any armed 5907c478bd9Sstevel@tonic-gate * events in the parent by switching t_pshandle and calling 5917c478bd9Sstevel@tonic-gate * se_disarm(). Do not change states or lose the matched list. 5927c478bd9Sstevel@tonic-gate */ 5937c478bd9Sstevel@tonic-gate t->t_pshandle = vfp->p_pshandle; 5947c478bd9Sstevel@tonic-gate 5957c478bd9Sstevel@tonic-gate for (sep = mdb_list_next(&t->t_active); sep != NULL; 5967c478bd9Sstevel@tonic-gate sep = mdb_list_next(sep)) { 5977c478bd9Sstevel@tonic-gate if (sep->se_state == MDB_TGT_SPEC_ARMED) 5987c478bd9Sstevel@tonic-gate (void) sep->se_ops->se_disarm(t, sep); 5997c478bd9Sstevel@tonic-gate } 6007c478bd9Sstevel@tonic-gate 6017c478bd9Sstevel@tonic-gate t->t_pshandle = P; 6027c478bd9Sstevel@tonic-gate 6037c478bd9Sstevel@tonic-gate Prelease(vfp->p_pshandle, PRELEASE_CLEAR); 6047c478bd9Sstevel@tonic-gate mdb_list_delete(&pt->p_vforkp, vfp); 6057c478bd9Sstevel@tonic-gate mdb_free(vfp, sizeof (pt_vforkp_t)); 6067c478bd9Sstevel@tonic-gate } 6077c478bd9Sstevel@tonic-gate } 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6107c478bd9Sstevel@tonic-gate static void 6117c478bd9Sstevel@tonic-gate pt_fork(mdb_tgt_t *t, int vid, void *private) 6127c478bd9Sstevel@tonic-gate { 6137c478bd9Sstevel@tonic-gate struct ps_prochandle *P = t->t_pshandle; 6147c478bd9Sstevel@tonic-gate const lwpstatus_t *psp = &Pstatus(P)->pr_lwp; 6157c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 6167c478bd9Sstevel@tonic-gate mdb_sespec_t *sep; 6177c478bd9Sstevel@tonic-gate 6187c478bd9Sstevel@tonic-gate int follow_parent = mdb.m_forkmode != MDB_FM_CHILD; 619657b1f3dSraf int is_vfork = (psp->pr_what == SYS_vfork || 620657b1f3dSraf (psp->pr_what == SYS_forksys && psp->pr_sysarg[0] == 2)); 6217c478bd9Sstevel@tonic-gate 6227c478bd9Sstevel@tonic-gate struct ps_prochandle *C; 6237c478bd9Sstevel@tonic-gate const lwpstatus_t *csp; 6247c478bd9Sstevel@tonic-gate char sysname[32]; 6257c478bd9Sstevel@tonic-gate int gcode; 6267c478bd9Sstevel@tonic-gate char c; 6277c478bd9Sstevel@tonic-gate 6287c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_TGT, "parent %s: errno=%d rv1=%ld rv2=%ld\n", 6297c478bd9Sstevel@tonic-gate proc_sysname(psp->pr_what, sysname, sizeof (sysname)), 6307c478bd9Sstevel@tonic-gate psp->pr_errno, psp->pr_rval1, psp->pr_rval2); 6317c478bd9Sstevel@tonic-gate 6327c478bd9Sstevel@tonic-gate if (psp->pr_errno != 0) { 6337c478bd9Sstevel@tonic-gate (void) mdb_tgt_continue(t, NULL); 6347c478bd9Sstevel@tonic-gate return; /* fork failed */ 6357c478bd9Sstevel@tonic-gate } 6367c478bd9Sstevel@tonic-gate 6377c478bd9Sstevel@tonic-gate /* 6387c478bd9Sstevel@tonic-gate * If forkmode is ASK and stdout is a terminal, then ask the user to 6397c478bd9Sstevel@tonic-gate * explicitly set the fork behavior for this particular fork. 6407c478bd9Sstevel@tonic-gate */ 6417c478bd9Sstevel@tonic-gate if (mdb.m_forkmode == MDB_FM_ASK && mdb.m_term != NULL) { 6427c478bd9Sstevel@tonic-gate mdb_iob_printf(mdb.m_err, "%s: %s detected: follow (p)arent " 6437c478bd9Sstevel@tonic-gate "or (c)hild? ", mdb.m_pname, sysname); 6447c478bd9Sstevel@tonic-gate mdb_iob_flush(mdb.m_err); 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate while (IOP_READ(mdb.m_term, &c, sizeof (c)) == sizeof (c)) { 6477c478bd9Sstevel@tonic-gate if (c == 'P' || c == 'p') { 6487c478bd9Sstevel@tonic-gate mdb_iob_printf(mdb.m_err, "%c\n", c); 6497c478bd9Sstevel@tonic-gate follow_parent = TRUE; 6507c478bd9Sstevel@tonic-gate break; 6517c478bd9Sstevel@tonic-gate } else if (c == 'C' || c == 'c') { 6527c478bd9Sstevel@tonic-gate mdb_iob_printf(mdb.m_err, "%c\n", c); 6537c478bd9Sstevel@tonic-gate follow_parent = FALSE; 6547c478bd9Sstevel@tonic-gate break; 6557c478bd9Sstevel@tonic-gate } 6567c478bd9Sstevel@tonic-gate } 6577c478bd9Sstevel@tonic-gate } 6587c478bd9Sstevel@tonic-gate 6597c478bd9Sstevel@tonic-gate /* 6607c478bd9Sstevel@tonic-gate * The parent is now stopped on exit from its fork call. We must now 6617c478bd9Sstevel@tonic-gate * grab the child on its return from fork in order to manipulate it. 6627c478bd9Sstevel@tonic-gate */ 6637c478bd9Sstevel@tonic-gate if ((C = Pgrab(psp->pr_rval1, PGRAB_RETAIN, &gcode)) == NULL) { 6647c478bd9Sstevel@tonic-gate warn("failed to grab forked child process %ld: %s\n", 6657c478bd9Sstevel@tonic-gate psp->pr_rval1, Pgrab_error(gcode)); 6667c478bd9Sstevel@tonic-gate return; /* just stop if we failed to grab the child */ 6677c478bd9Sstevel@tonic-gate } 6687c478bd9Sstevel@tonic-gate 6697c478bd9Sstevel@tonic-gate /* 6707c478bd9Sstevel@tonic-gate * We may have grabbed the child and stopped it prematurely before it 6717c478bd9Sstevel@tonic-gate * stopped on exit from fork. If so, wait up to 1 sec for it to settle. 6727c478bd9Sstevel@tonic-gate */ 6737c478bd9Sstevel@tonic-gate if (Pstatus(C)->pr_lwp.pr_why != PR_SYSEXIT) 6747c478bd9Sstevel@tonic-gate (void) Pwait(C, MILLISEC); 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate csp = &Pstatus(C)->pr_lwp; 6777c478bd9Sstevel@tonic-gate 678657b1f3dSraf if (csp->pr_why != PR_SYSEXIT || 6798fd04b83SRoger A. Faulkner (csp->pr_what != SYS_vfork && csp->pr_what != SYS_forksys)) { 6807c478bd9Sstevel@tonic-gate warn("forked child process %ld did not stop on exit from " 6817c478bd9Sstevel@tonic-gate "fork as expected\n", psp->pr_rval1); 6827c478bd9Sstevel@tonic-gate } 6837c478bd9Sstevel@tonic-gate 6847c478bd9Sstevel@tonic-gate warn("target forked child process %ld (debugger following %s)\n", 6857c478bd9Sstevel@tonic-gate psp->pr_rval1, follow_parent ? "parent" : "child"); 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate (void) Punsetflags(C, PR_ASYNC); /* require synchronous mode */ 6887c478bd9Sstevel@tonic-gate (void) Psetflags(C, PR_BPTADJ); /* always adjust eip on x86 */ 6897c478bd9Sstevel@tonic-gate (void) Prd_agent(C); /* initialize librtld_db */ 6907c478bd9Sstevel@tonic-gate 6917c478bd9Sstevel@tonic-gate /* 6927c478bd9Sstevel@tonic-gate * At the time pt_fork() is called, the target event engine has already 6937c478bd9Sstevel@tonic-gate * disarmed the specifiers on the active list, clearing out events in 6947c478bd9Sstevel@tonic-gate * the parent process. However, this means that events that change 6957c478bd9Sstevel@tonic-gate * the address space (e.g. breakpoints) have not been effectively 6967c478bd9Sstevel@tonic-gate * disarmed in the child since its address space reflects the state of 6977c478bd9Sstevel@tonic-gate * the process at the time of fork when events were armed. We must 6987c478bd9Sstevel@tonic-gate * therefore handle this as a special case and re-invoke the disarm 6997c478bd9Sstevel@tonic-gate * callback of each active specifier to clean out the child process. 7007c478bd9Sstevel@tonic-gate */ 7017c478bd9Sstevel@tonic-gate if (!is_vfork) { 7027c478bd9Sstevel@tonic-gate for (t->t_pshandle = C, sep = mdb_list_next(&t->t_active); 7037c478bd9Sstevel@tonic-gate sep != NULL; sep = mdb_list_next(sep)) { 7047c478bd9Sstevel@tonic-gate if (sep->se_state == MDB_TGT_SPEC_ACTIVE) 7057c478bd9Sstevel@tonic-gate (void) sep->se_ops->se_disarm(t, sep); 7067c478bd9Sstevel@tonic-gate } 7077c478bd9Sstevel@tonic-gate 7087c478bd9Sstevel@tonic-gate t->t_pshandle = P; /* restore pshandle to parent */ 7097c478bd9Sstevel@tonic-gate } 7107c478bd9Sstevel@tonic-gate 7117c478bd9Sstevel@tonic-gate /* 7127c478bd9Sstevel@tonic-gate * If we're following the parent process, we need to temporarily change 7137c478bd9Sstevel@tonic-gate * t_pshandle to refer to the child handle C so that we can clear out 7147c478bd9Sstevel@tonic-gate * all the events in the child prior to releasing it below. If we are 7157c478bd9Sstevel@tonic-gate * tracing a vfork, we also need to explicitly wait for the child to 7167c478bd9Sstevel@tonic-gate * exec, exit, or die before we can reset and continue the parent. We 7177c478bd9Sstevel@tonic-gate * avoid having to deal with the vfork child forking again by clearing 7187c478bd9Sstevel@tonic-gate * PR_FORK and setting PR_RLC; if it does fork it will effectively be 7197c478bd9Sstevel@tonic-gate * released from our control and we will continue following the parent. 7207c478bd9Sstevel@tonic-gate */ 7217c478bd9Sstevel@tonic-gate if (follow_parent) { 7227c478bd9Sstevel@tonic-gate if (is_vfork) { 7237c478bd9Sstevel@tonic-gate mdb_tgt_status_t status; 7247c478bd9Sstevel@tonic-gate 7257c478bd9Sstevel@tonic-gate ASSERT(psp->pr_flags & PR_VFORKP); 7267c478bd9Sstevel@tonic-gate mdb_tgt_sespec_idle_all(t, EBUSY, FALSE); 7277c478bd9Sstevel@tonic-gate t->t_pshandle = C; 7287c478bd9Sstevel@tonic-gate 7297c478bd9Sstevel@tonic-gate (void) Psysexit(C, SYS_execve, TRUE); 7307c478bd9Sstevel@tonic-gate 7317c478bd9Sstevel@tonic-gate (void) Punsetflags(C, PR_FORK | PR_KLC); 7327c478bd9Sstevel@tonic-gate (void) Psetflags(C, PR_RLC); 7337c478bd9Sstevel@tonic-gate 7347c478bd9Sstevel@tonic-gate do { 7357c478bd9Sstevel@tonic-gate if (pt_setrun(t, &status, 0) == -1 || 7367c478bd9Sstevel@tonic-gate status.st_state == MDB_TGT_UNDEAD || 7377c478bd9Sstevel@tonic-gate status.st_state == MDB_TGT_LOST) 7387c478bd9Sstevel@tonic-gate break; /* failure or process died */ 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate } while (csp->pr_why != PR_SYSEXIT || 7418fd04b83SRoger A. Faulkner csp->pr_errno != 0 || csp->pr_what != SYS_execve); 7427c478bd9Sstevel@tonic-gate } else 7437c478bd9Sstevel@tonic-gate t->t_pshandle = C; 7447c478bd9Sstevel@tonic-gate } 7457c478bd9Sstevel@tonic-gate 7467c478bd9Sstevel@tonic-gate /* 7477c478bd9Sstevel@tonic-gate * If we are following the child, destroy any active libthread_db 7487c478bd9Sstevel@tonic-gate * handle before we release the parent process. 7497c478bd9Sstevel@tonic-gate */ 7507c478bd9Sstevel@tonic-gate if (!follow_parent) { 7517c478bd9Sstevel@tonic-gate PTL_DTOR(t); 7527c478bd9Sstevel@tonic-gate pt->p_tdb_ops = NULL; 7537c478bd9Sstevel@tonic-gate pt->p_ptl_ops = &proc_lwp_ops; 7547c478bd9Sstevel@tonic-gate pt->p_ptl_hdl = NULL; 7557c478bd9Sstevel@tonic-gate } 7567c478bd9Sstevel@tonic-gate 7577c478bd9Sstevel@tonic-gate /* 7587c478bd9Sstevel@tonic-gate * Idle all events to make sure the address space and tracing flags are 7597c478bd9Sstevel@tonic-gate * restored, and then release the process we are not tracing. If we 7607c478bd9Sstevel@tonic-gate * are following the child of a vfork, we push the parent's pshandle 7617c478bd9Sstevel@tonic-gate * on to a list of vfork parents to be released when we exec or exit. 7627c478bd9Sstevel@tonic-gate */ 7637c478bd9Sstevel@tonic-gate if (is_vfork && !follow_parent) { 7647c478bd9Sstevel@tonic-gate pt_vforkp_t *vfp = mdb_alloc(sizeof (pt_vforkp_t), UM_SLEEP); 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate ASSERT(psp->pr_flags & PR_VFORKP); 7677c478bd9Sstevel@tonic-gate vfp->p_pshandle = P; 7687c478bd9Sstevel@tonic-gate mdb_list_append(&pt->p_vforkp, vfp); 7697c478bd9Sstevel@tonic-gate mdb_tgt_sespec_idle_all(t, EBUSY, FALSE); 7707c478bd9Sstevel@tonic-gate 7717c478bd9Sstevel@tonic-gate } else { 7727c478bd9Sstevel@tonic-gate mdb_tgt_sespec_idle_all(t, EBUSY, FALSE); 7737c478bd9Sstevel@tonic-gate Prelease(t->t_pshandle, PRELEASE_CLEAR); 7747c478bd9Sstevel@tonic-gate if (!follow_parent) 7757c478bd9Sstevel@tonic-gate pt_release_parents(t); 7767c478bd9Sstevel@tonic-gate } 7777c478bd9Sstevel@tonic-gate 7787c478bd9Sstevel@tonic-gate /* 7797c478bd9Sstevel@tonic-gate * Now that all the hard stuff is done, switch t_pshandle back to the 7807c478bd9Sstevel@tonic-gate * process we are following and reset our events to the ACTIVE state. 7817c478bd9Sstevel@tonic-gate * If we are following the child, reset the libthread_db handle as well 7827c478bd9Sstevel@tonic-gate * as the rtld agent. 7837c478bd9Sstevel@tonic-gate */ 7847c478bd9Sstevel@tonic-gate if (follow_parent) 7857c478bd9Sstevel@tonic-gate t->t_pshandle = P; 7867c478bd9Sstevel@tonic-gate else { 7877c478bd9Sstevel@tonic-gate t->t_pshandle = C; 7887c478bd9Sstevel@tonic-gate pt->p_rtld = Prd_agent(C); 78995d62a61SEdward Pilatowicz (void) Pobject_iter(t->t_pshandle, (proc_map_f *)thr_check, t); 7907c478bd9Sstevel@tonic-gate } 7917c478bd9Sstevel@tonic-gate 7927c478bd9Sstevel@tonic-gate (void) mdb_tgt_sespec_activate_all(t); 7937c478bd9Sstevel@tonic-gate (void) mdb_tgt_continue(t, NULL); 7947c478bd9Sstevel@tonic-gate } 7957c478bd9Sstevel@tonic-gate 7967c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 7977c478bd9Sstevel@tonic-gate static void 7987c478bd9Sstevel@tonic-gate pt_exec(mdb_tgt_t *t, int vid, void *private) 7997c478bd9Sstevel@tonic-gate { 8007c478bd9Sstevel@tonic-gate struct ps_prochandle *P = t->t_pshandle; 8017c478bd9Sstevel@tonic-gate const pstatus_t *psp = Pstatus(P); 8027c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 8037c478bd9Sstevel@tonic-gate int follow_exec = mdb.m_execmode == MDB_EM_FOLLOW; 8047c478bd9Sstevel@tonic-gate pid_t pid = psp->pr_pid; 8057c478bd9Sstevel@tonic-gate 8067c478bd9Sstevel@tonic-gate char execname[MAXPATHLEN]; 8077c478bd9Sstevel@tonic-gate mdb_sespec_t *sep, *nsep; 8087c478bd9Sstevel@tonic-gate mdb_io_t *io; 8097c478bd9Sstevel@tonic-gate char c; 8107c478bd9Sstevel@tonic-gate 8117c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_TGT, "exit from %s: errno=%d\n", proc_sysname( 8127c478bd9Sstevel@tonic-gate psp->pr_lwp.pr_what, execname, sizeof (execname)), 8137c478bd9Sstevel@tonic-gate psp->pr_lwp.pr_errno); 8147c478bd9Sstevel@tonic-gate 8157c478bd9Sstevel@tonic-gate if (psp->pr_lwp.pr_errno != 0) { 8167c478bd9Sstevel@tonic-gate (void) mdb_tgt_continue(t, NULL); 8177c478bd9Sstevel@tonic-gate return; /* exec failed */ 8187c478bd9Sstevel@tonic-gate } 8197c478bd9Sstevel@tonic-gate 8207c478bd9Sstevel@tonic-gate /* 8217c478bd9Sstevel@tonic-gate * If execmode is ASK and stdout is a terminal, then ask the user to 8227c478bd9Sstevel@tonic-gate * explicitly set the exec behavior for this particular exec. If 8237c478bd9Sstevel@tonic-gate * Pstate() still shows PS_LOST, we are being called from pt_setrun() 8247c478bd9Sstevel@tonic-gate * directly and therefore we must resume the terminal since it is still 8257c478bd9Sstevel@tonic-gate * in the suspended state as far as tgt_continue() is concerned. 8267c478bd9Sstevel@tonic-gate */ 8277c478bd9Sstevel@tonic-gate if (mdb.m_execmode == MDB_EM_ASK && mdb.m_term != NULL) { 8287c478bd9Sstevel@tonic-gate if (Pstate(P) == PS_LOST) 8297c478bd9Sstevel@tonic-gate IOP_RESUME(mdb.m_term); 8307c478bd9Sstevel@tonic-gate 8317c478bd9Sstevel@tonic-gate mdb_iob_printf(mdb.m_err, "%s: %s detected: (f)ollow new " 8327c478bd9Sstevel@tonic-gate "program or (s)top? ", mdb.m_pname, execname); 8337c478bd9Sstevel@tonic-gate mdb_iob_flush(mdb.m_err); 8347c478bd9Sstevel@tonic-gate 8357c478bd9Sstevel@tonic-gate while (IOP_READ(mdb.m_term, &c, sizeof (c)) == sizeof (c)) { 8367c478bd9Sstevel@tonic-gate if (c == 'F' || c == 'f') { 8377c478bd9Sstevel@tonic-gate mdb_iob_printf(mdb.m_err, "%c\n", c); 8387c478bd9Sstevel@tonic-gate follow_exec = TRUE; 8397c478bd9Sstevel@tonic-gate break; 8407c478bd9Sstevel@tonic-gate } else if (c == 'S' || c == 's') { 8417c478bd9Sstevel@tonic-gate mdb_iob_printf(mdb.m_err, "%c\n", c); 8427c478bd9Sstevel@tonic-gate follow_exec = FALSE; 8437c478bd9Sstevel@tonic-gate break; 8447c478bd9Sstevel@tonic-gate } 8457c478bd9Sstevel@tonic-gate } 8467c478bd9Sstevel@tonic-gate 8477c478bd9Sstevel@tonic-gate if (Pstate(P) == PS_LOST) 8487c478bd9Sstevel@tonic-gate IOP_SUSPEND(mdb.m_term); 8497c478bd9Sstevel@tonic-gate } 8507c478bd9Sstevel@tonic-gate 8517c478bd9Sstevel@tonic-gate pt_release_parents(t); /* release any waiting vfork parents */ 8527c478bd9Sstevel@tonic-gate pt_pre_detach(t, FALSE); /* remove our breakpoints and idle events */ 8537c478bd9Sstevel@tonic-gate Preset_maps(P); /* libproc must delete mappings and symtabs */ 8547c478bd9Sstevel@tonic-gate pt_close_aout(t); /* free pt symbol tables and GElf file data */ 8557c478bd9Sstevel@tonic-gate 8567c478bd9Sstevel@tonic-gate /* 8577c478bd9Sstevel@tonic-gate * If we lost control of the process across the exec and are not able 8587c478bd9Sstevel@tonic-gate * to reopen it, we have no choice but to clear the matched event list 8597c478bd9Sstevel@tonic-gate * and wait for the user to quit or otherwise release the process. 8607c478bd9Sstevel@tonic-gate */ 8617c478bd9Sstevel@tonic-gate if (Pstate(P) == PS_LOST && Preopen(P) == -1) { 8627c478bd9Sstevel@tonic-gate int error = errno; 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate warn("lost control of PID %d due to exec of %s executable\n", 8657c478bd9Sstevel@tonic-gate (int)pid, error == EOVERFLOW ? "64-bit" : "set-id"); 8667c478bd9Sstevel@tonic-gate 8677c478bd9Sstevel@tonic-gate for (sep = t->t_matched; sep != T_SE_END; sep = nsep) { 8687c478bd9Sstevel@tonic-gate nsep = sep->se_matched; 8697c478bd9Sstevel@tonic-gate sep->se_matched = NULL; 8707c478bd9Sstevel@tonic-gate mdb_tgt_sespec_rele(t, sep); 8717c478bd9Sstevel@tonic-gate } 8727c478bd9Sstevel@tonic-gate 8737c478bd9Sstevel@tonic-gate if (error != EOVERFLOW) 8747c478bd9Sstevel@tonic-gate return; /* just stop if we exec'd a set-id executable */ 8757c478bd9Sstevel@tonic-gate } 8767c478bd9Sstevel@tonic-gate 8777c478bd9Sstevel@tonic-gate if (Pstate(P) != PS_LOST) { 8787c478bd9Sstevel@tonic-gate if (Pexecname(P, execname, sizeof (execname)) == NULL) { 8797c478bd9Sstevel@tonic-gate (void) mdb_iob_snprintf(execname, sizeof (execname), 8807c478bd9Sstevel@tonic-gate "/proc/%d/object/a.out", (int)pid); 8817c478bd9Sstevel@tonic-gate } 8827c478bd9Sstevel@tonic-gate 8837c478bd9Sstevel@tonic-gate if (follow_exec == FALSE || psp->pr_dmodel == PR_MODEL_NATIVE) 8847c478bd9Sstevel@tonic-gate warn("target performed exec of %s\n", execname); 8857c478bd9Sstevel@tonic-gate 8867c478bd9Sstevel@tonic-gate io = mdb_fdio_create_path(NULL, execname, pt->p_oflags, 0); 8877c478bd9Sstevel@tonic-gate if (io == NULL) { 8887c478bd9Sstevel@tonic-gate warn("failed to open %s", execname); 8897c478bd9Sstevel@tonic-gate warn("a.out symbol tables will not be available\n"); 8907c478bd9Sstevel@tonic-gate } else if (pt_open_aout(t, io) == NULL) { 8917c478bd9Sstevel@tonic-gate (void) mdb_dis_select(pt_disasm(NULL)); 8927c478bd9Sstevel@tonic-gate mdb_io_destroy(io); 8937c478bd9Sstevel@tonic-gate } else 8947c478bd9Sstevel@tonic-gate (void) mdb_dis_select(pt_disasm(&pt->p_file->gf_ehdr)); 8957c478bd9Sstevel@tonic-gate } 8967c478bd9Sstevel@tonic-gate 8977c478bd9Sstevel@tonic-gate /* 8987c478bd9Sstevel@tonic-gate * We reset our libthread_db state here, but deliberately do NOT call 8997c478bd9Sstevel@tonic-gate * PTL_DTOR because we do not want to call libthread_db's td_ta_delete. 9007c478bd9Sstevel@tonic-gate * This interface is hopelessly broken in that it writes to the process 9017c478bd9Sstevel@tonic-gate * address space (which we do not want it to do after an exec) and it 9027c478bd9Sstevel@tonic-gate * doesn't bother deallocating any of its storage anyway. 9037c478bd9Sstevel@tonic-gate */ 9047c478bd9Sstevel@tonic-gate pt->p_tdb_ops = NULL; 9057c478bd9Sstevel@tonic-gate pt->p_ptl_ops = &proc_lwp_ops; 9067c478bd9Sstevel@tonic-gate pt->p_ptl_hdl = NULL; 9077c478bd9Sstevel@tonic-gate 9087c478bd9Sstevel@tonic-gate if (follow_exec && psp->pr_dmodel != PR_MODEL_NATIVE) { 9097c478bd9Sstevel@tonic-gate const char *argv[3]; 9107c478bd9Sstevel@tonic-gate char *state, *env; 9117c478bd9Sstevel@tonic-gate char pidarg[16]; 9127c478bd9Sstevel@tonic-gate size_t envlen; 9137c478bd9Sstevel@tonic-gate 9147c478bd9Sstevel@tonic-gate if (realpath(getexecname(), execname) == NULL) { 9157c478bd9Sstevel@tonic-gate warn("cannot follow PID %d -- failed to resolve " 9167c478bd9Sstevel@tonic-gate "debugger pathname for re-exec", (int)pid); 9177c478bd9Sstevel@tonic-gate return; 9187c478bd9Sstevel@tonic-gate } 9197c478bd9Sstevel@tonic-gate 9207c478bd9Sstevel@tonic-gate warn("restarting debugger to follow PID %d ...\n", (int)pid); 9217c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_TGT, "re-exec'ing %s\n", execname); 9227c478bd9Sstevel@tonic-gate 9237c478bd9Sstevel@tonic-gate (void) mdb_snprintf(pidarg, sizeof (pidarg), "-p%d", (int)pid); 9247c478bd9Sstevel@tonic-gate 9257c478bd9Sstevel@tonic-gate state = mdb_get_config(); 9267c478bd9Sstevel@tonic-gate envlen = strlen(MDB_CONFIG_ENV_VAR) + 1 + strlen(state) + 1; 9277c478bd9Sstevel@tonic-gate env = mdb_alloc(envlen, UM_SLEEP); 92880148899SSurya Prakki (void) snprintf(env, envlen, 92980148899SSurya Prakki "%s=%s", MDB_CONFIG_ENV_VAR, state); 9307c478bd9Sstevel@tonic-gate 9317c478bd9Sstevel@tonic-gate (void) putenv(env); 9327c478bd9Sstevel@tonic-gate 9337c478bd9Sstevel@tonic-gate argv[0] = mdb.m_pname; 9347c478bd9Sstevel@tonic-gate argv[1] = pidarg; 9357c478bd9Sstevel@tonic-gate argv[2] = NULL; 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate if (mdb.m_term != NULL) 9387c478bd9Sstevel@tonic-gate IOP_SUSPEND(mdb.m_term); 9397c478bd9Sstevel@tonic-gate 9407c478bd9Sstevel@tonic-gate Prelease(P, PRELEASE_CLEAR | PRELEASE_HANG); 9417c478bd9Sstevel@tonic-gate (void) execv(execname, (char *const *)argv); 9427c478bd9Sstevel@tonic-gate warn("failed to re-exec debugger"); 9437c478bd9Sstevel@tonic-gate 9447c478bd9Sstevel@tonic-gate if (mdb.m_term != NULL) 9457c478bd9Sstevel@tonic-gate IOP_RESUME(mdb.m_term); 9467c478bd9Sstevel@tonic-gate 9477c478bd9Sstevel@tonic-gate t->t_pshandle = pt->p_idlehandle; 9487c478bd9Sstevel@tonic-gate return; 9497c478bd9Sstevel@tonic-gate } 9507c478bd9Sstevel@tonic-gate 9517c478bd9Sstevel@tonic-gate pt_post_attach(t); /* install tracing flags and activate events */ 9527c478bd9Sstevel@tonic-gate pt_activate_common(t); /* initialize librtld_db and libthread_db */ 9537c478bd9Sstevel@tonic-gate 9547c478bd9Sstevel@tonic-gate if (psp->pr_dmodel != PR_MODEL_NATIVE && mdb.m_term != NULL) { 9557c478bd9Sstevel@tonic-gate warn("loadable dcmds will not operate on non-native %d-bit " 9567c478bd9Sstevel@tonic-gate "data model\n", psp->pr_dmodel == PR_MODEL_ILP32 ? 32 : 64); 9577c478bd9Sstevel@tonic-gate warn("use ::release -a and then run mdb -p %d to restart " 9587c478bd9Sstevel@tonic-gate "debugger\n", (int)pid); 9597c478bd9Sstevel@tonic-gate } 9607c478bd9Sstevel@tonic-gate 9617c478bd9Sstevel@tonic-gate if (follow_exec) 9627c478bd9Sstevel@tonic-gate (void) mdb_tgt_continue(t, NULL); 9637c478bd9Sstevel@tonic-gate } 9647c478bd9Sstevel@tonic-gate 9657c478bd9Sstevel@tonic-gate static int 9667c478bd9Sstevel@tonic-gate pt_setflags(mdb_tgt_t *t, int flags) 9677c478bd9Sstevel@tonic-gate { 9687c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 9697c478bd9Sstevel@tonic-gate 9707c478bd9Sstevel@tonic-gate if ((flags ^ t->t_flags) & MDB_TGT_F_RDWR) { 9717c478bd9Sstevel@tonic-gate int mode = (flags & MDB_TGT_F_RDWR) ? O_RDWR : O_RDONLY; 9727c478bd9Sstevel@tonic-gate mdb_io_t *io; 9737c478bd9Sstevel@tonic-gate 9747c478bd9Sstevel@tonic-gate if (pt->p_fio == NULL) 9757c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOEXEC)); 9767c478bd9Sstevel@tonic-gate 9777c478bd9Sstevel@tonic-gate io = mdb_fdio_create_path(NULL, IOP_NAME(pt->p_fio), mode, 0); 9787c478bd9Sstevel@tonic-gate 9797c478bd9Sstevel@tonic-gate if (io == NULL) 9807c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 9817c478bd9Sstevel@tonic-gate 9827c478bd9Sstevel@tonic-gate t->t_flags = (t->t_flags & ~MDB_TGT_F_RDWR) | 9837c478bd9Sstevel@tonic-gate (flags & MDB_TGT_F_RDWR); 9847c478bd9Sstevel@tonic-gate 9857c478bd9Sstevel@tonic-gate pt->p_fio = mdb_io_hold(io); 9867c478bd9Sstevel@tonic-gate mdb_io_rele(pt->p_file->gf_io); 9877c478bd9Sstevel@tonic-gate pt->p_file->gf_io = pt->p_fio; 9887c478bd9Sstevel@tonic-gate } 9897c478bd9Sstevel@tonic-gate 9907c478bd9Sstevel@tonic-gate if (flags & MDB_TGT_F_FORCE) { 9917c478bd9Sstevel@tonic-gate t->t_flags |= MDB_TGT_F_FORCE; 9927c478bd9Sstevel@tonic-gate pt->p_gflags |= PGRAB_FORCE; 9937c478bd9Sstevel@tonic-gate } 9947c478bd9Sstevel@tonic-gate 9957c478bd9Sstevel@tonic-gate return (0); 9967c478bd9Sstevel@tonic-gate } 9977c478bd9Sstevel@tonic-gate 9987c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 9997c478bd9Sstevel@tonic-gate static int 10007c478bd9Sstevel@tonic-gate pt_frame(void *arglim, uintptr_t pc, uint_t argc, const long *argv, 10017c478bd9Sstevel@tonic-gate const mdb_tgt_gregset_t *gregs) 10027c478bd9Sstevel@tonic-gate { 10037c478bd9Sstevel@tonic-gate argc = MIN(argc, (uint_t)(uintptr_t)arglim); 10047c478bd9Sstevel@tonic-gate mdb_printf("%a(", pc); 10057c478bd9Sstevel@tonic-gate 10067c478bd9Sstevel@tonic-gate if (argc != 0) { 10077c478bd9Sstevel@tonic-gate mdb_printf("%lr", *argv++); 10087c478bd9Sstevel@tonic-gate for (argc--; argc != 0; argc--) 10097c478bd9Sstevel@tonic-gate mdb_printf(", %lr", *argv++); 10107c478bd9Sstevel@tonic-gate } 10117c478bd9Sstevel@tonic-gate 10127c478bd9Sstevel@tonic-gate mdb_printf(")\n"); 10137c478bd9Sstevel@tonic-gate return (0); 10147c478bd9Sstevel@tonic-gate } 10157c478bd9Sstevel@tonic-gate 10167c478bd9Sstevel@tonic-gate static int 10177c478bd9Sstevel@tonic-gate pt_framev(void *arglim, uintptr_t pc, uint_t argc, const long *argv, 10187c478bd9Sstevel@tonic-gate const mdb_tgt_gregset_t *gregs) 10197c478bd9Sstevel@tonic-gate { 10207c478bd9Sstevel@tonic-gate argc = MIN(argc, (uint_t)(uintptr_t)arglim); 10217c478bd9Sstevel@tonic-gate #if defined(__i386) || defined(__amd64) 10227c478bd9Sstevel@tonic-gate mdb_printf("%0?lr %a(", gregs->gregs[R_FP], pc); 10237c478bd9Sstevel@tonic-gate #else 10247c478bd9Sstevel@tonic-gate mdb_printf("%0?lr %a(", gregs->gregs[R_SP], pc); 10257c478bd9Sstevel@tonic-gate #endif 10267c478bd9Sstevel@tonic-gate if (argc != 0) { 10277c478bd9Sstevel@tonic-gate mdb_printf("%lr", *argv++); 10287c478bd9Sstevel@tonic-gate for (argc--; argc != 0; argc--) 10297c478bd9Sstevel@tonic-gate mdb_printf(", %lr", *argv++); 10307c478bd9Sstevel@tonic-gate } 10317c478bd9Sstevel@tonic-gate 10327c478bd9Sstevel@tonic-gate mdb_printf(")\n"); 10337c478bd9Sstevel@tonic-gate return (0); 10347c478bd9Sstevel@tonic-gate } 10357c478bd9Sstevel@tonic-gate 10367c478bd9Sstevel@tonic-gate static int 10377c478bd9Sstevel@tonic-gate pt_framer(void *arglim, uintptr_t pc, uint_t argc, const long *argv, 10387c478bd9Sstevel@tonic-gate const mdb_tgt_gregset_t *gregs) 10397c478bd9Sstevel@tonic-gate { 10407c478bd9Sstevel@tonic-gate if (pt_frameregs(arglim, pc, argc, argv, gregs, pc == PC_FAKE) == -1) { 10417c478bd9Sstevel@tonic-gate /* 10427c478bd9Sstevel@tonic-gate * Use verbose format if register format is not supported. 10437c478bd9Sstevel@tonic-gate */ 10447c478bd9Sstevel@tonic-gate return (pt_framev(arglim, pc, argc, argv, gregs)); 10457c478bd9Sstevel@tonic-gate } 10467c478bd9Sstevel@tonic-gate 10477c478bd9Sstevel@tonic-gate return (0); 10487c478bd9Sstevel@tonic-gate } 10497c478bd9Sstevel@tonic-gate 10507c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 10517c478bd9Sstevel@tonic-gate static int 10527c478bd9Sstevel@tonic-gate pt_stack_common(uintptr_t addr, uint_t flags, int argc, 10537c478bd9Sstevel@tonic-gate const mdb_arg_t *argv, mdb_tgt_stack_f *func, prgreg_t saved_pc) 10547c478bd9Sstevel@tonic-gate { 10557c478bd9Sstevel@tonic-gate void *arg = (void *)(uintptr_t)mdb.m_nargs; 10567c478bd9Sstevel@tonic-gate mdb_tgt_t *t = mdb.m_target; 10577c478bd9Sstevel@tonic-gate mdb_tgt_gregset_t gregs; 10587c478bd9Sstevel@tonic-gate 10597c478bd9Sstevel@tonic-gate if (argc != 0) { 10607c478bd9Sstevel@tonic-gate if (argv->a_type == MDB_TYPE_CHAR || argc > 1) 10617c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 10627c478bd9Sstevel@tonic-gate 10637c478bd9Sstevel@tonic-gate if (argv->a_type == MDB_TYPE_STRING) 10647c478bd9Sstevel@tonic-gate arg = (void *)(uintptr_t)mdb_strtoull(argv->a_un.a_str); 10657c478bd9Sstevel@tonic-gate else 10667c478bd9Sstevel@tonic-gate arg = (void *)(uintptr_t)argv->a_un.a_val; 10677c478bd9Sstevel@tonic-gate } 10687c478bd9Sstevel@tonic-gate 10697c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL || Pstate(t->t_pshandle) == PS_IDLE) { 10707c478bd9Sstevel@tonic-gate mdb_warn("no process active\n"); 10717c478bd9Sstevel@tonic-gate return (DCMD_ERR); 10727c478bd9Sstevel@tonic-gate } 10737c478bd9Sstevel@tonic-gate 10747c478bd9Sstevel@tonic-gate /* 10757c478bd9Sstevel@tonic-gate * In the universe of sparcv7, sparcv9, ia32, and amd64 this code can be 10767c478bd9Sstevel@tonic-gate * common: <sys/procfs_isa.h> conveniently #defines R_FP to be the 10777c478bd9Sstevel@tonic-gate * appropriate register we need to set in order to perform a stack 10787c478bd9Sstevel@tonic-gate * traceback from a given frame address. 10797c478bd9Sstevel@tonic-gate */ 10807c478bd9Sstevel@tonic-gate if (flags & DCMD_ADDRSPEC) { 10817c478bd9Sstevel@tonic-gate bzero(&gregs, sizeof (gregs)); 10827c478bd9Sstevel@tonic-gate gregs.gregs[R_FP] = addr; 10837c478bd9Sstevel@tonic-gate #ifdef __sparc 10847c478bd9Sstevel@tonic-gate gregs.gregs[R_I7] = saved_pc; 10857c478bd9Sstevel@tonic-gate #endif /* __sparc */ 10867c478bd9Sstevel@tonic-gate } else if (PTL_GETREGS(t, PTL_TID(t), gregs.gregs) != 0) { 10877c478bd9Sstevel@tonic-gate mdb_warn("failed to get current register set"); 10887c478bd9Sstevel@tonic-gate return (DCMD_ERR); 10897c478bd9Sstevel@tonic-gate } 10907c478bd9Sstevel@tonic-gate 10917c478bd9Sstevel@tonic-gate (void) mdb_tgt_stack_iter(t, &gregs, func, arg); 10927c478bd9Sstevel@tonic-gate return (DCMD_OK); 10937c478bd9Sstevel@tonic-gate } 10947c478bd9Sstevel@tonic-gate 10957c478bd9Sstevel@tonic-gate static int 10967c478bd9Sstevel@tonic-gate pt_stack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 10977c478bd9Sstevel@tonic-gate { 10987c478bd9Sstevel@tonic-gate return (pt_stack_common(addr, flags, argc, argv, pt_frame, 0)); 10997c478bd9Sstevel@tonic-gate } 11007c478bd9Sstevel@tonic-gate 11017c478bd9Sstevel@tonic-gate static int 11027c478bd9Sstevel@tonic-gate pt_stackv(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 11037c478bd9Sstevel@tonic-gate { 11047c478bd9Sstevel@tonic-gate return (pt_stack_common(addr, flags, argc, argv, pt_framev, 0)); 11057c478bd9Sstevel@tonic-gate } 11067c478bd9Sstevel@tonic-gate 11077c478bd9Sstevel@tonic-gate static int 11087c478bd9Sstevel@tonic-gate pt_stackr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 11097c478bd9Sstevel@tonic-gate { 11107c478bd9Sstevel@tonic-gate /* 11117c478bd9Sstevel@tonic-gate * Force printing of first register window, by setting the 11127c478bd9Sstevel@tonic-gate * saved pc (%i7) to PC_FAKE. 11137c478bd9Sstevel@tonic-gate */ 11147c478bd9Sstevel@tonic-gate return (pt_stack_common(addr, flags, argc, argv, pt_framer, PC_FAKE)); 11157c478bd9Sstevel@tonic-gate } 11167c478bd9Sstevel@tonic-gate 11177c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 11187c478bd9Sstevel@tonic-gate static int 11197c478bd9Sstevel@tonic-gate pt_ignored(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 11207c478bd9Sstevel@tonic-gate { 11217c478bd9Sstevel@tonic-gate struct ps_prochandle *P = mdb.m_target->t_pshandle; 11227c478bd9Sstevel@tonic-gate char buf[PRSIGBUFSZ]; 11237c478bd9Sstevel@tonic-gate 11247c478bd9Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) || argc != 0) 11257c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 11267c478bd9Sstevel@tonic-gate 11277c478bd9Sstevel@tonic-gate if (P == NULL) { 11287c478bd9Sstevel@tonic-gate mdb_warn("no process is currently active\n"); 11297c478bd9Sstevel@tonic-gate return (DCMD_ERR); 11307c478bd9Sstevel@tonic-gate } 11317c478bd9Sstevel@tonic-gate 11327c478bd9Sstevel@tonic-gate mdb_printf("%s\n", proc_sigset2str(&Pstatus(P)->pr_sigtrace, " ", 11337c478bd9Sstevel@tonic-gate FALSE, buf, sizeof (buf))); 11347c478bd9Sstevel@tonic-gate 11357c478bd9Sstevel@tonic-gate return (DCMD_OK); 11367c478bd9Sstevel@tonic-gate } 11377c478bd9Sstevel@tonic-gate 11387c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 11397c478bd9Sstevel@tonic-gate static int 11407c478bd9Sstevel@tonic-gate pt_lwpid(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 11417c478bd9Sstevel@tonic-gate { 11427c478bd9Sstevel@tonic-gate struct ps_prochandle *P = mdb.m_target->t_pshandle; 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) || argc != 0) 11457c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 11467c478bd9Sstevel@tonic-gate 11477c478bd9Sstevel@tonic-gate if (P == NULL) { 11487c478bd9Sstevel@tonic-gate mdb_warn("no process is currently active\n"); 11497c478bd9Sstevel@tonic-gate return (DCMD_ERR); 11507c478bd9Sstevel@tonic-gate } 11517c478bd9Sstevel@tonic-gate 11527c478bd9Sstevel@tonic-gate mdb_printf("%d\n", Pstatus(P)->pr_lwp.pr_lwpid); 11537c478bd9Sstevel@tonic-gate return (DCMD_OK); 11547c478bd9Sstevel@tonic-gate } 11557c478bd9Sstevel@tonic-gate 11567c478bd9Sstevel@tonic-gate static int 11577c478bd9Sstevel@tonic-gate pt_print_lwpid(int *n, const lwpstatus_t *psp) 11587c478bd9Sstevel@tonic-gate { 11597c478bd9Sstevel@tonic-gate struct ps_prochandle *P = mdb.m_target->t_pshandle; 11607c478bd9Sstevel@tonic-gate int nlwp = Pstatus(P)->pr_nlwp; 11617c478bd9Sstevel@tonic-gate 11627c478bd9Sstevel@tonic-gate if (*n == nlwp - 2) 11637c478bd9Sstevel@tonic-gate mdb_printf("%d and ", (int)psp->pr_lwpid); 11647c478bd9Sstevel@tonic-gate else if (*n == nlwp - 1) 11657c478bd9Sstevel@tonic-gate mdb_printf("%d are", (int)psp->pr_lwpid); 11667c478bd9Sstevel@tonic-gate else 11677c478bd9Sstevel@tonic-gate mdb_printf("%d, ", (int)psp->pr_lwpid); 11687c478bd9Sstevel@tonic-gate 11697c478bd9Sstevel@tonic-gate (*n)++; 11707c478bd9Sstevel@tonic-gate return (0); 11717c478bd9Sstevel@tonic-gate } 11727c478bd9Sstevel@tonic-gate 11737c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 11747c478bd9Sstevel@tonic-gate static int 11757c478bd9Sstevel@tonic-gate pt_lwpids(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 11767c478bd9Sstevel@tonic-gate { 11777c478bd9Sstevel@tonic-gate struct ps_prochandle *P = mdb.m_target->t_pshandle; 11787c478bd9Sstevel@tonic-gate int n = 0; 11797c478bd9Sstevel@tonic-gate 11807c478bd9Sstevel@tonic-gate if (P == NULL) { 11817c478bd9Sstevel@tonic-gate mdb_warn("no process is currently active\n"); 11827c478bd9Sstevel@tonic-gate return (DCMD_ERR); 11837c478bd9Sstevel@tonic-gate } 11847c478bd9Sstevel@tonic-gate 11857c478bd9Sstevel@tonic-gate switch (Pstatus(P)->pr_nlwp) { 11867c478bd9Sstevel@tonic-gate case 0: 11877c478bd9Sstevel@tonic-gate mdb_printf("no lwps are"); 11887c478bd9Sstevel@tonic-gate break; 11897c478bd9Sstevel@tonic-gate case 1: 11907c478bd9Sstevel@tonic-gate mdb_printf("lwpid %d is the only lwp", 11917c478bd9Sstevel@tonic-gate Pstatus(P)->pr_lwp.pr_lwpid); 11927c478bd9Sstevel@tonic-gate break; 11937c478bd9Sstevel@tonic-gate default: 11947c478bd9Sstevel@tonic-gate mdb_printf("lwpids "); 11957c478bd9Sstevel@tonic-gate (void) Plwp_iter(P, (proc_lwp_f *)pt_print_lwpid, &n); 11967c478bd9Sstevel@tonic-gate } 11977c478bd9Sstevel@tonic-gate 11987c478bd9Sstevel@tonic-gate switch (Pstate(P)) { 11997c478bd9Sstevel@tonic-gate case PS_DEAD: 12007c478bd9Sstevel@tonic-gate mdb_printf(" in core of process %d.\n", Pstatus(P)->pr_pid); 12017c478bd9Sstevel@tonic-gate break; 12027c478bd9Sstevel@tonic-gate case PS_IDLE: 12037c478bd9Sstevel@tonic-gate mdb_printf(" in idle target.\n"); 12047c478bd9Sstevel@tonic-gate break; 12057c478bd9Sstevel@tonic-gate default: 12067c478bd9Sstevel@tonic-gate mdb_printf(" in process %d.\n", (int)Pstatus(P)->pr_pid); 12077c478bd9Sstevel@tonic-gate break; 12087c478bd9Sstevel@tonic-gate } 12097c478bd9Sstevel@tonic-gate 12107c478bd9Sstevel@tonic-gate return (DCMD_OK); 12117c478bd9Sstevel@tonic-gate } 12127c478bd9Sstevel@tonic-gate 12137c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 12147c478bd9Sstevel@tonic-gate static int 12157c478bd9Sstevel@tonic-gate pt_ignore(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 12167c478bd9Sstevel@tonic-gate { 12177c478bd9Sstevel@tonic-gate pt_data_t *pt = mdb.m_target->t_data; 12187c478bd9Sstevel@tonic-gate 12197c478bd9Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC) || argc != 0) 12207c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 12217c478bd9Sstevel@tonic-gate 12227c478bd9Sstevel@tonic-gate if (addr < 1 || addr > pt->p_maxsig) { 12237c478bd9Sstevel@tonic-gate mdb_warn("invalid signal number -- 0t%lu\n", addr); 12247c478bd9Sstevel@tonic-gate return (DCMD_ERR); 12257c478bd9Sstevel@tonic-gate } 12267c478bd9Sstevel@tonic-gate 12277c478bd9Sstevel@tonic-gate (void) mdb_tgt_vespec_iter(mdb.m_target, pt_ignore_sig, (void *)addr); 12287c478bd9Sstevel@tonic-gate return (DCMD_OK); 12297c478bd9Sstevel@tonic-gate } 12307c478bd9Sstevel@tonic-gate 12317c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 12327c478bd9Sstevel@tonic-gate static int 12337c478bd9Sstevel@tonic-gate pt_attach(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 12347c478bd9Sstevel@tonic-gate { 12357c478bd9Sstevel@tonic-gate mdb_tgt_t *t = mdb.m_target; 12367c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 12377c478bd9Sstevel@tonic-gate int state, perr; 12387c478bd9Sstevel@tonic-gate 12397c478bd9Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC) && argc == 0) 12407c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 12417c478bd9Sstevel@tonic-gate 12427c478bd9Sstevel@tonic-gate if (((flags & DCMD_ADDRSPEC) && argc != 0) || argc > 1 || 12437c478bd9Sstevel@tonic-gate (argc != 0 && argv->a_type != MDB_TYPE_STRING)) 12447c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 12457c478bd9Sstevel@tonic-gate 12467c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL && Pstate(t->t_pshandle) != PS_IDLE) { 12477c478bd9Sstevel@tonic-gate mdb_warn("debugger is already attached to a %s\n", 12487c478bd9Sstevel@tonic-gate (Pstate(t->t_pshandle) == PS_DEAD) ? "core" : "process"); 12497c478bd9Sstevel@tonic-gate return (DCMD_ERR); 12507c478bd9Sstevel@tonic-gate } 12517c478bd9Sstevel@tonic-gate 12527c478bd9Sstevel@tonic-gate if (pt->p_fio == NULL) { 12537c478bd9Sstevel@tonic-gate mdb_warn("attach requires executable to be specified on " 12547c478bd9Sstevel@tonic-gate "command-line (or use -p)\n"); 12557c478bd9Sstevel@tonic-gate return (DCMD_ERR); 12567c478bd9Sstevel@tonic-gate } 12577c478bd9Sstevel@tonic-gate 12587c478bd9Sstevel@tonic-gate if (flags & DCMD_ADDRSPEC) 12597c478bd9Sstevel@tonic-gate t->t_pshandle = Pgrab((pid_t)addr, pt->p_gflags, &perr); 12607c478bd9Sstevel@tonic-gate else 12617c478bd9Sstevel@tonic-gate t->t_pshandle = proc_arg_grab(argv->a_un.a_str, 12627c478bd9Sstevel@tonic-gate PR_ARG_ANY, pt->p_gflags, &perr); 12637c478bd9Sstevel@tonic-gate 12647c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) { 12657c478bd9Sstevel@tonic-gate t->t_pshandle = pt->p_idlehandle; 12667c478bd9Sstevel@tonic-gate mdb_warn("cannot attach: %s\n", Pgrab_error(perr)); 12677c478bd9Sstevel@tonic-gate return (DCMD_ERR); 12687c478bd9Sstevel@tonic-gate } 12697c478bd9Sstevel@tonic-gate 12707c478bd9Sstevel@tonic-gate state = Pstate(t->t_pshandle); 12717c478bd9Sstevel@tonic-gate if (state != PS_DEAD && state != PS_IDLE) { 12727c478bd9Sstevel@tonic-gate (void) Punsetflags(t->t_pshandle, PR_KLC); 12737c478bd9Sstevel@tonic-gate (void) Psetflags(t->t_pshandle, PR_RLC); 12747c478bd9Sstevel@tonic-gate pt_post_attach(t); 12757c478bd9Sstevel@tonic-gate pt_activate_common(t); 12767c478bd9Sstevel@tonic-gate } 12777c478bd9Sstevel@tonic-gate 12787c478bd9Sstevel@tonic-gate (void) mdb_tgt_status(t, &t->t_status); 12797c478bd9Sstevel@tonic-gate mdb_module_load_all(0); 12807c478bd9Sstevel@tonic-gate return (DCMD_OK); 12817c478bd9Sstevel@tonic-gate } 12827c478bd9Sstevel@tonic-gate 12837c478bd9Sstevel@tonic-gate static int 12847c478bd9Sstevel@tonic-gate pt_regstatus(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 12857c478bd9Sstevel@tonic-gate { 12867c478bd9Sstevel@tonic-gate mdb_tgt_t *t = mdb.m_target; 12877c478bd9Sstevel@tonic-gate 12887c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL) { 12897c478bd9Sstevel@tonic-gate const pstatus_t *psp = Pstatus(t->t_pshandle); 12907c478bd9Sstevel@tonic-gate int cursig = psp->pr_lwp.pr_cursig; 12917c478bd9Sstevel@tonic-gate char signame[SIG2STR_MAX]; 12927c478bd9Sstevel@tonic-gate int state = Pstate(t->t_pshandle); 12937c478bd9Sstevel@tonic-gate 12947c478bd9Sstevel@tonic-gate if (state != PS_DEAD && state != PS_IDLE) 12957c478bd9Sstevel@tonic-gate mdb_printf("process id = %d\n", psp->pr_pid); 12967c478bd9Sstevel@tonic-gate else 12977c478bd9Sstevel@tonic-gate mdb_printf("no process\n"); 12987c478bd9Sstevel@tonic-gate 12997c478bd9Sstevel@tonic-gate if (cursig != 0 && sig2str(cursig, signame) == 0) 13007c478bd9Sstevel@tonic-gate mdb_printf("SIG%s: %s\n", signame, strsignal(cursig)); 13017c478bd9Sstevel@tonic-gate } 13027c478bd9Sstevel@tonic-gate 13037c478bd9Sstevel@tonic-gate return (pt_regs(addr, flags, argc, argv)); 13047c478bd9Sstevel@tonic-gate } 13057c478bd9Sstevel@tonic-gate 13067c478bd9Sstevel@tonic-gate static int 13077c478bd9Sstevel@tonic-gate pt_findstack(uintptr_t tid, uint_t flags, int argc, const mdb_arg_t *argv) 13087c478bd9Sstevel@tonic-gate { 13097c478bd9Sstevel@tonic-gate mdb_tgt_t *t = mdb.m_target; 13107c478bd9Sstevel@tonic-gate mdb_tgt_gregset_t gregs; 13117c478bd9Sstevel@tonic-gate int showargs = 0; 13127c478bd9Sstevel@tonic-gate int count; 13137c478bd9Sstevel@tonic-gate uintptr_t pc, sp; 13147c478bd9Sstevel@tonic-gate 13157c478bd9Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC)) 13167c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 13177c478bd9Sstevel@tonic-gate 13187c478bd9Sstevel@tonic-gate count = mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &showargs, 13197c478bd9Sstevel@tonic-gate NULL); 13207c478bd9Sstevel@tonic-gate argc -= count; 13217c478bd9Sstevel@tonic-gate argv += count; 13227c478bd9Sstevel@tonic-gate 13237c478bd9Sstevel@tonic-gate if (argc > 1 || (argc == 1 && argv->a_type != MDB_TYPE_STRING)) 13247c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 13257c478bd9Sstevel@tonic-gate 13267c478bd9Sstevel@tonic-gate if (PTL_GETREGS(t, tid, gregs.gregs) != 0) { 13277c478bd9Sstevel@tonic-gate mdb_warn("failed to get register set for thread %p", tid); 13287c478bd9Sstevel@tonic-gate return (DCMD_ERR); 13297c478bd9Sstevel@tonic-gate } 13307c478bd9Sstevel@tonic-gate 13317c478bd9Sstevel@tonic-gate pc = gregs.gregs[R_PC]; 13327c478bd9Sstevel@tonic-gate #if defined(__i386) || defined(__amd64) 13337c478bd9Sstevel@tonic-gate sp = gregs.gregs[R_FP]; 13347c478bd9Sstevel@tonic-gate #else 13357c478bd9Sstevel@tonic-gate sp = gregs.gregs[R_SP]; 13367c478bd9Sstevel@tonic-gate #endif 13377c478bd9Sstevel@tonic-gate mdb_printf("stack pointer for thread %p: %p\n", tid, sp); 13387c478bd9Sstevel@tonic-gate if (pc != 0) 13397c478bd9Sstevel@tonic-gate mdb_printf("[ %0?lr %a() ]\n", sp, pc); 13407c478bd9Sstevel@tonic-gate 13417c478bd9Sstevel@tonic-gate (void) mdb_inc_indent(2); 13427c478bd9Sstevel@tonic-gate mdb_set_dot(sp); 13437c478bd9Sstevel@tonic-gate 13447c478bd9Sstevel@tonic-gate if (argc == 1) 13457c478bd9Sstevel@tonic-gate (void) mdb_eval(argv->a_un.a_str); 13467c478bd9Sstevel@tonic-gate else if (showargs) 13477c478bd9Sstevel@tonic-gate (void) mdb_eval("<.$C"); 13487c478bd9Sstevel@tonic-gate else 13497c478bd9Sstevel@tonic-gate (void) mdb_eval("<.$C0"); 13507c478bd9Sstevel@tonic-gate 13517c478bd9Sstevel@tonic-gate (void) mdb_dec_indent(2); 13527c478bd9Sstevel@tonic-gate return (DCMD_OK); 13537c478bd9Sstevel@tonic-gate } 13547c478bd9Sstevel@tonic-gate 13557c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 13567c478bd9Sstevel@tonic-gate static int 13577c478bd9Sstevel@tonic-gate pt_gcore(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 13587c478bd9Sstevel@tonic-gate { 13597c478bd9Sstevel@tonic-gate mdb_tgt_t *t = mdb.m_target; 13607c478bd9Sstevel@tonic-gate char *prefix = "core"; 13617c478bd9Sstevel@tonic-gate char *content_str = NULL; 13627c478bd9Sstevel@tonic-gate core_content_t content = CC_CONTENT_DEFAULT; 13637c478bd9Sstevel@tonic-gate size_t size; 13647c478bd9Sstevel@tonic-gate char *fname; 13657c478bd9Sstevel@tonic-gate pid_t pid; 13667c478bd9Sstevel@tonic-gate 13677c478bd9Sstevel@tonic-gate if (flags & DCMD_ADDRSPEC) 13687c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 13697c478bd9Sstevel@tonic-gate 13707c478bd9Sstevel@tonic-gate if (mdb_getopts(argc, argv, 13717c478bd9Sstevel@tonic-gate 'o', MDB_OPT_STR, &prefix, 13727c478bd9Sstevel@tonic-gate 'c', MDB_OPT_STR, &content_str, NULL) != argc) 13737c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 13747c478bd9Sstevel@tonic-gate 13757c478bd9Sstevel@tonic-gate if (content_str != NULL && 13767c478bd9Sstevel@tonic-gate (proc_str2content(content_str, &content) != 0 || 13777c478bd9Sstevel@tonic-gate content == CC_CONTENT_INVALID)) { 13787c478bd9Sstevel@tonic-gate mdb_warn("invalid content string '%s'\n", content_str); 13797c478bd9Sstevel@tonic-gate return (DCMD_ERR); 13807c478bd9Sstevel@tonic-gate } 13817c478bd9Sstevel@tonic-gate 1382f723faa1Seschrock if (t->t_pshandle == NULL) { 1383f723faa1Seschrock mdb_warn("no process active\n"); 1384f723faa1Seschrock return (DCMD_ERR); 1385f723faa1Seschrock } 1386f723faa1Seschrock 13877c478bd9Sstevel@tonic-gate pid = Pstatus(t->t_pshandle)->pr_pid; 13887c478bd9Sstevel@tonic-gate size = 1 + mdb_snprintf(NULL, 0, "%s.%d", prefix, (int)pid); 13897c478bd9Sstevel@tonic-gate fname = mdb_alloc(size, UM_SLEEP | UM_GC); 13907c478bd9Sstevel@tonic-gate (void) mdb_snprintf(fname, size, "%s.%d", prefix, (int)pid); 13917c478bd9Sstevel@tonic-gate 13927c478bd9Sstevel@tonic-gate if (Pgcore(t->t_pshandle, fname, content) != 0) { 139364e4e50aSKeith M Wesolowski /* 139464e4e50aSKeith M Wesolowski * Short writes during dumping are specifically described by 139564e4e50aSKeith M Wesolowski * EBADE, just as ZFS uses this otherwise-unused code for 139664e4e50aSKeith M Wesolowski * checksum errors. Translate to and mdb errno. 139764e4e50aSKeith M Wesolowski */ 139864e4e50aSKeith M Wesolowski if (errno == EBADE) 139964e4e50aSKeith M Wesolowski (void) set_errno(EMDB_SHORTWRITE); 14007c478bd9Sstevel@tonic-gate mdb_warn("couldn't dump core"); 14017c478bd9Sstevel@tonic-gate return (DCMD_ERR); 14027c478bd9Sstevel@tonic-gate } 14037c478bd9Sstevel@tonic-gate 14047c478bd9Sstevel@tonic-gate mdb_warn("%s dumped\n", fname); 14057c478bd9Sstevel@tonic-gate 14067c478bd9Sstevel@tonic-gate return (DCMD_OK); 14077c478bd9Sstevel@tonic-gate } 14087c478bd9Sstevel@tonic-gate 14097c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 14107c478bd9Sstevel@tonic-gate static int 14117c478bd9Sstevel@tonic-gate pt_kill(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 14127c478bd9Sstevel@tonic-gate { 14137c478bd9Sstevel@tonic-gate mdb_tgt_t *t = mdb.m_target; 14147c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 14157c478bd9Sstevel@tonic-gate int state; 14167c478bd9Sstevel@tonic-gate 14177c478bd9Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) || argc != 0) 14187c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 14197c478bd9Sstevel@tonic-gate 14207c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL && 14217c478bd9Sstevel@tonic-gate (state = Pstate(t->t_pshandle)) != PS_DEAD && state != PS_IDLE) { 14227c478bd9Sstevel@tonic-gate mdb_warn("victim process PID %d forcibly terminated\n", 14237c478bd9Sstevel@tonic-gate (int)Pstatus(t->t_pshandle)->pr_pid); 14247c478bd9Sstevel@tonic-gate pt_pre_detach(t, TRUE); 14257c478bd9Sstevel@tonic-gate pt_release_parents(t); 14267c478bd9Sstevel@tonic-gate Prelease(t->t_pshandle, PRELEASE_KILL); 14277c478bd9Sstevel@tonic-gate t->t_pshandle = pt->p_idlehandle; 14287c478bd9Sstevel@tonic-gate (void) mdb_tgt_status(t, &t->t_status); 14297c478bd9Sstevel@tonic-gate mdb.m_flags &= ~(MDB_FL_VCREATE | MDB_FL_JOBCTL); 14307c478bd9Sstevel@tonic-gate } else 14317c478bd9Sstevel@tonic-gate mdb_warn("no victim process is currently under control\n"); 14327c478bd9Sstevel@tonic-gate 14337c478bd9Sstevel@tonic-gate return (DCMD_OK); 14347c478bd9Sstevel@tonic-gate } 14357c478bd9Sstevel@tonic-gate 14367c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 14377c478bd9Sstevel@tonic-gate static int 14387c478bd9Sstevel@tonic-gate pt_detach(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 14397c478bd9Sstevel@tonic-gate { 14407c478bd9Sstevel@tonic-gate mdb_tgt_t *t = mdb.m_target; 14417c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 14427c478bd9Sstevel@tonic-gate int rflags = pt->p_rflags; 14437c478bd9Sstevel@tonic-gate 14447c478bd9Sstevel@tonic-gate if (argc != 0 && argv->a_type == MDB_TYPE_STRING && 14457c478bd9Sstevel@tonic-gate strcmp(argv->a_un.a_str, "-a") == 0) { 14467c478bd9Sstevel@tonic-gate rflags = PRELEASE_HANG | PRELEASE_CLEAR; 14477c478bd9Sstevel@tonic-gate argv++; 14487c478bd9Sstevel@tonic-gate argc--; 14497c478bd9Sstevel@tonic-gate } 14507c478bd9Sstevel@tonic-gate 14517c478bd9Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) || argc != 0) 14527c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 14537c478bd9Sstevel@tonic-gate 14547c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL || Pstate(t->t_pshandle) == PS_IDLE) { 14557c478bd9Sstevel@tonic-gate mdb_warn("debugger is not currently attached to a process " 14567c478bd9Sstevel@tonic-gate "or core file\n"); 14577c478bd9Sstevel@tonic-gate return (DCMD_ERR); 14587c478bd9Sstevel@tonic-gate } 14597c478bd9Sstevel@tonic-gate 14607c478bd9Sstevel@tonic-gate pt_pre_detach(t, TRUE); 14617c478bd9Sstevel@tonic-gate pt_release_parents(t); 14627c478bd9Sstevel@tonic-gate Prelease(t->t_pshandle, rflags); 14637c478bd9Sstevel@tonic-gate t->t_pshandle = pt->p_idlehandle; 14647c478bd9Sstevel@tonic-gate (void) mdb_tgt_status(t, &t->t_status); 14657c478bd9Sstevel@tonic-gate mdb.m_flags &= ~(MDB_FL_VCREATE | MDB_FL_JOBCTL); 14667c478bd9Sstevel@tonic-gate 14677c478bd9Sstevel@tonic-gate return (DCMD_OK); 14687c478bd9Sstevel@tonic-gate } 14697c478bd9Sstevel@tonic-gate 14707c478bd9Sstevel@tonic-gate static uintmax_t 14717c478bd9Sstevel@tonic-gate reg_disc_get(const mdb_var_t *v) 14727c478bd9Sstevel@tonic-gate { 14737c478bd9Sstevel@tonic-gate mdb_tgt_t *t = MDB_NV_COOKIE(v); 14747c478bd9Sstevel@tonic-gate mdb_tgt_tid_t tid = PTL_TID(t); 14757c478bd9Sstevel@tonic-gate mdb_tgt_reg_t r = 0; 14767c478bd9Sstevel@tonic-gate 14777c478bd9Sstevel@tonic-gate if (tid != (mdb_tgt_tid_t)-1L) 14787c478bd9Sstevel@tonic-gate (void) mdb_tgt_getareg(t, tid, mdb_nv_get_name(v), &r); 14797c478bd9Sstevel@tonic-gate 14807c478bd9Sstevel@tonic-gate return (r); 14817c478bd9Sstevel@tonic-gate } 14827c478bd9Sstevel@tonic-gate 14837c478bd9Sstevel@tonic-gate static void 14847c478bd9Sstevel@tonic-gate reg_disc_set(mdb_var_t *v, uintmax_t r) 14857c478bd9Sstevel@tonic-gate { 14867c478bd9Sstevel@tonic-gate mdb_tgt_t *t = MDB_NV_COOKIE(v); 14877c478bd9Sstevel@tonic-gate mdb_tgt_tid_t tid = PTL_TID(t); 14887c478bd9Sstevel@tonic-gate 14897c478bd9Sstevel@tonic-gate if (tid != (mdb_tgt_tid_t)-1L && mdb_tgt_putareg(t, tid, 14907c478bd9Sstevel@tonic-gate mdb_nv_get_name(v), r) == -1) 14917c478bd9Sstevel@tonic-gate mdb_warn("failed to modify %%%s register", mdb_nv_get_name(v)); 14927c478bd9Sstevel@tonic-gate } 14937c478bd9Sstevel@tonic-gate 14947c478bd9Sstevel@tonic-gate static void 14957c478bd9Sstevel@tonic-gate pt_print_reason(const lwpstatus_t *psp) 14967c478bd9Sstevel@tonic-gate { 14977c478bd9Sstevel@tonic-gate char name[SIG2STR_MAX + 4]; /* enough for SIG+name+\0, syscall or flt */ 14987c478bd9Sstevel@tonic-gate const char *desc; 14997c478bd9Sstevel@tonic-gate 15007c478bd9Sstevel@tonic-gate switch (psp->pr_why) { 15017c478bd9Sstevel@tonic-gate case PR_REQUESTED: 15027c478bd9Sstevel@tonic-gate mdb_printf("stopped by debugger"); 15037c478bd9Sstevel@tonic-gate break; 15047c478bd9Sstevel@tonic-gate case PR_SIGNALLED: 15057c478bd9Sstevel@tonic-gate mdb_printf("stopped on %s (%s)", proc_signame(psp->pr_what, 15067c478bd9Sstevel@tonic-gate name, sizeof (name)), strsignal(psp->pr_what)); 15077c478bd9Sstevel@tonic-gate break; 15087c478bd9Sstevel@tonic-gate case PR_SYSENTRY: 15097c478bd9Sstevel@tonic-gate mdb_printf("stopped on entry to %s system call", 15107c478bd9Sstevel@tonic-gate proc_sysname(psp->pr_what, name, sizeof (name))); 15117c478bd9Sstevel@tonic-gate break; 15127c478bd9Sstevel@tonic-gate case PR_SYSEXIT: 15137c478bd9Sstevel@tonic-gate mdb_printf("stopped on exit from %s system call", 15147c478bd9Sstevel@tonic-gate proc_sysname(psp->pr_what, name, sizeof (name))); 15157c478bd9Sstevel@tonic-gate break; 15167c478bd9Sstevel@tonic-gate case PR_JOBCONTROL: 15177c478bd9Sstevel@tonic-gate mdb_printf("stopped by job control"); 15187c478bd9Sstevel@tonic-gate break; 15197c478bd9Sstevel@tonic-gate case PR_FAULTED: 15207c478bd9Sstevel@tonic-gate if (psp->pr_what == FLTBPT) { 15217c478bd9Sstevel@tonic-gate mdb_printf("stopped on a breakpoint"); 15227c478bd9Sstevel@tonic-gate } else if (psp->pr_what == FLTWATCH) { 15237c478bd9Sstevel@tonic-gate switch (psp->pr_info.si_code) { 15247c478bd9Sstevel@tonic-gate case TRAP_RWATCH: 15257c478bd9Sstevel@tonic-gate desc = "read"; 15267c478bd9Sstevel@tonic-gate break; 15277c478bd9Sstevel@tonic-gate case TRAP_WWATCH: 15287c478bd9Sstevel@tonic-gate desc = "write"; 15297c478bd9Sstevel@tonic-gate break; 15307c478bd9Sstevel@tonic-gate case TRAP_XWATCH: 15317c478bd9Sstevel@tonic-gate desc = "execute"; 15327c478bd9Sstevel@tonic-gate break; 15337c478bd9Sstevel@tonic-gate default: 15347c478bd9Sstevel@tonic-gate desc = "unknown"; 15357c478bd9Sstevel@tonic-gate } 15367c478bd9Sstevel@tonic-gate mdb_printf("stopped %s a watchpoint (%s access to %p)", 15377c478bd9Sstevel@tonic-gate psp->pr_info.si_trapafter ? "after" : "on", 15387c478bd9Sstevel@tonic-gate desc, psp->pr_info.si_addr); 15397c478bd9Sstevel@tonic-gate } else if (psp->pr_what == FLTTRACE) { 15407c478bd9Sstevel@tonic-gate mdb_printf("stopped after a single-step"); 15417c478bd9Sstevel@tonic-gate } else { 15427c478bd9Sstevel@tonic-gate mdb_printf("stopped on a %s fault", 15437c478bd9Sstevel@tonic-gate proc_fltname(psp->pr_what, name, sizeof (name))); 15447c478bd9Sstevel@tonic-gate } 15457c478bd9Sstevel@tonic-gate break; 15467c478bd9Sstevel@tonic-gate case PR_SUSPENDED: 15477c478bd9Sstevel@tonic-gate case PR_CHECKPOINT: 15487c478bd9Sstevel@tonic-gate mdb_printf("suspended by the kernel"); 15497c478bd9Sstevel@tonic-gate break; 15507c478bd9Sstevel@tonic-gate default: 15517c478bd9Sstevel@tonic-gate mdb_printf("stopped for unknown reason (%d/%d)", 15527c478bd9Sstevel@tonic-gate psp->pr_why, psp->pr_what); 15537c478bd9Sstevel@tonic-gate } 15547c478bd9Sstevel@tonic-gate } 15557c478bd9Sstevel@tonic-gate 15567c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 15577c478bd9Sstevel@tonic-gate static int 15587c478bd9Sstevel@tonic-gate pt_status_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 15597c478bd9Sstevel@tonic-gate { 15607c478bd9Sstevel@tonic-gate mdb_tgt_t *t = mdb.m_target; 15617c478bd9Sstevel@tonic-gate struct ps_prochandle *P = t->t_pshandle; 15627c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 15637c478bd9Sstevel@tonic-gate 15647c478bd9Sstevel@tonic-gate if (P != NULL) { 15657c478bd9Sstevel@tonic-gate const psinfo_t *pip = Ppsinfo(P); 15667c478bd9Sstevel@tonic-gate const pstatus_t *psp = Pstatus(P); 15677c478bd9Sstevel@tonic-gate int cursig = 0, bits = 0, coredump = 0; 15687c478bd9Sstevel@tonic-gate int state; 15697c478bd9Sstevel@tonic-gate GElf_Sym sym; 15707c478bd9Sstevel@tonic-gate uintptr_t panicstr; 1571*f68770eaSRobert Mustacchi char *panicbuf = mdb_alloc(PANIC_BUFSIZE, UM_SLEEP); 157248fd701fSKrishnendu Sadhukhan - Sun Microsystems const siginfo_t *sip = &(psp->pr_lwp.pr_info); 15737c478bd9Sstevel@tonic-gate 15747c478bd9Sstevel@tonic-gate char execname[MAXPATHLEN], buf[BUFSIZ]; 15757c478bd9Sstevel@tonic-gate char signame[SIG2STR_MAX + 4]; /* enough for SIG+name+\0 */ 15767c478bd9Sstevel@tonic-gate 15777c478bd9Sstevel@tonic-gate mdb_tgt_spec_desc_t desc; 15787c478bd9Sstevel@tonic-gate mdb_sespec_t *sep; 15797c478bd9Sstevel@tonic-gate 15807c478bd9Sstevel@tonic-gate struct utsname uts; 15817c478bd9Sstevel@tonic-gate prcred_t cred; 15827c478bd9Sstevel@tonic-gate psinfo_t pi; 15837c478bd9Sstevel@tonic-gate 15847c478bd9Sstevel@tonic-gate (void) strcpy(uts.nodename, "unknown machine"); 15857c478bd9Sstevel@tonic-gate (void) Puname(P, &uts); 15867c478bd9Sstevel@tonic-gate 15877c478bd9Sstevel@tonic-gate if (pip != NULL) { 15887c478bd9Sstevel@tonic-gate bcopy(pip, &pi, sizeof (psinfo_t)); 15897c478bd9Sstevel@tonic-gate proc_unctrl_psinfo(&pi); 15907c478bd9Sstevel@tonic-gate } else 15917c478bd9Sstevel@tonic-gate bzero(&pi, sizeof (psinfo_t)); 15927c478bd9Sstevel@tonic-gate 15937c478bd9Sstevel@tonic-gate bits = pi.pr_dmodel == PR_MODEL_ILP32 ? 32 : 64; 15947c478bd9Sstevel@tonic-gate 15957c478bd9Sstevel@tonic-gate state = Pstate(P); 15967c478bd9Sstevel@tonic-gate if (psp != NULL && state != PS_UNDEAD && state != PS_IDLE) 15977c478bd9Sstevel@tonic-gate cursig = psp->pr_lwp.pr_cursig; 15987c478bd9Sstevel@tonic-gate 15997c478bd9Sstevel@tonic-gate if (state == PS_DEAD && pip != NULL) { 16007c478bd9Sstevel@tonic-gate mdb_printf("debugging core file of %s (%d-bit) " 16017c478bd9Sstevel@tonic-gate "from %s\n", pi.pr_fname, bits, uts.nodename); 16027c478bd9Sstevel@tonic-gate 16037c478bd9Sstevel@tonic-gate } else if (state == PS_DEAD) { 16047c478bd9Sstevel@tonic-gate mdb_printf("debugging core file\n"); 16057c478bd9Sstevel@tonic-gate 16067c478bd9Sstevel@tonic-gate } else if (state == PS_IDLE) { 16077c478bd9Sstevel@tonic-gate const GElf_Ehdr *ehp = &pt->p_file->gf_ehdr; 16087c478bd9Sstevel@tonic-gate 16097c478bd9Sstevel@tonic-gate mdb_printf("debugging %s file (%d-bit)\n", 16107c478bd9Sstevel@tonic-gate ehp->e_type == ET_EXEC ? "executable" : "object", 16117c478bd9Sstevel@tonic-gate ehp->e_ident[EI_CLASS] == ELFCLASS32 ? 32 : 64); 16127c478bd9Sstevel@tonic-gate 16137c478bd9Sstevel@tonic-gate } else if (state == PS_UNDEAD && pi.pr_pid == 0) { 16147c478bd9Sstevel@tonic-gate mdb_printf("debugging defunct process\n"); 16157c478bd9Sstevel@tonic-gate 16167c478bd9Sstevel@tonic-gate } else { 16177c478bd9Sstevel@tonic-gate mdb_printf("debugging PID %d (%d-bit)\n", 16187c478bd9Sstevel@tonic-gate pi.pr_pid, bits); 16197c478bd9Sstevel@tonic-gate } 16207c478bd9Sstevel@tonic-gate 16217c478bd9Sstevel@tonic-gate if (Pexecname(P, execname, sizeof (execname)) != NULL) 16227c478bd9Sstevel@tonic-gate mdb_printf("file: %s\n", execname); 16237c478bd9Sstevel@tonic-gate 16247c478bd9Sstevel@tonic-gate if (pip != NULL && state == PS_DEAD) 16257c478bd9Sstevel@tonic-gate mdb_printf("initial argv: %s\n", pi.pr_psargs); 16267c478bd9Sstevel@tonic-gate 16277c478bd9Sstevel@tonic-gate if (state != PS_UNDEAD && state != PS_IDLE) { 16287c478bd9Sstevel@tonic-gate mdb_printf("threading model: "); 16297c478bd9Sstevel@tonic-gate if (pt->p_ptl_ops == &proc_lwp_ops) 16307c478bd9Sstevel@tonic-gate mdb_printf("raw lwps\n"); 16317c478bd9Sstevel@tonic-gate else 16327c478bd9Sstevel@tonic-gate mdb_printf("native threads\n"); 16337c478bd9Sstevel@tonic-gate } 16347c478bd9Sstevel@tonic-gate 16357c478bd9Sstevel@tonic-gate mdb_printf("status: "); 16367c478bd9Sstevel@tonic-gate switch (state) { 16377c478bd9Sstevel@tonic-gate case PS_RUN: 16387c478bd9Sstevel@tonic-gate ASSERT(!(psp->pr_flags & PR_STOPPED)); 16397c478bd9Sstevel@tonic-gate mdb_printf("process is running"); 16407c478bd9Sstevel@tonic-gate if (psp->pr_flags & PR_DSTOP) 16417c478bd9Sstevel@tonic-gate mdb_printf(", debugger stop directive pending"); 16427c478bd9Sstevel@tonic-gate mdb_printf("\n"); 16437c478bd9Sstevel@tonic-gate break; 16447c478bd9Sstevel@tonic-gate 16457c478bd9Sstevel@tonic-gate case PS_STOP: 16467c478bd9Sstevel@tonic-gate ASSERT(psp->pr_flags & PR_STOPPED); 16477c478bd9Sstevel@tonic-gate pt_print_reason(&psp->pr_lwp); 16487c478bd9Sstevel@tonic-gate 16497c478bd9Sstevel@tonic-gate if (psp->pr_flags & PR_DSTOP) 16507c478bd9Sstevel@tonic-gate mdb_printf(", debugger stop directive pending"); 16517c478bd9Sstevel@tonic-gate if (psp->pr_flags & PR_ASLEEP) 16527c478bd9Sstevel@tonic-gate mdb_printf(", sleeping in %s system call", 16537c478bd9Sstevel@tonic-gate proc_sysname(psp->pr_lwp.pr_syscall, 16547c478bd9Sstevel@tonic-gate signame, sizeof (signame))); 16557c478bd9Sstevel@tonic-gate 16567c478bd9Sstevel@tonic-gate mdb_printf("\n"); 16577c478bd9Sstevel@tonic-gate 16587c478bd9Sstevel@tonic-gate for (sep = t->t_matched; sep != T_SE_END; 16597c478bd9Sstevel@tonic-gate sep = sep->se_matched) { 16607c478bd9Sstevel@tonic-gate mdb_printf("event: %s\n", sep->se_ops->se_info( 16617c478bd9Sstevel@tonic-gate t, sep, mdb_list_next(&sep->se_velist), 16627c478bd9Sstevel@tonic-gate &desc, buf, sizeof (buf))); 16637c478bd9Sstevel@tonic-gate } 16647c478bd9Sstevel@tonic-gate break; 16657c478bd9Sstevel@tonic-gate 16667c478bd9Sstevel@tonic-gate case PS_LOST: 16677c478bd9Sstevel@tonic-gate mdb_printf("debugger lost control of process\n"); 16687c478bd9Sstevel@tonic-gate break; 16697c478bd9Sstevel@tonic-gate 16707c478bd9Sstevel@tonic-gate case PS_UNDEAD: 16717c478bd9Sstevel@tonic-gate coredump = WIFSIGNALED(pi.pr_wstat) && 16727c478bd9Sstevel@tonic-gate WCOREDUMP(pi.pr_wstat); 16737c478bd9Sstevel@tonic-gate /*FALLTHRU*/ 16747c478bd9Sstevel@tonic-gate 16757c478bd9Sstevel@tonic-gate case PS_DEAD: 16767c478bd9Sstevel@tonic-gate if (cursig == 0 && WIFSIGNALED(pi.pr_wstat)) 16777c478bd9Sstevel@tonic-gate cursig = WTERMSIG(pi.pr_wstat); 16787c478bd9Sstevel@tonic-gate /* 16797c478bd9Sstevel@tonic-gate * We can only use pr_wstat == 0 as a test for gcore if 16807c478bd9Sstevel@tonic-gate * an NT_PRCRED note is present; these features were 16817c478bd9Sstevel@tonic-gate * added at the same time in Solaris 8. 16827c478bd9Sstevel@tonic-gate */ 16837c478bd9Sstevel@tonic-gate if (pi.pr_wstat == 0 && Pstate(P) == PS_DEAD && 16847c478bd9Sstevel@tonic-gate Pcred(P, &cred, 1) == 0) { 16857c478bd9Sstevel@tonic-gate mdb_printf("process core file generated " 16867c478bd9Sstevel@tonic-gate "with gcore(1)\n"); 16877c478bd9Sstevel@tonic-gate } else if (cursig != 0) { 16887c478bd9Sstevel@tonic-gate mdb_printf("process terminated by %s (%s)", 16897c478bd9Sstevel@tonic-gate proc_signame(cursig, signame, 16907c478bd9Sstevel@tonic-gate sizeof (signame)), strsignal(cursig)); 169148fd701fSKrishnendu Sadhukhan - Sun Microsystems 169248fd701fSKrishnendu Sadhukhan - Sun Microsystems if (sip->si_signo != 0 && SI_FROMUSER(sip) && 169348fd701fSKrishnendu Sadhukhan - Sun Microsystems sip->si_pid != 0) { 169448fd701fSKrishnendu Sadhukhan - Sun Microsystems mdb_printf(", pid=%d uid=%u", 169548fd701fSKrishnendu Sadhukhan - Sun Microsystems (int)sip->si_pid, sip->si_uid); 169648fd701fSKrishnendu Sadhukhan - Sun Microsystems if (sip->si_code != 0) { 169748fd701fSKrishnendu Sadhukhan - Sun Microsystems mdb_printf(" code=%d", 169848fd701fSKrishnendu Sadhukhan - Sun Microsystems sip->si_code); 169948fd701fSKrishnendu Sadhukhan - Sun Microsystems } 170048fd701fSKrishnendu Sadhukhan - Sun Microsystems } else { 170148fd701fSKrishnendu Sadhukhan - Sun Microsystems switch (sip->si_signo) { 170248fd701fSKrishnendu Sadhukhan - Sun Microsystems case SIGILL: 170348fd701fSKrishnendu Sadhukhan - Sun Microsystems case SIGTRAP: 170448fd701fSKrishnendu Sadhukhan - Sun Microsystems case SIGFPE: 170548fd701fSKrishnendu Sadhukhan - Sun Microsystems case SIGSEGV: 170648fd701fSKrishnendu Sadhukhan - Sun Microsystems case SIGBUS: 170748fd701fSKrishnendu Sadhukhan - Sun Microsystems case SIGEMT: 170848fd701fSKrishnendu Sadhukhan - Sun Microsystems mdb_printf(", addr=%p", 170948fd701fSKrishnendu Sadhukhan - Sun Microsystems sip->si_addr); 171048fd701fSKrishnendu Sadhukhan - Sun Microsystems default: 171148fd701fSKrishnendu Sadhukhan - Sun Microsystems break; 171248fd701fSKrishnendu Sadhukhan - Sun Microsystems } 171348fd701fSKrishnendu Sadhukhan - Sun Microsystems } 171448fd701fSKrishnendu Sadhukhan - Sun Microsystems 17157c478bd9Sstevel@tonic-gate if (coredump) 17167c478bd9Sstevel@tonic-gate mdb_printf(" - core file dumped"); 17177c478bd9Sstevel@tonic-gate mdb_printf("\n"); 17187c478bd9Sstevel@tonic-gate } else { 17197c478bd9Sstevel@tonic-gate mdb_printf("process terminated with exit " 17207c478bd9Sstevel@tonic-gate "status %d\n", WEXITSTATUS(pi.pr_wstat)); 17217c478bd9Sstevel@tonic-gate } 17227c478bd9Sstevel@tonic-gate 17237c478bd9Sstevel@tonic-gate if (Plookup_by_name(t->t_pshandle, "libc.so", 17247c478bd9Sstevel@tonic-gate "panicstr", &sym) == 0 && 17257c478bd9Sstevel@tonic-gate Pread(t->t_pshandle, &panicstr, sizeof (panicstr), 17267c478bd9Sstevel@tonic-gate sym.st_value) == sizeof (panicstr) && 17277c478bd9Sstevel@tonic-gate Pread_string(t->t_pshandle, panicbuf, 1728*f68770eaSRobert Mustacchi PANIC_BUFSIZE, panicstr) > 0) { 17297c478bd9Sstevel@tonic-gate mdb_printf("panic message: %s", 17307c478bd9Sstevel@tonic-gate panicbuf); 17317c478bd9Sstevel@tonic-gate } 17327c478bd9Sstevel@tonic-gate 17337c478bd9Sstevel@tonic-gate 17347c478bd9Sstevel@tonic-gate break; 17357c478bd9Sstevel@tonic-gate 17367c478bd9Sstevel@tonic-gate case PS_IDLE: 17377c478bd9Sstevel@tonic-gate mdb_printf("idle\n"); 17387c478bd9Sstevel@tonic-gate break; 17397c478bd9Sstevel@tonic-gate 17407c478bd9Sstevel@tonic-gate default: 17417c478bd9Sstevel@tonic-gate mdb_printf("unknown libproc Pstate: %d\n", Pstate(P)); 17427c478bd9Sstevel@tonic-gate } 1743*f68770eaSRobert Mustacchi mdb_free(panicbuf, PANIC_BUFSIZE); 17447c478bd9Sstevel@tonic-gate 17457c478bd9Sstevel@tonic-gate } else if (pt->p_file != NULL) { 17467c478bd9Sstevel@tonic-gate const GElf_Ehdr *ehp = &pt->p_file->gf_ehdr; 17477c478bd9Sstevel@tonic-gate 17487c478bd9Sstevel@tonic-gate mdb_printf("debugging %s file (%d-bit)\n", 17497c478bd9Sstevel@tonic-gate ehp->e_type == ET_EXEC ? "executable" : "object", 17507c478bd9Sstevel@tonic-gate ehp->e_ident[EI_CLASS] == ELFCLASS32 ? 32 : 64); 17517c478bd9Sstevel@tonic-gate mdb_printf("executable file: %s\n", IOP_NAME(pt->p_fio)); 17527c478bd9Sstevel@tonic-gate mdb_printf("status: idle\n"); 17537c478bd9Sstevel@tonic-gate } 17547c478bd9Sstevel@tonic-gate 17557c478bd9Sstevel@tonic-gate return (DCMD_OK); 17567c478bd9Sstevel@tonic-gate } 17577c478bd9Sstevel@tonic-gate 17587c478bd9Sstevel@tonic-gate static int 17597c478bd9Sstevel@tonic-gate pt_tls(uintptr_t tid, uint_t flags, int argc, const mdb_arg_t *argv) 17607c478bd9Sstevel@tonic-gate { 17617c478bd9Sstevel@tonic-gate const char *name; 17627c478bd9Sstevel@tonic-gate const char *object; 17637c478bd9Sstevel@tonic-gate GElf_Sym sym; 17647c478bd9Sstevel@tonic-gate mdb_syminfo_t si; 17657c478bd9Sstevel@tonic-gate mdb_tgt_t *t = mdb.m_target; 17667c478bd9Sstevel@tonic-gate 17677c478bd9Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC) || argc > 1) 17687c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 17697c478bd9Sstevel@tonic-gate 17707c478bd9Sstevel@tonic-gate if (argc == 0) { 17717c478bd9Sstevel@tonic-gate psaddr_t b; 17727c478bd9Sstevel@tonic-gate 17737c478bd9Sstevel@tonic-gate if (tlsbase(t, tid, PR_LMID_EVERY, MDB_TGT_OBJ_EXEC, &b) != 0) { 17747c478bd9Sstevel@tonic-gate mdb_warn("failed to lookup tlsbase for %r", tid); 17757c478bd9Sstevel@tonic-gate return (DCMD_ERR); 17767c478bd9Sstevel@tonic-gate } 17777c478bd9Sstevel@tonic-gate 17787c478bd9Sstevel@tonic-gate mdb_printf("%lr\n", b); 17797c478bd9Sstevel@tonic-gate mdb_set_dot(b); 17807c478bd9Sstevel@tonic-gate 17817c478bd9Sstevel@tonic-gate return (DCMD_OK); 17827c478bd9Sstevel@tonic-gate } 17837c478bd9Sstevel@tonic-gate 17847c478bd9Sstevel@tonic-gate name = argv[0].a_un.a_str; 17857c478bd9Sstevel@tonic-gate object = MDB_TGT_OBJ_EVERY; 17867c478bd9Sstevel@tonic-gate 17877c478bd9Sstevel@tonic-gate if (pt_lookup_by_name_thr(t, object, name, &sym, &si, tid) != 0) { 17887c478bd9Sstevel@tonic-gate mdb_warn("failed to lookup %s", name); 17897c478bd9Sstevel@tonic-gate return (DCMD_ABORT); /* avoid repeated failure */ 17907c478bd9Sstevel@tonic-gate } 17917c478bd9Sstevel@tonic-gate 17927c478bd9Sstevel@tonic-gate if (GELF_ST_TYPE(sym.st_info) != STT_TLS && DCMD_HDRSPEC(flags)) 17937c478bd9Sstevel@tonic-gate mdb_warn("%s does not refer to thread local storage\n", name); 17947c478bd9Sstevel@tonic-gate 17957c478bd9Sstevel@tonic-gate mdb_printf("%llr\n", sym.st_value); 17967c478bd9Sstevel@tonic-gate mdb_set_dot(sym.st_value); 17977c478bd9Sstevel@tonic-gate 17987c478bd9Sstevel@tonic-gate return (DCMD_OK); 17997c478bd9Sstevel@tonic-gate } 18007c478bd9Sstevel@tonic-gate 18017c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 18027c478bd9Sstevel@tonic-gate static int 18037c478bd9Sstevel@tonic-gate pt_tmodel(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 18047c478bd9Sstevel@tonic-gate { 18057c478bd9Sstevel@tonic-gate mdb_tgt_t *t = mdb.m_target; 18067c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 18077c478bd9Sstevel@tonic-gate const pt_ptl_ops_t *ptl_ops; 18087c478bd9Sstevel@tonic-gate 18097c478bd9Sstevel@tonic-gate if (argc != 1 || argv->a_type != MDB_TYPE_STRING) 18107c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 18117c478bd9Sstevel@tonic-gate 18127c478bd9Sstevel@tonic-gate if (strcmp(argv->a_un.a_str, "thread") == 0) 18137c478bd9Sstevel@tonic-gate ptl_ops = &proc_tdb_ops; 18147c478bd9Sstevel@tonic-gate else if (strcmp(argv->a_un.a_str, "lwp") == 0) 18157c478bd9Sstevel@tonic-gate ptl_ops = &proc_lwp_ops; 18167c478bd9Sstevel@tonic-gate else 18177c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 18187c478bd9Sstevel@tonic-gate 18197c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL && pt->p_ptl_ops != ptl_ops) { 18207c478bd9Sstevel@tonic-gate PTL_DTOR(t); 18217c478bd9Sstevel@tonic-gate pt->p_tdb_ops = NULL; 18227c478bd9Sstevel@tonic-gate pt->p_ptl_ops = &proc_lwp_ops; 18237c478bd9Sstevel@tonic-gate pt->p_ptl_hdl = NULL; 18247c478bd9Sstevel@tonic-gate 18257c478bd9Sstevel@tonic-gate if (ptl_ops == &proc_tdb_ops) { 182695d62a61SEdward Pilatowicz (void) Pobject_iter(t->t_pshandle, (proc_map_f *) 182795d62a61SEdward Pilatowicz thr_check, t); 18287c478bd9Sstevel@tonic-gate } 18297c478bd9Sstevel@tonic-gate } 18307c478bd9Sstevel@tonic-gate 18317c478bd9Sstevel@tonic-gate (void) mdb_tgt_status(t, &t->t_status); 18327c478bd9Sstevel@tonic-gate return (DCMD_OK); 18337c478bd9Sstevel@tonic-gate } 18347c478bd9Sstevel@tonic-gate 18357c478bd9Sstevel@tonic-gate static const char * 18367c478bd9Sstevel@tonic-gate env_match(const char *cmp, const char *nameval) 18377c478bd9Sstevel@tonic-gate { 18387c478bd9Sstevel@tonic-gate const char *loc; 18397c478bd9Sstevel@tonic-gate size_t cmplen = strlen(cmp); 18407c478bd9Sstevel@tonic-gate 18417c478bd9Sstevel@tonic-gate loc = strchr(nameval, '='); 18427c478bd9Sstevel@tonic-gate if (loc != NULL && (loc - nameval) == cmplen && 18437c478bd9Sstevel@tonic-gate strncmp(nameval, cmp, cmplen) == 0) { 18447c478bd9Sstevel@tonic-gate return (loc + 1); 18457c478bd9Sstevel@tonic-gate } 18467c478bd9Sstevel@tonic-gate 18477c478bd9Sstevel@tonic-gate return (NULL); 18487c478bd9Sstevel@tonic-gate } 18497c478bd9Sstevel@tonic-gate 18507c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 18517c478bd9Sstevel@tonic-gate static int 18527c478bd9Sstevel@tonic-gate print_env(void *data, struct ps_prochandle *P, uintptr_t addr, 18537c478bd9Sstevel@tonic-gate const char *nameval) 18547c478bd9Sstevel@tonic-gate { 18557c478bd9Sstevel@tonic-gate const char *value; 18567c478bd9Sstevel@tonic-gate 18577c478bd9Sstevel@tonic-gate if (nameval == NULL) { 18587c478bd9Sstevel@tonic-gate mdb_printf("<0x%p>\n", addr); 18597c478bd9Sstevel@tonic-gate } else { 18607c478bd9Sstevel@tonic-gate if (data == NULL) 18617c478bd9Sstevel@tonic-gate mdb_printf("%s\n", nameval); 18627c478bd9Sstevel@tonic-gate else if ((value = env_match(data, nameval)) != NULL) 18637c478bd9Sstevel@tonic-gate mdb_printf("%s\n", value); 18647c478bd9Sstevel@tonic-gate } 18657c478bd9Sstevel@tonic-gate 18667c478bd9Sstevel@tonic-gate return (0); 18677c478bd9Sstevel@tonic-gate } 18687c478bd9Sstevel@tonic-gate 18697c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 18707c478bd9Sstevel@tonic-gate static int 18717c478bd9Sstevel@tonic-gate pt_getenv(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 18727c478bd9Sstevel@tonic-gate { 18737c478bd9Sstevel@tonic-gate mdb_tgt_t *t = mdb.m_target; 18747c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 18757c478bd9Sstevel@tonic-gate int i; 18767c478bd9Sstevel@tonic-gate uint_t opt_t = 0; 18777c478bd9Sstevel@tonic-gate mdb_var_t *v; 18787c478bd9Sstevel@tonic-gate 18797c478bd9Sstevel@tonic-gate i = mdb_getopts(argc, argv, 18807c478bd9Sstevel@tonic-gate 't', MDB_OPT_SETBITS, TRUE, &opt_t, NULL); 18817c478bd9Sstevel@tonic-gate 18827c478bd9Sstevel@tonic-gate argc -= i; 18837c478bd9Sstevel@tonic-gate argv += i; 18847c478bd9Sstevel@tonic-gate 18857c478bd9Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) || argc > 1) 18867c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 18877c478bd9Sstevel@tonic-gate 18887c478bd9Sstevel@tonic-gate if (argc == 1 && argv->a_type != MDB_TYPE_STRING) 18897c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 18907c478bd9Sstevel@tonic-gate 1891f723faa1Seschrock if (opt_t && t->t_pshandle == NULL) { 1892f723faa1Seschrock mdb_warn("no process active\n"); 1893f723faa1Seschrock return (DCMD_ERR); 1894f723faa1Seschrock } 1895f723faa1Seschrock 18967c478bd9Sstevel@tonic-gate if (opt_t && (Pstate(t->t_pshandle) == PS_IDLE || 18977c478bd9Sstevel@tonic-gate Pstate(t->t_pshandle) == PS_UNDEAD)) { 18987c478bd9Sstevel@tonic-gate mdb_warn("-t option requires target to be running\n"); 18997c478bd9Sstevel@tonic-gate return (DCMD_ERR); 19007c478bd9Sstevel@tonic-gate } 19017c478bd9Sstevel@tonic-gate 19027c478bd9Sstevel@tonic-gate if (opt_t != 0) { 19037c478bd9Sstevel@tonic-gate if (Penv_iter(t->t_pshandle, print_env, 19047c478bd9Sstevel@tonic-gate argc == 0 ? NULL : (void *)argv->a_un.a_str) != 0) 19057c478bd9Sstevel@tonic-gate return (DCMD_ERR); 19067c478bd9Sstevel@tonic-gate } else if (argc == 1) { 19077c478bd9Sstevel@tonic-gate if ((v = mdb_nv_lookup(&pt->p_env, argv->a_un.a_str)) == NULL) 19087c478bd9Sstevel@tonic-gate return (DCMD_ERR); 19097c478bd9Sstevel@tonic-gate 19107c478bd9Sstevel@tonic-gate ASSERT(strchr(mdb_nv_get_cookie(v), '=') != NULL); 19117c478bd9Sstevel@tonic-gate mdb_printf("%s\n", strchr(mdb_nv_get_cookie(v), '=') + 1); 19127c478bd9Sstevel@tonic-gate } else { 19137c478bd9Sstevel@tonic-gate 19147c478bd9Sstevel@tonic-gate mdb_nv_rewind(&pt->p_env); 19157c478bd9Sstevel@tonic-gate while ((v = mdb_nv_advance(&pt->p_env)) != NULL) 19167c478bd9Sstevel@tonic-gate mdb_printf("%s\n", mdb_nv_get_cookie(v)); 19177c478bd9Sstevel@tonic-gate } 19187c478bd9Sstevel@tonic-gate 19197c478bd9Sstevel@tonic-gate return (DCMD_OK); 19207c478bd9Sstevel@tonic-gate } 19217c478bd9Sstevel@tonic-gate 19227c478bd9Sstevel@tonic-gate /* 19237c478bd9Sstevel@tonic-gate * Function to set a variable in the internal environment, which is used when 19247c478bd9Sstevel@tonic-gate * creating new processes. Note that it is possible that 'nameval' can refer to 19257c478bd9Sstevel@tonic-gate * read-only memory, if mdb calls putenv() on an existing value before calling 19267c478bd9Sstevel@tonic-gate * this function. While we should avoid this situation, this function is 19277c478bd9Sstevel@tonic-gate * designed to be robust in the face of such changes. 19287c478bd9Sstevel@tonic-gate */ 19297c478bd9Sstevel@tonic-gate static void 19307c478bd9Sstevel@tonic-gate pt_env_set(pt_data_t *pt, const char *nameval) 19317c478bd9Sstevel@tonic-gate { 19327c478bd9Sstevel@tonic-gate mdb_var_t *v; 19337c478bd9Sstevel@tonic-gate char *equals, *val; 19347c478bd9Sstevel@tonic-gate const char *name; 19357c478bd9Sstevel@tonic-gate size_t len; 19367c478bd9Sstevel@tonic-gate 19377c478bd9Sstevel@tonic-gate if ((equals = strchr(nameval, '=')) != NULL) { 19387c478bd9Sstevel@tonic-gate val = strdup(nameval); 19397c478bd9Sstevel@tonic-gate equals = val + (equals - nameval); 19407c478bd9Sstevel@tonic-gate } else { 19417c478bd9Sstevel@tonic-gate /* 19427c478bd9Sstevel@tonic-gate * nameval doesn't contain an equals character. Convert this to 19437c478bd9Sstevel@tonic-gate * be 'nameval='. 19447c478bd9Sstevel@tonic-gate */ 19457c478bd9Sstevel@tonic-gate len = strlen(nameval); 19467c478bd9Sstevel@tonic-gate val = mdb_alloc(len + 2, UM_SLEEP); 19477c478bd9Sstevel@tonic-gate (void) mdb_snprintf(val, len + 2, "%s=", nameval); 19487c478bd9Sstevel@tonic-gate equals = val + len; 19497c478bd9Sstevel@tonic-gate } 19507c478bd9Sstevel@tonic-gate 19517c478bd9Sstevel@tonic-gate /* temporary truncate the string for lookup/insert */ 19527c478bd9Sstevel@tonic-gate *equals = '\0'; 19537c478bd9Sstevel@tonic-gate v = mdb_nv_lookup(&pt->p_env, val); 19547c478bd9Sstevel@tonic-gate 19557c478bd9Sstevel@tonic-gate if (v != NULL) { 19567c478bd9Sstevel@tonic-gate char *old = mdb_nv_get_cookie(v); 19577c478bd9Sstevel@tonic-gate mdb_free(old, strlen(old) + 1); 19587c478bd9Sstevel@tonic-gate name = mdb_nv_get_name(v); 19597c478bd9Sstevel@tonic-gate } else { 19607c478bd9Sstevel@tonic-gate /* 19617c478bd9Sstevel@tonic-gate * The environment is created using MDB_NV_EXTNAME, so we must 19627c478bd9Sstevel@tonic-gate * provide external storage for the variable names. 19637c478bd9Sstevel@tonic-gate */ 19647c478bd9Sstevel@tonic-gate name = strdup(val); 19657c478bd9Sstevel@tonic-gate } 19667c478bd9Sstevel@tonic-gate 19677c478bd9Sstevel@tonic-gate *equals = '='; 19687c478bd9Sstevel@tonic-gate 19697c478bd9Sstevel@tonic-gate (void) mdb_nv_insert(&pt->p_env, name, NULL, (uintptr_t)val, 19707c478bd9Sstevel@tonic-gate MDB_NV_EXTNAME); 19717c478bd9Sstevel@tonic-gate 19727c478bd9Sstevel@tonic-gate if (equals) 19737c478bd9Sstevel@tonic-gate *equals = '='; 19747c478bd9Sstevel@tonic-gate } 19757c478bd9Sstevel@tonic-gate 19767c478bd9Sstevel@tonic-gate /* 19777c478bd9Sstevel@tonic-gate * Clears the internal environment. 19787c478bd9Sstevel@tonic-gate */ 19797c478bd9Sstevel@tonic-gate static void 19807c478bd9Sstevel@tonic-gate pt_env_clear(pt_data_t *pt) 19817c478bd9Sstevel@tonic-gate { 19827c478bd9Sstevel@tonic-gate mdb_var_t *v; 19837c478bd9Sstevel@tonic-gate char *val, *name; 19847c478bd9Sstevel@tonic-gate 19857c478bd9Sstevel@tonic-gate mdb_nv_rewind(&pt->p_env); 19867c478bd9Sstevel@tonic-gate while ((v = mdb_nv_advance(&pt->p_env)) != NULL) { 19877c478bd9Sstevel@tonic-gate 19887c478bd9Sstevel@tonic-gate name = (char *)mdb_nv_get_name(v); 19897c478bd9Sstevel@tonic-gate val = mdb_nv_get_cookie(v); 19907c478bd9Sstevel@tonic-gate 19917c478bd9Sstevel@tonic-gate mdb_nv_remove(&pt->p_env, v); 19927c478bd9Sstevel@tonic-gate 19937c478bd9Sstevel@tonic-gate mdb_free(name, strlen(name) + 1); 19947c478bd9Sstevel@tonic-gate mdb_free(val, strlen(val) + 1); 19957c478bd9Sstevel@tonic-gate } 19967c478bd9Sstevel@tonic-gate } 19977c478bd9Sstevel@tonic-gate 19987c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 19997c478bd9Sstevel@tonic-gate static int 20007c478bd9Sstevel@tonic-gate pt_setenv(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 20017c478bd9Sstevel@tonic-gate { 20027c478bd9Sstevel@tonic-gate mdb_tgt_t *t = mdb.m_target; 20037c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 20047c478bd9Sstevel@tonic-gate char *nameval; 20057c478bd9Sstevel@tonic-gate size_t len; 20067c478bd9Sstevel@tonic-gate int alloc; 20077c478bd9Sstevel@tonic-gate 20087c478bd9Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) || argc == 0 || argc > 2) 20097c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 20107c478bd9Sstevel@tonic-gate 20117c478bd9Sstevel@tonic-gate if ((argc > 0 && argv[0].a_type != MDB_TYPE_STRING) || 20127c478bd9Sstevel@tonic-gate (argc > 1 && argv[1].a_type != MDB_TYPE_STRING)) 20137c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 20147c478bd9Sstevel@tonic-gate 2015f723faa1Seschrock if (t->t_pshandle == NULL) { 2016f723faa1Seschrock mdb_warn("no process active\n"); 2017f723faa1Seschrock return (DCMD_ERR); 2018f723faa1Seschrock } 2019f723faa1Seschrock 20207c478bd9Sstevel@tonic-gate /* 20217c478bd9Sstevel@tonic-gate * If the process is in some sort of running state, warn the user that 20227c478bd9Sstevel@tonic-gate * changes won't immediately take effect. 20237c478bd9Sstevel@tonic-gate */ 20247c478bd9Sstevel@tonic-gate if (Pstate(t->t_pshandle) == PS_RUN || 20257c478bd9Sstevel@tonic-gate Pstate(t->t_pshandle) == PS_STOP) { 20267c478bd9Sstevel@tonic-gate mdb_warn("warning: changes will not take effect until process" 20277c478bd9Sstevel@tonic-gate " is restarted\n"); 20287c478bd9Sstevel@tonic-gate } 20297c478bd9Sstevel@tonic-gate 20307c478bd9Sstevel@tonic-gate /* 20317c478bd9Sstevel@tonic-gate * We allow two forms of operation. The first is the usual "name=value" 20327c478bd9Sstevel@tonic-gate * parameter. We also allow the user to specify two arguments, where 20337c478bd9Sstevel@tonic-gate * the first is the name of the variable, and the second is the value. 20347c478bd9Sstevel@tonic-gate */ 20357c478bd9Sstevel@tonic-gate alloc = 0; 20367c478bd9Sstevel@tonic-gate if (argc == 1) { 20377c478bd9Sstevel@tonic-gate nameval = (char *)argv->a_un.a_str; 20387c478bd9Sstevel@tonic-gate } else { 20397c478bd9Sstevel@tonic-gate len = strlen(argv[0].a_un.a_str) + 20407c478bd9Sstevel@tonic-gate strlen(argv[1].a_un.a_str) + 2; 20417c478bd9Sstevel@tonic-gate nameval = mdb_alloc(len, UM_SLEEP); 20427c478bd9Sstevel@tonic-gate (void) mdb_snprintf(nameval, len, "%s=%s", argv[0].a_un.a_str, 20437c478bd9Sstevel@tonic-gate argv[1].a_un.a_str); 20447c478bd9Sstevel@tonic-gate alloc = 1; 20457c478bd9Sstevel@tonic-gate } 20467c478bd9Sstevel@tonic-gate 20477c478bd9Sstevel@tonic-gate pt_env_set(pt, nameval); 20487c478bd9Sstevel@tonic-gate 20497c478bd9Sstevel@tonic-gate if (alloc) 20507c478bd9Sstevel@tonic-gate mdb_free(nameval, strlen(nameval) + 1); 20517c478bd9Sstevel@tonic-gate 20527c478bd9Sstevel@tonic-gate return (DCMD_OK); 20537c478bd9Sstevel@tonic-gate } 20547c478bd9Sstevel@tonic-gate 20557c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 20567c478bd9Sstevel@tonic-gate static int 20577c478bd9Sstevel@tonic-gate pt_unsetenv(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 20587c478bd9Sstevel@tonic-gate { 20597c478bd9Sstevel@tonic-gate mdb_tgt_t *t = mdb.m_target; 20607c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 20617c478bd9Sstevel@tonic-gate mdb_var_t *v; 20627c478bd9Sstevel@tonic-gate char *value, *name; 20637c478bd9Sstevel@tonic-gate 20647c478bd9Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) || argc > 1) 20657c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 20667c478bd9Sstevel@tonic-gate 20677c478bd9Sstevel@tonic-gate if (argc == 1 && argv->a_type != MDB_TYPE_STRING) 20687c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 20697c478bd9Sstevel@tonic-gate 2070f723faa1Seschrock if (t->t_pshandle == NULL) { 2071f723faa1Seschrock mdb_warn("no process active\n"); 2072f723faa1Seschrock return (DCMD_ERR); 2073f723faa1Seschrock } 2074f723faa1Seschrock 20757c478bd9Sstevel@tonic-gate /* 20767c478bd9Sstevel@tonic-gate * If the process is in some sort of running state, warn the user that 20777c478bd9Sstevel@tonic-gate * changes won't immediately take effect. 20787c478bd9Sstevel@tonic-gate */ 20797c478bd9Sstevel@tonic-gate if (Pstate(t->t_pshandle) == PS_RUN || 20807c478bd9Sstevel@tonic-gate Pstate(t->t_pshandle) == PS_STOP) { 20817c478bd9Sstevel@tonic-gate mdb_warn("warning: changes will not take effect until process" 20827c478bd9Sstevel@tonic-gate " is restarted\n"); 20837c478bd9Sstevel@tonic-gate } 20847c478bd9Sstevel@tonic-gate 20857c478bd9Sstevel@tonic-gate if (argc == 0) { 20867c478bd9Sstevel@tonic-gate pt_env_clear(pt); 20877c478bd9Sstevel@tonic-gate } else { 20887c478bd9Sstevel@tonic-gate if ((v = mdb_nv_lookup(&pt->p_env, argv->a_un.a_str)) != NULL) { 20897c478bd9Sstevel@tonic-gate name = (char *)mdb_nv_get_name(v); 20907c478bd9Sstevel@tonic-gate value = mdb_nv_get_cookie(v); 20917c478bd9Sstevel@tonic-gate 20927c478bd9Sstevel@tonic-gate mdb_nv_remove(&pt->p_env, v); 20937c478bd9Sstevel@tonic-gate 20947c478bd9Sstevel@tonic-gate mdb_free(name, strlen(name) + 1); 20957c478bd9Sstevel@tonic-gate mdb_free(value, strlen(value) + 1); 20967c478bd9Sstevel@tonic-gate } 20977c478bd9Sstevel@tonic-gate } 20987c478bd9Sstevel@tonic-gate 20997c478bd9Sstevel@tonic-gate return (DCMD_OK); 21007c478bd9Sstevel@tonic-gate } 21017c478bd9Sstevel@tonic-gate 2102b77e74e4Sjohnlev void 2103b77e74e4Sjohnlev getenv_help(void) 2104b77e74e4Sjohnlev { 2105b77e74e4Sjohnlev mdb_printf("-t show current process environment" 2106b77e74e4Sjohnlev " instead of initial environment.\n"); 2107b77e74e4Sjohnlev } 2108b77e74e4Sjohnlev 21097c478bd9Sstevel@tonic-gate static const mdb_dcmd_t pt_dcmds[] = { 21107c478bd9Sstevel@tonic-gate { "$c", "?[cnt]", "print stack backtrace", pt_stack }, 21117c478bd9Sstevel@tonic-gate { "$C", "?[cnt]", "print stack backtrace", pt_stackv }, 21127c478bd9Sstevel@tonic-gate { "$i", NULL, "print signals that are ignored", pt_ignored }, 21137c478bd9Sstevel@tonic-gate { "$l", NULL, "print the representative thread's lwp id", pt_lwpid }, 21147c478bd9Sstevel@tonic-gate { "$L", NULL, "print list of the active lwp ids", pt_lwpids }, 21158f88a51fSJoshua M. Clulow { "$r", "?[-u]", "print general-purpose registers", pt_regs }, 21167c478bd9Sstevel@tonic-gate { "$x", "?", "print floating point registers", pt_fpregs }, 21177c478bd9Sstevel@tonic-gate { "$X", "?", "print floating point registers", pt_fpregs }, 21187c478bd9Sstevel@tonic-gate { "$y", "?", "print floating point registers", pt_fpregs }, 21197c478bd9Sstevel@tonic-gate { "$Y", "?", "print floating point registers", pt_fpregs }, 21207c478bd9Sstevel@tonic-gate { "$?", "?", "print status and registers", pt_regstatus }, 21217c478bd9Sstevel@tonic-gate { ":A", "?[core|pid]", "attach to process or core file", pt_attach }, 21227c478bd9Sstevel@tonic-gate { ":i", ":", "ignore signal (delete all matching events)", pt_ignore }, 21237c478bd9Sstevel@tonic-gate { ":k", NULL, "forcibly kill and release target", pt_kill }, 21247c478bd9Sstevel@tonic-gate { ":R", "[-a]", "release the previously attached process", pt_detach }, 21257c478bd9Sstevel@tonic-gate { "attach", "?[core|pid]", 21267c478bd9Sstevel@tonic-gate "attach to process or core file", pt_attach }, 21277c478bd9Sstevel@tonic-gate { "findstack", ":[-v]", "find user thread stack", pt_findstack }, 21287c478bd9Sstevel@tonic-gate { "gcore", "[-o prefix] [-c content]", 21297c478bd9Sstevel@tonic-gate "produce a core file for the attached process", pt_gcore }, 21307c478bd9Sstevel@tonic-gate { "getenv", "[-t] [name]", "display an environment variable", 2131b77e74e4Sjohnlev pt_getenv, getenv_help }, 21327c478bd9Sstevel@tonic-gate { "kill", NULL, "forcibly kill and release target", pt_kill }, 21337c478bd9Sstevel@tonic-gate { "release", "[-a]", 21347c478bd9Sstevel@tonic-gate "release the previously attached process", pt_detach }, 21358f88a51fSJoshua M. Clulow { "regs", "?[-u]", "print general-purpose registers", pt_regs }, 21367c478bd9Sstevel@tonic-gate { "fpregs", "?[-dqs]", "print floating point registers", pt_fpregs }, 21377c478bd9Sstevel@tonic-gate { "setenv", "name=value", "set an environment variable", pt_setenv }, 21387c478bd9Sstevel@tonic-gate { "stack", "?[cnt]", "print stack backtrace", pt_stack }, 21397c478bd9Sstevel@tonic-gate { "stackregs", "?", "print stack backtrace and registers", pt_stackr }, 21407c478bd9Sstevel@tonic-gate { "status", NULL, "print summary of current target", pt_status_dcmd }, 21417c478bd9Sstevel@tonic-gate { "tls", ":symbol", 21427c478bd9Sstevel@tonic-gate "lookup TLS data in the context of a given thread", pt_tls }, 21437c478bd9Sstevel@tonic-gate { "tmodel", "{thread|lwp}", NULL, pt_tmodel }, 21447c478bd9Sstevel@tonic-gate { "unsetenv", "[name]", "clear an environment variable", pt_unsetenv }, 21457c478bd9Sstevel@tonic-gate { NULL } 21467c478bd9Sstevel@tonic-gate }; 21477c478bd9Sstevel@tonic-gate 21487c478bd9Sstevel@tonic-gate static void 21497c478bd9Sstevel@tonic-gate pt_thr_walk_fini(mdb_walk_state_t *wsp) 21507c478bd9Sstevel@tonic-gate { 21517c478bd9Sstevel@tonic-gate mdb_addrvec_destroy(wsp->walk_data); 21527c478bd9Sstevel@tonic-gate mdb_free(wsp->walk_data, sizeof (mdb_addrvec_t)); 21537c478bd9Sstevel@tonic-gate } 21547c478bd9Sstevel@tonic-gate 21557c478bd9Sstevel@tonic-gate static int 21567c478bd9Sstevel@tonic-gate pt_thr_walk_init(mdb_walk_state_t *wsp) 21577c478bd9Sstevel@tonic-gate { 21587c478bd9Sstevel@tonic-gate wsp->walk_data = mdb_zalloc(sizeof (mdb_addrvec_t), UM_SLEEP); 21597c478bd9Sstevel@tonic-gate mdb_addrvec_create(wsp->walk_data); 21607c478bd9Sstevel@tonic-gate 21617c478bd9Sstevel@tonic-gate if (PTL_ITER(mdb.m_target, wsp->walk_data) == -1) { 21627c478bd9Sstevel@tonic-gate mdb_warn("failed to iterate over threads"); 21637c478bd9Sstevel@tonic-gate pt_thr_walk_fini(wsp); 21647c478bd9Sstevel@tonic-gate return (WALK_ERR); 21657c478bd9Sstevel@tonic-gate } 21667c478bd9Sstevel@tonic-gate 21677c478bd9Sstevel@tonic-gate return (WALK_NEXT); 21687c478bd9Sstevel@tonic-gate } 21697c478bd9Sstevel@tonic-gate 21707c478bd9Sstevel@tonic-gate static int 21717c478bd9Sstevel@tonic-gate pt_thr_walk_step(mdb_walk_state_t *wsp) 21727c478bd9Sstevel@tonic-gate { 21737c478bd9Sstevel@tonic-gate if (mdb_addrvec_length(wsp->walk_data) != 0) { 21747c478bd9Sstevel@tonic-gate return (wsp->walk_callback(mdb_addrvec_shift(wsp->walk_data), 21757c478bd9Sstevel@tonic-gate NULL, wsp->walk_cbdata)); 21767c478bd9Sstevel@tonic-gate } 21777c478bd9Sstevel@tonic-gate return (WALK_DONE); 21787c478bd9Sstevel@tonic-gate } 21797c478bd9Sstevel@tonic-gate 21807c478bd9Sstevel@tonic-gate static const mdb_walker_t pt_walkers[] = { 21817c478bd9Sstevel@tonic-gate { "thread", "walk list of valid thread identifiers", 21827c478bd9Sstevel@tonic-gate pt_thr_walk_init, pt_thr_walk_step, pt_thr_walk_fini }, 21837c478bd9Sstevel@tonic-gate { NULL } 21847c478bd9Sstevel@tonic-gate }; 21857c478bd9Sstevel@tonic-gate 218628ea8e03SBryan Cantrill static int 218728ea8e03SBryan Cantrill pt_agent_check(boolean_t *agent, const lwpstatus_t *psp) 218828ea8e03SBryan Cantrill { 218928ea8e03SBryan Cantrill if (psp->pr_flags & PR_AGENT) 219028ea8e03SBryan Cantrill *agent = B_TRUE; 219128ea8e03SBryan Cantrill 219228ea8e03SBryan Cantrill return (0); 219328ea8e03SBryan Cantrill } 21947c478bd9Sstevel@tonic-gate 21957c478bd9Sstevel@tonic-gate static void 21967c478bd9Sstevel@tonic-gate pt_activate_common(mdb_tgt_t *t) 21977c478bd9Sstevel@tonic-gate { 21987c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 219928ea8e03SBryan Cantrill boolean_t hasagent = B_FALSE; 22007c478bd9Sstevel@tonic-gate GElf_Sym sym; 22017c478bd9Sstevel@tonic-gate 22027c478bd9Sstevel@tonic-gate /* 22037c478bd9Sstevel@tonic-gate * If we have a libproc handle and AT_BASE is set, the process or core 22047c478bd9Sstevel@tonic-gate * is dynamically linked. We call Prd_agent() to force libproc to 22057c478bd9Sstevel@tonic-gate * try to initialize librtld_db, and issue a warning if that fails. 22067c478bd9Sstevel@tonic-gate */ 22077c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL && Pgetauxval(t->t_pshandle, 22087c478bd9Sstevel@tonic-gate AT_BASE) != -1L && Prd_agent(t->t_pshandle) == NULL) { 22097c478bd9Sstevel@tonic-gate mdb_warn("warning: librtld_db failed to initialize; shared " 22107c478bd9Sstevel@tonic-gate "library information will not be available\n"); 22117c478bd9Sstevel@tonic-gate } 22127c478bd9Sstevel@tonic-gate 221328ea8e03SBryan Cantrill if (t->t_pshandle != NULL) { 221428ea8e03SBryan Cantrill (void) Plwp_iter(t->t_pshandle, 221528ea8e03SBryan Cantrill (proc_lwp_f *)pt_agent_check, &hasagent); 221628ea8e03SBryan Cantrill } 221728ea8e03SBryan Cantrill 221828ea8e03SBryan Cantrill if (hasagent) { 221928ea8e03SBryan Cantrill mdb_warn("agent lwp detected; forcing " 222028ea8e03SBryan Cantrill "lwp thread model (use ::tmodel to change)\n"); 222128ea8e03SBryan Cantrill } else if (t->t_pshandle != NULL && Pstate(t->t_pshandle) != PS_IDLE) { 22227c478bd9Sstevel@tonic-gate /* 222328ea8e03SBryan Cantrill * If we have a libproc handle and we do not have an agent LWP, 222428ea8e03SBryan Cantrill * look for the correct thread debugging library. (If we have 222528ea8e03SBryan Cantrill * an agent LWP, we leave the model as the raw LWP model to 222628ea8e03SBryan Cantrill * allow the agent LWP to be visible to the debugger.) 22277c478bd9Sstevel@tonic-gate */ 222895d62a61SEdward Pilatowicz (void) Pobject_iter(t->t_pshandle, (proc_map_f *)thr_check, t); 222928ea8e03SBryan Cantrill } 22307c478bd9Sstevel@tonic-gate 22317c478bd9Sstevel@tonic-gate /* 22327c478bd9Sstevel@tonic-gate * If there's a global object named '_mdb_abort_info', assuming we're 22337c478bd9Sstevel@tonic-gate * debugging mdb itself and load the developer support module. 22347c478bd9Sstevel@tonic-gate */ 22357c478bd9Sstevel@tonic-gate if (mdb_gelf_symtab_lookup_by_name(pt->p_symtab, "_mdb_abort_info", 22367c478bd9Sstevel@tonic-gate &sym, NULL) == 0 && GELF_ST_TYPE(sym.st_info) == STT_OBJECT) { 22377c478bd9Sstevel@tonic-gate if (mdb_module_load("mdb_ds", MDB_MOD_SILENT) < 0) 22387c478bd9Sstevel@tonic-gate mdb_warn("warning: failed to load developer support\n"); 22397c478bd9Sstevel@tonic-gate } 22407c478bd9Sstevel@tonic-gate 22417c478bd9Sstevel@tonic-gate mdb_tgt_elf_export(pt->p_file); 22427c478bd9Sstevel@tonic-gate } 22437c478bd9Sstevel@tonic-gate 22447c478bd9Sstevel@tonic-gate static void 22457c478bd9Sstevel@tonic-gate pt_activate(mdb_tgt_t *t) 22467c478bd9Sstevel@tonic-gate { 22477c478bd9Sstevel@tonic-gate static const mdb_nv_disc_t reg_disc = { reg_disc_set, reg_disc_get }; 22487c478bd9Sstevel@tonic-gate 22497c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 22507c478bd9Sstevel@tonic-gate struct utsname u1, u2; 22517c478bd9Sstevel@tonic-gate mdb_var_t *v; 22527c478bd9Sstevel@tonic-gate core_content_t content; 22537c478bd9Sstevel@tonic-gate 22547c478bd9Sstevel@tonic-gate if (t->t_pshandle) { 22557c478bd9Sstevel@tonic-gate mdb_prop_postmortem = (Pstate(t->t_pshandle) == PS_DEAD); 22567c478bd9Sstevel@tonic-gate mdb_prop_kernel = FALSE; 22577c478bd9Sstevel@tonic-gate } else 22587c478bd9Sstevel@tonic-gate mdb_prop_kernel = mdb_prop_postmortem = FALSE; 22597c478bd9Sstevel@tonic-gate 22607c478bd9Sstevel@tonic-gate mdb_prop_datamodel = MDB_TGT_MODEL_NATIVE; 22617c478bd9Sstevel@tonic-gate 22627c478bd9Sstevel@tonic-gate /* 22637c478bd9Sstevel@tonic-gate * If we're examining a core file that doesn't contain program text, 22647c478bd9Sstevel@tonic-gate * and uname(2) doesn't match the NT_UTSNAME note recorded in the 22657c478bd9Sstevel@tonic-gate * core file, issue a warning. 22667c478bd9Sstevel@tonic-gate */ 22677c478bd9Sstevel@tonic-gate if (mdb_prop_postmortem == TRUE && 22687c478bd9Sstevel@tonic-gate ((content = Pcontent(t->t_pshandle)) == CC_CONTENT_INVALID || 22697c478bd9Sstevel@tonic-gate !(content & CC_CONTENT_TEXT)) && 22707c478bd9Sstevel@tonic-gate uname(&u1) >= 0 && Puname(t->t_pshandle, &u2) == 0 && 22717c478bd9Sstevel@tonic-gate (strcmp(u1.release, u2.release) != 0 || 22727c478bd9Sstevel@tonic-gate strcmp(u1.version, u2.version) != 0)) { 22737c478bd9Sstevel@tonic-gate mdb_warn("warning: core file is from %s %s %s; shared text " 22747c478bd9Sstevel@tonic-gate "mappings may not match installed libraries\n", 22757c478bd9Sstevel@tonic-gate u2.sysname, u2.release, u2.version); 22767c478bd9Sstevel@tonic-gate } 22777c478bd9Sstevel@tonic-gate 22787c478bd9Sstevel@tonic-gate /* 22797c478bd9Sstevel@tonic-gate * Perform the common initialization tasks -- these are shared with 22807c478bd9Sstevel@tonic-gate * the pt_exec() and pt_run() subroutines. 22817c478bd9Sstevel@tonic-gate */ 22827c478bd9Sstevel@tonic-gate pt_activate_common(t); 22837c478bd9Sstevel@tonic-gate 22847c478bd9Sstevel@tonic-gate (void) mdb_tgt_register_dcmds(t, &pt_dcmds[0], MDB_MOD_FORCE); 22857c478bd9Sstevel@tonic-gate (void) mdb_tgt_register_walkers(t, &pt_walkers[0], MDB_MOD_FORCE); 22867c478bd9Sstevel@tonic-gate 22877c478bd9Sstevel@tonic-gate /* 22887c478bd9Sstevel@tonic-gate * Iterate through our register description list and export 22897c478bd9Sstevel@tonic-gate * each register as a named variable. 22907c478bd9Sstevel@tonic-gate */ 22917c478bd9Sstevel@tonic-gate mdb_nv_rewind(&pt->p_regs); 22927c478bd9Sstevel@tonic-gate while ((v = mdb_nv_advance(&pt->p_regs)) != NULL) { 22937c478bd9Sstevel@tonic-gate ushort_t rd_flags = MDB_TGT_R_FLAGS(mdb_nv_get_value(v)); 22947c478bd9Sstevel@tonic-gate 22957c478bd9Sstevel@tonic-gate if (!(rd_flags & MDB_TGT_R_EXPORT)) 22967c478bd9Sstevel@tonic-gate continue; /* Don't export register as a variable */ 22977c478bd9Sstevel@tonic-gate 22987c478bd9Sstevel@tonic-gate (void) mdb_nv_insert(&mdb.m_nv, mdb_nv_get_name(v), ®_disc, 22997c478bd9Sstevel@tonic-gate (uintptr_t)t, MDB_NV_PERSIST); 23007c478bd9Sstevel@tonic-gate } 23017c478bd9Sstevel@tonic-gate } 23027c478bd9Sstevel@tonic-gate 23037c478bd9Sstevel@tonic-gate static void 23047c478bd9Sstevel@tonic-gate pt_deactivate(mdb_tgt_t *t) 23057c478bd9Sstevel@tonic-gate { 23067c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 23077c478bd9Sstevel@tonic-gate const mdb_dcmd_t *dcp; 23087c478bd9Sstevel@tonic-gate const mdb_walker_t *wp; 23097c478bd9Sstevel@tonic-gate mdb_var_t *v, *w; 23107c478bd9Sstevel@tonic-gate 23117c478bd9Sstevel@tonic-gate mdb_nv_rewind(&pt->p_regs); 23127c478bd9Sstevel@tonic-gate while ((v = mdb_nv_advance(&pt->p_regs)) != NULL) { 23137c478bd9Sstevel@tonic-gate ushort_t rd_flags = MDB_TGT_R_FLAGS(mdb_nv_get_value(v)); 23147c478bd9Sstevel@tonic-gate 23157c478bd9Sstevel@tonic-gate if (!(rd_flags & MDB_TGT_R_EXPORT)) 23167c478bd9Sstevel@tonic-gate continue; /* Didn't export register as a variable */ 23177c478bd9Sstevel@tonic-gate 23187c478bd9Sstevel@tonic-gate if (w = mdb_nv_lookup(&mdb.m_nv, mdb_nv_get_name(v))) { 23197c478bd9Sstevel@tonic-gate w->v_flags &= ~MDB_NV_PERSIST; 23207c478bd9Sstevel@tonic-gate mdb_nv_remove(&mdb.m_nv, w); 23217c478bd9Sstevel@tonic-gate } 23227c478bd9Sstevel@tonic-gate } 23237c478bd9Sstevel@tonic-gate 23247c478bd9Sstevel@tonic-gate for (wp = &pt_walkers[0]; wp->walk_name != NULL; wp++) { 23257c478bd9Sstevel@tonic-gate if (mdb_module_remove_walker(t->t_module, wp->walk_name) == -1) 23267c478bd9Sstevel@tonic-gate warn("failed to remove walk %s", wp->walk_name); 23277c478bd9Sstevel@tonic-gate } 23287c478bd9Sstevel@tonic-gate 23297c478bd9Sstevel@tonic-gate for (dcp = &pt_dcmds[0]; dcp->dc_name != NULL; dcp++) { 23307c478bd9Sstevel@tonic-gate if (mdb_module_remove_dcmd(t->t_module, dcp->dc_name) == -1) 23317c478bd9Sstevel@tonic-gate warn("failed to remove dcmd %s", dcp->dc_name); 23327c478bd9Sstevel@tonic-gate } 23337c478bd9Sstevel@tonic-gate 23347c478bd9Sstevel@tonic-gate mdb_prop_postmortem = FALSE; 23357c478bd9Sstevel@tonic-gate mdb_prop_kernel = FALSE; 23367c478bd9Sstevel@tonic-gate mdb_prop_datamodel = MDB_TGT_MODEL_UNKNOWN; 23377c478bd9Sstevel@tonic-gate } 23387c478bd9Sstevel@tonic-gate 23397c478bd9Sstevel@tonic-gate static void 23407c478bd9Sstevel@tonic-gate pt_periodic(mdb_tgt_t *t) 23417c478bd9Sstevel@tonic-gate { 23427c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 23437c478bd9Sstevel@tonic-gate 23447c478bd9Sstevel@tonic-gate if (pt->p_rdstate == PT_RD_CONSIST) { 23457c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL && Pstate(t->t_pshandle) < PS_LOST && 23467c478bd9Sstevel@tonic-gate !(mdb.m_flags & MDB_FL_NOMODS)) { 23477c478bd9Sstevel@tonic-gate mdb_printf("%s: You've got symbols!\n", mdb.m_pname); 23487c478bd9Sstevel@tonic-gate mdb_module_load_all(0); 23497c478bd9Sstevel@tonic-gate } 23507c478bd9Sstevel@tonic-gate pt->p_rdstate = PT_RD_NONE; 23517c478bd9Sstevel@tonic-gate } 23527c478bd9Sstevel@tonic-gate } 23537c478bd9Sstevel@tonic-gate 23547c478bd9Sstevel@tonic-gate static void 23557c478bd9Sstevel@tonic-gate pt_destroy(mdb_tgt_t *t) 23567c478bd9Sstevel@tonic-gate { 23577c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 23587c478bd9Sstevel@tonic-gate 23597c478bd9Sstevel@tonic-gate if (pt->p_idlehandle != NULL && pt->p_idlehandle != t->t_pshandle) 23607c478bd9Sstevel@tonic-gate Prelease(pt->p_idlehandle, 0); 23617c478bd9Sstevel@tonic-gate 23627c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL) { 23637c478bd9Sstevel@tonic-gate PTL_DTOR(t); 23647c478bd9Sstevel@tonic-gate pt_release_parents(t); 23657c478bd9Sstevel@tonic-gate pt_pre_detach(t, TRUE); 23667c478bd9Sstevel@tonic-gate Prelease(t->t_pshandle, pt->p_rflags); 23677c478bd9Sstevel@tonic-gate } 23687c478bd9Sstevel@tonic-gate 23697c478bd9Sstevel@tonic-gate mdb.m_flags &= ~(MDB_FL_VCREATE | MDB_FL_JOBCTL); 23707c478bd9Sstevel@tonic-gate pt_close_aout(t); 23717c478bd9Sstevel@tonic-gate 23727c478bd9Sstevel@tonic-gate if (pt->p_aout_fio != NULL) 23737c478bd9Sstevel@tonic-gate mdb_io_rele(pt->p_aout_fio); 23747c478bd9Sstevel@tonic-gate 23757c478bd9Sstevel@tonic-gate pt_env_clear(pt); 23767c478bd9Sstevel@tonic-gate mdb_nv_destroy(&pt->p_env); 23777c478bd9Sstevel@tonic-gate 23787c478bd9Sstevel@tonic-gate mdb_nv_destroy(&pt->p_regs); 23797c478bd9Sstevel@tonic-gate mdb_free(pt, sizeof (pt_data_t)); 23807c478bd9Sstevel@tonic-gate } 23817c478bd9Sstevel@tonic-gate 23827c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 23837c478bd9Sstevel@tonic-gate static const char * 23847c478bd9Sstevel@tonic-gate pt_name(mdb_tgt_t *t) 23857c478bd9Sstevel@tonic-gate { 23867c478bd9Sstevel@tonic-gate return ("proc"); 23877c478bd9Sstevel@tonic-gate } 23887c478bd9Sstevel@tonic-gate 23897c478bd9Sstevel@tonic-gate static const char * 23907c478bd9Sstevel@tonic-gate pt_platform(mdb_tgt_t *t) 23917c478bd9Sstevel@tonic-gate { 23927c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 23937c478bd9Sstevel@tonic-gate 23947c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL && 23957c478bd9Sstevel@tonic-gate Pplatform(t->t_pshandle, pt->p_platform, MAXNAMELEN) != NULL) 23967c478bd9Sstevel@tonic-gate return (pt->p_platform); 23977c478bd9Sstevel@tonic-gate 23987c478bd9Sstevel@tonic-gate return (mdb_conf_platform()); 23997c478bd9Sstevel@tonic-gate } 24007c478bd9Sstevel@tonic-gate 24017c478bd9Sstevel@tonic-gate static int 24027c478bd9Sstevel@tonic-gate pt_uname(mdb_tgt_t *t, struct utsname *utsp) 24037c478bd9Sstevel@tonic-gate { 24047c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL) 24057c478bd9Sstevel@tonic-gate return (Puname(t->t_pshandle, utsp)); 24067c478bd9Sstevel@tonic-gate 24077c478bd9Sstevel@tonic-gate return (uname(utsp) >= 0 ? 0 : -1); 24087c478bd9Sstevel@tonic-gate } 24097c478bd9Sstevel@tonic-gate 24107c478bd9Sstevel@tonic-gate static int 24117c478bd9Sstevel@tonic-gate pt_dmodel(mdb_tgt_t *t) 24127c478bd9Sstevel@tonic-gate { 24137c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) 24147c478bd9Sstevel@tonic-gate return (MDB_TGT_MODEL_NATIVE); 24157c478bd9Sstevel@tonic-gate 24167c478bd9Sstevel@tonic-gate switch (Pstatus(t->t_pshandle)->pr_dmodel) { 24177c478bd9Sstevel@tonic-gate case PR_MODEL_ILP32: 24187c478bd9Sstevel@tonic-gate return (MDB_TGT_MODEL_ILP32); 24197c478bd9Sstevel@tonic-gate case PR_MODEL_LP64: 24207c478bd9Sstevel@tonic-gate return (MDB_TGT_MODEL_LP64); 24217c478bd9Sstevel@tonic-gate } 24227c478bd9Sstevel@tonic-gate 24237c478bd9Sstevel@tonic-gate return (MDB_TGT_MODEL_UNKNOWN); 24247c478bd9Sstevel@tonic-gate } 24257c478bd9Sstevel@tonic-gate 24267c478bd9Sstevel@tonic-gate static ssize_t 24277c478bd9Sstevel@tonic-gate pt_vread(mdb_tgt_t *t, void *buf, size_t nbytes, uintptr_t addr) 24287c478bd9Sstevel@tonic-gate { 24297c478bd9Sstevel@tonic-gate ssize_t n; 24307c478bd9Sstevel@tonic-gate 24317c478bd9Sstevel@tonic-gate /* 24327c478bd9Sstevel@tonic-gate * If no handle is open yet, reads from virtual addresses are 24337c478bd9Sstevel@tonic-gate * allowed to succeed but return zero-filled memory. 24347c478bd9Sstevel@tonic-gate */ 24357c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) { 24367c478bd9Sstevel@tonic-gate bzero(buf, nbytes); 24377c478bd9Sstevel@tonic-gate return (nbytes); 24387c478bd9Sstevel@tonic-gate } 24397c478bd9Sstevel@tonic-gate 24407c478bd9Sstevel@tonic-gate if ((n = Pread(t->t_pshandle, buf, nbytes, addr)) <= 0) 24417c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOMAP)); 24427c478bd9Sstevel@tonic-gate 24437c478bd9Sstevel@tonic-gate return (n); 24447c478bd9Sstevel@tonic-gate } 24457c478bd9Sstevel@tonic-gate 24467c478bd9Sstevel@tonic-gate static ssize_t 24477c478bd9Sstevel@tonic-gate pt_vwrite(mdb_tgt_t *t, const void *buf, size_t nbytes, uintptr_t addr) 24487c478bd9Sstevel@tonic-gate { 24497c478bd9Sstevel@tonic-gate ssize_t n; 24507c478bd9Sstevel@tonic-gate 24517c478bd9Sstevel@tonic-gate /* 24527c478bd9Sstevel@tonic-gate * If no handle is open yet, writes to virtual addresses are 24537c478bd9Sstevel@tonic-gate * allowed to succeed but do not actually modify anything. 24547c478bd9Sstevel@tonic-gate */ 24557c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) 24567c478bd9Sstevel@tonic-gate return (nbytes); 24577c478bd9Sstevel@tonic-gate 24587c478bd9Sstevel@tonic-gate n = Pwrite(t->t_pshandle, buf, nbytes, addr); 24597c478bd9Sstevel@tonic-gate 24607c478bd9Sstevel@tonic-gate if (n == -1 && errno == EIO) 24617c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOMAP)); 24627c478bd9Sstevel@tonic-gate 24637c478bd9Sstevel@tonic-gate return (n); 24647c478bd9Sstevel@tonic-gate } 24657c478bd9Sstevel@tonic-gate 24667c478bd9Sstevel@tonic-gate static ssize_t 24677c478bd9Sstevel@tonic-gate pt_fread(mdb_tgt_t *t, void *buf, size_t nbytes, uintptr_t addr) 24687c478bd9Sstevel@tonic-gate { 24697c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 24707c478bd9Sstevel@tonic-gate 24717c478bd9Sstevel@tonic-gate if (pt->p_file != NULL) { 24727c478bd9Sstevel@tonic-gate return (mdb_gelf_rw(pt->p_file, buf, nbytes, addr, 24737c478bd9Sstevel@tonic-gate IOPF_READ(pt->p_fio), GIO_READ)); 24747c478bd9Sstevel@tonic-gate } 24757c478bd9Sstevel@tonic-gate 24767c478bd9Sstevel@tonic-gate bzero(buf, nbytes); 24777c478bd9Sstevel@tonic-gate return (nbytes); 24787c478bd9Sstevel@tonic-gate } 24797c478bd9Sstevel@tonic-gate 24807c478bd9Sstevel@tonic-gate static ssize_t 24817c478bd9Sstevel@tonic-gate pt_fwrite(mdb_tgt_t *t, const void *buf, size_t nbytes, uintptr_t addr) 24827c478bd9Sstevel@tonic-gate { 24837c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 24847c478bd9Sstevel@tonic-gate 24857c478bd9Sstevel@tonic-gate if (pt->p_file != NULL) { 24867c478bd9Sstevel@tonic-gate return (mdb_gelf_rw(pt->p_file, (void *)buf, nbytes, addr, 24877c478bd9Sstevel@tonic-gate IOPF_WRITE(pt->p_fio), GIO_WRITE)); 24887c478bd9Sstevel@tonic-gate } 24897c478bd9Sstevel@tonic-gate 24907c478bd9Sstevel@tonic-gate return (nbytes); 24917c478bd9Sstevel@tonic-gate } 24927c478bd9Sstevel@tonic-gate 24937c478bd9Sstevel@tonic-gate static const char * 24947c478bd9Sstevel@tonic-gate pt_resolve_lmid(const char *object, Lmid_t *lmidp) 24957c478bd9Sstevel@tonic-gate { 24967c478bd9Sstevel@tonic-gate Lmid_t lmid = PR_LMID_EVERY; 24977c478bd9Sstevel@tonic-gate const char *p; 24987c478bd9Sstevel@tonic-gate 24997c478bd9Sstevel@tonic-gate if (object == MDB_TGT_OBJ_EVERY || object == MDB_TGT_OBJ_EXEC) 25007c478bd9Sstevel@tonic-gate lmid = LM_ID_BASE; /* restrict scope to a.out's link map */ 25017c478bd9Sstevel@tonic-gate else if (object != MDB_TGT_OBJ_RTLD && strncmp(object, "LM", 2) == 0 && 25027c478bd9Sstevel@tonic-gate (p = strchr(object, '`')) != NULL) { 25037c478bd9Sstevel@tonic-gate object += 2; /* skip past initial "LM" prefix */ 25047c478bd9Sstevel@tonic-gate lmid = strntoul(object, (size_t)(p - object), mdb.m_radix); 25057c478bd9Sstevel@tonic-gate object = p + 1; /* skip past link map specifier */ 25067c478bd9Sstevel@tonic-gate } 25077c478bd9Sstevel@tonic-gate 25087c478bd9Sstevel@tonic-gate *lmidp = lmid; 25097c478bd9Sstevel@tonic-gate return (object); 25107c478bd9Sstevel@tonic-gate } 25117c478bd9Sstevel@tonic-gate 25127c478bd9Sstevel@tonic-gate static int 25137c478bd9Sstevel@tonic-gate tlsbase(mdb_tgt_t *t, mdb_tgt_tid_t tid, Lmid_t lmid, const char *object, 25147c478bd9Sstevel@tonic-gate psaddr_t *basep) 25157c478bd9Sstevel@tonic-gate { 25167c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 25177c478bd9Sstevel@tonic-gate const rd_loadobj_t *loadobjp; 25187c478bd9Sstevel@tonic-gate td_thrhandle_t th; 25197c478bd9Sstevel@tonic-gate td_err_e err; 25207c478bd9Sstevel@tonic-gate 25217c478bd9Sstevel@tonic-gate if (object == MDB_TGT_OBJ_EVERY) 25227c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 25237c478bd9Sstevel@tonic-gate 25247c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL || Pstate(t->t_pshandle) == PS_IDLE) 25257c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 25267c478bd9Sstevel@tonic-gate 25277c478bd9Sstevel@tonic-gate if (pt->p_tdb_ops == NULL) 25287c478bd9Sstevel@tonic-gate return (set_errno(EMDB_TDB)); 25297c478bd9Sstevel@tonic-gate 25307c478bd9Sstevel@tonic-gate err = pt->p_tdb_ops->td_ta_map_id2thr(pt->p_ptl_hdl, tid, &th); 25317c478bd9Sstevel@tonic-gate if (err != TD_OK) 25327c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 25337c478bd9Sstevel@tonic-gate 25347c478bd9Sstevel@tonic-gate /* 25357c478bd9Sstevel@tonic-gate * If this fails, rtld_db has failed to initialize properly. 25367c478bd9Sstevel@tonic-gate */ 25377c478bd9Sstevel@tonic-gate if ((loadobjp = Plmid_to_loadobj(t->t_pshandle, lmid, object)) == NULL) 25387c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NORTLD)); 25397c478bd9Sstevel@tonic-gate 25407c478bd9Sstevel@tonic-gate /* 25417c478bd9Sstevel@tonic-gate * This will fail if the TLS block has not been allocated for the 25427c478bd9Sstevel@tonic-gate * object that contains the TLS symbol in question. 25437c478bd9Sstevel@tonic-gate */ 25447c478bd9Sstevel@tonic-gate err = pt->p_tdb_ops->td_thr_tlsbase(&th, loadobjp->rl_tlsmodid, basep); 25457c478bd9Sstevel@tonic-gate if (err != TD_OK) 25467c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 25477c478bd9Sstevel@tonic-gate 25487c478bd9Sstevel@tonic-gate return (0); 25497c478bd9Sstevel@tonic-gate } 25507c478bd9Sstevel@tonic-gate 25517c478bd9Sstevel@tonic-gate typedef struct { 25527c478bd9Sstevel@tonic-gate mdb_tgt_t *pl_tgt; 25537c478bd9Sstevel@tonic-gate const char *pl_name; 25547c478bd9Sstevel@tonic-gate Lmid_t pl_lmid; 25557c478bd9Sstevel@tonic-gate GElf_Sym *pl_symp; 25567c478bd9Sstevel@tonic-gate mdb_syminfo_t *pl_sip; 25577c478bd9Sstevel@tonic-gate mdb_tgt_tid_t pl_tid; 25587c478bd9Sstevel@tonic-gate mdb_bool_t pl_found; 25597c478bd9Sstevel@tonic-gate } pt_lookup_t; 25607c478bd9Sstevel@tonic-gate 25617c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 25627c478bd9Sstevel@tonic-gate static int 25637c478bd9Sstevel@tonic-gate pt_lookup_cb(void *data, const prmap_t *pmp, const char *object) 25647c478bd9Sstevel@tonic-gate { 25657c478bd9Sstevel@tonic-gate pt_lookup_t *plp = data; 25667c478bd9Sstevel@tonic-gate struct ps_prochandle *P = plp->pl_tgt->t_pshandle; 25677c478bd9Sstevel@tonic-gate prsyminfo_t si; 25687c478bd9Sstevel@tonic-gate GElf_Sym sym; 25697c478bd9Sstevel@tonic-gate 25707c478bd9Sstevel@tonic-gate if (Pxlookup_by_name(P, plp->pl_lmid, object, plp->pl_name, &sym, 25717c478bd9Sstevel@tonic-gate &si) != 0) 25727c478bd9Sstevel@tonic-gate return (0); 25737c478bd9Sstevel@tonic-gate 25747c478bd9Sstevel@tonic-gate /* 25757c478bd9Sstevel@tonic-gate * If we encounter a match with SHN_UNDEF, keep looking for a 25767c478bd9Sstevel@tonic-gate * better match. Return the first match with SHN_UNDEF set if no 25777c478bd9Sstevel@tonic-gate * better match is found. 25787c478bd9Sstevel@tonic-gate */ 25797c478bd9Sstevel@tonic-gate if (sym.st_shndx == SHN_UNDEF) { 25807c478bd9Sstevel@tonic-gate if (!plp->pl_found) { 25817c478bd9Sstevel@tonic-gate plp->pl_found = TRUE; 25827c478bd9Sstevel@tonic-gate *plp->pl_symp = sym; 25837c478bd9Sstevel@tonic-gate plp->pl_sip->sym_table = si.prs_table; 25847c478bd9Sstevel@tonic-gate plp->pl_sip->sym_id = si.prs_id; 25857c478bd9Sstevel@tonic-gate } 25867c478bd9Sstevel@tonic-gate 25877c478bd9Sstevel@tonic-gate return (0); 25887c478bd9Sstevel@tonic-gate } 25897c478bd9Sstevel@tonic-gate 25907c478bd9Sstevel@tonic-gate /* 25917c478bd9Sstevel@tonic-gate * Note that if the symbol's st_shndx is SHN_UNDEF we don't have the 25927c478bd9Sstevel@tonic-gate * TLS offset anyway, so adding in the tlsbase would be worthless. 25937c478bd9Sstevel@tonic-gate */ 25947c478bd9Sstevel@tonic-gate if (GELF_ST_TYPE(sym.st_info) == STT_TLS && 25957c478bd9Sstevel@tonic-gate plp->pl_tid != (mdb_tgt_tid_t)-1) { 25967c478bd9Sstevel@tonic-gate psaddr_t base; 25977c478bd9Sstevel@tonic-gate 25987c478bd9Sstevel@tonic-gate if (tlsbase(plp->pl_tgt, plp->pl_tid, plp->pl_lmid, object, 25997c478bd9Sstevel@tonic-gate &base) != 0) 26007c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 26017c478bd9Sstevel@tonic-gate 26027c478bd9Sstevel@tonic-gate sym.st_value += base; 26037c478bd9Sstevel@tonic-gate } 26047c478bd9Sstevel@tonic-gate 26057c478bd9Sstevel@tonic-gate plp->pl_found = TRUE; 26067c478bd9Sstevel@tonic-gate *plp->pl_symp = sym; 26077c478bd9Sstevel@tonic-gate plp->pl_sip->sym_table = si.prs_table; 26087c478bd9Sstevel@tonic-gate plp->pl_sip->sym_id = si.prs_id; 26097c478bd9Sstevel@tonic-gate 26107c478bd9Sstevel@tonic-gate return (1); 26117c478bd9Sstevel@tonic-gate } 26127c478bd9Sstevel@tonic-gate 26137c478bd9Sstevel@tonic-gate /* 26147c478bd9Sstevel@tonic-gate * Lookup the symbol with a thread context so that we can adjust TLS symbols 26157c478bd9Sstevel@tonic-gate * to get the values as they would appear in the context of the given thread. 26167c478bd9Sstevel@tonic-gate */ 26177c478bd9Sstevel@tonic-gate static int 26187c478bd9Sstevel@tonic-gate pt_lookup_by_name_thr(mdb_tgt_t *t, const char *object, 26197c478bd9Sstevel@tonic-gate const char *name, GElf_Sym *symp, mdb_syminfo_t *sip, mdb_tgt_tid_t tid) 26207c478bd9Sstevel@tonic-gate { 26217c478bd9Sstevel@tonic-gate struct ps_prochandle *P = t->t_pshandle; 26227c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 26237c478bd9Sstevel@tonic-gate Lmid_t lmid; 26247c478bd9Sstevel@tonic-gate uint_t i; 26257c478bd9Sstevel@tonic-gate const rd_loadobj_t *aout_lop; 26267c478bd9Sstevel@tonic-gate 26277c478bd9Sstevel@tonic-gate object = pt_resolve_lmid(object, &lmid); 26287c478bd9Sstevel@tonic-gate 26297c478bd9Sstevel@tonic-gate if (P != NULL) { 26307c478bd9Sstevel@tonic-gate pt_lookup_t pl; 26317c478bd9Sstevel@tonic-gate 26327c478bd9Sstevel@tonic-gate pl.pl_tgt = t; 26337c478bd9Sstevel@tonic-gate pl.pl_name = name; 26347c478bd9Sstevel@tonic-gate pl.pl_lmid = lmid; 26357c478bd9Sstevel@tonic-gate pl.pl_symp = symp; 26367c478bd9Sstevel@tonic-gate pl.pl_sip = sip; 26377c478bd9Sstevel@tonic-gate pl.pl_tid = tid; 26387c478bd9Sstevel@tonic-gate pl.pl_found = FALSE; 26397c478bd9Sstevel@tonic-gate 26407c478bd9Sstevel@tonic-gate if (object == MDB_TGT_OBJ_EVERY) { 264195d62a61SEdward Pilatowicz if (Pobject_iter_resolved(P, pt_lookup_cb, &pl) == -1) 2642186f7fbfSEdward Pilatowicz return (-1); /* errno is set for us */ 264395d62a61SEdward Pilatowicz if ((!pl.pl_found) && 264495d62a61SEdward Pilatowicz (Pobject_iter(P, pt_lookup_cb, &pl) == -1)) 26457c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 26467c478bd9Sstevel@tonic-gate } else { 26477c478bd9Sstevel@tonic-gate const prmap_t *pmp; 26487c478bd9Sstevel@tonic-gate 26497c478bd9Sstevel@tonic-gate /* 26507c478bd9Sstevel@tonic-gate * This can fail either due to an invalid lmid or 26517c478bd9Sstevel@tonic-gate * an invalid object. To determine which is 26527c478bd9Sstevel@tonic-gate * faulty, we test the lmid against known valid 26537c478bd9Sstevel@tonic-gate * lmids and then see if using a wild-card lmid 26547c478bd9Sstevel@tonic-gate * improves ths situation. 26557c478bd9Sstevel@tonic-gate */ 26567c478bd9Sstevel@tonic-gate if ((pmp = Plmid_to_map(P, lmid, object)) == NULL) { 26577c478bd9Sstevel@tonic-gate if (lmid != PR_LMID_EVERY && 26587c478bd9Sstevel@tonic-gate lmid != LM_ID_BASE && 26597c478bd9Sstevel@tonic-gate lmid != LM_ID_LDSO && 26607c478bd9Sstevel@tonic-gate Plmid_to_map(P, PR_LMID_EVERY, object) 26617c478bd9Sstevel@tonic-gate != NULL) 26627c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOLMID)); 26637c478bd9Sstevel@tonic-gate else 26647c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOOBJ)); 26657c478bd9Sstevel@tonic-gate } 26667c478bd9Sstevel@tonic-gate 26677c478bd9Sstevel@tonic-gate if (pt_lookup_cb(&pl, pmp, object) == -1) 26687c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 26697c478bd9Sstevel@tonic-gate } 26707c478bd9Sstevel@tonic-gate 26717c478bd9Sstevel@tonic-gate if (pl.pl_found) 26727c478bd9Sstevel@tonic-gate return (0); 26737c478bd9Sstevel@tonic-gate } 26747c478bd9Sstevel@tonic-gate 26757c478bd9Sstevel@tonic-gate /* 26767c478bd9Sstevel@tonic-gate * If libproc doesn't have the symbols for rtld, we're cooked -- 26777c478bd9Sstevel@tonic-gate * mdb doesn't have those symbols either. 26787c478bd9Sstevel@tonic-gate */ 26797c478bd9Sstevel@tonic-gate if (object == MDB_TGT_OBJ_RTLD) 26807c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOSYM)); 26817c478bd9Sstevel@tonic-gate 26827c478bd9Sstevel@tonic-gate if (object != MDB_TGT_OBJ_EXEC && object != MDB_TGT_OBJ_EVERY) { 26837c478bd9Sstevel@tonic-gate int status = mdb_gelf_symtab_lookup_by_file(pt->p_symtab, 26847c478bd9Sstevel@tonic-gate object, name, symp, &sip->sym_id); 26857c478bd9Sstevel@tonic-gate 26867c478bd9Sstevel@tonic-gate if (status != 0) { 26877c478bd9Sstevel@tonic-gate if (P != NULL && 26887c478bd9Sstevel@tonic-gate Plmid_to_map(P, PR_LMID_EVERY, object) != NULL) 26897c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOSYM)); 26907c478bd9Sstevel@tonic-gate else 26917c478bd9Sstevel@tonic-gate return (-1); /* errno set from lookup_by_file */ 26927c478bd9Sstevel@tonic-gate } 26937c478bd9Sstevel@tonic-gate 26947c478bd9Sstevel@tonic-gate goto found; 26957c478bd9Sstevel@tonic-gate } 26967c478bd9Sstevel@tonic-gate 26977c478bd9Sstevel@tonic-gate if (mdb_gelf_symtab_lookup_by_name(pt->p_symtab, name, symp, &i) == 0) { 26987c478bd9Sstevel@tonic-gate sip->sym_table = MDB_TGT_SYMTAB; 26997c478bd9Sstevel@tonic-gate sip->sym_id = i; 27007c478bd9Sstevel@tonic-gate goto local_found; 27017c478bd9Sstevel@tonic-gate } 27027c478bd9Sstevel@tonic-gate 27037c478bd9Sstevel@tonic-gate if (mdb_gelf_symtab_lookup_by_name(pt->p_dynsym, name, symp, &i) == 0) { 27047c478bd9Sstevel@tonic-gate sip->sym_table = MDB_TGT_DYNSYM; 27057c478bd9Sstevel@tonic-gate sip->sym_id = i; 27067c478bd9Sstevel@tonic-gate goto local_found; 27077c478bd9Sstevel@tonic-gate } 27087c478bd9Sstevel@tonic-gate 27097c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOSYM)); 27107c478bd9Sstevel@tonic-gate 27117c478bd9Sstevel@tonic-gate local_found: 27127c478bd9Sstevel@tonic-gate if (pt->p_file != NULL && 27137c478bd9Sstevel@tonic-gate pt->p_file->gf_ehdr.e_type == ET_DYN && 27147c478bd9Sstevel@tonic-gate P != NULL && 27157c478bd9Sstevel@tonic-gate (aout_lop = Pname_to_loadobj(P, PR_OBJ_EXEC)) != NULL) 27167c478bd9Sstevel@tonic-gate symp->st_value += aout_lop->rl_base; 27177c478bd9Sstevel@tonic-gate 27187c478bd9Sstevel@tonic-gate found: 27197c478bd9Sstevel@tonic-gate /* 27207c478bd9Sstevel@tonic-gate * If the symbol has type TLS, libproc should have found the symbol 27217c478bd9Sstevel@tonic-gate * if it exists and has been allocated. 27227c478bd9Sstevel@tonic-gate */ 27237c478bd9Sstevel@tonic-gate if (GELF_ST_TYPE(symp->st_info) == STT_TLS) 27247c478bd9Sstevel@tonic-gate return (set_errno(EMDB_TLS)); 27257c478bd9Sstevel@tonic-gate 27267c478bd9Sstevel@tonic-gate return (0); 27277c478bd9Sstevel@tonic-gate } 27287c478bd9Sstevel@tonic-gate 27297c478bd9Sstevel@tonic-gate static int 27307c478bd9Sstevel@tonic-gate pt_lookup_by_name(mdb_tgt_t *t, const char *object, 27317c478bd9Sstevel@tonic-gate const char *name, GElf_Sym *symp, mdb_syminfo_t *sip) 27327c478bd9Sstevel@tonic-gate { 27337c478bd9Sstevel@tonic-gate return (pt_lookup_by_name_thr(t, object, name, symp, sip, PTL_TID(t))); 27347c478bd9Sstevel@tonic-gate } 27357c478bd9Sstevel@tonic-gate 27367c478bd9Sstevel@tonic-gate static int 27377c478bd9Sstevel@tonic-gate pt_lookup_by_addr(mdb_tgt_t *t, uintptr_t addr, uint_t flags, 27387c478bd9Sstevel@tonic-gate char *buf, size_t nbytes, GElf_Sym *symp, mdb_syminfo_t *sip) 27397c478bd9Sstevel@tonic-gate { 27407c478bd9Sstevel@tonic-gate struct ps_prochandle *P = t->t_pshandle; 27417c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 27427c478bd9Sstevel@tonic-gate rd_plt_info_t rpi = { 0 }; 2743186f7fbfSEdward Pilatowicz 27447c478bd9Sstevel@tonic-gate const char *pltsym; 2745186f7fbfSEdward Pilatowicz int rv, match, i; 27467c478bd9Sstevel@tonic-gate 27477c478bd9Sstevel@tonic-gate mdb_gelf_symtab_t *gsts[3]; /* mdb.m_prsym, .symtab, .dynsym */ 27487c478bd9Sstevel@tonic-gate int gstc = 0; /* number of valid gsts[] entries */ 27497c478bd9Sstevel@tonic-gate 27507c478bd9Sstevel@tonic-gate mdb_gelf_symtab_t *gst = NULL; /* set if 'sym' is from a gst */ 27517c478bd9Sstevel@tonic-gate const prmap_t *pmp = NULL; /* set if 'sym' is from libproc */ 27527c478bd9Sstevel@tonic-gate GElf_Sym sym; /* best symbol found so far if !exact */ 27537c478bd9Sstevel@tonic-gate prsyminfo_t si; 27547c478bd9Sstevel@tonic-gate 27557c478bd9Sstevel@tonic-gate /* 27567c478bd9Sstevel@tonic-gate * Fill in our array of symbol table pointers with the private symbol 27577c478bd9Sstevel@tonic-gate * table, static symbol table, and dynamic symbol table if applicable. 27587c478bd9Sstevel@tonic-gate * These are done in order of precedence so that if we match and 27597c478bd9Sstevel@tonic-gate * MDB_TGT_SYM_EXACT is set, we need not look any further. 27607c478bd9Sstevel@tonic-gate */ 27617c478bd9Sstevel@tonic-gate if (mdb.m_prsym != NULL) 27627c478bd9Sstevel@tonic-gate gsts[gstc++] = mdb.m_prsym; 27637c478bd9Sstevel@tonic-gate if (P == NULL && pt->p_symtab != NULL) 27647c478bd9Sstevel@tonic-gate gsts[gstc++] = pt->p_symtab; 27657c478bd9Sstevel@tonic-gate if (P == NULL && pt->p_dynsym != NULL) 27667c478bd9Sstevel@tonic-gate gsts[gstc++] = pt->p_dynsym; 27677c478bd9Sstevel@tonic-gate 27687c478bd9Sstevel@tonic-gate /* 27697c478bd9Sstevel@tonic-gate * Loop through our array attempting to match the address. If we match 27707c478bd9Sstevel@tonic-gate * and we're in exact mode, we're done. Otherwise save the symbol in 27717c478bd9Sstevel@tonic-gate * the local sym variable if it is closer than our previous match. 27727c478bd9Sstevel@tonic-gate * We explicitly watch for zero-valued symbols since DevPro insists 27737c478bd9Sstevel@tonic-gate * on storing __fsr_init_value's value as the symbol value instead 27747c478bd9Sstevel@tonic-gate * of storing it in a constant integer. 27757c478bd9Sstevel@tonic-gate */ 27767c478bd9Sstevel@tonic-gate for (i = 0; i < gstc; i++) { 27777c478bd9Sstevel@tonic-gate if (mdb_gelf_symtab_lookup_by_addr(gsts[i], addr, flags, buf, 27787c478bd9Sstevel@tonic-gate nbytes, symp, &sip->sym_id) != 0 || symp->st_value == 0) 27797c478bd9Sstevel@tonic-gate continue; 27807c478bd9Sstevel@tonic-gate 27817c478bd9Sstevel@tonic-gate if (flags & MDB_TGT_SYM_EXACT) { 27827c478bd9Sstevel@tonic-gate gst = gsts[i]; 27837c478bd9Sstevel@tonic-gate goto found; 27847c478bd9Sstevel@tonic-gate } 27857c478bd9Sstevel@tonic-gate 27867c478bd9Sstevel@tonic-gate if (gst == NULL || mdb_gelf_sym_closer(symp, &sym, addr)) { 27877c478bd9Sstevel@tonic-gate gst = gsts[i]; 27887c478bd9Sstevel@tonic-gate sym = *symp; 27897c478bd9Sstevel@tonic-gate } 27907c478bd9Sstevel@tonic-gate } 27917c478bd9Sstevel@tonic-gate 27927c478bd9Sstevel@tonic-gate /* 27937c478bd9Sstevel@tonic-gate * If we have no libproc handle active, we're done: fail if gst is 27947c478bd9Sstevel@tonic-gate * NULL; otherwise copy out our best symbol and skip to the end. 27957c478bd9Sstevel@tonic-gate * We also skip to found if gst is the private symbol table: we 27967c478bd9Sstevel@tonic-gate * want this to always take precedence over PLT re-vectoring. 27977c478bd9Sstevel@tonic-gate */ 27987c478bd9Sstevel@tonic-gate if (P == NULL || (gst != NULL && gst == mdb.m_prsym)) { 27997c478bd9Sstevel@tonic-gate if (gst == NULL) 28007c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOSYMADDR)); 28017c478bd9Sstevel@tonic-gate *symp = sym; 28027c478bd9Sstevel@tonic-gate goto found; 28037c478bd9Sstevel@tonic-gate } 28047c478bd9Sstevel@tonic-gate 28057c478bd9Sstevel@tonic-gate /* 28067c478bd9Sstevel@tonic-gate * Check to see if the address is in a PLT: if it is, use librtld_db to 28077c478bd9Sstevel@tonic-gate * attempt to resolve the PLT entry. If the entry is bound, reset addr 28087c478bd9Sstevel@tonic-gate * to the bound address, add a special prefix to the caller's buf, 28097c478bd9Sstevel@tonic-gate * forget our previous guess, and then continue using the new addr. 28107c478bd9Sstevel@tonic-gate * If the entry is not bound, copy the corresponding symbol name into 28117c478bd9Sstevel@tonic-gate * buf and return a fake symbol for the given address. 28127c478bd9Sstevel@tonic-gate */ 28137c478bd9Sstevel@tonic-gate if ((pltsym = Ppltdest(P, addr)) != NULL) { 28147c478bd9Sstevel@tonic-gate const rd_loadobj_t *rlp; 28157c478bd9Sstevel@tonic-gate rd_agent_t *rap; 28167c478bd9Sstevel@tonic-gate 28177c478bd9Sstevel@tonic-gate if ((rap = Prd_agent(P)) != NULL && 28187c478bd9Sstevel@tonic-gate (rlp = Paddr_to_loadobj(P, addr)) != NULL && 28197c478bd9Sstevel@tonic-gate rd_plt_resolution(rap, addr, Pstatus(P)->pr_lwp.pr_lwpid, 28207c478bd9Sstevel@tonic-gate rlp->rl_plt_base, &rpi) == RD_OK && 28217c478bd9Sstevel@tonic-gate (rpi.pi_flags & RD_FLG_PI_PLTBOUND)) { 28227c478bd9Sstevel@tonic-gate size_t n; 28237c478bd9Sstevel@tonic-gate n = mdb_iob_snprintf(buf, nbytes, "PLT="); 28247c478bd9Sstevel@tonic-gate addr = rpi.pi_baddr; 28257c478bd9Sstevel@tonic-gate if (n > nbytes) { 28267c478bd9Sstevel@tonic-gate buf += nbytes; 28277c478bd9Sstevel@tonic-gate nbytes = 0; 28287c478bd9Sstevel@tonic-gate } else { 28297c478bd9Sstevel@tonic-gate buf += n; 28307c478bd9Sstevel@tonic-gate nbytes -= n; 28317c478bd9Sstevel@tonic-gate } 28327c478bd9Sstevel@tonic-gate gst = NULL; 28337c478bd9Sstevel@tonic-gate } else { 28347c478bd9Sstevel@tonic-gate (void) mdb_iob_snprintf(buf, nbytes, "PLT:%s", pltsym); 28357c478bd9Sstevel@tonic-gate bzero(symp, sizeof (GElf_Sym)); 28367c478bd9Sstevel@tonic-gate symp->st_value = addr; 28377c478bd9Sstevel@tonic-gate symp->st_info = GELF_ST_INFO(STB_GLOBAL, STT_FUNC); 28387c478bd9Sstevel@tonic-gate return (0); 28397c478bd9Sstevel@tonic-gate } 28407c478bd9Sstevel@tonic-gate } 28417c478bd9Sstevel@tonic-gate 28427c478bd9Sstevel@tonic-gate /* 28437c478bd9Sstevel@tonic-gate * Ask libproc to convert the address to the closest symbol for us. 28447c478bd9Sstevel@tonic-gate * Once we get the closest symbol, we perform the EXACT match or 28457c478bd9Sstevel@tonic-gate * smart-mode or absolute distance check ourself: 28467c478bd9Sstevel@tonic-gate */ 28478f68126cSBryan Cantrill if (PT_LIBPROC_RESOLVE(P)) { 2848186f7fbfSEdward Pilatowicz rv = Pxlookup_by_addr_resolved(P, addr, buf, nbytes, 2849186f7fbfSEdward Pilatowicz symp, &si); 2850186f7fbfSEdward Pilatowicz } else { 2851186f7fbfSEdward Pilatowicz rv = Pxlookup_by_addr(P, addr, buf, nbytes, 2852186f7fbfSEdward Pilatowicz symp, &si); 2853186f7fbfSEdward Pilatowicz } 2854186f7fbfSEdward Pilatowicz if ((rv == 0) && (symp->st_value != 0) && 2855186f7fbfSEdward Pilatowicz (gst == NULL || mdb_gelf_sym_closer(symp, &sym, addr))) { 28567c478bd9Sstevel@tonic-gate 28577c478bd9Sstevel@tonic-gate if (flags & MDB_TGT_SYM_EXACT) 28587c478bd9Sstevel@tonic-gate match = (addr == symp->st_value); 28597c478bd9Sstevel@tonic-gate else if (mdb.m_symdist == 0) 28607c478bd9Sstevel@tonic-gate match = (addr >= symp->st_value && 28617c478bd9Sstevel@tonic-gate addr < symp->st_value + symp->st_size); 28627c478bd9Sstevel@tonic-gate else 28637c478bd9Sstevel@tonic-gate match = (addr >= symp->st_value && 28647c478bd9Sstevel@tonic-gate addr < symp->st_value + mdb.m_symdist); 28657c478bd9Sstevel@tonic-gate 28667c478bd9Sstevel@tonic-gate if (match) { 28677c478bd9Sstevel@tonic-gate pmp = Paddr_to_map(P, addr); 28687c478bd9Sstevel@tonic-gate gst = NULL; 28697c478bd9Sstevel@tonic-gate sip->sym_table = si.prs_table; 28707c478bd9Sstevel@tonic-gate sip->sym_id = si.prs_id; 28717c478bd9Sstevel@tonic-gate goto found; 28727c478bd9Sstevel@tonic-gate } 28737c478bd9Sstevel@tonic-gate } 28747c478bd9Sstevel@tonic-gate 28757c478bd9Sstevel@tonic-gate /* 28767c478bd9Sstevel@tonic-gate * If we get here, Plookup_by_addr has failed us. If we have no 28777c478bd9Sstevel@tonic-gate * previous best symbol (gst == NULL), we've failed completely. 28787c478bd9Sstevel@tonic-gate * Otherwise we copy out that symbol and continue on to 'found'. 28797c478bd9Sstevel@tonic-gate */ 28807c478bd9Sstevel@tonic-gate if (gst == NULL) 28817c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOSYMADDR)); 28827c478bd9Sstevel@tonic-gate *symp = sym; 28837c478bd9Sstevel@tonic-gate found: 28847c478bd9Sstevel@tonic-gate /* 28857c478bd9Sstevel@tonic-gate * Once we've found something, copy the final name into the caller's 28867c478bd9Sstevel@tonic-gate * buffer and prefix it with the mapping name if appropriate. 28877c478bd9Sstevel@tonic-gate */ 28887c478bd9Sstevel@tonic-gate if (pmp != NULL && pmp != Pname_to_map(P, PR_OBJ_EXEC)) { 28897c478bd9Sstevel@tonic-gate const char *prefix = pmp->pr_mapname; 28907c478bd9Sstevel@tonic-gate Lmid_t lmid; 28917c478bd9Sstevel@tonic-gate 28928f68126cSBryan Cantrill if (PT_LIBPROC_RESOLVE(P)) { 2893186f7fbfSEdward Pilatowicz if (Pobjname_resolved(P, addr, pt->p_objname, 2894186f7fbfSEdward Pilatowicz MDB_TGT_MAPSZ)) 2895186f7fbfSEdward Pilatowicz prefix = pt->p_objname; 2896186f7fbfSEdward Pilatowicz } else { 28977c478bd9Sstevel@tonic-gate if (Pobjname(P, addr, pt->p_objname, MDB_TGT_MAPSZ)) 28987c478bd9Sstevel@tonic-gate prefix = pt->p_objname; 2899186f7fbfSEdward Pilatowicz } 29007c478bd9Sstevel@tonic-gate 29017c478bd9Sstevel@tonic-gate if (buf != NULL && nbytes > 1) { 29027c478bd9Sstevel@tonic-gate (void) strncpy(pt->p_symname, buf, MDB_TGT_SYM_NAMLEN); 29037c478bd9Sstevel@tonic-gate pt->p_symname[MDB_TGT_SYM_NAMLEN - 1] = '\0'; 29047c478bd9Sstevel@tonic-gate } else { 29057c478bd9Sstevel@tonic-gate pt->p_symname[0] = '\0'; 29067c478bd9Sstevel@tonic-gate } 29077c478bd9Sstevel@tonic-gate 29087c478bd9Sstevel@tonic-gate if (prefix == pt->p_objname && Plmid(P, addr, &lmid) == 0 && ( 29097c478bd9Sstevel@tonic-gate (lmid != LM_ID_BASE && lmid != LM_ID_LDSO) || 29107c478bd9Sstevel@tonic-gate (mdb.m_flags & MDB_FL_SHOWLMID))) { 29117c478bd9Sstevel@tonic-gate (void) mdb_iob_snprintf(buf, nbytes, "LM%lr`%s`%s", 29127c478bd9Sstevel@tonic-gate lmid, strbasename(prefix), pt->p_symname); 29137c478bd9Sstevel@tonic-gate } else { 29147c478bd9Sstevel@tonic-gate (void) mdb_iob_snprintf(buf, nbytes, "%s`%s", 29157c478bd9Sstevel@tonic-gate strbasename(prefix), pt->p_symname); 29167c478bd9Sstevel@tonic-gate } 29177c478bd9Sstevel@tonic-gate 29187c478bd9Sstevel@tonic-gate } else if (gst != NULL && buf != NULL && nbytes > 0) { 29197c478bd9Sstevel@tonic-gate (void) strncpy(buf, mdb_gelf_sym_name(gst, symp), nbytes); 29207c478bd9Sstevel@tonic-gate buf[nbytes - 1] = '\0'; 29217c478bd9Sstevel@tonic-gate } 29227c478bd9Sstevel@tonic-gate 29237c478bd9Sstevel@tonic-gate return (0); 29247c478bd9Sstevel@tonic-gate } 29257c478bd9Sstevel@tonic-gate 29267c478bd9Sstevel@tonic-gate 29277c478bd9Sstevel@tonic-gate static int 29287c478bd9Sstevel@tonic-gate pt_symbol_iter_cb(void *arg, const GElf_Sym *sym, const char *name, 29297c478bd9Sstevel@tonic-gate const prsyminfo_t *sip) 29307c478bd9Sstevel@tonic-gate { 29317c478bd9Sstevel@tonic-gate pt_symarg_t *psp = arg; 29327c478bd9Sstevel@tonic-gate 29337c478bd9Sstevel@tonic-gate psp->psym_info.sym_id = sip->prs_id; 29347c478bd9Sstevel@tonic-gate 29357c478bd9Sstevel@tonic-gate return (psp->psym_func(psp->psym_private, sym, name, &psp->psym_info, 29367c478bd9Sstevel@tonic-gate psp->psym_obj)); 29377c478bd9Sstevel@tonic-gate } 29387c478bd9Sstevel@tonic-gate 29397c478bd9Sstevel@tonic-gate static int 29407c478bd9Sstevel@tonic-gate pt_objsym_iter(void *arg, const prmap_t *pmp, const char *object) 29417c478bd9Sstevel@tonic-gate { 29427c478bd9Sstevel@tonic-gate Lmid_t lmid = PR_LMID_EVERY; 29437c478bd9Sstevel@tonic-gate pt_symarg_t *psp = arg; 29447c478bd9Sstevel@tonic-gate 29457c478bd9Sstevel@tonic-gate psp->psym_obj = object; 29467c478bd9Sstevel@tonic-gate 29477c478bd9Sstevel@tonic-gate (void) Plmid(psp->psym_targ->t_pshandle, pmp->pr_vaddr, &lmid); 29487c478bd9Sstevel@tonic-gate (void) Pxsymbol_iter(psp->psym_targ->t_pshandle, lmid, object, 29497c478bd9Sstevel@tonic-gate psp->psym_which, psp->psym_type, pt_symbol_iter_cb, arg); 29507c478bd9Sstevel@tonic-gate 29517c478bd9Sstevel@tonic-gate return (0); 29527c478bd9Sstevel@tonic-gate } 29537c478bd9Sstevel@tonic-gate 29547c478bd9Sstevel@tonic-gate static int 29557c478bd9Sstevel@tonic-gate pt_symbol_filt(void *arg, const GElf_Sym *sym, const char *name, uint_t id) 29567c478bd9Sstevel@tonic-gate { 29577c478bd9Sstevel@tonic-gate pt_symarg_t *psp = arg; 29587c478bd9Sstevel@tonic-gate 29597c478bd9Sstevel@tonic-gate if (mdb_tgt_sym_match(sym, psp->psym_type)) { 29607c478bd9Sstevel@tonic-gate psp->psym_info.sym_id = id; 29617c478bd9Sstevel@tonic-gate return (psp->psym_func(psp->psym_private, sym, name, 29627c478bd9Sstevel@tonic-gate &psp->psym_info, psp->psym_obj)); 29637c478bd9Sstevel@tonic-gate } 29647c478bd9Sstevel@tonic-gate 29657c478bd9Sstevel@tonic-gate return (0); 29667c478bd9Sstevel@tonic-gate } 29677c478bd9Sstevel@tonic-gate 29687c478bd9Sstevel@tonic-gate static int 29697c478bd9Sstevel@tonic-gate pt_symbol_iter(mdb_tgt_t *t, const char *object, uint_t which, 29707c478bd9Sstevel@tonic-gate uint_t type, mdb_tgt_sym_f *func, void *private) 29717c478bd9Sstevel@tonic-gate { 29727c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 29737c478bd9Sstevel@tonic-gate mdb_gelf_symtab_t *gst; 29747c478bd9Sstevel@tonic-gate pt_symarg_t ps; 29757c478bd9Sstevel@tonic-gate Lmid_t lmid; 29767c478bd9Sstevel@tonic-gate 29777c478bd9Sstevel@tonic-gate object = pt_resolve_lmid(object, &lmid); 29787c478bd9Sstevel@tonic-gate 29797c478bd9Sstevel@tonic-gate ps.psym_targ = t; 29807c478bd9Sstevel@tonic-gate ps.psym_which = which; 29817c478bd9Sstevel@tonic-gate ps.psym_type = type; 29827c478bd9Sstevel@tonic-gate ps.psym_func = func; 29837c478bd9Sstevel@tonic-gate ps.psym_private = private; 29847c478bd9Sstevel@tonic-gate ps.psym_obj = object; 29857c478bd9Sstevel@tonic-gate 29867c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL) { 29877c478bd9Sstevel@tonic-gate if (object != MDB_TGT_OBJ_EVERY) { 29887c478bd9Sstevel@tonic-gate if (Plmid_to_map(t->t_pshandle, lmid, object) == NULL) 29897c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOOBJ)); 29907c478bd9Sstevel@tonic-gate (void) Pxsymbol_iter(t->t_pshandle, lmid, object, 29917c478bd9Sstevel@tonic-gate which, type, pt_symbol_iter_cb, &ps); 29927c478bd9Sstevel@tonic-gate return (0); 29937c478bd9Sstevel@tonic-gate } else if (Prd_agent(t->t_pshandle) != NULL) { 29948f68126cSBryan Cantrill if (PT_LIBPROC_RESOLVE(t->t_pshandle)) { 2995186f7fbfSEdward Pilatowicz (void) Pobject_iter_resolved(t->t_pshandle, 2996186f7fbfSEdward Pilatowicz pt_objsym_iter, &ps); 2997186f7fbfSEdward Pilatowicz } else { 2998186f7fbfSEdward Pilatowicz (void) Pobject_iter(t->t_pshandle, 2999186f7fbfSEdward Pilatowicz pt_objsym_iter, &ps); 3000186f7fbfSEdward Pilatowicz } 30017c478bd9Sstevel@tonic-gate return (0); 30027c478bd9Sstevel@tonic-gate } 30037c478bd9Sstevel@tonic-gate } 30047c478bd9Sstevel@tonic-gate 30057c478bd9Sstevel@tonic-gate if (lmid != LM_ID_BASE && lmid != PR_LMID_EVERY) 30067c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOLMID)); 30077c478bd9Sstevel@tonic-gate 30087c478bd9Sstevel@tonic-gate if (object != MDB_TGT_OBJ_EXEC && object != MDB_TGT_OBJ_EVERY && 30097c478bd9Sstevel@tonic-gate pt->p_fio != NULL && 30107c478bd9Sstevel@tonic-gate strcmp(object, IOP_NAME(pt->p_fio)) != 0) 30117c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOOBJ)); 30127c478bd9Sstevel@tonic-gate 30137c478bd9Sstevel@tonic-gate if (which == MDB_TGT_SYMTAB) 30147c478bd9Sstevel@tonic-gate gst = pt->p_symtab; 30157c478bd9Sstevel@tonic-gate else 30167c478bd9Sstevel@tonic-gate gst = pt->p_dynsym; 30177c478bd9Sstevel@tonic-gate 30187c478bd9Sstevel@tonic-gate if (gst != NULL) { 30197c478bd9Sstevel@tonic-gate ps.psym_info.sym_table = gst->gst_tabid; 30207c478bd9Sstevel@tonic-gate mdb_gelf_symtab_iter(gst, pt_symbol_filt, &ps); 30217c478bd9Sstevel@tonic-gate } 30227c478bd9Sstevel@tonic-gate 30237c478bd9Sstevel@tonic-gate return (0); 30247c478bd9Sstevel@tonic-gate } 30257c478bd9Sstevel@tonic-gate 30267c478bd9Sstevel@tonic-gate static const mdb_map_t * 30277c478bd9Sstevel@tonic-gate pt_prmap_to_mdbmap(mdb_tgt_t *t, const prmap_t *prp, mdb_map_t *mp) 30287c478bd9Sstevel@tonic-gate { 30297c478bd9Sstevel@tonic-gate struct ps_prochandle *P = t->t_pshandle; 3030186f7fbfSEdward Pilatowicz char *rv, name[MAXPATHLEN]; 30317c478bd9Sstevel@tonic-gate Lmid_t lmid; 30327c478bd9Sstevel@tonic-gate 30338f68126cSBryan Cantrill if (PT_LIBPROC_RESOLVE(P)) { 3034186f7fbfSEdward Pilatowicz rv = Pobjname_resolved(P, prp->pr_vaddr, name, sizeof (name)); 3035186f7fbfSEdward Pilatowicz } else { 3036186f7fbfSEdward Pilatowicz rv = Pobjname(P, prp->pr_vaddr, name, sizeof (name)); 3037186f7fbfSEdward Pilatowicz } 3038186f7fbfSEdward Pilatowicz 3039186f7fbfSEdward Pilatowicz if (rv != NULL) { 30407c478bd9Sstevel@tonic-gate if (Plmid(P, prp->pr_vaddr, &lmid) == 0 && ( 30417c478bd9Sstevel@tonic-gate (lmid != LM_ID_BASE && lmid != LM_ID_LDSO) || 30427c478bd9Sstevel@tonic-gate (mdb.m_flags & MDB_FL_SHOWLMID))) { 30437c478bd9Sstevel@tonic-gate (void) mdb_iob_snprintf(mp->map_name, MDB_TGT_MAPSZ, 30447c478bd9Sstevel@tonic-gate "LM%lr`%s", lmid, name); 30457c478bd9Sstevel@tonic-gate } else { 30467c478bd9Sstevel@tonic-gate (void) strncpy(mp->map_name, name, MDB_TGT_MAPSZ - 1); 30477c478bd9Sstevel@tonic-gate mp->map_name[MDB_TGT_MAPSZ - 1] = '\0'; 30487c478bd9Sstevel@tonic-gate } 30497c478bd9Sstevel@tonic-gate } else { 30507c478bd9Sstevel@tonic-gate (void) strncpy(mp->map_name, prp->pr_mapname, 30517c478bd9Sstevel@tonic-gate MDB_TGT_MAPSZ - 1); 30527c478bd9Sstevel@tonic-gate mp->map_name[MDB_TGT_MAPSZ - 1] = '\0'; 30537c478bd9Sstevel@tonic-gate } 30547c478bd9Sstevel@tonic-gate 30557c478bd9Sstevel@tonic-gate mp->map_base = prp->pr_vaddr; 30567c478bd9Sstevel@tonic-gate mp->map_size = prp->pr_size; 30577c478bd9Sstevel@tonic-gate mp->map_flags = 0; 30587c478bd9Sstevel@tonic-gate 30597c478bd9Sstevel@tonic-gate if (prp->pr_mflags & MA_READ) 30607c478bd9Sstevel@tonic-gate mp->map_flags |= MDB_TGT_MAP_R; 30617c478bd9Sstevel@tonic-gate if (prp->pr_mflags & MA_WRITE) 30627c478bd9Sstevel@tonic-gate mp->map_flags |= MDB_TGT_MAP_W; 30637c478bd9Sstevel@tonic-gate if (prp->pr_mflags & MA_EXEC) 30647c478bd9Sstevel@tonic-gate mp->map_flags |= MDB_TGT_MAP_X; 30657c478bd9Sstevel@tonic-gate 30667c478bd9Sstevel@tonic-gate if (prp->pr_mflags & MA_SHM) 30677c478bd9Sstevel@tonic-gate mp->map_flags |= MDB_TGT_MAP_SHMEM; 30687c478bd9Sstevel@tonic-gate if (prp->pr_mflags & MA_BREAK) 30697c478bd9Sstevel@tonic-gate mp->map_flags |= MDB_TGT_MAP_HEAP; 30707c478bd9Sstevel@tonic-gate if (prp->pr_mflags & MA_STACK) 30717c478bd9Sstevel@tonic-gate mp->map_flags |= MDB_TGT_MAP_STACK; 30727c478bd9Sstevel@tonic-gate if (prp->pr_mflags & MA_ANON) 30737c478bd9Sstevel@tonic-gate mp->map_flags |= MDB_TGT_MAP_ANON; 30747c478bd9Sstevel@tonic-gate 30757c478bd9Sstevel@tonic-gate return (mp); 30767c478bd9Sstevel@tonic-gate } 30777c478bd9Sstevel@tonic-gate 30787c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 30797c478bd9Sstevel@tonic-gate static int 30807c478bd9Sstevel@tonic-gate pt_map_apply(void *arg, const prmap_t *prp, const char *name) 30817c478bd9Sstevel@tonic-gate { 30827c478bd9Sstevel@tonic-gate pt_maparg_t *pmp = arg; 30837c478bd9Sstevel@tonic-gate mdb_map_t map; 30847c478bd9Sstevel@tonic-gate 30857c478bd9Sstevel@tonic-gate return (pmp->pmap_func(pmp->pmap_private, 30867c478bd9Sstevel@tonic-gate pt_prmap_to_mdbmap(pmp->pmap_targ, prp, &map), map.map_name)); 30877c478bd9Sstevel@tonic-gate } 30887c478bd9Sstevel@tonic-gate 30897c478bd9Sstevel@tonic-gate static int 30907c478bd9Sstevel@tonic-gate pt_mapping_iter(mdb_tgt_t *t, mdb_tgt_map_f *func, void *private) 30917c478bd9Sstevel@tonic-gate { 30927c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL) { 30937c478bd9Sstevel@tonic-gate pt_maparg_t pm; 30947c478bd9Sstevel@tonic-gate 30957c478bd9Sstevel@tonic-gate pm.pmap_targ = t; 30967c478bd9Sstevel@tonic-gate pm.pmap_func = func; 30977c478bd9Sstevel@tonic-gate pm.pmap_private = private; 30987c478bd9Sstevel@tonic-gate 30998f68126cSBryan Cantrill if (PT_LIBPROC_RESOLVE(t->t_pshandle)) { 3100186f7fbfSEdward Pilatowicz (void) Pmapping_iter_resolved(t->t_pshandle, 3101186f7fbfSEdward Pilatowicz pt_map_apply, &pm); 3102186f7fbfSEdward Pilatowicz } else { 3103186f7fbfSEdward Pilatowicz (void) Pmapping_iter(t->t_pshandle, 3104186f7fbfSEdward Pilatowicz pt_map_apply, &pm); 3105186f7fbfSEdward Pilatowicz } 31067c478bd9Sstevel@tonic-gate return (0); 31077c478bd9Sstevel@tonic-gate } 31087c478bd9Sstevel@tonic-gate 31097c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 31107c478bd9Sstevel@tonic-gate } 31117c478bd9Sstevel@tonic-gate 31127c478bd9Sstevel@tonic-gate static int 31137c478bd9Sstevel@tonic-gate pt_object_iter(mdb_tgt_t *t, mdb_tgt_map_f *func, void *private) 31147c478bd9Sstevel@tonic-gate { 31157c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 31167c478bd9Sstevel@tonic-gate 31177c478bd9Sstevel@tonic-gate /* 31187c478bd9Sstevel@tonic-gate * If we have a libproc handle, we can just call Pobject_iter to 31197c478bd9Sstevel@tonic-gate * iterate over its list of load object information. 31207c478bd9Sstevel@tonic-gate */ 31217c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL) { 31227c478bd9Sstevel@tonic-gate pt_maparg_t pm; 31237c478bd9Sstevel@tonic-gate 31247c478bd9Sstevel@tonic-gate pm.pmap_targ = t; 31257c478bd9Sstevel@tonic-gate pm.pmap_func = func; 31267c478bd9Sstevel@tonic-gate pm.pmap_private = private; 31277c478bd9Sstevel@tonic-gate 31288f68126cSBryan Cantrill if (PT_LIBPROC_RESOLVE(t->t_pshandle)) { 3129186f7fbfSEdward Pilatowicz (void) Pobject_iter_resolved(t->t_pshandle, 3130186f7fbfSEdward Pilatowicz pt_map_apply, &pm); 3131186f7fbfSEdward Pilatowicz } else { 3132186f7fbfSEdward Pilatowicz (void) Pobject_iter(t->t_pshandle, 3133186f7fbfSEdward Pilatowicz pt_map_apply, &pm); 3134186f7fbfSEdward Pilatowicz } 31357c478bd9Sstevel@tonic-gate return (0); 31367c478bd9Sstevel@tonic-gate } 31377c478bd9Sstevel@tonic-gate 31387c478bd9Sstevel@tonic-gate /* 31397c478bd9Sstevel@tonic-gate * If we're examining an executable or other ELF file but we have no 31407c478bd9Sstevel@tonic-gate * libproc handle, fake up some information based on DT_NEEDED entries. 31417c478bd9Sstevel@tonic-gate */ 31427c478bd9Sstevel@tonic-gate if (pt->p_dynsym != NULL && pt->p_file->gf_dyns != NULL && 31437c478bd9Sstevel@tonic-gate pt->p_fio != NULL) { 31447c478bd9Sstevel@tonic-gate mdb_gelf_sect_t *gsp = pt->p_dynsym->gst_ssect; 31457c478bd9Sstevel@tonic-gate GElf_Dyn *dynp = pt->p_file->gf_dyns; 31467c478bd9Sstevel@tonic-gate mdb_map_t *mp = &pt->p_map; 31477c478bd9Sstevel@tonic-gate const char *s = IOP_NAME(pt->p_fio); 31487c478bd9Sstevel@tonic-gate size_t i; 31497c478bd9Sstevel@tonic-gate 31507c478bd9Sstevel@tonic-gate (void) strncpy(mp->map_name, s, MDB_TGT_MAPSZ); 31517c478bd9Sstevel@tonic-gate mp->map_name[MDB_TGT_MAPSZ - 1] = '\0'; 31527c478bd9Sstevel@tonic-gate mp->map_flags = MDB_TGT_MAP_R | MDB_TGT_MAP_X; 31537c478bd9Sstevel@tonic-gate mp->map_base = NULL; 31547c478bd9Sstevel@tonic-gate mp->map_size = 0; 31557c478bd9Sstevel@tonic-gate 31567c478bd9Sstevel@tonic-gate if (func(private, mp, s) != 0) 31577c478bd9Sstevel@tonic-gate return (0); 31587c478bd9Sstevel@tonic-gate 31597c478bd9Sstevel@tonic-gate for (i = 0; i < pt->p_file->gf_ndyns; i++, dynp++) { 31607c478bd9Sstevel@tonic-gate if (dynp->d_tag == DT_NEEDED) { 31617c478bd9Sstevel@tonic-gate s = (char *)gsp->gs_data + dynp->d_un.d_val; 31627c478bd9Sstevel@tonic-gate (void) strncpy(mp->map_name, s, MDB_TGT_MAPSZ); 31637c478bd9Sstevel@tonic-gate mp->map_name[MDB_TGT_MAPSZ - 1] = '\0'; 31647c478bd9Sstevel@tonic-gate if (func(private, mp, s) != 0) 31657c478bd9Sstevel@tonic-gate return (0); 31667c478bd9Sstevel@tonic-gate } 31677c478bd9Sstevel@tonic-gate } 31687c478bd9Sstevel@tonic-gate 31697c478bd9Sstevel@tonic-gate return (0); 31707c478bd9Sstevel@tonic-gate } 31717c478bd9Sstevel@tonic-gate 31727c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 31737c478bd9Sstevel@tonic-gate } 31747c478bd9Sstevel@tonic-gate 31757c478bd9Sstevel@tonic-gate static const mdb_map_t * 31767c478bd9Sstevel@tonic-gate pt_addr_to_map(mdb_tgt_t *t, uintptr_t addr) 31777c478bd9Sstevel@tonic-gate { 31787c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 31797c478bd9Sstevel@tonic-gate const prmap_t *pmp; 31807c478bd9Sstevel@tonic-gate 31817c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) { 31827c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_NOPROC); 31837c478bd9Sstevel@tonic-gate return (NULL); 31847c478bd9Sstevel@tonic-gate } 31857c478bd9Sstevel@tonic-gate 31867c478bd9Sstevel@tonic-gate if ((pmp = Paddr_to_map(t->t_pshandle, addr)) == NULL) { 31877c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_NOMAP); 31887c478bd9Sstevel@tonic-gate return (NULL); 31897c478bd9Sstevel@tonic-gate } 31907c478bd9Sstevel@tonic-gate 31917c478bd9Sstevel@tonic-gate return (pt_prmap_to_mdbmap(t, pmp, &pt->p_map)); 31927c478bd9Sstevel@tonic-gate } 31937c478bd9Sstevel@tonic-gate 31947c478bd9Sstevel@tonic-gate static const mdb_map_t * 31957c478bd9Sstevel@tonic-gate pt_name_to_map(mdb_tgt_t *t, const char *object) 31967c478bd9Sstevel@tonic-gate { 31977c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 31987c478bd9Sstevel@tonic-gate const prmap_t *pmp; 31997c478bd9Sstevel@tonic-gate Lmid_t lmid; 32007c478bd9Sstevel@tonic-gate 32017c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) { 32027c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_NOPROC); 32037c478bd9Sstevel@tonic-gate return (NULL); 32047c478bd9Sstevel@tonic-gate } 32057c478bd9Sstevel@tonic-gate 32067c478bd9Sstevel@tonic-gate object = pt_resolve_lmid(object, &lmid); 32077c478bd9Sstevel@tonic-gate 32087c478bd9Sstevel@tonic-gate if ((pmp = Plmid_to_map(t->t_pshandle, lmid, object)) == NULL) { 32097c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_NOOBJ); 32107c478bd9Sstevel@tonic-gate return (NULL); 32117c478bd9Sstevel@tonic-gate } 32127c478bd9Sstevel@tonic-gate 32137c478bd9Sstevel@tonic-gate return (pt_prmap_to_mdbmap(t, pmp, &pt->p_map)); 32147c478bd9Sstevel@tonic-gate } 32157c478bd9Sstevel@tonic-gate 32167c478bd9Sstevel@tonic-gate static ctf_file_t * 32177c478bd9Sstevel@tonic-gate pt_addr_to_ctf(mdb_tgt_t *t, uintptr_t addr) 32187c478bd9Sstevel@tonic-gate { 32197c478bd9Sstevel@tonic-gate ctf_file_t *ret; 32207c478bd9Sstevel@tonic-gate 32217c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) { 32227c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_NOPROC); 32237c478bd9Sstevel@tonic-gate return (NULL); 32247c478bd9Sstevel@tonic-gate } 32257c478bd9Sstevel@tonic-gate 32267c478bd9Sstevel@tonic-gate if ((ret = Paddr_to_ctf(t->t_pshandle, addr)) == NULL) { 32277c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_NOOBJ); 32287c478bd9Sstevel@tonic-gate return (NULL); 32297c478bd9Sstevel@tonic-gate } 32307c478bd9Sstevel@tonic-gate 32317c478bd9Sstevel@tonic-gate return (ret); 32327c478bd9Sstevel@tonic-gate } 32337c478bd9Sstevel@tonic-gate 32347c478bd9Sstevel@tonic-gate static ctf_file_t * 32357c478bd9Sstevel@tonic-gate pt_name_to_ctf(mdb_tgt_t *t, const char *name) 32367c478bd9Sstevel@tonic-gate { 32377c478bd9Sstevel@tonic-gate ctf_file_t *ret; 32387c478bd9Sstevel@tonic-gate 32397c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) { 32407c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_NOPROC); 32417c478bd9Sstevel@tonic-gate return (NULL); 32427c478bd9Sstevel@tonic-gate } 32437c478bd9Sstevel@tonic-gate 32447c478bd9Sstevel@tonic-gate if ((ret = Pname_to_ctf(t->t_pshandle, name)) == NULL) { 32457c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_NOOBJ); 32467c478bd9Sstevel@tonic-gate return (NULL); 32477c478bd9Sstevel@tonic-gate } 32487c478bd9Sstevel@tonic-gate 32497c478bd9Sstevel@tonic-gate return (ret); 32507c478bd9Sstevel@tonic-gate } 32517c478bd9Sstevel@tonic-gate 32527c478bd9Sstevel@tonic-gate static int 32537c478bd9Sstevel@tonic-gate pt_status(mdb_tgt_t *t, mdb_tgt_status_t *tsp) 32547c478bd9Sstevel@tonic-gate { 32557c478bd9Sstevel@tonic-gate const pstatus_t *psp; 32567c478bd9Sstevel@tonic-gate prgregset_t gregs; 32577c478bd9Sstevel@tonic-gate int state; 32587c478bd9Sstevel@tonic-gate 32597c478bd9Sstevel@tonic-gate bzero(tsp, sizeof (mdb_tgt_status_t)); 32607c478bd9Sstevel@tonic-gate 32617c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) { 32627c478bd9Sstevel@tonic-gate tsp->st_state = MDB_TGT_IDLE; 32637c478bd9Sstevel@tonic-gate return (0); 32647c478bd9Sstevel@tonic-gate } 32657c478bd9Sstevel@tonic-gate 32667c478bd9Sstevel@tonic-gate switch (state = Pstate(t->t_pshandle)) { 32677c478bd9Sstevel@tonic-gate case PS_RUN: 32687c478bd9Sstevel@tonic-gate tsp->st_state = MDB_TGT_RUNNING; 32697c478bd9Sstevel@tonic-gate break; 32707c478bd9Sstevel@tonic-gate 32717c478bd9Sstevel@tonic-gate case PS_STOP: 32727c478bd9Sstevel@tonic-gate tsp->st_state = MDB_TGT_STOPPED; 32737c478bd9Sstevel@tonic-gate psp = Pstatus(t->t_pshandle); 32747c478bd9Sstevel@tonic-gate 32757c478bd9Sstevel@tonic-gate tsp->st_tid = PTL_TID(t); 32767c478bd9Sstevel@tonic-gate if (PTL_GETREGS(t, tsp->st_tid, gregs) == 0) 32777c478bd9Sstevel@tonic-gate tsp->st_pc = gregs[R_PC]; 32787c478bd9Sstevel@tonic-gate 32797c478bd9Sstevel@tonic-gate if (psp->pr_flags & PR_ISTOP) 32807c478bd9Sstevel@tonic-gate tsp->st_flags |= MDB_TGT_ISTOP; 32817c478bd9Sstevel@tonic-gate if (psp->pr_flags & PR_DSTOP) 32827c478bd9Sstevel@tonic-gate tsp->st_flags |= MDB_TGT_DSTOP; 32837c478bd9Sstevel@tonic-gate 32847c478bd9Sstevel@tonic-gate break; 32857c478bd9Sstevel@tonic-gate 32867c478bd9Sstevel@tonic-gate case PS_LOST: 32877c478bd9Sstevel@tonic-gate tsp->st_state = MDB_TGT_LOST; 32887c478bd9Sstevel@tonic-gate break; 32897c478bd9Sstevel@tonic-gate case PS_UNDEAD: 32907c478bd9Sstevel@tonic-gate tsp->st_state = MDB_TGT_UNDEAD; 32917c478bd9Sstevel@tonic-gate break; 32927c478bd9Sstevel@tonic-gate case PS_DEAD: 32937c478bd9Sstevel@tonic-gate tsp->st_state = MDB_TGT_DEAD; 32947c478bd9Sstevel@tonic-gate break; 32957c478bd9Sstevel@tonic-gate case PS_IDLE: 32967c478bd9Sstevel@tonic-gate tsp->st_state = MDB_TGT_IDLE; 32977c478bd9Sstevel@tonic-gate break; 32987c478bd9Sstevel@tonic-gate default: 32997c478bd9Sstevel@tonic-gate fail("unknown libproc state (%d)\n", state); 33007c478bd9Sstevel@tonic-gate } 33017c478bd9Sstevel@tonic-gate 33027c478bd9Sstevel@tonic-gate if (t->t_flags & MDB_TGT_F_BUSY) 33037c478bd9Sstevel@tonic-gate tsp->st_flags |= MDB_TGT_BUSY; 33047c478bd9Sstevel@tonic-gate 33057c478bd9Sstevel@tonic-gate return (0); 33067c478bd9Sstevel@tonic-gate } 33077c478bd9Sstevel@tonic-gate 33087c478bd9Sstevel@tonic-gate static void 33097c478bd9Sstevel@tonic-gate pt_dupfd(const char *file, int oflags, mode_t mode, int dfd) 33107c478bd9Sstevel@tonic-gate { 33117c478bd9Sstevel@tonic-gate int fd; 33127c478bd9Sstevel@tonic-gate 33137c478bd9Sstevel@tonic-gate if ((fd = open(file, oflags, mode)) >= 0) { 33147c478bd9Sstevel@tonic-gate (void) fcntl(fd, F_DUP2FD, dfd); 33157c478bd9Sstevel@tonic-gate (void) close(fd); 33167c478bd9Sstevel@tonic-gate } else 33177c478bd9Sstevel@tonic-gate warn("failed to open %s as descriptor %d", file, dfd); 33187c478bd9Sstevel@tonic-gate } 33197c478bd9Sstevel@tonic-gate 33207c478bd9Sstevel@tonic-gate /* 33217c478bd9Sstevel@tonic-gate * The Pcreate_callback() function interposes on the default, empty libproc 33227c478bd9Sstevel@tonic-gate * definition. It will be called following a fork of a new child process by 33237c478bd9Sstevel@tonic-gate * Pcreate() below, but before the exec of the new process image. We use this 33247c478bd9Sstevel@tonic-gate * callback to optionally redirect stdin and stdout and reset the dispositions 33257c478bd9Sstevel@tonic-gate * of SIGPIPE and SIGQUIT from SIG_IGN back to SIG_DFL. 33267c478bd9Sstevel@tonic-gate */ 33277c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 33287c478bd9Sstevel@tonic-gate void 33297c478bd9Sstevel@tonic-gate Pcreate_callback(struct ps_prochandle *P) 33307c478bd9Sstevel@tonic-gate { 33317c478bd9Sstevel@tonic-gate pt_data_t *pt = mdb.m_target->t_data; 33327c478bd9Sstevel@tonic-gate 33337c478bd9Sstevel@tonic-gate if (pt->p_stdin != NULL) 33347c478bd9Sstevel@tonic-gate pt_dupfd(pt->p_stdin, O_RDWR, 0, STDIN_FILENO); 33357c478bd9Sstevel@tonic-gate if (pt->p_stdout != NULL) 33367c478bd9Sstevel@tonic-gate pt_dupfd(pt->p_stdout, O_CREAT | O_WRONLY, 0666, STDOUT_FILENO); 33377c478bd9Sstevel@tonic-gate 33387c478bd9Sstevel@tonic-gate (void) mdb_signal_sethandler(SIGPIPE, SIG_DFL, NULL); 33397c478bd9Sstevel@tonic-gate (void) mdb_signal_sethandler(SIGQUIT, SIG_DFL, NULL); 33407c478bd9Sstevel@tonic-gate } 33417c478bd9Sstevel@tonic-gate 33427c478bd9Sstevel@tonic-gate static int 33437c478bd9Sstevel@tonic-gate pt_run(mdb_tgt_t *t, int argc, const mdb_arg_t *argv) 33447c478bd9Sstevel@tonic-gate { 33457c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 33467c478bd9Sstevel@tonic-gate struct ps_prochandle *P; 33477c478bd9Sstevel@tonic-gate char execname[MAXPATHLEN]; 33487c478bd9Sstevel@tonic-gate const char **pargv; 33497c478bd9Sstevel@tonic-gate int pargc = 0; 33507c478bd9Sstevel@tonic-gate int i, perr; 33517c478bd9Sstevel@tonic-gate char **penv; 33527c478bd9Sstevel@tonic-gate mdb_var_t *v; 33537c478bd9Sstevel@tonic-gate 33547c478bd9Sstevel@tonic-gate if (pt->p_aout_fio == NULL) { 33557c478bd9Sstevel@tonic-gate warn("run requires executable to be specified on " 33567c478bd9Sstevel@tonic-gate "command-line\n"); 33577c478bd9Sstevel@tonic-gate return (set_errno(EMDB_TGT)); 33587c478bd9Sstevel@tonic-gate } 33597c478bd9Sstevel@tonic-gate 33607c478bd9Sstevel@tonic-gate pargv = mdb_alloc(sizeof (char *) * (argc + 2), UM_SLEEP); 33617c478bd9Sstevel@tonic-gate pargv[pargc++] = strbasename(IOP_NAME(pt->p_aout_fio)); 33627c478bd9Sstevel@tonic-gate 33637c478bd9Sstevel@tonic-gate for (i = 0; i < argc; i++) { 33647c478bd9Sstevel@tonic-gate if (argv[i].a_type != MDB_TYPE_STRING) { 33657c478bd9Sstevel@tonic-gate mdb_free(pargv, sizeof (char *) * (argc + 2)); 33667c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 33677c478bd9Sstevel@tonic-gate } 33687c478bd9Sstevel@tonic-gate if (argv[i].a_un.a_str[0] == '<') 33697c478bd9Sstevel@tonic-gate pt->p_stdin = argv[i].a_un.a_str + 1; 33707c478bd9Sstevel@tonic-gate else if (argv[i].a_un.a_str[0] == '>') 33717c478bd9Sstevel@tonic-gate pt->p_stdout = argv[i].a_un.a_str + 1; 33727c478bd9Sstevel@tonic-gate else 33737c478bd9Sstevel@tonic-gate pargv[pargc++] = argv[i].a_un.a_str; 33747c478bd9Sstevel@tonic-gate } 33757c478bd9Sstevel@tonic-gate pargv[pargc] = NULL; 33767c478bd9Sstevel@tonic-gate 33777c478bd9Sstevel@tonic-gate /* 33787c478bd9Sstevel@tonic-gate * Since Pcreate() uses execvp() and "." may not be present in $PATH, 33797c478bd9Sstevel@tonic-gate * we must manually prepend "./" when the executable is a simple name. 33807c478bd9Sstevel@tonic-gate */ 33817c478bd9Sstevel@tonic-gate if (strchr(IOP_NAME(pt->p_aout_fio), '/') == NULL) { 33827c478bd9Sstevel@tonic-gate (void) snprintf(execname, sizeof (execname), "./%s", 33837c478bd9Sstevel@tonic-gate IOP_NAME(pt->p_aout_fio)); 33847c478bd9Sstevel@tonic-gate } else { 33857c478bd9Sstevel@tonic-gate (void) snprintf(execname, sizeof (execname), "%s", 33867c478bd9Sstevel@tonic-gate IOP_NAME(pt->p_aout_fio)); 33877c478bd9Sstevel@tonic-gate } 33887c478bd9Sstevel@tonic-gate 33897c478bd9Sstevel@tonic-gate penv = mdb_alloc((mdb_nv_size(&pt->p_env)+ 1) * sizeof (char *), 33907c478bd9Sstevel@tonic-gate UM_SLEEP); 33917c478bd9Sstevel@tonic-gate for (mdb_nv_rewind(&pt->p_env), i = 0; 33927c478bd9Sstevel@tonic-gate (v = mdb_nv_advance(&pt->p_env)) != NULL; i++) 33937c478bd9Sstevel@tonic-gate penv[i] = mdb_nv_get_cookie(v); 33947c478bd9Sstevel@tonic-gate penv[i] = NULL; 33957c478bd9Sstevel@tonic-gate 33967c478bd9Sstevel@tonic-gate P = Pxcreate(execname, (char **)pargv, penv, &perr, NULL, 0); 33977c478bd9Sstevel@tonic-gate mdb_free(pargv, sizeof (char *) * (argc + 2)); 33987c478bd9Sstevel@tonic-gate pt->p_stdin = pt->p_stdout = NULL; 33997c478bd9Sstevel@tonic-gate 34007c478bd9Sstevel@tonic-gate mdb_free(penv, i * sizeof (char *)); 34017c478bd9Sstevel@tonic-gate 34027c478bd9Sstevel@tonic-gate if (P == NULL) { 34037c478bd9Sstevel@tonic-gate warn("failed to create process: %s\n", Pcreate_error(perr)); 34047c478bd9Sstevel@tonic-gate return (set_errno(EMDB_TGT)); 34057c478bd9Sstevel@tonic-gate } 34067c478bd9Sstevel@tonic-gate 34077c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL) { 34087c478bd9Sstevel@tonic-gate pt_pre_detach(t, TRUE); 34097c478bd9Sstevel@tonic-gate if (t->t_pshandle != pt->p_idlehandle) 34107c478bd9Sstevel@tonic-gate Prelease(t->t_pshandle, pt->p_rflags); 34117c478bd9Sstevel@tonic-gate } 34127c478bd9Sstevel@tonic-gate 34137c478bd9Sstevel@tonic-gate (void) Punsetflags(P, PR_RLC); /* make sure run-on-last-close is off */ 34147c478bd9Sstevel@tonic-gate (void) Psetflags(P, PR_KLC); /* kill on last close by debugger */ 34157c478bd9Sstevel@tonic-gate pt->p_rflags = PRELEASE_KILL; /* kill on debugger Prelease */ 34167c478bd9Sstevel@tonic-gate t->t_pshandle = P; 34177c478bd9Sstevel@tonic-gate 34187c478bd9Sstevel@tonic-gate pt_post_attach(t); 34197c478bd9Sstevel@tonic-gate pt_activate_common(t); 34207c478bd9Sstevel@tonic-gate (void) mdb_tgt_status(t, &t->t_status); 34217c478bd9Sstevel@tonic-gate mdb.m_flags |= MDB_FL_VCREATE; 34227c478bd9Sstevel@tonic-gate 34237c478bd9Sstevel@tonic-gate return (0); 34247c478bd9Sstevel@tonic-gate } 34257c478bd9Sstevel@tonic-gate 34267c478bd9Sstevel@tonic-gate /* 34277c478bd9Sstevel@tonic-gate * Forward a signal to the victim process in order to force it to stop or die. 34287c478bd9Sstevel@tonic-gate * Refer to the comments above pt_setrun(), below, for more info. 34297c478bd9Sstevel@tonic-gate */ 34307c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 34317c478bd9Sstevel@tonic-gate static void 34327c478bd9Sstevel@tonic-gate pt_sigfwd(int sig, siginfo_t *sip, ucontext_t *ucp, mdb_tgt_t *t) 34337c478bd9Sstevel@tonic-gate { 34347c478bd9Sstevel@tonic-gate struct ps_prochandle *P = t->t_pshandle; 34357c478bd9Sstevel@tonic-gate const lwpstatus_t *psp = &Pstatus(P)->pr_lwp; 34367c478bd9Sstevel@tonic-gate pid_t pid = Pstatus(P)->pr_pid; 34377c478bd9Sstevel@tonic-gate long ctl[2]; 34387c478bd9Sstevel@tonic-gate 34397c478bd9Sstevel@tonic-gate if (getpgid(pid) != mdb.m_pgid) { 34407c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_TGT, "fwd SIG#%d to %d\n", sig, (int)pid); 34417c478bd9Sstevel@tonic-gate (void) kill(pid, sig); 34427c478bd9Sstevel@tonic-gate } 34437c478bd9Sstevel@tonic-gate 34447c478bd9Sstevel@tonic-gate if (Pwait(P, 1) == 0 && (psp->pr_flags & PR_STOPPED) && 34457c478bd9Sstevel@tonic-gate psp->pr_why == PR_JOBCONTROL && Pdstop(P) == 0) { 34467c478bd9Sstevel@tonic-gate /* 34477c478bd9Sstevel@tonic-gate * If we're job control stopped and our DSTOP is pending, the 34487c478bd9Sstevel@tonic-gate * victim will never see our signal, so undo the kill() and 34497c478bd9Sstevel@tonic-gate * then send SIGCONT the victim to kick it out of the job 34507c478bd9Sstevel@tonic-gate * control stop and force our DSTOP to take effect. 34517c478bd9Sstevel@tonic-gate */ 34527c478bd9Sstevel@tonic-gate if ((psp->pr_flags & PR_DSTOP) && 34537c478bd9Sstevel@tonic-gate prismember(&Pstatus(P)->pr_sigpend, sig)) { 34547c478bd9Sstevel@tonic-gate ctl[0] = PCUNKILL; 34557c478bd9Sstevel@tonic-gate ctl[1] = sig; 34567c478bd9Sstevel@tonic-gate (void) write(Pctlfd(P), ctl, sizeof (ctl)); 34577c478bd9Sstevel@tonic-gate } 34587c478bd9Sstevel@tonic-gate 34597c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_TGT, "fwd SIGCONT to %d\n", (int)pid); 34607c478bd9Sstevel@tonic-gate (void) kill(pid, SIGCONT); 34617c478bd9Sstevel@tonic-gate } 34627c478bd9Sstevel@tonic-gate } 34637c478bd9Sstevel@tonic-gate 34647c478bd9Sstevel@tonic-gate /* 34657c478bd9Sstevel@tonic-gate * Common code for step and continue: if no victim process has been created, 34667c478bd9Sstevel@tonic-gate * call pt_run() to create one. Then set the victim running, clearing any 34677c478bd9Sstevel@tonic-gate * pending fault. One special case is that if the victim was previously 34687c478bd9Sstevel@tonic-gate * stopped on reception of SIGINT, we know that SIGINT was traced and the user 34697c478bd9Sstevel@tonic-gate * requested the victim to stop, so clear this signal before continuing. 34707c478bd9Sstevel@tonic-gate * For all other traced signals, the signal will be delivered on continue. 34717c478bd9Sstevel@tonic-gate * 34727c478bd9Sstevel@tonic-gate * Once the victim process is running, we wait for it to stop on an event of 34737c478bd9Sstevel@tonic-gate * interest. Although libproc provides the basic primitive to wait for the 34747c478bd9Sstevel@tonic-gate * victim, we must be careful in our handling of signals. We want to allow the 34757c478bd9Sstevel@tonic-gate * user to issue a SIGINT or SIGQUIT using the designated terminal control 34767c478bd9Sstevel@tonic-gate * character (typically ^C and ^\), and have these signals stop the target and 34777c478bd9Sstevel@tonic-gate * return control to the debugger if the signals are traced. There are three 34787c478bd9Sstevel@tonic-gate * cases to be considered in our implementation: 34797c478bd9Sstevel@tonic-gate * 34807c478bd9Sstevel@tonic-gate * (1) If the debugger and victim are in the same process group, both receive 34817c478bd9Sstevel@tonic-gate * the signal from the terminal driver. The debugger returns from Pwait() with 34827c478bd9Sstevel@tonic-gate * errno = EINTR, so we want to loop back and continue waiting until the victim 34837c478bd9Sstevel@tonic-gate * stops on receipt of its SIGINT or SIGQUIT. 34847c478bd9Sstevel@tonic-gate * 34857c478bd9Sstevel@tonic-gate * (2) If the debugger and victim are in different process groups, and the 34867c478bd9Sstevel@tonic-gate * victim is a member of the foreground process group, it will receive the 34877c478bd9Sstevel@tonic-gate * signal from the terminal driver and the debugger will not. As such, we 34887c478bd9Sstevel@tonic-gate * will remain blocked in Pwait() until the victim stops on its signal. 34897c478bd9Sstevel@tonic-gate * 34907c478bd9Sstevel@tonic-gate * (3) If the debugger and victim are in different process groups, and the 34917c478bd9Sstevel@tonic-gate * debugger is a member of the foreground process group, it will receive the 34927c478bd9Sstevel@tonic-gate * signal from the terminal driver, and the victim will not. The debugger 34937c478bd9Sstevel@tonic-gate * returns from Pwait() with errno = EINTR, so we need to forward the signal 34947c478bd9Sstevel@tonic-gate * to the victim process directly and then Pwait() again for it to stop. 34957c478bd9Sstevel@tonic-gate * 34967c478bd9Sstevel@tonic-gate * We can observe that all three cases are handled by simply calling Pwait() 34977c478bd9Sstevel@tonic-gate * repeatedly if it fails with EINTR, and forwarding SIGINT and SIGQUIT to 34987c478bd9Sstevel@tonic-gate * the victim if it is in a different process group, using pt_sigfwd() above. 34997c478bd9Sstevel@tonic-gate * 35007c478bd9Sstevel@tonic-gate * An additional complication is that the process may not be able to field 35017c478bd9Sstevel@tonic-gate * the signal if it is currently stopped by job control. In this case, we 35027c478bd9Sstevel@tonic-gate * also DSTOP the process, and then send it a SIGCONT to wake it up from 35037c478bd9Sstevel@tonic-gate * job control and force it to re-enter stop() under the control of /proc. 35047c478bd9Sstevel@tonic-gate * 35057c478bd9Sstevel@tonic-gate * Finally, we would like to allow the user to suspend the process using the 35067c478bd9Sstevel@tonic-gate * terminal suspend character (typically ^Z) if both are in the same session. 35077c478bd9Sstevel@tonic-gate * We again employ pt_sigfwd() to forward SIGTSTP to the victim, wait for it to 35087c478bd9Sstevel@tonic-gate * stop from job control, and then capture it using /proc. Once the process 35097c478bd9Sstevel@tonic-gate * has stopped, normal SIGTSTP processing is restored and the user can issue 35107c478bd9Sstevel@tonic-gate * another ^Z in order to suspend the debugger and return to the parent shell. 35117c478bd9Sstevel@tonic-gate */ 35127c478bd9Sstevel@tonic-gate static int 35137c478bd9Sstevel@tonic-gate pt_setrun(mdb_tgt_t *t, mdb_tgt_status_t *tsp, int flags) 35147c478bd9Sstevel@tonic-gate { 35157c478bd9Sstevel@tonic-gate struct ps_prochandle *P = t->t_pshandle; 35167c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 35177c478bd9Sstevel@tonic-gate pid_t old_pgid = -1; 35187c478bd9Sstevel@tonic-gate 35197c478bd9Sstevel@tonic-gate mdb_signal_f *intf, *quitf, *tstpf; 35207c478bd9Sstevel@tonic-gate const lwpstatus_t *psp; 35217c478bd9Sstevel@tonic-gate void *intd, *quitd, *tstpd; 35227c478bd9Sstevel@tonic-gate 35237c478bd9Sstevel@tonic-gate int sig = pt->p_signal; 35247c478bd9Sstevel@tonic-gate int error = 0; 35257c478bd9Sstevel@tonic-gate int pgid = -1; 35267c478bd9Sstevel@tonic-gate 35277c478bd9Sstevel@tonic-gate pt->p_signal = 0; /* clear pending signal */ 35287c478bd9Sstevel@tonic-gate 35297c478bd9Sstevel@tonic-gate if (P == NULL && pt_run(t, 0, NULL) == -1) 35307c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 35317c478bd9Sstevel@tonic-gate 35327c478bd9Sstevel@tonic-gate P = t->t_pshandle; 35337c478bd9Sstevel@tonic-gate psp = &Pstatus(P)->pr_lwp; 35347c478bd9Sstevel@tonic-gate 35357c478bd9Sstevel@tonic-gate if (sig == 0 && psp->pr_why == PR_SIGNALLED && psp->pr_what == SIGINT) 35367c478bd9Sstevel@tonic-gate flags |= PRCSIG; /* clear pending SIGINT */ 35377c478bd9Sstevel@tonic-gate else 35387c478bd9Sstevel@tonic-gate flags |= PRCFAULT; /* clear any pending fault (e.g. BPT) */ 35397c478bd9Sstevel@tonic-gate 35407c478bd9Sstevel@tonic-gate intf = mdb_signal_gethandler(SIGINT, &intd); 35417c478bd9Sstevel@tonic-gate quitf = mdb_signal_gethandler(SIGQUIT, &quitd); 35427c478bd9Sstevel@tonic-gate tstpf = mdb_signal_gethandler(SIGTSTP, &tstpd); 35437c478bd9Sstevel@tonic-gate 35447c478bd9Sstevel@tonic-gate (void) mdb_signal_sethandler(SIGINT, (mdb_signal_f *)pt_sigfwd, t); 35457c478bd9Sstevel@tonic-gate (void) mdb_signal_sethandler(SIGQUIT, (mdb_signal_f *)pt_sigfwd, t); 35467c478bd9Sstevel@tonic-gate (void) mdb_signal_sethandler(SIGTSTP, (mdb_signal_f *)pt_sigfwd, t); 35477c478bd9Sstevel@tonic-gate 35487c478bd9Sstevel@tonic-gate if (sig != 0 && Pstate(P) == PS_RUN && 35497c478bd9Sstevel@tonic-gate kill(Pstatus(P)->pr_pid, sig) == -1) { 35507c478bd9Sstevel@tonic-gate error = errno; 35517c478bd9Sstevel@tonic-gate goto out; 35527c478bd9Sstevel@tonic-gate } 35537c478bd9Sstevel@tonic-gate 35547c478bd9Sstevel@tonic-gate /* 35557c478bd9Sstevel@tonic-gate * If we attached to a job stopped background process in the same 35567c478bd9Sstevel@tonic-gate * session, make its pgid the foreground process group before running 35577c478bd9Sstevel@tonic-gate * it. Ignore SIGTTOU while doing this to avoid being suspended. 35587c478bd9Sstevel@tonic-gate */ 35597c478bd9Sstevel@tonic-gate if (mdb.m_flags & MDB_FL_JOBCTL) { 35607c478bd9Sstevel@tonic-gate (void) mdb_signal_sethandler(SIGTTOU, SIG_IGN, NULL); 35617c478bd9Sstevel@tonic-gate (void) IOP_CTL(mdb.m_term, TIOCGPGRP, &old_pgid); 35627c478bd9Sstevel@tonic-gate (void) IOP_CTL(mdb.m_term, TIOCSPGRP, 35637c478bd9Sstevel@tonic-gate (void *)&Pstatus(P)->pr_pgid); 35647c478bd9Sstevel@tonic-gate (void) mdb_signal_sethandler(SIGTTOU, SIG_DFL, NULL); 35657c478bd9Sstevel@tonic-gate } 35667c478bd9Sstevel@tonic-gate 35677c478bd9Sstevel@tonic-gate if (Pstate(P) != PS_RUN && Psetrun(P, sig, flags) == -1) { 35687c478bd9Sstevel@tonic-gate error = errno; 35697c478bd9Sstevel@tonic-gate goto out; 35707c478bd9Sstevel@tonic-gate } 35717c478bd9Sstevel@tonic-gate 35727c478bd9Sstevel@tonic-gate /* 35737c478bd9Sstevel@tonic-gate * If the process is stopped on job control, resume its process group 35747c478bd9Sstevel@tonic-gate * by sending it a SIGCONT if we are in the same session. Otherwise 35757c478bd9Sstevel@tonic-gate * we have no choice but to wait for someone else to foreground it. 35767c478bd9Sstevel@tonic-gate */ 35777c478bd9Sstevel@tonic-gate if (psp->pr_why == PR_JOBCONTROL) { 35787c478bd9Sstevel@tonic-gate if (mdb.m_flags & MDB_FL_JOBCTL) 35797c478bd9Sstevel@tonic-gate (void) kill(-Pstatus(P)->pr_pgid, SIGCONT); 35807c478bd9Sstevel@tonic-gate else if (mdb.m_term != NULL) 35817c478bd9Sstevel@tonic-gate warn("process is still suspended by job control ...\n"); 35827c478bd9Sstevel@tonic-gate } 35837c478bd9Sstevel@tonic-gate 35847c478bd9Sstevel@tonic-gate /* 35857c478bd9Sstevel@tonic-gate * Wait for the process to stop. As described above, we loop around if 35867c478bd9Sstevel@tonic-gate * we are interrupted (EINTR). If we lose control, attempt to re-open 35877c478bd9Sstevel@tonic-gate * the process, or call pt_exec() if that fails to handle a re-exec. 35887c478bd9Sstevel@tonic-gate * If the process dies (ENOENT) or Pwait() fails, break out of the loop. 35897c478bd9Sstevel@tonic-gate */ 35907c478bd9Sstevel@tonic-gate while (Pwait(P, 0) == -1) { 35917c478bd9Sstevel@tonic-gate if (errno != EINTR) { 35927c478bd9Sstevel@tonic-gate if (Pstate(P) == PS_LOST) { 35937c478bd9Sstevel@tonic-gate if (Preopen(P) == 0) 35947c478bd9Sstevel@tonic-gate continue; /* Pwait() again */ 35957c478bd9Sstevel@tonic-gate else 35967c478bd9Sstevel@tonic-gate pt_exec(t, 0, NULL); 35977c478bd9Sstevel@tonic-gate } else if (errno != ENOENT) 35987c478bd9Sstevel@tonic-gate warn("failed to wait for event"); 35997c478bd9Sstevel@tonic-gate break; 36007c478bd9Sstevel@tonic-gate } 36017c478bd9Sstevel@tonic-gate } 36027c478bd9Sstevel@tonic-gate 36037c478bd9Sstevel@tonic-gate /* 36047c478bd9Sstevel@tonic-gate * If we changed the foreground process group, restore the old pgid 36057c478bd9Sstevel@tonic-gate * while ignoring SIGTTOU so we are not accidentally suspended. 36067c478bd9Sstevel@tonic-gate */ 36077c478bd9Sstevel@tonic-gate if (old_pgid != -1) { 36087c478bd9Sstevel@tonic-gate (void) mdb_signal_sethandler(SIGTTOU, SIG_IGN, NULL); 36097c478bd9Sstevel@tonic-gate (void) IOP_CTL(mdb.m_term, TIOCSPGRP, &pgid); 36107c478bd9Sstevel@tonic-gate (void) mdb_signal_sethandler(SIGTTOU, SIG_DFL, NULL); 36117c478bd9Sstevel@tonic-gate } 36127c478bd9Sstevel@tonic-gate 36137c478bd9Sstevel@tonic-gate /* 36147c478bd9Sstevel@tonic-gate * If we're now stopped on exit from a successful exec, release any 36157c478bd9Sstevel@tonic-gate * vfork parents and clean out their address space before returning 36167c478bd9Sstevel@tonic-gate * to tgt_continue() and perturbing the list of armed event specs. 36177c478bd9Sstevel@tonic-gate * If we're stopped for any other reason, just update the mappings. 36187c478bd9Sstevel@tonic-gate */ 36197c478bd9Sstevel@tonic-gate switch (Pstate(P)) { 36207c478bd9Sstevel@tonic-gate case PS_STOP: 36217c478bd9Sstevel@tonic-gate if (psp->pr_why == PR_SYSEXIT && psp->pr_errno == 0 && 36228fd04b83SRoger A. Faulkner psp->pr_what == SYS_execve) 36237c478bd9Sstevel@tonic-gate pt_release_parents(t); 36247c478bd9Sstevel@tonic-gate else 36257c478bd9Sstevel@tonic-gate Pupdate_maps(P); 36267c478bd9Sstevel@tonic-gate break; 36277c478bd9Sstevel@tonic-gate 36287c478bd9Sstevel@tonic-gate case PS_UNDEAD: 36297c478bd9Sstevel@tonic-gate case PS_LOST: 36307c478bd9Sstevel@tonic-gate pt_release_parents(t); 36317c478bd9Sstevel@tonic-gate break; 36327c478bd9Sstevel@tonic-gate } 36337c478bd9Sstevel@tonic-gate 36347c478bd9Sstevel@tonic-gate out: 36357c478bd9Sstevel@tonic-gate (void) mdb_signal_sethandler(SIGINT, intf, intd); 36367c478bd9Sstevel@tonic-gate (void) mdb_signal_sethandler(SIGQUIT, quitf, quitd); 36377c478bd9Sstevel@tonic-gate (void) mdb_signal_sethandler(SIGTSTP, tstpf, tstpd); 36387c478bd9Sstevel@tonic-gate (void) pt_status(t, tsp); 36397c478bd9Sstevel@tonic-gate 36407c478bd9Sstevel@tonic-gate return (error ? set_errno(error) : 0); 36417c478bd9Sstevel@tonic-gate } 36427c478bd9Sstevel@tonic-gate 36437c478bd9Sstevel@tonic-gate static int 36447c478bd9Sstevel@tonic-gate pt_step(mdb_tgt_t *t, mdb_tgt_status_t *tsp) 36457c478bd9Sstevel@tonic-gate { 36467c478bd9Sstevel@tonic-gate return (pt_setrun(t, tsp, PRSTEP)); 36477c478bd9Sstevel@tonic-gate } 36487c478bd9Sstevel@tonic-gate 36497c478bd9Sstevel@tonic-gate static int 36507c478bd9Sstevel@tonic-gate pt_continue(mdb_tgt_t *t, mdb_tgt_status_t *tsp) 36517c478bd9Sstevel@tonic-gate { 36527c478bd9Sstevel@tonic-gate return (pt_setrun(t, tsp, 0)); 36537c478bd9Sstevel@tonic-gate } 36547c478bd9Sstevel@tonic-gate 36557c478bd9Sstevel@tonic-gate static int 36567c478bd9Sstevel@tonic-gate pt_signal(mdb_tgt_t *t, int sig) 36577c478bd9Sstevel@tonic-gate { 36587c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 36597c478bd9Sstevel@tonic-gate 36607c478bd9Sstevel@tonic-gate if (sig > 0 && sig <= pt->p_maxsig) { 36617c478bd9Sstevel@tonic-gate pt->p_signal = sig; /* pending until next pt_setrun */ 36627c478bd9Sstevel@tonic-gate return (0); 36637c478bd9Sstevel@tonic-gate } 36647c478bd9Sstevel@tonic-gate 36657c478bd9Sstevel@tonic-gate return (set_errno(EMDB_BADSIGNUM)); 36667c478bd9Sstevel@tonic-gate } 36677c478bd9Sstevel@tonic-gate 36687c478bd9Sstevel@tonic-gate static int 36697c478bd9Sstevel@tonic-gate pt_sysenter_ctor(mdb_tgt_t *t, mdb_sespec_t *sep, void *args) 36707c478bd9Sstevel@tonic-gate { 36717c478bd9Sstevel@tonic-gate struct ps_prochandle *P = t->t_pshandle; 36727c478bd9Sstevel@tonic-gate 36737c478bd9Sstevel@tonic-gate if (P != NULL && Pstate(P) < PS_LOST) { 36747c478bd9Sstevel@tonic-gate sep->se_data = args; /* data is raw system call number */ 36757c478bd9Sstevel@tonic-gate return (Psysentry(P, (intptr_t)args, TRUE) < 0 ? -1 : 0); 36767c478bd9Sstevel@tonic-gate } 36777c478bd9Sstevel@tonic-gate 36787c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 36797c478bd9Sstevel@tonic-gate } 36807c478bd9Sstevel@tonic-gate 36817c478bd9Sstevel@tonic-gate static void 36827c478bd9Sstevel@tonic-gate pt_sysenter_dtor(mdb_tgt_t *t, mdb_sespec_t *sep) 36837c478bd9Sstevel@tonic-gate { 36847c478bd9Sstevel@tonic-gate (void) Psysentry(t->t_pshandle, (intptr_t)sep->se_data, FALSE); 36857c478bd9Sstevel@tonic-gate } 36867c478bd9Sstevel@tonic-gate 36877c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 36887c478bd9Sstevel@tonic-gate static char * 36897c478bd9Sstevel@tonic-gate pt_sysenter_info(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_vespec_t *vep, 36907c478bd9Sstevel@tonic-gate mdb_tgt_spec_desc_t *sp, char *buf, size_t nbytes) 36917c478bd9Sstevel@tonic-gate { 36927c478bd9Sstevel@tonic-gate char name[32]; 36937c478bd9Sstevel@tonic-gate int sysnum; 36947c478bd9Sstevel@tonic-gate 36957c478bd9Sstevel@tonic-gate if (vep != NULL) 36967c478bd9Sstevel@tonic-gate sysnum = (intptr_t)vep->ve_args; 36977c478bd9Sstevel@tonic-gate else 36987c478bd9Sstevel@tonic-gate sysnum = (intptr_t)sep->se_data; 36997c478bd9Sstevel@tonic-gate 37007c478bd9Sstevel@tonic-gate (void) proc_sysname(sysnum, name, sizeof (name)); 37017c478bd9Sstevel@tonic-gate (void) mdb_iob_snprintf(buf, nbytes, "stop on entry to %s", name); 37027c478bd9Sstevel@tonic-gate 37037c478bd9Sstevel@tonic-gate return (buf); 37047c478bd9Sstevel@tonic-gate } 37057c478bd9Sstevel@tonic-gate 37067c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 37077c478bd9Sstevel@tonic-gate static int 37087c478bd9Sstevel@tonic-gate pt_sysenter_match(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_tgt_status_t *tsp) 37097c478bd9Sstevel@tonic-gate { 37107c478bd9Sstevel@tonic-gate const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp; 37117c478bd9Sstevel@tonic-gate int sysnum = (intptr_t)sep->se_data; 37127c478bd9Sstevel@tonic-gate 37137c478bd9Sstevel@tonic-gate return (psp->pr_why == PR_SYSENTRY && psp->pr_what == sysnum); 37147c478bd9Sstevel@tonic-gate } 37157c478bd9Sstevel@tonic-gate 37167c478bd9Sstevel@tonic-gate static const mdb_se_ops_t proc_sysenter_ops = { 37177c478bd9Sstevel@tonic-gate pt_sysenter_ctor, /* se_ctor */ 37187c478bd9Sstevel@tonic-gate pt_sysenter_dtor, /* se_dtor */ 37197c478bd9Sstevel@tonic-gate pt_sysenter_info, /* se_info */ 37207c478bd9Sstevel@tonic-gate no_se_secmp, /* se_secmp */ 37217c478bd9Sstevel@tonic-gate no_se_vecmp, /* se_vecmp */ 37227c478bd9Sstevel@tonic-gate no_se_arm, /* se_arm */ 37237c478bd9Sstevel@tonic-gate no_se_disarm, /* se_disarm */ 37247c478bd9Sstevel@tonic-gate no_se_cont, /* se_cont */ 37257c478bd9Sstevel@tonic-gate pt_sysenter_match /* se_match */ 37267c478bd9Sstevel@tonic-gate }; 37277c478bd9Sstevel@tonic-gate 37287c478bd9Sstevel@tonic-gate static int 37297c478bd9Sstevel@tonic-gate pt_sysexit_ctor(mdb_tgt_t *t, mdb_sespec_t *sep, void *args) 37307c478bd9Sstevel@tonic-gate { 37317c478bd9Sstevel@tonic-gate struct ps_prochandle *P = t->t_pshandle; 37327c478bd9Sstevel@tonic-gate 37337c478bd9Sstevel@tonic-gate if (P != NULL && Pstate(P) < PS_LOST) { 37347c478bd9Sstevel@tonic-gate sep->se_data = args; /* data is raw system call number */ 37357c478bd9Sstevel@tonic-gate return (Psysexit(P, (intptr_t)args, TRUE) < 0 ? -1 : 0); 37367c478bd9Sstevel@tonic-gate } 37377c478bd9Sstevel@tonic-gate 37387c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 37397c478bd9Sstevel@tonic-gate } 37407c478bd9Sstevel@tonic-gate 37417c478bd9Sstevel@tonic-gate static void 37427c478bd9Sstevel@tonic-gate pt_sysexit_dtor(mdb_tgt_t *t, mdb_sespec_t *sep) 37437c478bd9Sstevel@tonic-gate { 37447c478bd9Sstevel@tonic-gate (void) Psysexit(t->t_pshandle, (intptr_t)sep->se_data, FALSE); 37457c478bd9Sstevel@tonic-gate } 37467c478bd9Sstevel@tonic-gate 37477c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 37487c478bd9Sstevel@tonic-gate static char * 37497c478bd9Sstevel@tonic-gate pt_sysexit_info(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_vespec_t *vep, 37507c478bd9Sstevel@tonic-gate mdb_tgt_spec_desc_t *sp, char *buf, size_t nbytes) 37517c478bd9Sstevel@tonic-gate { 37527c478bd9Sstevel@tonic-gate char name[32]; 37537c478bd9Sstevel@tonic-gate int sysnum; 37547c478bd9Sstevel@tonic-gate 37557c478bd9Sstevel@tonic-gate if (vep != NULL) 37567c478bd9Sstevel@tonic-gate sysnum = (intptr_t)vep->ve_args; 37577c478bd9Sstevel@tonic-gate else 37587c478bd9Sstevel@tonic-gate sysnum = (intptr_t)sep->se_data; 37597c478bd9Sstevel@tonic-gate 37607c478bd9Sstevel@tonic-gate (void) proc_sysname(sysnum, name, sizeof (name)); 37617c478bd9Sstevel@tonic-gate (void) mdb_iob_snprintf(buf, nbytes, "stop on exit from %s", name); 37627c478bd9Sstevel@tonic-gate 37637c478bd9Sstevel@tonic-gate return (buf); 37647c478bd9Sstevel@tonic-gate } 37657c478bd9Sstevel@tonic-gate 37667c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 37677c478bd9Sstevel@tonic-gate static int 37687c478bd9Sstevel@tonic-gate pt_sysexit_match(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_tgt_status_t *tsp) 37697c478bd9Sstevel@tonic-gate { 37707c478bd9Sstevel@tonic-gate const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp; 37717c478bd9Sstevel@tonic-gate int sysnum = (intptr_t)sep->se_data; 37727c478bd9Sstevel@tonic-gate 37737c478bd9Sstevel@tonic-gate return (psp->pr_why == PR_SYSEXIT && psp->pr_what == sysnum); 37747c478bd9Sstevel@tonic-gate } 37757c478bd9Sstevel@tonic-gate 37767c478bd9Sstevel@tonic-gate static const mdb_se_ops_t proc_sysexit_ops = { 37777c478bd9Sstevel@tonic-gate pt_sysexit_ctor, /* se_ctor */ 37787c478bd9Sstevel@tonic-gate pt_sysexit_dtor, /* se_dtor */ 37797c478bd9Sstevel@tonic-gate pt_sysexit_info, /* se_info */ 37807c478bd9Sstevel@tonic-gate no_se_secmp, /* se_secmp */ 37817c478bd9Sstevel@tonic-gate no_se_vecmp, /* se_vecmp */ 37827c478bd9Sstevel@tonic-gate no_se_arm, /* se_arm */ 37837c478bd9Sstevel@tonic-gate no_se_disarm, /* se_disarm */ 37847c478bd9Sstevel@tonic-gate no_se_cont, /* se_cont */ 37857c478bd9Sstevel@tonic-gate pt_sysexit_match /* se_match */ 37867c478bd9Sstevel@tonic-gate }; 37877c478bd9Sstevel@tonic-gate 37887c478bd9Sstevel@tonic-gate static int 37897c478bd9Sstevel@tonic-gate pt_signal_ctor(mdb_tgt_t *t, mdb_sespec_t *sep, void *args) 37907c478bd9Sstevel@tonic-gate { 37917c478bd9Sstevel@tonic-gate struct ps_prochandle *P = t->t_pshandle; 37927c478bd9Sstevel@tonic-gate 37937c478bd9Sstevel@tonic-gate if (P != NULL && Pstate(P) < PS_LOST) { 37947c478bd9Sstevel@tonic-gate sep->se_data = args; /* data is raw signal number */ 37957c478bd9Sstevel@tonic-gate return (Psignal(P, (intptr_t)args, TRUE) < 0 ? -1 : 0); 37967c478bd9Sstevel@tonic-gate } 37977c478bd9Sstevel@tonic-gate 37987c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 37997c478bd9Sstevel@tonic-gate } 38007c478bd9Sstevel@tonic-gate 38017c478bd9Sstevel@tonic-gate static void 38027c478bd9Sstevel@tonic-gate pt_signal_dtor(mdb_tgt_t *t, mdb_sespec_t *sep) 38037c478bd9Sstevel@tonic-gate { 38047c478bd9Sstevel@tonic-gate (void) Psignal(t->t_pshandle, (intptr_t)sep->se_data, FALSE); 38057c478bd9Sstevel@tonic-gate } 38067c478bd9Sstevel@tonic-gate 38077c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 38087c478bd9Sstevel@tonic-gate static char * 38097c478bd9Sstevel@tonic-gate pt_signal_info(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_vespec_t *vep, 38107c478bd9Sstevel@tonic-gate mdb_tgt_spec_desc_t *sp, char *buf, size_t nbytes) 38117c478bd9Sstevel@tonic-gate { 38127c478bd9Sstevel@tonic-gate char name[SIG2STR_MAX]; 38137c478bd9Sstevel@tonic-gate int signum; 38147c478bd9Sstevel@tonic-gate 38157c478bd9Sstevel@tonic-gate if (vep != NULL) 38167c478bd9Sstevel@tonic-gate signum = (intptr_t)vep->ve_args; 38177c478bd9Sstevel@tonic-gate else 38187c478bd9Sstevel@tonic-gate signum = (intptr_t)sep->se_data; 38197c478bd9Sstevel@tonic-gate 38207c478bd9Sstevel@tonic-gate (void) proc_signame(signum, name, sizeof (name)); 38217c478bd9Sstevel@tonic-gate (void) mdb_iob_snprintf(buf, nbytes, "stop on %s", name); 38227c478bd9Sstevel@tonic-gate 38237c478bd9Sstevel@tonic-gate return (buf); 38247c478bd9Sstevel@tonic-gate } 38257c478bd9Sstevel@tonic-gate 38267c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 38277c478bd9Sstevel@tonic-gate static int 38287c478bd9Sstevel@tonic-gate pt_signal_match(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_tgt_status_t *tsp) 38297c478bd9Sstevel@tonic-gate { 38307c478bd9Sstevel@tonic-gate const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp; 38317c478bd9Sstevel@tonic-gate int signum = (intptr_t)sep->se_data; 38327c478bd9Sstevel@tonic-gate 38337c478bd9Sstevel@tonic-gate return (psp->pr_why == PR_SIGNALLED && psp->pr_what == signum); 38347c478bd9Sstevel@tonic-gate } 38357c478bd9Sstevel@tonic-gate 38367c478bd9Sstevel@tonic-gate static const mdb_se_ops_t proc_signal_ops = { 38377c478bd9Sstevel@tonic-gate pt_signal_ctor, /* se_ctor */ 38387c478bd9Sstevel@tonic-gate pt_signal_dtor, /* se_dtor */ 38397c478bd9Sstevel@tonic-gate pt_signal_info, /* se_info */ 38407c478bd9Sstevel@tonic-gate no_se_secmp, /* se_secmp */ 38417c478bd9Sstevel@tonic-gate no_se_vecmp, /* se_vecmp */ 38427c478bd9Sstevel@tonic-gate no_se_arm, /* se_arm */ 38437c478bd9Sstevel@tonic-gate no_se_disarm, /* se_disarm */ 38447c478bd9Sstevel@tonic-gate no_se_cont, /* se_cont */ 38457c478bd9Sstevel@tonic-gate pt_signal_match /* se_match */ 38467c478bd9Sstevel@tonic-gate }; 38477c478bd9Sstevel@tonic-gate 38487c478bd9Sstevel@tonic-gate static int 38497c478bd9Sstevel@tonic-gate pt_fault_ctor(mdb_tgt_t *t, mdb_sespec_t *sep, void *args) 38507c478bd9Sstevel@tonic-gate { 38517c478bd9Sstevel@tonic-gate struct ps_prochandle *P = t->t_pshandle; 38527c478bd9Sstevel@tonic-gate 38537c478bd9Sstevel@tonic-gate if (P != NULL && Pstate(P) < PS_LOST) { 38547c478bd9Sstevel@tonic-gate sep->se_data = args; /* data is raw fault number */ 38557c478bd9Sstevel@tonic-gate return (Pfault(P, (intptr_t)args, TRUE) < 0 ? -1 : 0); 38567c478bd9Sstevel@tonic-gate } 38577c478bd9Sstevel@tonic-gate 38587c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 38597c478bd9Sstevel@tonic-gate } 38607c478bd9Sstevel@tonic-gate 38617c478bd9Sstevel@tonic-gate static void 38627c478bd9Sstevel@tonic-gate pt_fault_dtor(mdb_tgt_t *t, mdb_sespec_t *sep) 38637c478bd9Sstevel@tonic-gate { 38647c478bd9Sstevel@tonic-gate int fault = (intptr_t)sep->se_data; 38657c478bd9Sstevel@tonic-gate 38667c478bd9Sstevel@tonic-gate if (fault != FLTBPT && fault != FLTTRACE && fault != FLTWATCH) 38677c478bd9Sstevel@tonic-gate (void) Pfault(t->t_pshandle, fault, FALSE); 38687c478bd9Sstevel@tonic-gate } 38697c478bd9Sstevel@tonic-gate 38707c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 38717c478bd9Sstevel@tonic-gate static char * 38727c478bd9Sstevel@tonic-gate pt_fault_info(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_vespec_t *vep, 38737c478bd9Sstevel@tonic-gate mdb_tgt_spec_desc_t *sp, char *buf, size_t nbytes) 38747c478bd9Sstevel@tonic-gate { 38757c478bd9Sstevel@tonic-gate char name[32]; 38767c478bd9Sstevel@tonic-gate int fltnum; 38777c478bd9Sstevel@tonic-gate 38787c478bd9Sstevel@tonic-gate if (vep != NULL) 38797c478bd9Sstevel@tonic-gate fltnum = (intptr_t)vep->ve_args; 38807c478bd9Sstevel@tonic-gate else 38817c478bd9Sstevel@tonic-gate fltnum = (intptr_t)sep->se_data; 38827c478bd9Sstevel@tonic-gate 38837c478bd9Sstevel@tonic-gate (void) proc_fltname(fltnum, name, sizeof (name)); 38847c478bd9Sstevel@tonic-gate (void) mdb_iob_snprintf(buf, nbytes, "stop on %s", name); 38857c478bd9Sstevel@tonic-gate 38867c478bd9Sstevel@tonic-gate return (buf); 38877c478bd9Sstevel@tonic-gate } 38887c478bd9Sstevel@tonic-gate 38897c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 38907c478bd9Sstevel@tonic-gate static int 38917c478bd9Sstevel@tonic-gate pt_fault_match(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_tgt_status_t *tsp) 38927c478bd9Sstevel@tonic-gate { 38937c478bd9Sstevel@tonic-gate const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp; 38947c478bd9Sstevel@tonic-gate int fltnum = (intptr_t)sep->se_data; 38957c478bd9Sstevel@tonic-gate 38967c478bd9Sstevel@tonic-gate return (psp->pr_why == PR_FAULTED && psp->pr_what == fltnum); 38977c478bd9Sstevel@tonic-gate } 38987c478bd9Sstevel@tonic-gate 38997c478bd9Sstevel@tonic-gate static const mdb_se_ops_t proc_fault_ops = { 39007c478bd9Sstevel@tonic-gate pt_fault_ctor, /* se_ctor */ 39017c478bd9Sstevel@tonic-gate pt_fault_dtor, /* se_dtor */ 39027c478bd9Sstevel@tonic-gate pt_fault_info, /* se_info */ 39037c478bd9Sstevel@tonic-gate no_se_secmp, /* se_secmp */ 39047c478bd9Sstevel@tonic-gate no_se_vecmp, /* se_vecmp */ 39057c478bd9Sstevel@tonic-gate no_se_arm, /* se_arm */ 39067c478bd9Sstevel@tonic-gate no_se_disarm, /* se_disarm */ 39077c478bd9Sstevel@tonic-gate no_se_cont, /* se_cont */ 39087c478bd9Sstevel@tonic-gate pt_fault_match /* se_match */ 39097c478bd9Sstevel@tonic-gate }; 39107c478bd9Sstevel@tonic-gate 39117c478bd9Sstevel@tonic-gate /* 39127c478bd9Sstevel@tonic-gate * Callback for pt_ignore() dcmd above: for each VID, determine if it 39137c478bd9Sstevel@tonic-gate * corresponds to a vespec that traces the specified signal, and delete it. 39147c478bd9Sstevel@tonic-gate */ 39157c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 39167c478bd9Sstevel@tonic-gate static int 39177c478bd9Sstevel@tonic-gate pt_ignore_sig(mdb_tgt_t *t, void *sig, int vid, void *data) 39187c478bd9Sstevel@tonic-gate { 39197c478bd9Sstevel@tonic-gate mdb_vespec_t *vep = mdb_tgt_vespec_lookup(t, vid); 39207c478bd9Sstevel@tonic-gate 39217c478bd9Sstevel@tonic-gate if (vep->ve_se->se_ops == &proc_signal_ops && vep->ve_args == sig) 39227c478bd9Sstevel@tonic-gate (void) mdb_tgt_vespec_delete(t, vid); 39237c478bd9Sstevel@tonic-gate 39247c478bd9Sstevel@tonic-gate return (0); 39257c478bd9Sstevel@tonic-gate } 39267c478bd9Sstevel@tonic-gate 39277c478bd9Sstevel@tonic-gate static int 39287c478bd9Sstevel@tonic-gate pt_brkpt_ctor(mdb_tgt_t *t, mdb_sespec_t *sep, void *args) 39297c478bd9Sstevel@tonic-gate { 39307c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 39317c478bd9Sstevel@tonic-gate pt_bparg_t *pta = args; 39327c478bd9Sstevel@tonic-gate pt_brkpt_t *ptb; 39337c478bd9Sstevel@tonic-gate GElf_Sym s; 39347c478bd9Sstevel@tonic-gate 39357c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL || Pstate(t->t_pshandle) >= PS_LOST) 39367c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 39377c478bd9Sstevel@tonic-gate 39387c478bd9Sstevel@tonic-gate if (pta->pta_symbol != NULL) { 39397c478bd9Sstevel@tonic-gate if (!pt->p_rtld_finished && 39407c478bd9Sstevel@tonic-gate strchr(pta->pta_symbol, '`') == NULL) 39417c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOSYM)); 39427c478bd9Sstevel@tonic-gate if (mdb_tgt_lookup_by_scope(t, pta->pta_symbol, &s, 39437c478bd9Sstevel@tonic-gate NULL) == -1) { 39447c478bd9Sstevel@tonic-gate if (errno != EMDB_NOOBJ && !(errno == EMDB_NOSYM && 39457c478bd9Sstevel@tonic-gate (!(mdb.m_flags & MDB_FL_BPTNOSYMSTOP) || 39467c478bd9Sstevel@tonic-gate !pt->p_rtld_finished))) { 39477c478bd9Sstevel@tonic-gate warn("breakpoint %s activation failed", 39487c478bd9Sstevel@tonic-gate pta->pta_symbol); 39497c478bd9Sstevel@tonic-gate } 39507c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 39517c478bd9Sstevel@tonic-gate } 39527c478bd9Sstevel@tonic-gate 39537c478bd9Sstevel@tonic-gate pta->pta_addr = (uintptr_t)s.st_value; 39547c478bd9Sstevel@tonic-gate } 39557c478bd9Sstevel@tonic-gate 39567c478bd9Sstevel@tonic-gate #ifdef __sparc 39577c478bd9Sstevel@tonic-gate if (pta->pta_addr & 3) 39587c478bd9Sstevel@tonic-gate return (set_errno(EMDB_BPALIGN)); 39597c478bd9Sstevel@tonic-gate #endif 39607c478bd9Sstevel@tonic-gate 39617c478bd9Sstevel@tonic-gate if (Paddr_to_map(t->t_pshandle, pta->pta_addr) == NULL) 39627c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOMAP)); 39637c478bd9Sstevel@tonic-gate 39647c478bd9Sstevel@tonic-gate ptb = mdb_alloc(sizeof (pt_brkpt_t), UM_SLEEP); 39657c478bd9Sstevel@tonic-gate ptb->ptb_addr = pta->pta_addr; 39667c478bd9Sstevel@tonic-gate ptb->ptb_instr = NULL; 39677c478bd9Sstevel@tonic-gate sep->se_data = ptb; 39687c478bd9Sstevel@tonic-gate 39697c478bd9Sstevel@tonic-gate return (0); 39707c478bd9Sstevel@tonic-gate } 39717c478bd9Sstevel@tonic-gate 39727c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 39737c478bd9Sstevel@tonic-gate static void 39747c478bd9Sstevel@tonic-gate pt_brkpt_dtor(mdb_tgt_t *t, mdb_sespec_t *sep) 39757c478bd9Sstevel@tonic-gate { 39767c478bd9Sstevel@tonic-gate mdb_free(sep->se_data, sizeof (pt_brkpt_t)); 39777c478bd9Sstevel@tonic-gate } 39787c478bd9Sstevel@tonic-gate 39797c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 39807c478bd9Sstevel@tonic-gate static char * 39817c478bd9Sstevel@tonic-gate pt_brkpt_info(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_vespec_t *vep, 39827c478bd9Sstevel@tonic-gate mdb_tgt_spec_desc_t *sp, char *buf, size_t nbytes) 39837c478bd9Sstevel@tonic-gate { 39847c478bd9Sstevel@tonic-gate uintptr_t addr = NULL; 39857c478bd9Sstevel@tonic-gate 39867c478bd9Sstevel@tonic-gate if (vep != NULL) { 39877c478bd9Sstevel@tonic-gate pt_bparg_t *pta = vep->ve_args; 39887c478bd9Sstevel@tonic-gate 39897c478bd9Sstevel@tonic-gate if (pta->pta_symbol != NULL) { 39907c478bd9Sstevel@tonic-gate (void) mdb_iob_snprintf(buf, nbytes, "stop at %s", 39917c478bd9Sstevel@tonic-gate pta->pta_symbol); 39927c478bd9Sstevel@tonic-gate } else { 39937c478bd9Sstevel@tonic-gate (void) mdb_iob_snprintf(buf, nbytes, "stop at %a", 39947c478bd9Sstevel@tonic-gate pta->pta_addr); 39957c478bd9Sstevel@tonic-gate addr = pta->pta_addr; 39967c478bd9Sstevel@tonic-gate } 39977c478bd9Sstevel@tonic-gate 39987c478bd9Sstevel@tonic-gate } else { 39997c478bd9Sstevel@tonic-gate addr = ((pt_brkpt_t *)sep->se_data)->ptb_addr; 40007c478bd9Sstevel@tonic-gate (void) mdb_iob_snprintf(buf, nbytes, "stop at %a", addr); 40017c478bd9Sstevel@tonic-gate } 40027c478bd9Sstevel@tonic-gate 40037c478bd9Sstevel@tonic-gate sp->spec_base = addr; 40047c478bd9Sstevel@tonic-gate sp->spec_size = sizeof (instr_t); 40057c478bd9Sstevel@tonic-gate 40067c478bd9Sstevel@tonic-gate return (buf); 40077c478bd9Sstevel@tonic-gate } 40087c478bd9Sstevel@tonic-gate 40097c478bd9Sstevel@tonic-gate static int 40107c478bd9Sstevel@tonic-gate pt_brkpt_secmp(mdb_tgt_t *t, mdb_sespec_t *sep, void *args) 40117c478bd9Sstevel@tonic-gate { 40127c478bd9Sstevel@tonic-gate pt_brkpt_t *ptb = sep->se_data; 40137c478bd9Sstevel@tonic-gate pt_bparg_t *pta = args; 40147c478bd9Sstevel@tonic-gate GElf_Sym sym; 40157c478bd9Sstevel@tonic-gate 40167c478bd9Sstevel@tonic-gate if (pta->pta_symbol != NULL) { 40177c478bd9Sstevel@tonic-gate return (mdb_tgt_lookup_by_scope(t, pta->pta_symbol, 40187c478bd9Sstevel@tonic-gate &sym, NULL) == 0 && sym.st_value == ptb->ptb_addr); 40197c478bd9Sstevel@tonic-gate } 40207c478bd9Sstevel@tonic-gate 40217c478bd9Sstevel@tonic-gate return (pta->pta_addr == ptb->ptb_addr); 40227c478bd9Sstevel@tonic-gate } 40237c478bd9Sstevel@tonic-gate 40247c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 40257c478bd9Sstevel@tonic-gate static int 40267c478bd9Sstevel@tonic-gate pt_brkpt_vecmp(mdb_tgt_t *t, mdb_vespec_t *vep, void *args) 40277c478bd9Sstevel@tonic-gate { 40287c478bd9Sstevel@tonic-gate pt_bparg_t *pta1 = vep->ve_args; 40297c478bd9Sstevel@tonic-gate pt_bparg_t *pta2 = args; 40307c478bd9Sstevel@tonic-gate 40317c478bd9Sstevel@tonic-gate if (pta1->pta_symbol != NULL && pta2->pta_symbol != NULL) 40327c478bd9Sstevel@tonic-gate return (strcmp(pta1->pta_symbol, pta2->pta_symbol) == 0); 40337c478bd9Sstevel@tonic-gate 40347c478bd9Sstevel@tonic-gate if (pta1->pta_symbol == NULL && pta2->pta_symbol == NULL) 40357c478bd9Sstevel@tonic-gate return (pta1->pta_addr == pta2->pta_addr); 40367c478bd9Sstevel@tonic-gate 40377c478bd9Sstevel@tonic-gate return (0); /* fail if one is symbolic, other is an explicit address */ 40387c478bd9Sstevel@tonic-gate } 40397c478bd9Sstevel@tonic-gate 40407c478bd9Sstevel@tonic-gate static int 40417c478bd9Sstevel@tonic-gate pt_brkpt_arm(mdb_tgt_t *t, mdb_sespec_t *sep) 40427c478bd9Sstevel@tonic-gate { 40437c478bd9Sstevel@tonic-gate pt_brkpt_t *ptb = sep->se_data; 40447c478bd9Sstevel@tonic-gate return (Psetbkpt(t->t_pshandle, ptb->ptb_addr, &ptb->ptb_instr)); 40457c478bd9Sstevel@tonic-gate } 40467c478bd9Sstevel@tonic-gate 40477c478bd9Sstevel@tonic-gate /* 40487c478bd9Sstevel@tonic-gate * In order to disarm a breakpoint, we replace the trap instruction at ptb_addr 40497c478bd9Sstevel@tonic-gate * with the saved instruction. However, if we have stopped after a successful 40507c478bd9Sstevel@tonic-gate * exec(2), we do not want to restore ptb_instr because the address space has 40517c478bd9Sstevel@tonic-gate * now been replaced with the text of a different executable, and so restoring 40527c478bd9Sstevel@tonic-gate * the saved instruction would be incorrect. The exec itself has effectively 40537c478bd9Sstevel@tonic-gate * removed all breakpoint trap instructions for us, so we can just return. 40547c478bd9Sstevel@tonic-gate */ 40557c478bd9Sstevel@tonic-gate static int 40567c478bd9Sstevel@tonic-gate pt_brkpt_disarm(mdb_tgt_t *t, mdb_sespec_t *sep) 40577c478bd9Sstevel@tonic-gate { 40587c478bd9Sstevel@tonic-gate const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp; 40597c478bd9Sstevel@tonic-gate pt_brkpt_t *ptb = sep->se_data; 40607c478bd9Sstevel@tonic-gate 40618fd04b83SRoger A. Faulkner if (psp->pr_why == PR_SYSEXIT && psp->pr_errno == 0 && 40628fd04b83SRoger A. Faulkner psp->pr_what == SYS_execve) 40637c478bd9Sstevel@tonic-gate return (0); /* do not restore saved instruction */ 40647c478bd9Sstevel@tonic-gate 40657c478bd9Sstevel@tonic-gate return (Pdelbkpt(t->t_pshandle, ptb->ptb_addr, ptb->ptb_instr)); 40667c478bd9Sstevel@tonic-gate } 40677c478bd9Sstevel@tonic-gate 40687c478bd9Sstevel@tonic-gate /* 40697c478bd9Sstevel@tonic-gate * Determine whether the specified sespec is an armed watchpoint that overlaps 40707c478bd9Sstevel@tonic-gate * with the given breakpoint and has the given flags set. We use this to find 40717c478bd9Sstevel@tonic-gate * conflicts with breakpoints, below. 40727c478bd9Sstevel@tonic-gate */ 40737c478bd9Sstevel@tonic-gate static int 40747c478bd9Sstevel@tonic-gate pt_wp_overlap(mdb_sespec_t *sep, pt_brkpt_t *ptb, int flags) 40757c478bd9Sstevel@tonic-gate { 40767c478bd9Sstevel@tonic-gate const prwatch_t *wp = sep->se_data; 40777c478bd9Sstevel@tonic-gate 40787c478bd9Sstevel@tonic-gate return (sep->se_state == MDB_TGT_SPEC_ARMED && 40797c478bd9Sstevel@tonic-gate sep->se_ops == &proc_wapt_ops && (wp->pr_wflags & flags) && 40807c478bd9Sstevel@tonic-gate ptb->ptb_addr - wp->pr_vaddr < wp->pr_size); 40817c478bd9Sstevel@tonic-gate } 40827c478bd9Sstevel@tonic-gate 40837c478bd9Sstevel@tonic-gate /* 40847c478bd9Sstevel@tonic-gate * We step over breakpoints using Pxecbkpt() in libproc. If a conflicting 40857c478bd9Sstevel@tonic-gate * watchpoint is present, we must temporarily remove it before stepping over 40867c478bd9Sstevel@tonic-gate * the breakpoint so we do not immediately re-trigger the watchpoint. We know 40877c478bd9Sstevel@tonic-gate * the watchpoint has already triggered on our trap instruction as part of 40887c478bd9Sstevel@tonic-gate * fetching it. Before we return, we must re-install any disabled watchpoints. 40897c478bd9Sstevel@tonic-gate */ 40907c478bd9Sstevel@tonic-gate static int 40917c478bd9Sstevel@tonic-gate pt_brkpt_cont(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_tgt_status_t *tsp) 40927c478bd9Sstevel@tonic-gate { 40937c478bd9Sstevel@tonic-gate pt_brkpt_t *ptb = sep->se_data; 40947c478bd9Sstevel@tonic-gate int status = -1; 40957c478bd9Sstevel@tonic-gate int error; 40967c478bd9Sstevel@tonic-gate const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp; 40977c478bd9Sstevel@tonic-gate 40987c478bd9Sstevel@tonic-gate /* 40997c478bd9Sstevel@tonic-gate * If the PC no longer matches our original address, then the user has 41007c478bd9Sstevel@tonic-gate * changed it while we have been stopped. In this case, it no longer 41017c478bd9Sstevel@tonic-gate * makes any sense to continue over this breakpoint. We return as if we 41027c478bd9Sstevel@tonic-gate * continued normally. 41037c478bd9Sstevel@tonic-gate */ 41047c478bd9Sstevel@tonic-gate if ((uintptr_t)psp->pr_info.si_addr != psp->pr_reg[R_PC]) 41057c478bd9Sstevel@tonic-gate return (pt_status(t, tsp)); 41067c478bd9Sstevel@tonic-gate 41077c478bd9Sstevel@tonic-gate for (sep = mdb_list_next(&t->t_active); sep; sep = mdb_list_next(sep)) { 41087c478bd9Sstevel@tonic-gate if (pt_wp_overlap(sep, ptb, WA_EXEC)) 41097c478bd9Sstevel@tonic-gate (void) Pdelwapt(t->t_pshandle, sep->se_data); 41107c478bd9Sstevel@tonic-gate } 41117c478bd9Sstevel@tonic-gate 41127c478bd9Sstevel@tonic-gate if (Pxecbkpt(t->t_pshandle, ptb->ptb_instr) == 0 && 41137c478bd9Sstevel@tonic-gate Pdelbkpt(t->t_pshandle, ptb->ptb_addr, ptb->ptb_instr) == 0) 41147c478bd9Sstevel@tonic-gate status = pt_status(t, tsp); 41157c478bd9Sstevel@tonic-gate 41167c478bd9Sstevel@tonic-gate error = errno; /* save errno from Pxecbkpt, Pdelbkpt, or pt_status */ 41177c478bd9Sstevel@tonic-gate 41187c478bd9Sstevel@tonic-gate for (sep = mdb_list_next(&t->t_active); sep; sep = mdb_list_next(sep)) { 41197c478bd9Sstevel@tonic-gate if (pt_wp_overlap(sep, ptb, WA_EXEC) && 41207c478bd9Sstevel@tonic-gate Psetwapt(t->t_pshandle, sep->se_data) == -1) { 41217c478bd9Sstevel@tonic-gate sep->se_state = MDB_TGT_SPEC_ERROR; 41227c478bd9Sstevel@tonic-gate sep->se_errno = errno; 41237c478bd9Sstevel@tonic-gate } 41247c478bd9Sstevel@tonic-gate } 41257c478bd9Sstevel@tonic-gate 41267c478bd9Sstevel@tonic-gate (void) set_errno(error); 41277c478bd9Sstevel@tonic-gate return (status); 41287c478bd9Sstevel@tonic-gate } 41297c478bd9Sstevel@tonic-gate 41307c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 41317c478bd9Sstevel@tonic-gate static int 41327c478bd9Sstevel@tonic-gate pt_brkpt_match(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_tgt_status_t *tsp) 41337c478bd9Sstevel@tonic-gate { 41347c478bd9Sstevel@tonic-gate const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp; 41357c478bd9Sstevel@tonic-gate pt_brkpt_t *ptb = sep->se_data; 41367c478bd9Sstevel@tonic-gate 41377c478bd9Sstevel@tonic-gate return (psp->pr_why == PR_FAULTED && psp->pr_what == FLTBPT && 41387c478bd9Sstevel@tonic-gate psp->pr_reg[R_PC] == ptb->ptb_addr); 41397c478bd9Sstevel@tonic-gate } 41407c478bd9Sstevel@tonic-gate 41417c478bd9Sstevel@tonic-gate static const mdb_se_ops_t proc_brkpt_ops = { 41427c478bd9Sstevel@tonic-gate pt_brkpt_ctor, /* se_ctor */ 41437c478bd9Sstevel@tonic-gate pt_brkpt_dtor, /* se_dtor */ 41447c478bd9Sstevel@tonic-gate pt_brkpt_info, /* se_info */ 41457c478bd9Sstevel@tonic-gate pt_brkpt_secmp, /* se_secmp */ 41467c478bd9Sstevel@tonic-gate pt_brkpt_vecmp, /* se_vecmp */ 41477c478bd9Sstevel@tonic-gate pt_brkpt_arm, /* se_arm */ 41487c478bd9Sstevel@tonic-gate pt_brkpt_disarm, /* se_disarm */ 41497c478bd9Sstevel@tonic-gate pt_brkpt_cont, /* se_cont */ 41507c478bd9Sstevel@tonic-gate pt_brkpt_match /* se_match */ 41517c478bd9Sstevel@tonic-gate }; 41527c478bd9Sstevel@tonic-gate 41537c478bd9Sstevel@tonic-gate static int 41547c478bd9Sstevel@tonic-gate pt_wapt_ctor(mdb_tgt_t *t, mdb_sespec_t *sep, void *args) 41557c478bd9Sstevel@tonic-gate { 41567c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL || Pstate(t->t_pshandle) >= PS_LOST) 41577c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 41587c478bd9Sstevel@tonic-gate 41597c478bd9Sstevel@tonic-gate sep->se_data = mdb_alloc(sizeof (prwatch_t), UM_SLEEP); 41607c478bd9Sstevel@tonic-gate bcopy(args, sep->se_data, sizeof (prwatch_t)); 41617c478bd9Sstevel@tonic-gate return (0); 41627c478bd9Sstevel@tonic-gate } 41637c478bd9Sstevel@tonic-gate 41647c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 41657c478bd9Sstevel@tonic-gate static void 41667c478bd9Sstevel@tonic-gate pt_wapt_dtor(mdb_tgt_t *t, mdb_sespec_t *sep) 41677c478bd9Sstevel@tonic-gate { 41687c478bd9Sstevel@tonic-gate mdb_free(sep->se_data, sizeof (prwatch_t)); 41697c478bd9Sstevel@tonic-gate } 41707c478bd9Sstevel@tonic-gate 41717c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 41727c478bd9Sstevel@tonic-gate static char * 41737c478bd9Sstevel@tonic-gate pt_wapt_info(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_vespec_t *vep, 41747c478bd9Sstevel@tonic-gate mdb_tgt_spec_desc_t *sp, char *buf, size_t nbytes) 41757c478bd9Sstevel@tonic-gate { 41767c478bd9Sstevel@tonic-gate prwatch_t *wp = vep != NULL ? vep->ve_args : sep->se_data; 41777c478bd9Sstevel@tonic-gate char desc[24]; 41787c478bd9Sstevel@tonic-gate 41797c478bd9Sstevel@tonic-gate ASSERT(wp->pr_wflags != 0); 41807c478bd9Sstevel@tonic-gate desc[0] = '\0'; 41817c478bd9Sstevel@tonic-gate 41827c478bd9Sstevel@tonic-gate switch (wp->pr_wflags) { 41837c478bd9Sstevel@tonic-gate case WA_READ: 41847c478bd9Sstevel@tonic-gate (void) strcat(desc, "/read"); 41857c478bd9Sstevel@tonic-gate break; 41867c478bd9Sstevel@tonic-gate case WA_WRITE: 41877c478bd9Sstevel@tonic-gate (void) strcat(desc, "/write"); 41887c478bd9Sstevel@tonic-gate break; 41897c478bd9Sstevel@tonic-gate case WA_EXEC: 41907c478bd9Sstevel@tonic-gate (void) strcat(desc, "/exec"); 41917c478bd9Sstevel@tonic-gate break; 41927c478bd9Sstevel@tonic-gate default: 41937c478bd9Sstevel@tonic-gate if (wp->pr_wflags & WA_READ) 41947c478bd9Sstevel@tonic-gate (void) strcat(desc, "/r"); 41957c478bd9Sstevel@tonic-gate if (wp->pr_wflags & WA_WRITE) 41967c478bd9Sstevel@tonic-gate (void) strcat(desc, "/w"); 41977c478bd9Sstevel@tonic-gate if (wp->pr_wflags & WA_EXEC) 41987c478bd9Sstevel@tonic-gate (void) strcat(desc, "/x"); 41997c478bd9Sstevel@tonic-gate } 42007c478bd9Sstevel@tonic-gate 42017c478bd9Sstevel@tonic-gate (void) mdb_iob_snprintf(buf, nbytes, "stop on %s of [%la, %la)", 42027c478bd9Sstevel@tonic-gate desc + 1, wp->pr_vaddr, wp->pr_vaddr + wp->pr_size); 42037c478bd9Sstevel@tonic-gate 42047c478bd9Sstevel@tonic-gate sp->spec_base = wp->pr_vaddr; 42057c478bd9Sstevel@tonic-gate sp->spec_size = wp->pr_size; 42067c478bd9Sstevel@tonic-gate 42077c478bd9Sstevel@tonic-gate return (buf); 42087c478bd9Sstevel@tonic-gate } 42097c478bd9Sstevel@tonic-gate 42107c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 42117c478bd9Sstevel@tonic-gate static int 42127c478bd9Sstevel@tonic-gate pt_wapt_secmp(mdb_tgt_t *t, mdb_sespec_t *sep, void *args) 42137c478bd9Sstevel@tonic-gate { 42147c478bd9Sstevel@tonic-gate prwatch_t *wp1 = sep->se_data; 42157c478bd9Sstevel@tonic-gate prwatch_t *wp2 = args; 42167c478bd9Sstevel@tonic-gate 42177c478bd9Sstevel@tonic-gate return (wp1->pr_vaddr == wp2->pr_vaddr && 42187c478bd9Sstevel@tonic-gate wp1->pr_size == wp2->pr_size && wp1->pr_wflags == wp2->pr_wflags); 42197c478bd9Sstevel@tonic-gate } 42207c478bd9Sstevel@tonic-gate 42217c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 42227c478bd9Sstevel@tonic-gate static int 42237c478bd9Sstevel@tonic-gate pt_wapt_vecmp(mdb_tgt_t *t, mdb_vespec_t *vep, void *args) 42247c478bd9Sstevel@tonic-gate { 42257c478bd9Sstevel@tonic-gate prwatch_t *wp1 = vep->ve_args; 42267c478bd9Sstevel@tonic-gate prwatch_t *wp2 = args; 42277c478bd9Sstevel@tonic-gate 42287c478bd9Sstevel@tonic-gate return (wp1->pr_vaddr == wp2->pr_vaddr && 42297c478bd9Sstevel@tonic-gate wp1->pr_size == wp2->pr_size && wp1->pr_wflags == wp2->pr_wflags); 42307c478bd9Sstevel@tonic-gate } 42317c478bd9Sstevel@tonic-gate 42327c478bd9Sstevel@tonic-gate static int 42337c478bd9Sstevel@tonic-gate pt_wapt_arm(mdb_tgt_t *t, mdb_sespec_t *sep) 42347c478bd9Sstevel@tonic-gate { 42357c478bd9Sstevel@tonic-gate return (Psetwapt(t->t_pshandle, sep->se_data)); 42367c478bd9Sstevel@tonic-gate } 42377c478bd9Sstevel@tonic-gate 42387c478bd9Sstevel@tonic-gate static int 42397c478bd9Sstevel@tonic-gate pt_wapt_disarm(mdb_tgt_t *t, mdb_sespec_t *sep) 42407c478bd9Sstevel@tonic-gate { 42417c478bd9Sstevel@tonic-gate return (Pdelwapt(t->t_pshandle, sep->se_data)); 42427c478bd9Sstevel@tonic-gate } 42437c478bd9Sstevel@tonic-gate 42447c478bd9Sstevel@tonic-gate /* 42457c478bd9Sstevel@tonic-gate * Determine whether the specified sespec is an armed breakpoint at the 42467c478bd9Sstevel@tonic-gate * given %pc. We use this to find conflicts with watchpoints below. 42477c478bd9Sstevel@tonic-gate */ 42487c478bd9Sstevel@tonic-gate static int 42497c478bd9Sstevel@tonic-gate pt_bp_overlap(mdb_sespec_t *sep, uintptr_t pc) 42507c478bd9Sstevel@tonic-gate { 42517c478bd9Sstevel@tonic-gate pt_brkpt_t *ptb = sep->se_data; 42527c478bd9Sstevel@tonic-gate 42537c478bd9Sstevel@tonic-gate return (sep->se_state == MDB_TGT_SPEC_ARMED && 42547c478bd9Sstevel@tonic-gate sep->se_ops == &proc_brkpt_ops && ptb->ptb_addr == pc); 42557c478bd9Sstevel@tonic-gate } 42567c478bd9Sstevel@tonic-gate 42577c478bd9Sstevel@tonic-gate /* 42587c478bd9Sstevel@tonic-gate * We step over watchpoints using Pxecwapt() in libproc. If a conflicting 42597c478bd9Sstevel@tonic-gate * breakpoint is present, we must temporarily disarm it before stepping 42607c478bd9Sstevel@tonic-gate * over the watchpoint so we do not immediately re-trigger the breakpoint. 42617c478bd9Sstevel@tonic-gate * This is similar to the case handled in pt_brkpt_cont(), above. 42627c478bd9Sstevel@tonic-gate */ 42637c478bd9Sstevel@tonic-gate static int 42647c478bd9Sstevel@tonic-gate pt_wapt_cont(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_tgt_status_t *tsp) 42657c478bd9Sstevel@tonic-gate { 42667c478bd9Sstevel@tonic-gate const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp; 42677c478bd9Sstevel@tonic-gate mdb_sespec_t *bep = NULL; 42687c478bd9Sstevel@tonic-gate int status = -1; 42697c478bd9Sstevel@tonic-gate int error; 42707c478bd9Sstevel@tonic-gate 42717c478bd9Sstevel@tonic-gate /* 42727c478bd9Sstevel@tonic-gate * If the PC no longer matches our original address, then the user has 42737c478bd9Sstevel@tonic-gate * changed it while we have been stopped. In this case, it no longer 42747c478bd9Sstevel@tonic-gate * makes any sense to continue over this instruction. We return as if 42757c478bd9Sstevel@tonic-gate * we continued normally. 42767c478bd9Sstevel@tonic-gate */ 42777c478bd9Sstevel@tonic-gate if ((uintptr_t)psp->pr_info.si_pc != psp->pr_reg[R_PC]) 42787c478bd9Sstevel@tonic-gate return (pt_status(t, tsp)); 42797c478bd9Sstevel@tonic-gate 42807c478bd9Sstevel@tonic-gate if (psp->pr_info.si_code != TRAP_XWATCH) { 42817c478bd9Sstevel@tonic-gate for (bep = mdb_list_next(&t->t_active); bep != NULL; 42827c478bd9Sstevel@tonic-gate bep = mdb_list_next(bep)) { 42837c478bd9Sstevel@tonic-gate if (pt_bp_overlap(bep, psp->pr_reg[R_PC])) { 42847c478bd9Sstevel@tonic-gate (void) bep->se_ops->se_disarm(t, bep); 42857c478bd9Sstevel@tonic-gate bep->se_state = MDB_TGT_SPEC_ACTIVE; 42867c478bd9Sstevel@tonic-gate break; 42877c478bd9Sstevel@tonic-gate } 42887c478bd9Sstevel@tonic-gate } 42897c478bd9Sstevel@tonic-gate } 42907c478bd9Sstevel@tonic-gate 42917c478bd9Sstevel@tonic-gate if (Pxecwapt(t->t_pshandle, sep->se_data) == 0) 42927c478bd9Sstevel@tonic-gate status = pt_status(t, tsp); 42937c478bd9Sstevel@tonic-gate 42947c478bd9Sstevel@tonic-gate error = errno; /* save errno from Pxecwapt or pt_status */ 42957c478bd9Sstevel@tonic-gate 42967c478bd9Sstevel@tonic-gate if (bep != NULL) 42977c478bd9Sstevel@tonic-gate mdb_tgt_sespec_arm_one(t, bep); 42987c478bd9Sstevel@tonic-gate 42997c478bd9Sstevel@tonic-gate (void) set_errno(error); 43007c478bd9Sstevel@tonic-gate return (status); 43017c478bd9Sstevel@tonic-gate } 43027c478bd9Sstevel@tonic-gate 43037c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 43047c478bd9Sstevel@tonic-gate static int 43057c478bd9Sstevel@tonic-gate pt_wapt_match(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_tgt_status_t *tsp) 43067c478bd9Sstevel@tonic-gate { 43077c478bd9Sstevel@tonic-gate const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp; 43087c478bd9Sstevel@tonic-gate prwatch_t *wp = sep->se_data; 43097c478bd9Sstevel@tonic-gate 43107c478bd9Sstevel@tonic-gate return (psp->pr_why == PR_FAULTED && psp->pr_what == FLTWATCH && 43117c478bd9Sstevel@tonic-gate (uintptr_t)psp->pr_info.si_addr - wp->pr_vaddr < wp->pr_size); 43127c478bd9Sstevel@tonic-gate } 43137c478bd9Sstevel@tonic-gate 43147c478bd9Sstevel@tonic-gate static const mdb_se_ops_t proc_wapt_ops = { 43157c478bd9Sstevel@tonic-gate pt_wapt_ctor, /* se_ctor */ 43167c478bd9Sstevel@tonic-gate pt_wapt_dtor, /* se_dtor */ 43177c478bd9Sstevel@tonic-gate pt_wapt_info, /* se_info */ 43187c478bd9Sstevel@tonic-gate pt_wapt_secmp, /* se_secmp */ 43197c478bd9Sstevel@tonic-gate pt_wapt_vecmp, /* se_vecmp */ 43207c478bd9Sstevel@tonic-gate pt_wapt_arm, /* se_arm */ 43217c478bd9Sstevel@tonic-gate pt_wapt_disarm, /* se_disarm */ 43227c478bd9Sstevel@tonic-gate pt_wapt_cont, /* se_cont */ 43237c478bd9Sstevel@tonic-gate pt_wapt_match /* se_match */ 43247c478bd9Sstevel@tonic-gate }; 43257c478bd9Sstevel@tonic-gate 43267c478bd9Sstevel@tonic-gate static void 43277c478bd9Sstevel@tonic-gate pt_bparg_dtor(mdb_vespec_t *vep) 43287c478bd9Sstevel@tonic-gate { 43297c478bd9Sstevel@tonic-gate pt_bparg_t *pta = vep->ve_args; 43307c478bd9Sstevel@tonic-gate 43317c478bd9Sstevel@tonic-gate if (pta->pta_symbol != NULL) 43327c478bd9Sstevel@tonic-gate strfree(pta->pta_symbol); 43337c478bd9Sstevel@tonic-gate 43347c478bd9Sstevel@tonic-gate mdb_free(pta, sizeof (pt_bparg_t)); 43357c478bd9Sstevel@tonic-gate } 43367c478bd9Sstevel@tonic-gate 43377c478bd9Sstevel@tonic-gate static int 43387c478bd9Sstevel@tonic-gate pt_add_vbrkpt(mdb_tgt_t *t, uintptr_t addr, 43397c478bd9Sstevel@tonic-gate int spec_flags, mdb_tgt_se_f *func, void *data) 43407c478bd9Sstevel@tonic-gate { 43417c478bd9Sstevel@tonic-gate pt_bparg_t *pta = mdb_alloc(sizeof (pt_bparg_t), UM_SLEEP); 43427c478bd9Sstevel@tonic-gate 43437c478bd9Sstevel@tonic-gate pta->pta_symbol = NULL; 43447c478bd9Sstevel@tonic-gate pta->pta_addr = addr; 43457c478bd9Sstevel@tonic-gate 43467c478bd9Sstevel@tonic-gate return (mdb_tgt_vespec_insert(t, &proc_brkpt_ops, spec_flags, 43477c478bd9Sstevel@tonic-gate func, data, pta, pt_bparg_dtor)); 43487c478bd9Sstevel@tonic-gate } 43497c478bd9Sstevel@tonic-gate 43507c478bd9Sstevel@tonic-gate static int 43517c478bd9Sstevel@tonic-gate pt_add_sbrkpt(mdb_tgt_t *t, const char *sym, 43527c478bd9Sstevel@tonic-gate int spec_flags, mdb_tgt_se_f *func, void *data) 43537c478bd9Sstevel@tonic-gate { 43547c478bd9Sstevel@tonic-gate pt_bparg_t *pta; 43557c478bd9Sstevel@tonic-gate 43567c478bd9Sstevel@tonic-gate if (sym[0] == '`') { 43577c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_NOOBJ); 43587c478bd9Sstevel@tonic-gate return (0); 43597c478bd9Sstevel@tonic-gate } 43607c478bd9Sstevel@tonic-gate 43617c478bd9Sstevel@tonic-gate if (sym[strlen(sym) - 1] == '`') { 43627c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_NOSYM); 43637c478bd9Sstevel@tonic-gate return (0); 43647c478bd9Sstevel@tonic-gate } 43657c478bd9Sstevel@tonic-gate 43667c478bd9Sstevel@tonic-gate pta = mdb_alloc(sizeof (pt_bparg_t), UM_SLEEP); 43677c478bd9Sstevel@tonic-gate pta->pta_symbol = strdup(sym); 43687c478bd9Sstevel@tonic-gate pta->pta_addr = NULL; 43697c478bd9Sstevel@tonic-gate 43707c478bd9Sstevel@tonic-gate return (mdb_tgt_vespec_insert(t, &proc_brkpt_ops, spec_flags, 43717c478bd9Sstevel@tonic-gate func, data, pta, pt_bparg_dtor)); 43727c478bd9Sstevel@tonic-gate } 43737c478bd9Sstevel@tonic-gate 43747c478bd9Sstevel@tonic-gate static int 43757c478bd9Sstevel@tonic-gate pt_wparg_overlap(const prwatch_t *wp1, const prwatch_t *wp2) 43767c478bd9Sstevel@tonic-gate { 43777c478bd9Sstevel@tonic-gate if (wp2->pr_vaddr + wp2->pr_size <= wp1->pr_vaddr) 43787c478bd9Sstevel@tonic-gate return (0); /* no range overlap */ 43797c478bd9Sstevel@tonic-gate 43807c478bd9Sstevel@tonic-gate if (wp1->pr_vaddr + wp1->pr_size <= wp2->pr_vaddr) 43817c478bd9Sstevel@tonic-gate return (0); /* no range overlap */ 43827c478bd9Sstevel@tonic-gate 43837c478bd9Sstevel@tonic-gate return (wp1->pr_vaddr != wp2->pr_vaddr || 43847c478bd9Sstevel@tonic-gate wp1->pr_size != wp2->pr_size || wp1->pr_wflags != wp2->pr_wflags); 43857c478bd9Sstevel@tonic-gate } 43867c478bd9Sstevel@tonic-gate 43877c478bd9Sstevel@tonic-gate static void 43887c478bd9Sstevel@tonic-gate pt_wparg_dtor(mdb_vespec_t *vep) 43897c478bd9Sstevel@tonic-gate { 43907c478bd9Sstevel@tonic-gate mdb_free(vep->ve_args, sizeof (prwatch_t)); 43917c478bd9Sstevel@tonic-gate } 43927c478bd9Sstevel@tonic-gate 43937c478bd9Sstevel@tonic-gate static int 43947c478bd9Sstevel@tonic-gate pt_add_vwapt(mdb_tgt_t *t, uintptr_t addr, size_t len, uint_t wflags, 43957c478bd9Sstevel@tonic-gate int spec_flags, mdb_tgt_se_f *func, void *data) 43967c478bd9Sstevel@tonic-gate { 43977c478bd9Sstevel@tonic-gate prwatch_t *wp = mdb_alloc(sizeof (prwatch_t), UM_SLEEP); 43987c478bd9Sstevel@tonic-gate mdb_sespec_t *sep; 43997c478bd9Sstevel@tonic-gate 44007c478bd9Sstevel@tonic-gate wp->pr_vaddr = addr; 44017c478bd9Sstevel@tonic-gate wp->pr_size = len; 44027c478bd9Sstevel@tonic-gate wp->pr_wflags = 0; 44037c478bd9Sstevel@tonic-gate 44047c478bd9Sstevel@tonic-gate if (wflags & MDB_TGT_WA_R) 44057c478bd9Sstevel@tonic-gate wp->pr_wflags |= WA_READ; 44067c478bd9Sstevel@tonic-gate if (wflags & MDB_TGT_WA_W) 44077c478bd9Sstevel@tonic-gate wp->pr_wflags |= WA_WRITE; 44087c478bd9Sstevel@tonic-gate if (wflags & MDB_TGT_WA_X) 44097c478bd9Sstevel@tonic-gate wp->pr_wflags |= WA_EXEC; 44107c478bd9Sstevel@tonic-gate 44117c478bd9Sstevel@tonic-gate for (sep = mdb_list_next(&t->t_active); sep; sep = mdb_list_next(sep)) { 44127c478bd9Sstevel@tonic-gate if (sep->se_ops == &proc_wapt_ops && 44137c478bd9Sstevel@tonic-gate mdb_list_next(&sep->se_velist) != NULL && 44147c478bd9Sstevel@tonic-gate pt_wparg_overlap(wp, sep->se_data)) 44157c478bd9Sstevel@tonic-gate goto dup; 44167c478bd9Sstevel@tonic-gate } 44177c478bd9Sstevel@tonic-gate 44187c478bd9Sstevel@tonic-gate for (sep = mdb_list_next(&t->t_idle); sep; sep = mdb_list_next(sep)) { 44197c478bd9Sstevel@tonic-gate if (sep->se_ops == &proc_wapt_ops && pt_wparg_overlap(wp, 44207c478bd9Sstevel@tonic-gate ((mdb_vespec_t *)mdb_list_next(&sep->se_velist))->ve_args)) 44217c478bd9Sstevel@tonic-gate goto dup; 44227c478bd9Sstevel@tonic-gate } 44237c478bd9Sstevel@tonic-gate 44247c478bd9Sstevel@tonic-gate return (mdb_tgt_vespec_insert(t, &proc_wapt_ops, spec_flags, 44257c478bd9Sstevel@tonic-gate func, data, wp, pt_wparg_dtor)); 44267c478bd9Sstevel@tonic-gate 44277c478bd9Sstevel@tonic-gate dup: 44287c478bd9Sstevel@tonic-gate mdb_free(wp, sizeof (prwatch_t)); 44297c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_WPDUP); 44307c478bd9Sstevel@tonic-gate return (0); 44317c478bd9Sstevel@tonic-gate } 44327c478bd9Sstevel@tonic-gate 44337c478bd9Sstevel@tonic-gate static int 44347c478bd9Sstevel@tonic-gate pt_add_sysenter(mdb_tgt_t *t, int sysnum, 44357c478bd9Sstevel@tonic-gate int spec_flags, mdb_tgt_se_f *func, void *data) 44367c478bd9Sstevel@tonic-gate { 44377c478bd9Sstevel@tonic-gate if (sysnum <= 0 || sysnum > PRMAXSYS) { 44387c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_BADSYSNUM); 44397c478bd9Sstevel@tonic-gate return (0); 44407c478bd9Sstevel@tonic-gate } 44417c478bd9Sstevel@tonic-gate 44427c478bd9Sstevel@tonic-gate return (mdb_tgt_vespec_insert(t, &proc_sysenter_ops, spec_flags, 44437c478bd9Sstevel@tonic-gate func, data, (void *)(uintptr_t)sysnum, no_ve_dtor)); 44447c478bd9Sstevel@tonic-gate } 44457c478bd9Sstevel@tonic-gate 44467c478bd9Sstevel@tonic-gate static int 44477c478bd9Sstevel@tonic-gate pt_add_sysexit(mdb_tgt_t *t, int sysnum, 44487c478bd9Sstevel@tonic-gate int spec_flags, mdb_tgt_se_f *func, void *data) 44497c478bd9Sstevel@tonic-gate { 44507c478bd9Sstevel@tonic-gate if (sysnum <= 0 || sysnum > PRMAXSYS) { 44517c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_BADSYSNUM); 44527c478bd9Sstevel@tonic-gate return (0); 44537c478bd9Sstevel@tonic-gate } 44547c478bd9Sstevel@tonic-gate 44557c478bd9Sstevel@tonic-gate return (mdb_tgt_vespec_insert(t, &proc_sysexit_ops, spec_flags, 44567c478bd9Sstevel@tonic-gate func, data, (void *)(uintptr_t)sysnum, no_ve_dtor)); 44577c478bd9Sstevel@tonic-gate } 44587c478bd9Sstevel@tonic-gate 44597c478bd9Sstevel@tonic-gate static int 44607c478bd9Sstevel@tonic-gate pt_add_signal(mdb_tgt_t *t, int signum, 44617c478bd9Sstevel@tonic-gate int spec_flags, mdb_tgt_se_f *func, void *data) 44627c478bd9Sstevel@tonic-gate { 44637c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 44647c478bd9Sstevel@tonic-gate 44657c478bd9Sstevel@tonic-gate if (signum <= 0 || signum > pt->p_maxsig) { 44667c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_BADSIGNUM); 44677c478bd9Sstevel@tonic-gate return (0); 44687c478bd9Sstevel@tonic-gate } 44697c478bd9Sstevel@tonic-gate 44707c478bd9Sstevel@tonic-gate return (mdb_tgt_vespec_insert(t, &proc_signal_ops, spec_flags, 44717c478bd9Sstevel@tonic-gate func, data, (void *)(uintptr_t)signum, no_ve_dtor)); 44727c478bd9Sstevel@tonic-gate } 44737c478bd9Sstevel@tonic-gate 44747c478bd9Sstevel@tonic-gate static int 44757c478bd9Sstevel@tonic-gate pt_add_fault(mdb_tgt_t *t, int fltnum, 44767c478bd9Sstevel@tonic-gate int spec_flags, mdb_tgt_se_f *func, void *data) 44777c478bd9Sstevel@tonic-gate { 44787c478bd9Sstevel@tonic-gate if (fltnum <= 0 || fltnum > PRMAXFAULT) { 44797c478bd9Sstevel@tonic-gate (void) set_errno(EMDB_BADFLTNUM); 44807c478bd9Sstevel@tonic-gate return (0); 44817c478bd9Sstevel@tonic-gate } 44827c478bd9Sstevel@tonic-gate 44837c478bd9Sstevel@tonic-gate return (mdb_tgt_vespec_insert(t, &proc_fault_ops, spec_flags, 44847c478bd9Sstevel@tonic-gate func, data, (void *)(uintptr_t)fltnum, no_ve_dtor)); 44857c478bd9Sstevel@tonic-gate } 44867c478bd9Sstevel@tonic-gate 44877c478bd9Sstevel@tonic-gate static int 44887c478bd9Sstevel@tonic-gate pt_getareg(mdb_tgt_t *t, mdb_tgt_tid_t tid, 44897c478bd9Sstevel@tonic-gate const char *rname, mdb_tgt_reg_t *rp) 44907c478bd9Sstevel@tonic-gate { 44917c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 44927c478bd9Sstevel@tonic-gate prgregset_t grs; 44937c478bd9Sstevel@tonic-gate mdb_var_t *v; 44947c478bd9Sstevel@tonic-gate 44957c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) 44967c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 44977c478bd9Sstevel@tonic-gate 44987c478bd9Sstevel@tonic-gate if ((v = mdb_nv_lookup(&pt->p_regs, rname)) != NULL) { 44997c478bd9Sstevel@tonic-gate uintmax_t rd_nval = mdb_nv_get_value(v); 45007c478bd9Sstevel@tonic-gate ushort_t rd_num = MDB_TGT_R_NUM(rd_nval); 45017c478bd9Sstevel@tonic-gate ushort_t rd_flags = MDB_TGT_R_FLAGS(rd_nval); 45027c478bd9Sstevel@tonic-gate 45037c478bd9Sstevel@tonic-gate if (!MDB_TGT_R_IS_FP(rd_flags)) { 45047c478bd9Sstevel@tonic-gate mdb_tgt_reg_t r = 0; 45057c478bd9Sstevel@tonic-gate 45067c478bd9Sstevel@tonic-gate #if defined(__sparc) && defined(_ILP32) 45077c478bd9Sstevel@tonic-gate /* 45087c478bd9Sstevel@tonic-gate * If we are debugging on 32-bit SPARC, the globals and 45097c478bd9Sstevel@tonic-gate * outs can have 32 upper bits hiding in the xregs. 45107c478bd9Sstevel@tonic-gate */ 451189518a1cSdmick /* gcc doesn't like >= R_G0 because R_G0 == 0 */ 451289518a1cSdmick int is_g = (rd_num == R_G0 || 451389518a1cSdmick rd_num >= R_G1 && rd_num <= R_G7); 45147c478bd9Sstevel@tonic-gate int is_o = (rd_num >= R_O0 && rd_num <= R_O7); 45157c478bd9Sstevel@tonic-gate prxregset_t xrs; 45167c478bd9Sstevel@tonic-gate 45177c478bd9Sstevel@tonic-gate if (is_g && PTL_GETXREGS(t, tid, &xrs) == 0 && 45187c478bd9Sstevel@tonic-gate xrs.pr_type == XR_TYPE_V8P) { 45197c478bd9Sstevel@tonic-gate r |= (uint64_t)xrs.pr_un.pr_v8p.pr_xg[ 45207c478bd9Sstevel@tonic-gate rd_num - R_G0 + XR_G0] << 32; 45217c478bd9Sstevel@tonic-gate } 45227c478bd9Sstevel@tonic-gate 45237c478bd9Sstevel@tonic-gate if (is_o && PTL_GETXREGS(t, tid, &xrs) == 0 && 45247c478bd9Sstevel@tonic-gate xrs.pr_type == XR_TYPE_V8P) { 45257c478bd9Sstevel@tonic-gate r |= (uint64_t)xrs.pr_un.pr_v8p.pr_xo[ 45267c478bd9Sstevel@tonic-gate rd_num - R_O0 + XR_O0] << 32; 45277c478bd9Sstevel@tonic-gate } 45287c478bd9Sstevel@tonic-gate #endif /* __sparc && _ILP32 */ 45297c478bd9Sstevel@tonic-gate 45307c478bd9Sstevel@tonic-gate /* 45317c478bd9Sstevel@tonic-gate * Avoid sign-extension by casting: recall that procfs 45327c478bd9Sstevel@tonic-gate * defines prgreg_t as a long or int and our native 45337c478bd9Sstevel@tonic-gate * register handling uses uint64_t's. 45347c478bd9Sstevel@tonic-gate */ 45357c478bd9Sstevel@tonic-gate if (PTL_GETREGS(t, tid, grs) == 0) { 45367c478bd9Sstevel@tonic-gate *rp = r | (ulong_t)grs[rd_num]; 45370a47c91cSRobert Mustacchi if (rd_flags & MDB_TGT_R_32) 45380a47c91cSRobert Mustacchi *rp &= 0xffffffffULL; 45390a47c91cSRobert Mustacchi else if (rd_flags & MDB_TGT_R_16) 45400a47c91cSRobert Mustacchi *rp &= 0xffffULL; 45410a47c91cSRobert Mustacchi else if (rd_flags & MDB_TGT_R_8H) 45420a47c91cSRobert Mustacchi *rp = (*rp & 0xff00ULL) >> 8; 45430a47c91cSRobert Mustacchi else if (rd_flags & MDB_TGT_R_8L) 45440a47c91cSRobert Mustacchi *rp &= 0xffULL; 45457c478bd9Sstevel@tonic-gate return (0); 45467c478bd9Sstevel@tonic-gate } 45477c478bd9Sstevel@tonic-gate return (-1); 45487c478bd9Sstevel@tonic-gate } else 45497c478bd9Sstevel@tonic-gate return (pt_getfpreg(t, tid, rd_num, rd_flags, rp)); 45507c478bd9Sstevel@tonic-gate } 45517c478bd9Sstevel@tonic-gate 45527c478bd9Sstevel@tonic-gate return (set_errno(EMDB_BADREG)); 45537c478bd9Sstevel@tonic-gate } 45547c478bd9Sstevel@tonic-gate 45557c478bd9Sstevel@tonic-gate static int 45567c478bd9Sstevel@tonic-gate pt_putareg(mdb_tgt_t *t, mdb_tgt_tid_t tid, const char *rname, mdb_tgt_reg_t r) 45577c478bd9Sstevel@tonic-gate { 45587c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 45597c478bd9Sstevel@tonic-gate prgregset_t grs; 45607c478bd9Sstevel@tonic-gate mdb_var_t *v; 45617c478bd9Sstevel@tonic-gate 45627c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) 45637c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 45647c478bd9Sstevel@tonic-gate 45657c478bd9Sstevel@tonic-gate if ((v = mdb_nv_lookup(&pt->p_regs, rname)) != NULL) { 45667c478bd9Sstevel@tonic-gate uintmax_t rd_nval = mdb_nv_get_value(v); 45677c478bd9Sstevel@tonic-gate ushort_t rd_num = MDB_TGT_R_NUM(rd_nval); 45687c478bd9Sstevel@tonic-gate ushort_t rd_flags = MDB_TGT_R_FLAGS(rd_nval); 45697c478bd9Sstevel@tonic-gate 45707c478bd9Sstevel@tonic-gate if (!MDB_TGT_R_IS_FP(rd_flags)) { 45710a47c91cSRobert Mustacchi 45720a47c91cSRobert Mustacchi if (rd_flags & MDB_TGT_R_32) 45730a47c91cSRobert Mustacchi r &= 0xffffffffULL; 45740a47c91cSRobert Mustacchi else if (rd_flags & MDB_TGT_R_16) 45750a47c91cSRobert Mustacchi r &= 0xffffULL; 45760a47c91cSRobert Mustacchi else if (rd_flags & MDB_TGT_R_8H) 45770a47c91cSRobert Mustacchi r = (r & 0xffULL) << 8; 45780a47c91cSRobert Mustacchi else if (rd_flags & MDB_TGT_R_8L) 45790a47c91cSRobert Mustacchi r &= 0xffULL; 45800a47c91cSRobert Mustacchi 45817c478bd9Sstevel@tonic-gate #if defined(__sparc) && defined(_ILP32) 45827c478bd9Sstevel@tonic-gate /* 45837c478bd9Sstevel@tonic-gate * If we are debugging on 32-bit SPARC, the globals and 45847c478bd9Sstevel@tonic-gate * outs can have 32 upper bits stored in the xregs. 45857c478bd9Sstevel@tonic-gate */ 458689518a1cSdmick int is_g = (rd_num == R_G0 || 458789518a1cSdmick rd_num >= R_G1 && rd_num <= R_G7); 45887c478bd9Sstevel@tonic-gate int is_o = (rd_num >= R_O0 && rd_num <= R_O7); 45897c478bd9Sstevel@tonic-gate prxregset_t xrs; 45907c478bd9Sstevel@tonic-gate 45917c478bd9Sstevel@tonic-gate if ((is_g || is_o) && PTL_GETXREGS(t, tid, &xrs) == 0 && 45927c478bd9Sstevel@tonic-gate xrs.pr_type == XR_TYPE_V8P) { 45937c478bd9Sstevel@tonic-gate if (is_g) { 45947c478bd9Sstevel@tonic-gate xrs.pr_un.pr_v8p.pr_xg[rd_num - 45957c478bd9Sstevel@tonic-gate R_G0 + XR_G0] = (uint32_t)(r >> 32); 45967c478bd9Sstevel@tonic-gate } else if (is_o) { 45977c478bd9Sstevel@tonic-gate xrs.pr_un.pr_v8p.pr_xo[rd_num - 45987c478bd9Sstevel@tonic-gate R_O0 + XR_O0] = (uint32_t)(r >> 32); 45997c478bd9Sstevel@tonic-gate } 46007c478bd9Sstevel@tonic-gate 46017c478bd9Sstevel@tonic-gate if (PTL_SETXREGS(t, tid, &xrs) == -1) 46027c478bd9Sstevel@tonic-gate return (-1); 46037c478bd9Sstevel@tonic-gate } 46047c478bd9Sstevel@tonic-gate #endif /* __sparc && _ILP32 */ 46057c478bd9Sstevel@tonic-gate 46067c478bd9Sstevel@tonic-gate if (PTL_GETREGS(t, tid, grs) == 0) { 46077c478bd9Sstevel@tonic-gate grs[rd_num] = (prgreg_t)r; 46087c478bd9Sstevel@tonic-gate return (PTL_SETREGS(t, tid, grs)); 46097c478bd9Sstevel@tonic-gate } 46107c478bd9Sstevel@tonic-gate return (-1); 46117c478bd9Sstevel@tonic-gate } else 46127c478bd9Sstevel@tonic-gate return (pt_putfpreg(t, tid, rd_num, rd_flags, r)); 46137c478bd9Sstevel@tonic-gate } 46147c478bd9Sstevel@tonic-gate 46157c478bd9Sstevel@tonic-gate return (set_errno(EMDB_BADREG)); 46167c478bd9Sstevel@tonic-gate } 46177c478bd9Sstevel@tonic-gate 46187c478bd9Sstevel@tonic-gate static int 46197c478bd9Sstevel@tonic-gate pt_stack_call(pt_stkarg_t *psp, const prgregset_t grs, uint_t argc, long *argv) 46207c478bd9Sstevel@tonic-gate { 46217c478bd9Sstevel@tonic-gate psp->pstk_gotpc |= (grs[R_PC] != 0); 46227c478bd9Sstevel@tonic-gate 46237c478bd9Sstevel@tonic-gate if (!psp->pstk_gotpc) 46247c478bd9Sstevel@tonic-gate return (0); /* skip initial zeroed frames */ 46257c478bd9Sstevel@tonic-gate 46267c478bd9Sstevel@tonic-gate return (psp->pstk_func(psp->pstk_private, grs[R_PC], 46277c478bd9Sstevel@tonic-gate argc, argv, (const struct mdb_tgt_gregset *)grs)); 46287c478bd9Sstevel@tonic-gate } 46297c478bd9Sstevel@tonic-gate 46307c478bd9Sstevel@tonic-gate static int 46317c478bd9Sstevel@tonic-gate pt_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp, 46327c478bd9Sstevel@tonic-gate mdb_tgt_stack_f *func, void *arg) 46337c478bd9Sstevel@tonic-gate { 46347c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL) { 46357c478bd9Sstevel@tonic-gate pt_stkarg_t pstk; 46367c478bd9Sstevel@tonic-gate 46377c478bd9Sstevel@tonic-gate pstk.pstk_func = func; 46387c478bd9Sstevel@tonic-gate pstk.pstk_private = arg; 46397c478bd9Sstevel@tonic-gate pstk.pstk_gotpc = FALSE; 46407c478bd9Sstevel@tonic-gate 46417c478bd9Sstevel@tonic-gate (void) Pstack_iter(t->t_pshandle, gsp->gregs, 46427c478bd9Sstevel@tonic-gate (proc_stack_f *)pt_stack_call, &pstk); 46437c478bd9Sstevel@tonic-gate 46447c478bd9Sstevel@tonic-gate return (0); 46457c478bd9Sstevel@tonic-gate } 46467c478bd9Sstevel@tonic-gate 46477c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 46487c478bd9Sstevel@tonic-gate } 46497c478bd9Sstevel@tonic-gate 46509acbbeafSnn35248 static int 46519acbbeafSnn35248 pt_auxv(mdb_tgt_t *t, const auxv_t **auxvp) 46529acbbeafSnn35248 { 46539acbbeafSnn35248 if (t->t_pshandle != NULL) { 46549acbbeafSnn35248 *auxvp = Pgetauxvec(t->t_pshandle); 46559acbbeafSnn35248 return (0); 46569acbbeafSnn35248 } 46579acbbeafSnn35248 46589acbbeafSnn35248 return (set_errno(EMDB_NOPROC)); 46599acbbeafSnn35248 } 46609acbbeafSnn35248 46619acbbeafSnn35248 46627c478bd9Sstevel@tonic-gate static const mdb_tgt_ops_t proc_ops = { 46637c478bd9Sstevel@tonic-gate pt_setflags, /* t_setflags */ 46647c478bd9Sstevel@tonic-gate (int (*)()) mdb_tgt_notsup, /* t_setcontext */ 46657c478bd9Sstevel@tonic-gate pt_activate, /* t_activate */ 46667c478bd9Sstevel@tonic-gate pt_deactivate, /* t_deactivate */ 46677c478bd9Sstevel@tonic-gate pt_periodic, /* t_periodic */ 46687c478bd9Sstevel@tonic-gate pt_destroy, /* t_destroy */ 46697c478bd9Sstevel@tonic-gate pt_name, /* t_name */ 46707c478bd9Sstevel@tonic-gate (const char *(*)()) mdb_conf_isa, /* t_isa */ 46717c478bd9Sstevel@tonic-gate pt_platform, /* t_platform */ 46727c478bd9Sstevel@tonic-gate pt_uname, /* t_uname */ 46737c478bd9Sstevel@tonic-gate pt_dmodel, /* t_dmodel */ 46747c478bd9Sstevel@tonic-gate (ssize_t (*)()) mdb_tgt_notsup, /* t_aread */ 46757c478bd9Sstevel@tonic-gate (ssize_t (*)()) mdb_tgt_notsup, /* t_awrite */ 46767c478bd9Sstevel@tonic-gate pt_vread, /* t_vread */ 46777c478bd9Sstevel@tonic-gate pt_vwrite, /* t_vwrite */ 46787c478bd9Sstevel@tonic-gate (ssize_t (*)()) mdb_tgt_notsup, /* t_pread */ 46797c478bd9Sstevel@tonic-gate (ssize_t (*)()) mdb_tgt_notsup, /* t_pwrite */ 46807c478bd9Sstevel@tonic-gate pt_fread, /* t_fread */ 46817c478bd9Sstevel@tonic-gate pt_fwrite, /* t_fwrite */ 46827c478bd9Sstevel@tonic-gate (ssize_t (*)()) mdb_tgt_notsup, /* t_ioread */ 46837c478bd9Sstevel@tonic-gate (ssize_t (*)()) mdb_tgt_notsup, /* t_iowrite */ 46847c478bd9Sstevel@tonic-gate (int (*)()) mdb_tgt_notsup, /* t_vtop */ 46857c478bd9Sstevel@tonic-gate pt_lookup_by_name, /* t_lookup_by_name */ 46867c478bd9Sstevel@tonic-gate pt_lookup_by_addr, /* t_lookup_by_addr */ 46877c478bd9Sstevel@tonic-gate pt_symbol_iter, /* t_symbol_iter */ 46887c478bd9Sstevel@tonic-gate pt_mapping_iter, /* t_mapping_iter */ 46897c478bd9Sstevel@tonic-gate pt_object_iter, /* t_object_iter */ 46907c478bd9Sstevel@tonic-gate pt_addr_to_map, /* t_addr_to_map */ 46917c478bd9Sstevel@tonic-gate pt_name_to_map, /* t_name_to_map */ 46927c478bd9Sstevel@tonic-gate pt_addr_to_ctf, /* t_addr_to_ctf */ 46937c478bd9Sstevel@tonic-gate pt_name_to_ctf, /* t_name_to_ctf */ 46947c478bd9Sstevel@tonic-gate pt_status, /* t_status */ 46957c478bd9Sstevel@tonic-gate pt_run, /* t_run */ 46967c478bd9Sstevel@tonic-gate pt_step, /* t_step */ 46977c478bd9Sstevel@tonic-gate pt_step_out, /* t_step_out */ 46987c478bd9Sstevel@tonic-gate (int (*)()) mdb_tgt_notsup, /* t_step_branch */ 46997c478bd9Sstevel@tonic-gate pt_next, /* t_next */ 47007c478bd9Sstevel@tonic-gate pt_continue, /* t_cont */ 47017c478bd9Sstevel@tonic-gate pt_signal, /* t_signal */ 47027c478bd9Sstevel@tonic-gate pt_add_vbrkpt, /* t_add_vbrkpt */ 47037c478bd9Sstevel@tonic-gate pt_add_sbrkpt, /* t_add_sbrkpt */ 47047c478bd9Sstevel@tonic-gate (int (*)()) mdb_tgt_null, /* t_add_pwapt */ 47057c478bd9Sstevel@tonic-gate pt_add_vwapt, /* t_add_vwapt */ 47067c478bd9Sstevel@tonic-gate (int (*)()) mdb_tgt_null, /* t_add_iowapt */ 47077c478bd9Sstevel@tonic-gate pt_add_sysenter, /* t_add_sysenter */ 47087c478bd9Sstevel@tonic-gate pt_add_sysexit, /* t_add_sysexit */ 47097c478bd9Sstevel@tonic-gate pt_add_signal, /* t_add_signal */ 47107c478bd9Sstevel@tonic-gate pt_add_fault, /* t_add_fault */ 47117c478bd9Sstevel@tonic-gate pt_getareg, /* t_getareg */ 47127c478bd9Sstevel@tonic-gate pt_putareg, /* t_putareg */ 47139acbbeafSnn35248 pt_stack_iter, /* t_stack_iter */ 47149acbbeafSnn35248 pt_auxv /* t_auxv */ 47157c478bd9Sstevel@tonic-gate }; 47167c478bd9Sstevel@tonic-gate 47177c478bd9Sstevel@tonic-gate /* 47187c478bd9Sstevel@tonic-gate * Utility function for converting libproc errno values to mdb error values 47197c478bd9Sstevel@tonic-gate * for the ptl calls below. Currently, we only need to convert ENOENT to 47207c478bd9Sstevel@tonic-gate * EMDB_NOTHREAD to produce a more useful error message for the user. 47217c478bd9Sstevel@tonic-gate */ 47227c478bd9Sstevel@tonic-gate static int 47237c478bd9Sstevel@tonic-gate ptl_err(int error) 47247c478bd9Sstevel@tonic-gate { 47257c478bd9Sstevel@tonic-gate if (error != 0 && errno == ENOENT) 47267c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOTHREAD)); 47277c478bd9Sstevel@tonic-gate 47287c478bd9Sstevel@tonic-gate return (error); 47297c478bd9Sstevel@tonic-gate } 47307c478bd9Sstevel@tonic-gate 47317c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 47327c478bd9Sstevel@tonic-gate static mdb_tgt_tid_t 47337c478bd9Sstevel@tonic-gate pt_lwp_tid(mdb_tgt_t *t, void *tap) 47347c478bd9Sstevel@tonic-gate { 47357c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL) 47367c478bd9Sstevel@tonic-gate return (Pstatus(t->t_pshandle)->pr_lwp.pr_lwpid); 47377c478bd9Sstevel@tonic-gate 47387c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 47397c478bd9Sstevel@tonic-gate } 47407c478bd9Sstevel@tonic-gate 47417c478bd9Sstevel@tonic-gate static int 47427c478bd9Sstevel@tonic-gate pt_lwp_add(mdb_addrvec_t *ap, const lwpstatus_t *psp) 47437c478bd9Sstevel@tonic-gate { 47447c478bd9Sstevel@tonic-gate mdb_addrvec_unshift(ap, psp->pr_lwpid); 47457c478bd9Sstevel@tonic-gate return (0); 47467c478bd9Sstevel@tonic-gate } 47477c478bd9Sstevel@tonic-gate 47487c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 47497c478bd9Sstevel@tonic-gate static int 47507c478bd9Sstevel@tonic-gate pt_lwp_iter(mdb_tgt_t *t, void *tap, mdb_addrvec_t *ap) 47517c478bd9Sstevel@tonic-gate { 47527c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL) 47537c478bd9Sstevel@tonic-gate return (Plwp_iter(t->t_pshandle, (proc_lwp_f *)pt_lwp_add, ap)); 47547c478bd9Sstevel@tonic-gate 47557c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 47567c478bd9Sstevel@tonic-gate } 47577c478bd9Sstevel@tonic-gate 47587c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 47597c478bd9Sstevel@tonic-gate static int 47607c478bd9Sstevel@tonic-gate pt_lwp_getregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid, prgregset_t gregs) 47617c478bd9Sstevel@tonic-gate { 47627c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL) { 47637c478bd9Sstevel@tonic-gate return (ptl_err(Plwp_getregs(t->t_pshandle, 47647c478bd9Sstevel@tonic-gate (lwpid_t)tid, gregs))); 47657c478bd9Sstevel@tonic-gate } 47667c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 47677c478bd9Sstevel@tonic-gate } 47687c478bd9Sstevel@tonic-gate 47697c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 47707c478bd9Sstevel@tonic-gate static int 47717c478bd9Sstevel@tonic-gate pt_lwp_setregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid, prgregset_t gregs) 47727c478bd9Sstevel@tonic-gate { 47737c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL) { 47747c478bd9Sstevel@tonic-gate return (ptl_err(Plwp_setregs(t->t_pshandle, 47757c478bd9Sstevel@tonic-gate (lwpid_t)tid, gregs))); 47767c478bd9Sstevel@tonic-gate } 47777c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 47787c478bd9Sstevel@tonic-gate } 47797c478bd9Sstevel@tonic-gate 47807c478bd9Sstevel@tonic-gate #ifdef __sparc 47817c478bd9Sstevel@tonic-gate 47827c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 47837c478bd9Sstevel@tonic-gate static int 47847c478bd9Sstevel@tonic-gate pt_lwp_getxregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid, prxregset_t *xregs) 47857c478bd9Sstevel@tonic-gate { 47867c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL) { 47877c478bd9Sstevel@tonic-gate return (ptl_err(Plwp_getxregs(t->t_pshandle, 47887c478bd9Sstevel@tonic-gate (lwpid_t)tid, xregs))); 47897c478bd9Sstevel@tonic-gate } 47907c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 47917c478bd9Sstevel@tonic-gate } 47927c478bd9Sstevel@tonic-gate 47937c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 47947c478bd9Sstevel@tonic-gate static int 47957c478bd9Sstevel@tonic-gate pt_lwp_setxregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid, 47967c478bd9Sstevel@tonic-gate const prxregset_t *xregs) 47977c478bd9Sstevel@tonic-gate { 47987c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL) { 47997c478bd9Sstevel@tonic-gate return (ptl_err(Plwp_setxregs(t->t_pshandle, 48007c478bd9Sstevel@tonic-gate (lwpid_t)tid, xregs))); 48017c478bd9Sstevel@tonic-gate } 48027c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 48037c478bd9Sstevel@tonic-gate } 48047c478bd9Sstevel@tonic-gate 48057c478bd9Sstevel@tonic-gate #endif /* __sparc */ 48067c478bd9Sstevel@tonic-gate 48077c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 48087c478bd9Sstevel@tonic-gate static int 48097c478bd9Sstevel@tonic-gate pt_lwp_getfpregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid, 48107c478bd9Sstevel@tonic-gate prfpregset_t *fpregs) 48117c478bd9Sstevel@tonic-gate { 48127c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL) { 48137c478bd9Sstevel@tonic-gate return (ptl_err(Plwp_getfpregs(t->t_pshandle, 48147c478bd9Sstevel@tonic-gate (lwpid_t)tid, fpregs))); 48157c478bd9Sstevel@tonic-gate } 48167c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 48177c478bd9Sstevel@tonic-gate } 48187c478bd9Sstevel@tonic-gate 48197c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 48207c478bd9Sstevel@tonic-gate static int 48217c478bd9Sstevel@tonic-gate pt_lwp_setfpregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid, 48227c478bd9Sstevel@tonic-gate const prfpregset_t *fpregs) 48237c478bd9Sstevel@tonic-gate { 48247c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL) { 48257c478bd9Sstevel@tonic-gate return (ptl_err(Plwp_setfpregs(t->t_pshandle, 48267c478bd9Sstevel@tonic-gate (lwpid_t)tid, fpregs))); 48277c478bd9Sstevel@tonic-gate } 48287c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 48297c478bd9Sstevel@tonic-gate } 48307c478bd9Sstevel@tonic-gate 48317c478bd9Sstevel@tonic-gate static const pt_ptl_ops_t proc_lwp_ops = { 48327c478bd9Sstevel@tonic-gate (int (*)()) mdb_tgt_nop, 48337c478bd9Sstevel@tonic-gate (void (*)()) mdb_tgt_nop, 48347c478bd9Sstevel@tonic-gate pt_lwp_tid, 48357c478bd9Sstevel@tonic-gate pt_lwp_iter, 48367c478bd9Sstevel@tonic-gate pt_lwp_getregs, 48377c478bd9Sstevel@tonic-gate pt_lwp_setregs, 48387c478bd9Sstevel@tonic-gate #ifdef __sparc 48397c478bd9Sstevel@tonic-gate pt_lwp_getxregs, 48407c478bd9Sstevel@tonic-gate pt_lwp_setxregs, 48417c478bd9Sstevel@tonic-gate #endif 48427c478bd9Sstevel@tonic-gate pt_lwp_getfpregs, 48437c478bd9Sstevel@tonic-gate pt_lwp_setfpregs 48447c478bd9Sstevel@tonic-gate }; 48457c478bd9Sstevel@tonic-gate 48467c478bd9Sstevel@tonic-gate static int 48477c478bd9Sstevel@tonic-gate pt_tdb_ctor(mdb_tgt_t *t) 48487c478bd9Sstevel@tonic-gate { 48497c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 48507c478bd9Sstevel@tonic-gate td_thragent_t *tap; 48517c478bd9Sstevel@tonic-gate td_err_e err; 48527c478bd9Sstevel@tonic-gate 48537c478bd9Sstevel@tonic-gate if ((err = pt->p_tdb_ops->td_ta_new(t->t_pshandle, &tap)) != TD_OK) 48547c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 48557c478bd9Sstevel@tonic-gate 48567c478bd9Sstevel@tonic-gate pt->p_ptl_hdl = tap; 48577c478bd9Sstevel@tonic-gate return (0); 48587c478bd9Sstevel@tonic-gate } 48597c478bd9Sstevel@tonic-gate 48607c478bd9Sstevel@tonic-gate static void 48617c478bd9Sstevel@tonic-gate pt_tdb_dtor(mdb_tgt_t *t, void *tap) 48627c478bd9Sstevel@tonic-gate { 48637c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 48647c478bd9Sstevel@tonic-gate 48657c478bd9Sstevel@tonic-gate ASSERT(tap == pt->p_ptl_hdl); 48667c478bd9Sstevel@tonic-gate (void) pt->p_tdb_ops->td_ta_delete(tap); 48677c478bd9Sstevel@tonic-gate pt->p_ptl_hdl = NULL; 48687c478bd9Sstevel@tonic-gate } 48697c478bd9Sstevel@tonic-gate 48707c478bd9Sstevel@tonic-gate static mdb_tgt_tid_t 48717c478bd9Sstevel@tonic-gate pt_tdb_tid(mdb_tgt_t *t, void *tap) 48727c478bd9Sstevel@tonic-gate { 48737c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 48747c478bd9Sstevel@tonic-gate 48757c478bd9Sstevel@tonic-gate td_thrhandle_t th; 48767c478bd9Sstevel@tonic-gate td_thrinfo_t ti; 48777c478bd9Sstevel@tonic-gate td_err_e err; 48787c478bd9Sstevel@tonic-gate 48797c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) 48807c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 48817c478bd9Sstevel@tonic-gate 48827c478bd9Sstevel@tonic-gate if ((err = pt->p_tdb_ops->td_ta_map_lwp2thr(tap, 48837c478bd9Sstevel@tonic-gate Pstatus(t->t_pshandle)->pr_lwp.pr_lwpid, &th)) != TD_OK) 48847c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 48857c478bd9Sstevel@tonic-gate 48867c478bd9Sstevel@tonic-gate if ((err = pt->p_tdb_ops->td_thr_get_info(&th, &ti)) != TD_OK) 48877c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 48887c478bd9Sstevel@tonic-gate 48897c478bd9Sstevel@tonic-gate return (ti.ti_tid); 48907c478bd9Sstevel@tonic-gate } 48917c478bd9Sstevel@tonic-gate 48927c478bd9Sstevel@tonic-gate static int 48937c478bd9Sstevel@tonic-gate pt_tdb_add(const td_thrhandle_t *thp, pt_addarg_t *pap) 48947c478bd9Sstevel@tonic-gate { 48957c478bd9Sstevel@tonic-gate td_thrinfo_t ti; 48967c478bd9Sstevel@tonic-gate 48977c478bd9Sstevel@tonic-gate if (pap->pa_pt->p_tdb_ops->td_thr_get_info(thp, &ti) == TD_OK && 48987c478bd9Sstevel@tonic-gate ti.ti_state != TD_THR_ZOMBIE) 48997c478bd9Sstevel@tonic-gate mdb_addrvec_unshift(pap->pa_ap, ti.ti_tid); 49007c478bd9Sstevel@tonic-gate 49017c478bd9Sstevel@tonic-gate return (0); 49027c478bd9Sstevel@tonic-gate } 49037c478bd9Sstevel@tonic-gate 49047c478bd9Sstevel@tonic-gate static int 49057c478bd9Sstevel@tonic-gate pt_tdb_iter(mdb_tgt_t *t, void *tap, mdb_addrvec_t *ap) 49067c478bd9Sstevel@tonic-gate { 49077c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 49087c478bd9Sstevel@tonic-gate pt_addarg_t arg; 49097c478bd9Sstevel@tonic-gate int err; 49107c478bd9Sstevel@tonic-gate 49117c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) 49127c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 49137c478bd9Sstevel@tonic-gate 49147c478bd9Sstevel@tonic-gate arg.pa_pt = pt; 49157c478bd9Sstevel@tonic-gate arg.pa_ap = ap; 49167c478bd9Sstevel@tonic-gate 49177c478bd9Sstevel@tonic-gate if ((err = pt->p_tdb_ops->td_ta_thr_iter(tap, (td_thr_iter_f *) 49187c478bd9Sstevel@tonic-gate pt_tdb_add, &arg, TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY, 49197c478bd9Sstevel@tonic-gate TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS)) != TD_OK) 49207c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 49217c478bd9Sstevel@tonic-gate 49227c478bd9Sstevel@tonic-gate return (0); 49237c478bd9Sstevel@tonic-gate } 49247c478bd9Sstevel@tonic-gate 49257c478bd9Sstevel@tonic-gate static int 49267c478bd9Sstevel@tonic-gate pt_tdb_getregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid, prgregset_t gregs) 49277c478bd9Sstevel@tonic-gate { 49287c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 49297c478bd9Sstevel@tonic-gate 49307c478bd9Sstevel@tonic-gate td_thrhandle_t th; 49317c478bd9Sstevel@tonic-gate td_err_e err; 49327c478bd9Sstevel@tonic-gate 49337c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) 49347c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 49357c478bd9Sstevel@tonic-gate 49367c478bd9Sstevel@tonic-gate if ((err = pt->p_tdb_ops->td_ta_map_id2thr(tap, tid, &th)) != TD_OK) 49377c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 49387c478bd9Sstevel@tonic-gate 49397c478bd9Sstevel@tonic-gate err = pt->p_tdb_ops->td_thr_getgregs(&th, gregs); 49407c478bd9Sstevel@tonic-gate if (err != TD_OK && err != TD_PARTIALREG) 49417c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 49427c478bd9Sstevel@tonic-gate 49437c478bd9Sstevel@tonic-gate return (0); 49447c478bd9Sstevel@tonic-gate } 49457c478bd9Sstevel@tonic-gate 49467c478bd9Sstevel@tonic-gate static int 49477c478bd9Sstevel@tonic-gate pt_tdb_setregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid, prgregset_t gregs) 49487c478bd9Sstevel@tonic-gate { 49497c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 49507c478bd9Sstevel@tonic-gate 49517c478bd9Sstevel@tonic-gate td_thrhandle_t th; 49527c478bd9Sstevel@tonic-gate td_err_e err; 49537c478bd9Sstevel@tonic-gate 49547c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) 49557c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 49567c478bd9Sstevel@tonic-gate 49577c478bd9Sstevel@tonic-gate if ((err = pt->p_tdb_ops->td_ta_map_id2thr(tap, tid, &th)) != TD_OK) 49587c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 49597c478bd9Sstevel@tonic-gate 49607c478bd9Sstevel@tonic-gate err = pt->p_tdb_ops->td_thr_setgregs(&th, gregs); 49617c478bd9Sstevel@tonic-gate if (err != TD_OK && err != TD_PARTIALREG) 49627c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 49637c478bd9Sstevel@tonic-gate 49647c478bd9Sstevel@tonic-gate return (0); 49657c478bd9Sstevel@tonic-gate } 49667c478bd9Sstevel@tonic-gate 49677c478bd9Sstevel@tonic-gate #ifdef __sparc 49687c478bd9Sstevel@tonic-gate 49697c478bd9Sstevel@tonic-gate static int 49707c478bd9Sstevel@tonic-gate pt_tdb_getxregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid, prxregset_t *xregs) 49717c478bd9Sstevel@tonic-gate { 49727c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 49737c478bd9Sstevel@tonic-gate 49747c478bd9Sstevel@tonic-gate td_thrhandle_t th; 49757c478bd9Sstevel@tonic-gate td_err_e err; 49767c478bd9Sstevel@tonic-gate 49777c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) 49787c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 49797c478bd9Sstevel@tonic-gate 49807c478bd9Sstevel@tonic-gate if ((err = pt->p_tdb_ops->td_ta_map_id2thr(tap, tid, &th)) != TD_OK) 49817c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 49827c478bd9Sstevel@tonic-gate 49837c478bd9Sstevel@tonic-gate err = pt->p_tdb_ops->td_thr_getxregs(&th, xregs); 49847c478bd9Sstevel@tonic-gate if (err != TD_OK && err != TD_PARTIALREG) 49857c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 49867c478bd9Sstevel@tonic-gate 49877c478bd9Sstevel@tonic-gate return (0); 49887c478bd9Sstevel@tonic-gate } 49897c478bd9Sstevel@tonic-gate 49907c478bd9Sstevel@tonic-gate static int 49917c478bd9Sstevel@tonic-gate pt_tdb_setxregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid, 49927c478bd9Sstevel@tonic-gate const prxregset_t *xregs) 49937c478bd9Sstevel@tonic-gate { 49947c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 49957c478bd9Sstevel@tonic-gate 49967c478bd9Sstevel@tonic-gate td_thrhandle_t th; 49977c478bd9Sstevel@tonic-gate td_err_e err; 49987c478bd9Sstevel@tonic-gate 49997c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) 50007c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 50017c478bd9Sstevel@tonic-gate 50027c478bd9Sstevel@tonic-gate if ((err = pt->p_tdb_ops->td_ta_map_id2thr(tap, tid, &th)) != TD_OK) 50037c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 50047c478bd9Sstevel@tonic-gate 50057c478bd9Sstevel@tonic-gate err = pt->p_tdb_ops->td_thr_setxregs(&th, xregs); 50067c478bd9Sstevel@tonic-gate if (err != TD_OK && err != TD_PARTIALREG) 50077c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 50087c478bd9Sstevel@tonic-gate 50097c478bd9Sstevel@tonic-gate return (0); 50107c478bd9Sstevel@tonic-gate } 50117c478bd9Sstevel@tonic-gate 50127c478bd9Sstevel@tonic-gate #endif /* __sparc */ 50137c478bd9Sstevel@tonic-gate 50147c478bd9Sstevel@tonic-gate static int 50157c478bd9Sstevel@tonic-gate pt_tdb_getfpregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid, 50167c478bd9Sstevel@tonic-gate prfpregset_t *fpregs) 50177c478bd9Sstevel@tonic-gate { 50187c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 50197c478bd9Sstevel@tonic-gate 50207c478bd9Sstevel@tonic-gate td_thrhandle_t th; 50217c478bd9Sstevel@tonic-gate td_err_e err; 50227c478bd9Sstevel@tonic-gate 50237c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) 50247c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 50257c478bd9Sstevel@tonic-gate 50267c478bd9Sstevel@tonic-gate if ((err = pt->p_tdb_ops->td_ta_map_id2thr(tap, tid, &th)) != TD_OK) 50277c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 50287c478bd9Sstevel@tonic-gate 50297c478bd9Sstevel@tonic-gate err = pt->p_tdb_ops->td_thr_getfpregs(&th, fpregs); 50307c478bd9Sstevel@tonic-gate if (err != TD_OK && err != TD_PARTIALREG) 50317c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 50327c478bd9Sstevel@tonic-gate 50337c478bd9Sstevel@tonic-gate return (0); 50347c478bd9Sstevel@tonic-gate } 50357c478bd9Sstevel@tonic-gate 50367c478bd9Sstevel@tonic-gate static int 50377c478bd9Sstevel@tonic-gate pt_tdb_setfpregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid, 50387c478bd9Sstevel@tonic-gate const prfpregset_t *fpregs) 50397c478bd9Sstevel@tonic-gate { 50407c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 50417c478bd9Sstevel@tonic-gate 50427c478bd9Sstevel@tonic-gate td_thrhandle_t th; 50437c478bd9Sstevel@tonic-gate td_err_e err; 50447c478bd9Sstevel@tonic-gate 50457c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL) 50467c478bd9Sstevel@tonic-gate return (set_errno(EMDB_NOPROC)); 50477c478bd9Sstevel@tonic-gate 50487c478bd9Sstevel@tonic-gate if ((err = pt->p_tdb_ops->td_ta_map_id2thr(tap, tid, &th)) != TD_OK) 50497c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 50507c478bd9Sstevel@tonic-gate 50517c478bd9Sstevel@tonic-gate err = pt->p_tdb_ops->td_thr_setfpregs(&th, fpregs); 50527c478bd9Sstevel@tonic-gate if (err != TD_OK && err != TD_PARTIALREG) 50537c478bd9Sstevel@tonic-gate return (set_errno(tdb_to_errno(err))); 50547c478bd9Sstevel@tonic-gate 50557c478bd9Sstevel@tonic-gate return (0); 50567c478bd9Sstevel@tonic-gate } 50577c478bd9Sstevel@tonic-gate 50587c478bd9Sstevel@tonic-gate static const pt_ptl_ops_t proc_tdb_ops = { 50597c478bd9Sstevel@tonic-gate pt_tdb_ctor, 50607c478bd9Sstevel@tonic-gate pt_tdb_dtor, 50617c478bd9Sstevel@tonic-gate pt_tdb_tid, 50627c478bd9Sstevel@tonic-gate pt_tdb_iter, 50637c478bd9Sstevel@tonic-gate pt_tdb_getregs, 50647c478bd9Sstevel@tonic-gate pt_tdb_setregs, 50657c478bd9Sstevel@tonic-gate #ifdef __sparc 50667c478bd9Sstevel@tonic-gate pt_tdb_getxregs, 50677c478bd9Sstevel@tonic-gate pt_tdb_setxregs, 50687c478bd9Sstevel@tonic-gate #endif 50697c478bd9Sstevel@tonic-gate pt_tdb_getfpregs, 50707c478bd9Sstevel@tonic-gate pt_tdb_setfpregs 50717c478bd9Sstevel@tonic-gate }; 50727c478bd9Sstevel@tonic-gate 50737c478bd9Sstevel@tonic-gate static ssize_t 50747c478bd9Sstevel@tonic-gate pt_xd_auxv(mdb_tgt_t *t, void *buf, size_t nbytes) 50757c478bd9Sstevel@tonic-gate { 50767c478bd9Sstevel@tonic-gate struct ps_prochandle *P = t->t_pshandle; 50777c478bd9Sstevel@tonic-gate const auxv_t *auxp, *auxv = NULL; 50787c478bd9Sstevel@tonic-gate int auxn = 0; 50797c478bd9Sstevel@tonic-gate 50807c478bd9Sstevel@tonic-gate if (P != NULL && (auxv = Pgetauxvec(P)) != NULL && 50817c478bd9Sstevel@tonic-gate auxv->a_type != AT_NULL) { 50827c478bd9Sstevel@tonic-gate for (auxp = auxv, auxn = 1; auxp->a_type != NULL; auxp++) 50837c478bd9Sstevel@tonic-gate auxn++; 50847c478bd9Sstevel@tonic-gate } 50857c478bd9Sstevel@tonic-gate 50867c478bd9Sstevel@tonic-gate if (buf == NULL && nbytes == 0) 50877c478bd9Sstevel@tonic-gate return (sizeof (auxv_t) * auxn); 50887c478bd9Sstevel@tonic-gate 50897c478bd9Sstevel@tonic-gate if (auxn == 0) 50907c478bd9Sstevel@tonic-gate return (set_errno(ENODATA)); 50917c478bd9Sstevel@tonic-gate 50927c478bd9Sstevel@tonic-gate nbytes = MIN(nbytes, sizeof (auxv_t) * auxn); 50937c478bd9Sstevel@tonic-gate bcopy(auxv, buf, nbytes); 50947c478bd9Sstevel@tonic-gate return (nbytes); 50957c478bd9Sstevel@tonic-gate } 50967c478bd9Sstevel@tonic-gate 50977c478bd9Sstevel@tonic-gate static ssize_t 50987c478bd9Sstevel@tonic-gate pt_xd_cred(mdb_tgt_t *t, void *buf, size_t nbytes) 50997c478bd9Sstevel@tonic-gate { 51007c478bd9Sstevel@tonic-gate prcred_t cr, *crp; 51017c478bd9Sstevel@tonic-gate size_t cbytes = 0; 51027c478bd9Sstevel@tonic-gate 51037c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL && Pcred(t->t_pshandle, &cr, 1) == 0) { 51047c478bd9Sstevel@tonic-gate cbytes = (cr.pr_ngroups <= 1) ? sizeof (prcred_t) : 51057c478bd9Sstevel@tonic-gate (sizeof (prcred_t) + (cr.pr_ngroups - 1) * sizeof (gid_t)); 51067c478bd9Sstevel@tonic-gate } 51077c478bd9Sstevel@tonic-gate 51087c478bd9Sstevel@tonic-gate if (buf == NULL && nbytes == 0) 51097c478bd9Sstevel@tonic-gate return (cbytes); 51107c478bd9Sstevel@tonic-gate 51117c478bd9Sstevel@tonic-gate if (cbytes == 0) 51127c478bd9Sstevel@tonic-gate return (set_errno(ENODATA)); 51137c478bd9Sstevel@tonic-gate 51147c478bd9Sstevel@tonic-gate crp = mdb_alloc(cbytes, UM_SLEEP); 51157c478bd9Sstevel@tonic-gate 51167c478bd9Sstevel@tonic-gate if (Pcred(t->t_pshandle, crp, cr.pr_ngroups) == -1) 51177c478bd9Sstevel@tonic-gate return (set_errno(ENODATA)); 51187c478bd9Sstevel@tonic-gate 51197c478bd9Sstevel@tonic-gate nbytes = MIN(nbytes, cbytes); 51207c478bd9Sstevel@tonic-gate bcopy(crp, buf, nbytes); 51217c478bd9Sstevel@tonic-gate mdb_free(crp, cbytes); 51227c478bd9Sstevel@tonic-gate return (nbytes); 51237c478bd9Sstevel@tonic-gate } 51247c478bd9Sstevel@tonic-gate 51257c478bd9Sstevel@tonic-gate static ssize_t 51267c478bd9Sstevel@tonic-gate pt_xd_ehdr(mdb_tgt_t *t, void *buf, size_t nbytes) 51277c478bd9Sstevel@tonic-gate { 51287c478bd9Sstevel@tonic-gate pt_data_t *pt = t->t_data; 51297c478bd9Sstevel@tonic-gate 51307c478bd9Sstevel@tonic-gate if (buf == NULL && nbytes == 0) 51317c478bd9Sstevel@tonic-gate return (sizeof (GElf_Ehdr)); 51327c478bd9Sstevel@tonic-gate 51337c478bd9Sstevel@tonic-gate if (pt->p_file == NULL) 51347c478bd9Sstevel@tonic-gate return (set_errno(ENODATA)); 51357c478bd9Sstevel@tonic-gate 51367c478bd9Sstevel@tonic-gate nbytes = MIN(nbytes, sizeof (GElf_Ehdr)); 51377c478bd9Sstevel@tonic-gate bcopy(&pt->p_file->gf_ehdr, buf, nbytes); 51387c478bd9Sstevel@tonic-gate return (nbytes); 51397c478bd9Sstevel@tonic-gate } 51407c478bd9Sstevel@tonic-gate 51417c478bd9Sstevel@tonic-gate static int 51427c478bd9Sstevel@tonic-gate pt_copy_lwp(lwpstatus_t **lspp, const lwpstatus_t *lsp) 51437c478bd9Sstevel@tonic-gate { 51447c478bd9Sstevel@tonic-gate bcopy(lsp, *lspp, sizeof (lwpstatus_t)); 51457c478bd9Sstevel@tonic-gate (*lspp)++; 51467c478bd9Sstevel@tonic-gate return (0); 51477c478bd9Sstevel@tonic-gate } 51487c478bd9Sstevel@tonic-gate 51497c478bd9Sstevel@tonic-gate static ssize_t 51507c478bd9Sstevel@tonic-gate pt_xd_lwpstatus(mdb_tgt_t *t, void *buf, size_t nbytes) 51517c478bd9Sstevel@tonic-gate { 51527c478bd9Sstevel@tonic-gate lwpstatus_t *lsp, *lbuf; 51537c478bd9Sstevel@tonic-gate const pstatus_t *psp; 51547c478bd9Sstevel@tonic-gate int nlwp = 0; 51557c478bd9Sstevel@tonic-gate 51567c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL && (psp = Pstatus(t->t_pshandle)) != NULL) 51577c478bd9Sstevel@tonic-gate nlwp = psp->pr_nlwp; 51587c478bd9Sstevel@tonic-gate 51597c478bd9Sstevel@tonic-gate if (buf == NULL && nbytes == 0) 51607c478bd9Sstevel@tonic-gate return (sizeof (lwpstatus_t) * nlwp); 51617c478bd9Sstevel@tonic-gate 51627c478bd9Sstevel@tonic-gate if (nlwp == 0) 51637c478bd9Sstevel@tonic-gate return (set_errno(ENODATA)); 51647c478bd9Sstevel@tonic-gate 51657c478bd9Sstevel@tonic-gate lsp = lbuf = mdb_alloc(sizeof (lwpstatus_t) * nlwp, UM_SLEEP); 51667c478bd9Sstevel@tonic-gate nbytes = MIN(nbytes, sizeof (lwpstatus_t) * nlwp); 51677c478bd9Sstevel@tonic-gate 51687c478bd9Sstevel@tonic-gate (void) Plwp_iter(t->t_pshandle, (proc_lwp_f *)pt_copy_lwp, &lsp); 51697c478bd9Sstevel@tonic-gate bcopy(lbuf, buf, nbytes); 51707c478bd9Sstevel@tonic-gate 51717c478bd9Sstevel@tonic-gate mdb_free(lbuf, sizeof (lwpstatus_t) * nlwp); 51727c478bd9Sstevel@tonic-gate return (nbytes); 51737c478bd9Sstevel@tonic-gate } 51747c478bd9Sstevel@tonic-gate 51757c478bd9Sstevel@tonic-gate static ssize_t 51767c478bd9Sstevel@tonic-gate pt_xd_pshandle(mdb_tgt_t *t, void *buf, size_t nbytes) 51777c478bd9Sstevel@tonic-gate { 51787c478bd9Sstevel@tonic-gate if (buf == NULL && nbytes == 0) 51797c478bd9Sstevel@tonic-gate return (sizeof (struct ps_prochandle *)); 51807c478bd9Sstevel@tonic-gate 51817c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL || nbytes != sizeof (struct ps_prochandle *)) 51827c478bd9Sstevel@tonic-gate return (set_errno(ENODATA)); 51837c478bd9Sstevel@tonic-gate 51847c478bd9Sstevel@tonic-gate bcopy(&t->t_pshandle, buf, nbytes); 51857c478bd9Sstevel@tonic-gate return (nbytes); 51867c478bd9Sstevel@tonic-gate } 51877c478bd9Sstevel@tonic-gate 51887c478bd9Sstevel@tonic-gate static ssize_t 51897c478bd9Sstevel@tonic-gate pt_xd_psinfo(mdb_tgt_t *t, void *buf, size_t nbytes) 51907c478bd9Sstevel@tonic-gate { 51917c478bd9Sstevel@tonic-gate const psinfo_t *psp; 51927c478bd9Sstevel@tonic-gate 51937c478bd9Sstevel@tonic-gate if (buf == NULL && nbytes == 0) 51947c478bd9Sstevel@tonic-gate return (sizeof (psinfo_t)); 51957c478bd9Sstevel@tonic-gate 51967c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL || (psp = Ppsinfo(t->t_pshandle)) == NULL) 51977c478bd9Sstevel@tonic-gate return (set_errno(ENODATA)); 51987c478bd9Sstevel@tonic-gate 51997c478bd9Sstevel@tonic-gate nbytes = MIN(nbytes, sizeof (psinfo_t)); 52007c478bd9Sstevel@tonic-gate bcopy(psp, buf, nbytes); 52017c478bd9Sstevel@tonic-gate return (nbytes); 52027c478bd9Sstevel@tonic-gate } 52037c478bd9Sstevel@tonic-gate 52047c478bd9Sstevel@tonic-gate static ssize_t 52057c478bd9Sstevel@tonic-gate pt_xd_pstatus(mdb_tgt_t *t, void *buf, size_t nbytes) 52067c478bd9Sstevel@tonic-gate { 52077c478bd9Sstevel@tonic-gate const pstatus_t *psp; 52087c478bd9Sstevel@tonic-gate 52097c478bd9Sstevel@tonic-gate if (buf == NULL && nbytes == 0) 52107c478bd9Sstevel@tonic-gate return (sizeof (pstatus_t)); 52117c478bd9Sstevel@tonic-gate 52127c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL || (psp = Pstatus(t->t_pshandle)) == NULL) 52137c478bd9Sstevel@tonic-gate return (set_errno(ENODATA)); 52147c478bd9Sstevel@tonic-gate 52157c478bd9Sstevel@tonic-gate nbytes = MIN(nbytes, sizeof (pstatus_t)); 52167c478bd9Sstevel@tonic-gate bcopy(psp, buf, nbytes); 52177c478bd9Sstevel@tonic-gate return (nbytes); 52187c478bd9Sstevel@tonic-gate } 52197c478bd9Sstevel@tonic-gate 52207c478bd9Sstevel@tonic-gate static ssize_t 52217c478bd9Sstevel@tonic-gate pt_xd_utsname(mdb_tgt_t *t, void *buf, size_t nbytes) 52227c478bd9Sstevel@tonic-gate { 52237c478bd9Sstevel@tonic-gate struct utsname uts; 52247c478bd9Sstevel@tonic-gate 52257c478bd9Sstevel@tonic-gate if (buf == NULL && nbytes == 0) 52267c478bd9Sstevel@tonic-gate return (sizeof (struct utsname)); 52277c478bd9Sstevel@tonic-gate 52287c478bd9Sstevel@tonic-gate if (t->t_pshandle == NULL || Puname(t->t_pshandle, &uts) != 0) 52297c478bd9Sstevel@tonic-gate return (set_errno(ENODATA)); 52307c478bd9Sstevel@tonic-gate 52317c478bd9Sstevel@tonic-gate nbytes = MIN(nbytes, sizeof (struct utsname)); 52327c478bd9Sstevel@tonic-gate bcopy(&uts, buf, nbytes); 52337c478bd9Sstevel@tonic-gate return (nbytes); 52347c478bd9Sstevel@tonic-gate } 52357c478bd9Sstevel@tonic-gate 52367c478bd9Sstevel@tonic-gate int 52377c478bd9Sstevel@tonic-gate mdb_proc_tgt_create(mdb_tgt_t *t, int argc, const char *argv[]) 52387c478bd9Sstevel@tonic-gate { 52397c478bd9Sstevel@tonic-gate pt_data_t *pt = mdb_zalloc(sizeof (pt_data_t), UM_SLEEP); 52407c478bd9Sstevel@tonic-gate 52417c478bd9Sstevel@tonic-gate const char *aout_path = argc > 0 ? argv[0] : PT_EXEC_PATH; 52427c478bd9Sstevel@tonic-gate const char *core_path = argc > 1 ? argv[1] : NULL; 52437c478bd9Sstevel@tonic-gate 52447c478bd9Sstevel@tonic-gate const mdb_tgt_regdesc_t *rdp; 52457c478bd9Sstevel@tonic-gate char execname[MAXPATHLEN]; 52467c478bd9Sstevel@tonic-gate struct stat64 st; 52477c478bd9Sstevel@tonic-gate int perr; 52487c478bd9Sstevel@tonic-gate int state; 52497c478bd9Sstevel@tonic-gate struct rlimit rlim; 52507c478bd9Sstevel@tonic-gate int i; 52517c478bd9Sstevel@tonic-gate 52527c478bd9Sstevel@tonic-gate if (argc > 2) { 52537c478bd9Sstevel@tonic-gate mdb_free(pt, sizeof (pt_data_t)); 52547c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 52557c478bd9Sstevel@tonic-gate } 52567c478bd9Sstevel@tonic-gate 52577c478bd9Sstevel@tonic-gate if (t->t_flags & MDB_TGT_F_RDWR) 52587c478bd9Sstevel@tonic-gate pt->p_oflags = O_RDWR; 52597c478bd9Sstevel@tonic-gate else 52607c478bd9Sstevel@tonic-gate pt->p_oflags = O_RDONLY; 52617c478bd9Sstevel@tonic-gate 52627c478bd9Sstevel@tonic-gate if (t->t_flags & MDB_TGT_F_FORCE) 52637c478bd9Sstevel@tonic-gate pt->p_gflags |= PGRAB_FORCE; 52647c478bd9Sstevel@tonic-gate if (t->t_flags & MDB_TGT_F_NOSTOP) 52657c478bd9Sstevel@tonic-gate pt->p_gflags |= PGRAB_NOSTOP; 52667c478bd9Sstevel@tonic-gate 52677c478bd9Sstevel@tonic-gate pt->p_ptl_ops = &proc_lwp_ops; 52687c478bd9Sstevel@tonic-gate pt->p_maxsig = sysconf(_SC_SIGRT_MAX); 52697c478bd9Sstevel@tonic-gate 52707c478bd9Sstevel@tonic-gate (void) mdb_nv_create(&pt->p_regs, UM_SLEEP); 52717c478bd9Sstevel@tonic-gate (void) mdb_nv_create(&pt->p_env, UM_SLEEP); 52727c478bd9Sstevel@tonic-gate 52737c478bd9Sstevel@tonic-gate t->t_ops = &proc_ops; 52747c478bd9Sstevel@tonic-gate t->t_data = pt; 52757c478bd9Sstevel@tonic-gate 52767c478bd9Sstevel@tonic-gate /* 52777c478bd9Sstevel@tonic-gate * If no core file name was specified, but the file ./core is present, 52787c478bd9Sstevel@tonic-gate * infer that we want to debug it. I find this behavior confusing, 52797c478bd9Sstevel@tonic-gate * so we only do this when precise adb(1) compatibility is required. 52807c478bd9Sstevel@tonic-gate */ 52817c478bd9Sstevel@tonic-gate if (core_path == NULL && (mdb.m_flags & MDB_FL_ADB) && 52827c478bd9Sstevel@tonic-gate access(PT_CORE_PATH, F_OK) == 0) 52837c478bd9Sstevel@tonic-gate core_path = PT_CORE_PATH; 52847c478bd9Sstevel@tonic-gate 52857c478bd9Sstevel@tonic-gate /* 52867c478bd9Sstevel@tonic-gate * For compatibility with adb(1), the special name "-" may be used 52877c478bd9Sstevel@tonic-gate * to suppress the loading of the executable or core file. 52887c478bd9Sstevel@tonic-gate */ 52897c478bd9Sstevel@tonic-gate if (aout_path != NULL && strcmp(aout_path, "-") == 0) 52907c478bd9Sstevel@tonic-gate aout_path = NULL; 52917c478bd9Sstevel@tonic-gate if (core_path != NULL && strcmp(core_path, "-") == 0) 52927c478bd9Sstevel@tonic-gate core_path = NULL; 52937c478bd9Sstevel@tonic-gate 52947c478bd9Sstevel@tonic-gate /* 52957c478bd9Sstevel@tonic-gate * If a core file or pid was specified, attempt to grab it now using 52967c478bd9Sstevel@tonic-gate * proc_arg_grab(); otherwise we'll create a fresh process later. 52977c478bd9Sstevel@tonic-gate */ 52987c478bd9Sstevel@tonic-gate if (core_path != NULL && (t->t_pshandle = proc_arg_xgrab(core_path, 52997c478bd9Sstevel@tonic-gate aout_path == PT_EXEC_PATH ? NULL : aout_path, PR_ARG_ANY, 53007c478bd9Sstevel@tonic-gate pt->p_gflags, &perr, NULL)) == NULL) { 53017c478bd9Sstevel@tonic-gate mdb_warn("cannot debug %s: %s\n", core_path, Pgrab_error(perr)); 53027c478bd9Sstevel@tonic-gate goto err; 53037c478bd9Sstevel@tonic-gate } 53047c478bd9Sstevel@tonic-gate 53057c478bd9Sstevel@tonic-gate if (aout_path != NULL && 53067c478bd9Sstevel@tonic-gate (pt->p_idlehandle = Pgrab_file(aout_path, &perr)) != NULL && 53077c478bd9Sstevel@tonic-gate t->t_pshandle == NULL) 53087c478bd9Sstevel@tonic-gate t->t_pshandle = pt->p_idlehandle; 53097c478bd9Sstevel@tonic-gate 53107c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL) 53117c478bd9Sstevel@tonic-gate state = Pstate(t->t_pshandle); 53127c478bd9Sstevel@tonic-gate 53137c478bd9Sstevel@tonic-gate /* 53147c478bd9Sstevel@tonic-gate * Make sure we'll have enough file descriptors to handle a target 53157c478bd9Sstevel@tonic-gate * has many many mappings. 53167c478bd9Sstevel@tonic-gate */ 53177c478bd9Sstevel@tonic-gate if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) { 53187c478bd9Sstevel@tonic-gate rlim.rlim_cur = rlim.rlim_max; 53197c478bd9Sstevel@tonic-gate (void) setrlimit(RLIMIT_NOFILE, &rlim); 5320004388ebScasper (void) enable_extended_FILE_stdio(-1, -1); 53217c478bd9Sstevel@tonic-gate } 53227c478bd9Sstevel@tonic-gate 53237c478bd9Sstevel@tonic-gate /* 53247c478bd9Sstevel@tonic-gate * If we don't have an executable path or the executable path is the 53257c478bd9Sstevel@tonic-gate * /proc/<pid>/object/a.out path, but we now have a libproc handle, 53267c478bd9Sstevel@tonic-gate * attempt to derive the executable path using Pexecname(). We need 53277c478bd9Sstevel@tonic-gate * to do this in the /proc case in order to open the executable for 53287c478bd9Sstevel@tonic-gate * writing because /proc/object/<file> permission are masked with 0555. 53297c478bd9Sstevel@tonic-gate * If Pexecname() fails us, fall back to /proc/<pid>/object/a.out. 53307c478bd9Sstevel@tonic-gate */ 53317c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL && (aout_path == NULL || (stat64(aout_path, 53327c478bd9Sstevel@tonic-gate &st) == 0 && strcmp(st.st_fstype, "proc") == 0))) { 53337c478bd9Sstevel@tonic-gate GElf_Sym s; 53347c478bd9Sstevel@tonic-gate aout_path = Pexecname(t->t_pshandle, execname, MAXPATHLEN); 53357c478bd9Sstevel@tonic-gate if (aout_path == NULL && state != PS_DEAD && state != PS_IDLE) { 53367c478bd9Sstevel@tonic-gate (void) mdb_iob_snprintf(execname, sizeof (execname), 53377c478bd9Sstevel@tonic-gate "/proc/%d/object/a.out", 53387c478bd9Sstevel@tonic-gate (int)Pstatus(t->t_pshandle)->pr_pid); 53397c478bd9Sstevel@tonic-gate aout_path = execname; 53407c478bd9Sstevel@tonic-gate } 53417c478bd9Sstevel@tonic-gate if (aout_path == NULL && 53427c478bd9Sstevel@tonic-gate Plookup_by_name(t->t_pshandle, "a.out", "_start", &s) != 0) 53437c478bd9Sstevel@tonic-gate mdb_warn("warning: failed to infer pathname to " 53447c478bd9Sstevel@tonic-gate "executable; symbol table will not be available\n"); 53457c478bd9Sstevel@tonic-gate 53467c478bd9Sstevel@tonic-gate mdb_dprintf(MDB_DBG_TGT, "a.out is %s\n", aout_path); 53477c478bd9Sstevel@tonic-gate } 53487c478bd9Sstevel@tonic-gate 53497c478bd9Sstevel@tonic-gate /* 53507c478bd9Sstevel@tonic-gate * Attempt to open the executable file. We only want this operation 53517c478bd9Sstevel@tonic-gate * to actually cause the constructor to abort if the executable file 53527c478bd9Sstevel@tonic-gate * name was given explicitly. If we defaulted to PT_EXEC_PATH or 53537c478bd9Sstevel@tonic-gate * derived the executable using Pexecname, then we want to continue 53547c478bd9Sstevel@tonic-gate * along with p_fio and p_file set to NULL. 53557c478bd9Sstevel@tonic-gate */ 53567c478bd9Sstevel@tonic-gate if (aout_path != NULL && (pt->p_aout_fio = mdb_fdio_create_path(NULL, 53577c478bd9Sstevel@tonic-gate aout_path, pt->p_oflags, 0)) == NULL && argc > 0) { 53587c478bd9Sstevel@tonic-gate mdb_warn("failed to open %s", aout_path); 53597c478bd9Sstevel@tonic-gate goto err; 53607c478bd9Sstevel@tonic-gate } 53617c478bd9Sstevel@tonic-gate 53627c478bd9Sstevel@tonic-gate /* 53637c478bd9Sstevel@tonic-gate * Now create an ELF file from the input file, if we have one. Again, 53647c478bd9Sstevel@tonic-gate * only abort the constructor if the name was given explicitly. 53657c478bd9Sstevel@tonic-gate */ 53667c478bd9Sstevel@tonic-gate if (pt->p_aout_fio != NULL && pt_open_aout(t, 53677c478bd9Sstevel@tonic-gate mdb_io_hold(pt->p_aout_fio)) == NULL && argc > 0) 53687c478bd9Sstevel@tonic-gate goto err; 53697c478bd9Sstevel@tonic-gate 53707c478bd9Sstevel@tonic-gate /* 53717c478bd9Sstevel@tonic-gate * If we've successfully opened an ELF file, select the appropriate 53727c478bd9Sstevel@tonic-gate * disassembler based on the ELF header. 53737c478bd9Sstevel@tonic-gate */ 53747c478bd9Sstevel@tonic-gate if (pt->p_file != NULL) 53757c478bd9Sstevel@tonic-gate (void) mdb_dis_select(pt_disasm(&pt->p_file->gf_ehdr)); 53767c478bd9Sstevel@tonic-gate else 53777c478bd9Sstevel@tonic-gate (void) mdb_dis_select(pt_disasm(NULL)); 53787c478bd9Sstevel@tonic-gate 53797c478bd9Sstevel@tonic-gate /* 53807c478bd9Sstevel@tonic-gate * Add each register described in the target ISA register description 53817c478bd9Sstevel@tonic-gate * list to our hash table of register descriptions and then add any 53827c478bd9Sstevel@tonic-gate * appropriate ISA-specific floating-point register descriptions. 53837c478bd9Sstevel@tonic-gate */ 53847c478bd9Sstevel@tonic-gate for (rdp = pt_regdesc; rdp->rd_name != NULL; rdp++) { 53857c478bd9Sstevel@tonic-gate (void) mdb_nv_insert(&pt->p_regs, rdp->rd_name, NULL, 53867c478bd9Sstevel@tonic-gate MDB_TGT_R_NVAL(rdp->rd_num, rdp->rd_flags), MDB_NV_RDONLY); 53877c478bd9Sstevel@tonic-gate } 53887c478bd9Sstevel@tonic-gate pt_addfpregs(t); 53897c478bd9Sstevel@tonic-gate 53907c478bd9Sstevel@tonic-gate /* 53917c478bd9Sstevel@tonic-gate * Certain important /proc structures may be of interest to mdb 53927c478bd9Sstevel@tonic-gate * modules and their dcmds. Export these using the xdata interface: 53937c478bd9Sstevel@tonic-gate */ 53947c478bd9Sstevel@tonic-gate (void) mdb_tgt_xdata_insert(t, "auxv", 53957c478bd9Sstevel@tonic-gate "procfs auxv_t array", pt_xd_auxv); 53967c478bd9Sstevel@tonic-gate (void) mdb_tgt_xdata_insert(t, "cred", 53977c478bd9Sstevel@tonic-gate "procfs prcred_t structure", pt_xd_cred); 53987c478bd9Sstevel@tonic-gate (void) mdb_tgt_xdata_insert(t, "ehdr", 53997c478bd9Sstevel@tonic-gate "executable file GElf_Ehdr structure", pt_xd_ehdr); 54007c478bd9Sstevel@tonic-gate (void) mdb_tgt_xdata_insert(t, "lwpstatus", 54017c478bd9Sstevel@tonic-gate "procfs lwpstatus_t array", pt_xd_lwpstatus); 54027c478bd9Sstevel@tonic-gate (void) mdb_tgt_xdata_insert(t, "pshandle", 54037c478bd9Sstevel@tonic-gate "libproc proc service API handle", pt_xd_pshandle); 54047c478bd9Sstevel@tonic-gate (void) mdb_tgt_xdata_insert(t, "psinfo", 54057c478bd9Sstevel@tonic-gate "procfs psinfo_t structure", pt_xd_psinfo); 54067c478bd9Sstevel@tonic-gate (void) mdb_tgt_xdata_insert(t, "pstatus", 54077c478bd9Sstevel@tonic-gate "procfs pstatus_t structure", pt_xd_pstatus); 54087c478bd9Sstevel@tonic-gate (void) mdb_tgt_xdata_insert(t, "utsname", 54097c478bd9Sstevel@tonic-gate "utsname structure", pt_xd_utsname); 54107c478bd9Sstevel@tonic-gate 54117c478bd9Sstevel@tonic-gate /* 54127c478bd9Sstevel@tonic-gate * Force a status update now so that we fill in t_status with the 54137c478bd9Sstevel@tonic-gate * latest information based on any successful grab. 54147c478bd9Sstevel@tonic-gate */ 54157c478bd9Sstevel@tonic-gate (void) mdb_tgt_status(t, &t->t_status); 54167c478bd9Sstevel@tonic-gate 54177c478bd9Sstevel@tonic-gate /* 54187c478bd9Sstevel@tonic-gate * If we're not examining a core file, trace SIGINT and all signals 54197c478bd9Sstevel@tonic-gate * that cause the process to dump core as part of our initialization. 54207c478bd9Sstevel@tonic-gate */ 54217c478bd9Sstevel@tonic-gate if ((t->t_pshandle != NULL && state != PS_DEAD && state != PS_IDLE) || 54227c478bd9Sstevel@tonic-gate (pt->p_file != NULL && pt->p_file->gf_ehdr.e_type == ET_EXEC)) { 54237c478bd9Sstevel@tonic-gate 54247c478bd9Sstevel@tonic-gate int tflag = MDB_TGT_SPEC_STICKY; /* default sigs are sticky */ 54257c478bd9Sstevel@tonic-gate 54267c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_signal(t, SIGINT, tflag, no_se_f, NULL); 54277c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_signal(t, SIGQUIT, tflag, no_se_f, NULL); 54287c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_signal(t, SIGILL, tflag, no_se_f, NULL); 54297c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_signal(t, SIGTRAP, tflag, no_se_f, NULL); 54307c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_signal(t, SIGABRT, tflag, no_se_f, NULL); 54317c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_signal(t, SIGEMT, tflag, no_se_f, NULL); 54327c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_signal(t, SIGFPE, tflag, no_se_f, NULL); 54337c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_signal(t, SIGBUS, tflag, no_se_f, NULL); 54347c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_signal(t, SIGSEGV, tflag, no_se_f, NULL); 54357c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_signal(t, SIGSYS, tflag, no_se_f, NULL); 54367c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_signal(t, SIGXCPU, tflag, no_se_f, NULL); 54377c478bd9Sstevel@tonic-gate (void) mdb_tgt_add_signal(t, SIGXFSZ, tflag, no_se_f, NULL); 54387c478bd9Sstevel@tonic-gate } 54397c478bd9Sstevel@tonic-gate 54407c478bd9Sstevel@tonic-gate /* 54417c478bd9Sstevel@tonic-gate * If we've grabbed a live process, establish our initial breakpoints 54427c478bd9Sstevel@tonic-gate * and librtld_db agent so we can track rtld activity. If FL_VCREATE 54437c478bd9Sstevel@tonic-gate * is set, this process was created by a previous instantiation of 54447c478bd9Sstevel@tonic-gate * the debugger, so reset pr_flags to kill it; otherwise we attached 54457c478bd9Sstevel@tonic-gate * to an already running process. Pgrab() has already set the PR_RLC 54467c478bd9Sstevel@tonic-gate * flag appropriately based on whether the process was stopped when we 54477c478bd9Sstevel@tonic-gate * attached. 54487c478bd9Sstevel@tonic-gate */ 54497c478bd9Sstevel@tonic-gate if (t->t_pshandle != NULL && state != PS_DEAD && state != PS_IDLE) { 54507c478bd9Sstevel@tonic-gate if (mdb.m_flags & MDB_FL_VCREATE) { 54517c478bd9Sstevel@tonic-gate (void) Punsetflags(t->t_pshandle, PR_RLC); 54527c478bd9Sstevel@tonic-gate (void) Psetflags(t->t_pshandle, PR_KLC); 54537c478bd9Sstevel@tonic-gate pt->p_rflags = PRELEASE_KILL; 54547c478bd9Sstevel@tonic-gate } else { 54557c478bd9Sstevel@tonic-gate (void) Punsetflags(t->t_pshandle, PR_KLC); 54567c478bd9Sstevel@tonic-gate } 54577c478bd9Sstevel@tonic-gate pt_post_attach(t); 54587c478bd9Sstevel@tonic-gate } 54597c478bd9Sstevel@tonic-gate 54607c478bd9Sstevel@tonic-gate /* 54617c478bd9Sstevel@tonic-gate * Initialize a local copy of the environment, which can be modified 54627c478bd9Sstevel@tonic-gate * before running the program. 54637c478bd9Sstevel@tonic-gate */ 54647c478bd9Sstevel@tonic-gate for (i = 0; mdb.m_env[i] != NULL; i++) 54657c478bd9Sstevel@tonic-gate pt_env_set(pt, mdb.m_env[i]); 54667c478bd9Sstevel@tonic-gate 54677c478bd9Sstevel@tonic-gate /* 54687c478bd9Sstevel@tonic-gate * If adb(1) compatibility mode is on, then print the appropriate 54697c478bd9Sstevel@tonic-gate * greeting message if we have grabbed a core file. 54707c478bd9Sstevel@tonic-gate */ 54717c478bd9Sstevel@tonic-gate if ((mdb.m_flags & MDB_FL_ADB) && t->t_pshandle != NULL && 54727c478bd9Sstevel@tonic-gate state == PS_DEAD) { 54737c478bd9Sstevel@tonic-gate const pstatus_t *psp = Pstatus(t->t_pshandle); 54747c478bd9Sstevel@tonic-gate int cursig = psp->pr_lwp.pr_cursig; 54757c478bd9Sstevel@tonic-gate char signame[SIG2STR_MAX]; 54767c478bd9Sstevel@tonic-gate 54777c478bd9Sstevel@tonic-gate mdb_printf("core file = %s -- program ``%s'' on platform %s\n", 54787c478bd9Sstevel@tonic-gate core_path, aout_path ? aout_path : "?", pt_platform(t)); 54797c478bd9Sstevel@tonic-gate 54807c478bd9Sstevel@tonic-gate if (cursig != 0 && sig2str(cursig, signame) == 0) 54817c478bd9Sstevel@tonic-gate mdb_printf("SIG%s: %s\n", signame, strsignal(cursig)); 54827c478bd9Sstevel@tonic-gate } 54837c478bd9Sstevel@tonic-gate 54847c478bd9Sstevel@tonic-gate return (0); 54857c478bd9Sstevel@tonic-gate 54867c478bd9Sstevel@tonic-gate err: 54877c478bd9Sstevel@tonic-gate pt_destroy(t); 54887c478bd9Sstevel@tonic-gate return (-1); 54897c478bd9Sstevel@tonic-gate } 5490