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