blob: 33994c11e65124d99a132dbe3b6d93a18f4ef9ff [file] [log] [blame]
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
casper004388e2006-05-01 11:23:49 -07005 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07007 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
Roger A. Faulkner8fd04b82010-02-28 18:42:20 -080021
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070022/*
Roger A. Faulkner8fd04b82010-02-28 18:42:20 -080023 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070024 * Use is subject to license terms.
25 */
Bryan Cantrill8f681262013-02-28 07:21:34 +000026/*
John Levon399ca3a2018-01-17 22:05:38 +000027 * Copyright 2018 Joyent, Inc.
Prakash Surya255ca532015-05-16 11:52:32 -070028 * Copyright (c) 2014 by Delphix. All rights reserved.
Bryan Cantrill8f681262013-02-28 07:21:34 +000029 */
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070030
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070031/*
32 * User Process Target
33 *
34 * The user process target is invoked when the -u or -p command-line options
35 * are used, or when an ELF executable file or ELF core file is specified on
36 * the command-line. This target is also selected by default when no target
37 * options are present. In this case, it defaults the executable name to
38 * "a.out". If no process or core file is currently attached, the target
39 * functions as a kind of virtual /dev/zero (in accordance with adb(1)
40 * semantics); reads from the virtual address space return zeroes and writes
41 * fail silently. The proc target itself is designed as a wrapper around the
42 * services provided by libproc.so: t->t_pshandle is set to the struct
43 * ps_prochandle pointer returned as a handle by libproc. The target also
44 * opens the executable file itself using the MDB GElf services, for
45 * interpreting the .symtab and .dynsym if no libproc handle has been
46 * initialized, and for handling i/o to and from the object file. Currently,
47 * the only ISA-dependent portions of the proc target are the $r and ::fpregs
48 * dcmds, the callbacks for t_next() and t_step_out(), and the list of named
49 * registers; these are linked in from the proc_isadep.c file for each ISA and
50 * called from the common code in this file.
51 *
52 * The user process target implements complete user process control using the
53 * facilities provided by libproc.so. The MDB execution control model and
54 * an overview of software event management is described in mdb_target.c. The
55 * proc target implements breakpoints by replacing the instruction of interest
56 * with a trap instruction, and then restoring the original instruction to step
57 * over the breakpoint. The idea of replacing program text with instructions
58 * that transfer control to the debugger dates back as far as 1951 [1]. When
59 * the target stops, we replace each breakpoint with the original instruction
60 * as part of the disarm operation. This means that no special processing is
61 * required for t_vread() because the instrumented instructions will never be
62 * seen by the debugger once the target stops. Some debuggers have improved
63 * start/stop performance by leaving breakpoint traps in place and then
64 * handling a read from a breakpoint address as a special case. Although this
65 * improves efficiency for a source-level debugger, it runs somewhat contrary
66 * to the philosophy of the low-level debugger. Since we remove the
67 * instructions, users can apply other external debugging tools to the process
68 * once it has stopped (e.g. the proc(1) tools) and not be misled by MDB
69 * instrumentation. The tracing of faults, signals, system calls, and
70 * watchpoints and general process inspection is implemented directly using
71 * the mechanisms provided by /proc, as described originally in [2] and [3].
72 *
73 * References
74 *
75 * [1] S. Gill, "The Diagnosis Of Mistakes In Programmes on the EDSAC",
76 * Proceedings of the Royal Society Series A Mathematical and Physical
77 * Sciences, Cambridge University Press, 206(1087), May 1951, pp. 538-554.
78 *
79 * [2] T.J. Killian, "Processes as Files", Proceedings of the USENIX Association
80 * Summer Conference, Salt Lake City, June 1984, pp. 203-207.
81 *
82 * [3] Roger Faulkner and Ron Gomes, "The Process File System and Process
83 * Model in UNIX System V", Proceedings of the USENIX Association
84 * Winter Conference, Dallas, January 1991, pp. 243-252.
85 */
86
87#include <mdb/mdb_proc.h>
88#include <mdb/mdb_disasm.h>
89#include <mdb/mdb_signal.h>
90#include <mdb/mdb_string.h>
91#include <mdb/mdb_module.h>
92#include <mdb/mdb_debug.h>
93#include <mdb/mdb_conf.h>
94#include <mdb/mdb_err.h>
95#include <mdb/mdb_types.h>
96#include <mdb/mdb.h>
97
98#include <sys/utsname.h>
99#include <sys/wait.h>
100#include <sys/stat.h>
101#include <termio.h>
102#include <signal.h>
casper004388e2006-05-01 11:23:49 -0700103#include <stdio_ext.h>
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700104#include <stdlib.h>
105#include <string.h>
106
107#define PC_FAKE -1UL /* illegal pc value unequal 0 */
Robert Mustacchif68770e2015-06-09 16:42:36 +0200108#define PANIC_BUFSIZE 1024
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700109
110static const char PT_EXEC_PATH[] = "a.out"; /* Default executable */
111static const char PT_CORE_PATH[] = "core"; /* Default core file */
112
113static const pt_ptl_ops_t proc_lwp_ops;
114static const pt_ptl_ops_t proc_tdb_ops;
115static const mdb_se_ops_t proc_brkpt_ops;
116static const mdb_se_ops_t proc_wapt_ops;
117
118static int pt_setrun(mdb_tgt_t *, mdb_tgt_status_t *, int);
119static void pt_activate_common(mdb_tgt_t *);
120static mdb_tgt_vespec_f pt_ignore_sig;
121static mdb_tgt_se_f pt_fork;
122static mdb_tgt_se_f pt_exec;
123
124static int pt_lookup_by_name_thr(mdb_tgt_t *, const char *,
125 const char *, GElf_Sym *, mdb_syminfo_t *, mdb_tgt_tid_t);
126static int tlsbase(mdb_tgt_t *, mdb_tgt_tid_t, Lmid_t, const char *,
127 psaddr_t *);
128
129/*
Bryan Cantrill8f681262013-02-28 07:21:34 +0000130 * When debugging postmortem, we don't resolve names as we may very well not
131 * be on a system on which those names resolve.
132 */
133#define PT_LIBPROC_RESOLVE(P) \
134 (!(mdb.m_flags & MDB_FL_LMRAW) && Pstate(P) != PS_DEAD)
135
136/*
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700137 * The Perror_printf() function interposes on the default, empty libproc
138 * definition. It will be called to report additional information on complex
139 * errors, such as a corrupt core file. We just pass the args to vwarn.
140 */
141/*ARGSUSED*/
142void
143Perror_printf(struct ps_prochandle *P, const char *format, ...)
144{
145 va_list alist;
146
147 va_start(alist, format);
148 vwarn(format, alist);
149 va_end(alist);
150}
151
152/*
153 * Open the specified i/o backend as the a.out executable file, and attempt to
154 * load its standard and dynamic symbol tables. Note that if mdb_gelf_create
155 * succeeds, io is assigned to p_fio and is automatically held by gelf_create.
156 */
157static mdb_gelf_file_t *
158pt_open_aout(mdb_tgt_t *t, mdb_io_t *io)
159{
160 pt_data_t *pt = t->t_data;
161 GElf_Sym s1, s2;
162
163 if ((pt->p_file = mdb_gelf_create(io, ET_NONE, GF_FILE)) == NULL)
164 return (NULL);
165
166 pt->p_symtab = mdb_gelf_symtab_create_file(pt->p_file,
167 SHT_SYMTAB, MDB_TGT_SYMTAB);
168 pt->p_dynsym = mdb_gelf_symtab_create_file(pt->p_file,
169 SHT_DYNSYM, MDB_TGT_DYNSYM);
170
171 /*
172 * If we've got an _start symbol with a zero size, prime the private
173 * symbol table with a copy of _start with its size set to the distance
174 * between _mcount and _start. We do this because DevPro has shipped
175 * the Intel crt1.o without proper .size directives for years, which
176 * precludes proper identification of _start in stack traces.
177 */
178 if (mdb_gelf_symtab_lookup_by_name(pt->p_dynsym, "_start", &s1,
179 NULL) == 0 && s1.st_size == 0 &&
180 GELF_ST_TYPE(s1.st_info) == STT_FUNC) {
181 if (mdb_gelf_symtab_lookup_by_name(pt->p_dynsym, "_mcount",
182 &s2, NULL) == 0 && GELF_ST_TYPE(s2.st_info) == STT_FUNC) {
183 s1.st_size = s2.st_value - s1.st_value;
184 mdb_gelf_symtab_insert(mdb.m_prsym, "_start", &s1);
185 }
186 }
187
188 pt->p_fio = io;
189 return (pt->p_file);
190}
191
192/*
193 * Destroy the symbol tables and GElf file object associated with p_fio. Note
194 * that we do not need to explicitly free p_fio: its reference count is
195 * automatically decremented by mdb_gelf_destroy, which will free it if needed.
196 */
197static void
198pt_close_aout(mdb_tgt_t *t)
199{
200 pt_data_t *pt = t->t_data;
201
202 if (pt->p_symtab != NULL) {
203 mdb_gelf_symtab_destroy(pt->p_symtab);
204 pt->p_symtab = NULL;
205 }
206
207 if (pt->p_dynsym != NULL) {
208 mdb_gelf_symtab_destroy(pt->p_dynsym);
209 pt->p_dynsym = NULL;
210 }
211
212 if (pt->p_file != NULL) {
213 mdb_gelf_destroy(pt->p_file);
214 pt->p_file = NULL;
215 }
216
217 mdb_gelf_symtab_delete(mdb.m_prsym, "_start", NULL);
218 pt->p_fio = NULL;
219}
220
Edward Pilatowicz95d62a62008-10-23 14:14:11 -0700221typedef struct tdb_mapping {
222 const char *tm_thr_lib;
223 const char *tm_db_dir;
224 const char *tm_db_name;
225} tdb_mapping_t;
226
227static const tdb_mapping_t tdb_map[] = {
228 { "/lwp/amd64/libthread.so", "/usr/lib/lwp/", "libthread_db.so" },
229 { "/lwp/sparcv9/libthread.so", "/usr/lib/lwp/", "libthread_db.so" },
230 { "/lwp/libthread.so", "/usr/lib/lwp/", "libthread_db.so" },
231 { "/libthread.so", "/lib/", "libthread_db.so" },
232 { "/libc_hwcap", "/lib/", "libc_db.so" },
233 { "/libc.so", "/lib/", "libc_db.so" }
234};
235
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700236/*
237 * Pobject_iter callback that we use to search for the presence of libthread in
238 * order to load the corresponding libthread_db support. We derive the
239 * libthread_db path dynamically based on the libthread path. If libthread is
240 * found, this function returns 1 (and thus Pobject_iter aborts and returns 1)
241 * regardless of whether it was successful in loading the libthread_db support.
242 * If we iterate over all objects and no libthread is found, 0 is returned.
243 * Since libthread_db support was then merged into libc_db, we load either
244 * libc_db or libthread_db, depending on which library we see first.
245 */
246/*ARGSUSED*/
247static int
248thr_check(mdb_tgt_t *t, const prmap_t *pmp, const char *name)
249{
250 pt_data_t *pt = t->t_data;
251 const mdb_tdb_ops_t *ops;
Edward Pilatowicz95d62a62008-10-23 14:14:11 -0700252 char *p;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700253
Edward Pilatowicz95d62a62008-10-23 14:14:11 -0700254 char path[MAXPATHLEN];
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700255
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700256 int libn;
257
258 if (name == NULL)
259 return (0); /* no rtld_db object name; keep going */
260
Edward Pilatowicz95d62a62008-10-23 14:14:11 -0700261 for (libn = 0; libn < sizeof (tdb_map) / sizeof (tdb_map[0]); libn++) {
262 if ((p = strstr(name, tdb_map[libn].tm_thr_lib)) != NULL)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700263 break;
264 }
265
266 if (p == NULL)
267 return (0); /* no match; keep going */
268
Edward Pilatowicz95d62a62008-10-23 14:14:11 -0700269 path[0] = '\0';
270 (void) strlcat(path, mdb.m_root, sizeof (path));
271 (void) strlcat(path, tdb_map[libn].tm_db_dir, sizeof (path));
272#if !defined(_ILP32)
273 (void) strlcat(path, "64/", sizeof (path));
274#endif /* !_ILP32 */
275 (void) strlcat(path, tdb_map[libn].tm_db_name, sizeof (path));
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700276
Edward Pilatowicz95d62a62008-10-23 14:14:11 -0700277 /* Append the trailing library version number. */
278 (void) strlcat(path, strrchr(name, '.'), sizeof (path));
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700279
280 if ((ops = mdb_tdb_load(path)) == NULL) {
281 if (libn != 0 || errno != ENOENT)
282 warn("failed to load %s", path);
283 goto err;
284 }
285
286 if (ops == pt->p_tdb_ops)
287 return (1); /* no changes needed */
288
289 PTL_DTOR(t);
290 pt->p_tdb_ops = ops;
291 pt->p_ptl_ops = &proc_tdb_ops;
292 pt->p_ptl_hdl = NULL;
293
294 if (PTL_CTOR(t) == -1) {
295 warn("failed to initialize %s", path);
296 goto err;
297 }
298
299 mdb_dprintf(MDB_DBG_TGT, "loaded %s for debugging %s\n", path, name);
300 (void) mdb_tgt_status(t, &t->t_status);
301 return (1);
302err:
303 PTL_DTOR(t);
304 pt->p_tdb_ops = NULL;
305 pt->p_ptl_ops = &proc_lwp_ops;
306 pt->p_ptl_hdl = NULL;
307
308 if (libn != 0 || errno != ENOENT) {
309 warn("warning: debugger will only be able to "
310 "examine raw LWPs\n");
311 }
312
313 (void) mdb_tgt_status(t, &t->t_status);
314 return (1);
315}
316
317/*
318 * Whenever the link map is consistent following an add or delete event, we ask
319 * libproc to update its mappings, check to see if we need to load libthread_db,
320 * and then update breakpoints which have been mapped or unmapped.
321 */
322/*ARGSUSED*/
323static void
324pt_rtld_event(mdb_tgt_t *t, int vid, void *private)
325{
326 struct ps_prochandle *P = t->t_pshandle;
327 pt_data_t *pt = t->t_data;
328 rd_event_msg_t rdm;
Edward Pilatowicz95d62a62008-10-23 14:14:11 -0700329 int docontinue = 1;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700330
331 if (rd_event_getmsg(pt->p_rtld, &rdm) == RD_OK) {
332
333 mdb_dprintf(MDB_DBG_TGT, "rtld event type 0x%x state 0x%x\n",
334 rdm.type, rdm.u.state);
335
336 if (rdm.type == RD_DLACTIVITY && rdm.u.state == RD_CONSISTENT) {
337 mdb_sespec_t *sep, *nsep = mdb_list_next(&t->t_active);
338 pt_brkpt_t *ptb;
339
340 Pupdate_maps(P);
341
Edward Pilatowicz95d62a62008-10-23 14:14:11 -0700342 if (Pobject_iter(P, (proc_map_f *)thr_check, t) == 0 &&
343 pt->p_ptl_ops != &proc_lwp_ops) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700344 mdb_dprintf(MDB_DBG_TGT, "unloading thread_db "
345 "support after dlclose\n");
346 PTL_DTOR(t);
347 pt->p_tdb_ops = NULL;
348 pt->p_ptl_ops = &proc_lwp_ops;
349 pt->p_ptl_hdl = NULL;
350 (void) mdb_tgt_status(t, &t->t_status);
351 }
352
353 for (sep = nsep; sep != NULL; sep = nsep) {
354 nsep = mdb_list_next(sep);
355 ptb = sep->se_data;
356
357 if (sep->se_ops == &proc_brkpt_ops &&
358 Paddr_to_map(P, ptb->ptb_addr) == NULL)
359 mdb_tgt_sespec_idle_one(t, sep,
360 EMDB_NOMAP);
361 }
362
363 if (!mdb_tgt_sespec_activate_all(t) &&
364 (mdb.m_flags & MDB_FL_BPTNOSYMSTOP) &&
365 pt->p_rtld_finished) {
366 /*
367 * We weren't able to activate the breakpoints.
368 * If so requested, we'll return without
369 * calling continue, thus throwing the user into
370 * the debugger.
371 */
372 docontinue = 0;
373 }
374
375 if (pt->p_rdstate == PT_RD_ADD)
376 pt->p_rdstate = PT_RD_CONSIST;
377 }
378
379 if (rdm.type == RD_PREINIT)
380 (void) mdb_tgt_sespec_activate_all(t);
381
382 if (rdm.type == RD_POSTINIT) {
383 pt->p_rtld_finished = TRUE;
384 if (!mdb_tgt_sespec_activate_all(t) &&
385 (mdb.m_flags & MDB_FL_BPTNOSYMSTOP)) {
386 /*
387 * Now that rtld has been initialized, we
388 * should be able to initialize all deferred
389 * breakpoints. If we can't, don't let the
390 * target continue.
391 */
392 docontinue = 0;
393 }
394 }
395
396 if (rdm.type == RD_DLACTIVITY && rdm.u.state == RD_ADD &&
397 pt->p_rtld_finished)
398 pt->p_rdstate = MAX(pt->p_rdstate, PT_RD_ADD);
399 }
400
401 if (docontinue)
402 (void) mdb_tgt_continue(t, NULL);
403}
404
405static void
406pt_post_attach(mdb_tgt_t *t)
407{
408 struct ps_prochandle *P = t->t_pshandle;
409 const lwpstatus_t *psp = &Pstatus(P)->pr_lwp;
410 pt_data_t *pt = t->t_data;
411 int hflag = MDB_TGT_SPEC_HIDDEN;
412
413 mdb_dprintf(MDB_DBG_TGT, "attach pr_flags=0x%x pr_why=%d pr_what=%d\n",
414 psp->pr_flags, psp->pr_why, psp->pr_what);
415
416 /*
417 * When we grab a process, the initial setting of p_rtld_finished
418 * should be false if the process was just created by exec; otherwise
419 * we permit unscoped references to resolve because we do not know how
420 * far the process has proceeded through linker initialization.
421 */
422 if ((psp->pr_flags & PR_ISTOP) && psp->pr_why == PR_SYSEXIT &&
Roger A. Faulkner8fd04b82010-02-28 18:42:20 -0800423 psp->pr_errno == 0 && psp->pr_what == SYS_execve) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700424 if (mdb.m_target == NULL) {
425 warn("target performed exec of %s\n",
426 IOP_NAME(pt->p_fio));
427 }
428 pt->p_rtld_finished = FALSE;
429 } else
430 pt->p_rtld_finished = TRUE;
431
432 /*
433 * When we grab a process, if it is stopped by job control and part of
434 * the same session (i.e. same controlling tty), set MDB_FL_JOBCTL so
435 * we will know to bring it to the foreground when we continue it.
436 */
437 if (mdb.m_term != NULL && (psp->pr_flags & PR_STOPPED) &&
438 psp->pr_why == PR_JOBCONTROL && getsid(0) == Pstatus(P)->pr_sid)
439 mdb.m_flags |= MDB_FL_JOBCTL;
440
441 /*
442 * When we grab control of a live process, set F_RDWR so that the
443 * target layer permits writes to the target's address space.
444 */
445 t->t_flags |= MDB_TGT_F_RDWR;
446
447 (void) Pfault(P, FLTBPT, TRUE); /* always trace breakpoints */
448 (void) Pfault(P, FLTWATCH, TRUE); /* always trace watchpoints */
449 (void) Pfault(P, FLTTRACE, TRUE); /* always trace single-step */
450
451 (void) Punsetflags(P, PR_ASYNC); /* require synchronous mode */
452 (void) Psetflags(P, PR_BPTADJ); /* always adjust eip on x86 */
453 (void) Psetflags(P, PR_FORK); /* inherit tracing on fork */
454
455 /*
456 * Install event specifiers to track fork and exec activities:
457 */
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700458 (void) mdb_tgt_add_sysexit(t, SYS_vfork, hflag, pt_fork, NULL);
raf657b1f32006-12-13 11:41:29 -0800459 (void) mdb_tgt_add_sysexit(t, SYS_forksys, hflag, pt_fork, NULL);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700460 (void) mdb_tgt_add_sysexit(t, SYS_execve, hflag, pt_exec, NULL);
461
462 /*
463 * Attempt to instantiate the librtld_db agent and set breakpoints
464 * to track rtld activity. We will legitimately fail to instantiate
465 * the rtld_db agent if the target is statically linked.
466 */
467 if (pt->p_rtld == NULL && (pt->p_rtld = Prd_agent(P)) != NULL) {
468 rd_notify_t rdn;
469 rd_err_e err;
470
471 if ((err = rd_event_enable(pt->p_rtld, TRUE)) != RD_OK) {
472 warn("failed to enable rtld_db event tracing: %s\n",
473 rd_errstr(err));
474 goto out;
475 }
476
477 if ((err = rd_event_addr(pt->p_rtld, RD_PREINIT,
478 &rdn)) == RD_OK && rdn.type == RD_NOTIFY_BPT) {
479 (void) mdb_tgt_add_vbrkpt(t, rdn.u.bptaddr,
480 hflag, pt_rtld_event, NULL);
481 } else {
482 warn("failed to install rtld_db preinit tracing: %s\n",
483 rd_errstr(err));
484 }
485
486 if ((err = rd_event_addr(pt->p_rtld, RD_POSTINIT,
487 &rdn)) == RD_OK && rdn.type == RD_NOTIFY_BPT) {
488 (void) mdb_tgt_add_vbrkpt(t, rdn.u.bptaddr,
489 hflag, pt_rtld_event, NULL);
490 } else {
491 warn("failed to install rtld_db postinit tracing: %s\n",
492 rd_errstr(err));
493 }
494
495 if ((err = rd_event_addr(pt->p_rtld, RD_DLACTIVITY,
496 &rdn)) == RD_OK && rdn.type == RD_NOTIFY_BPT) {
497 (void) mdb_tgt_add_vbrkpt(t, rdn.u.bptaddr,
498 hflag, pt_rtld_event, NULL);
499 } else {
500 warn("failed to install rtld_db activity tracing: %s\n",
501 rd_errstr(err));
502 }
503 }
504out:
505 Pupdate_maps(P);
506 Psync(P);
507
508 /*
509 * If librtld_db failed to initialize due to an error or because we are
510 * debugging a statically linked executable, allow unscoped references.
511 */
512 if (pt->p_rtld == NULL)
513 pt->p_rtld_finished = TRUE;
514
515 (void) mdb_tgt_sespec_activate_all(t);
516}
517
518/*ARGSUSED*/
519static int
520pt_vespec_delete(mdb_tgt_t *t, void *private, int id, void *data)
521{
522 if (id < 0) {
523 ASSERT(data == NULL); /* we don't use any ve_data */
524 (void) mdb_tgt_vespec_delete(t, id);
525 }
526 return (0);
527}
528
529static void
530pt_pre_detach(mdb_tgt_t *t, int clear_matched)
531{
532 const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp;
533 pt_data_t *pt = t->t_data;
534 long cmd = 0;
535
536 /*
537 * If we are about to release the process and it is stopped on a traced
538 * SIGINT, breakpoint fault, single-step fault, or watchpoint, make
539 * sure to clear this event prior to releasing the process so that it
540 * does not subsequently reissue the fault and die from SIGTRAP.
541 */
542 if (psp->pr_flags & PR_ISTOP) {
543 if (psp->pr_why == PR_FAULTED && (psp->pr_what == FLTBPT ||
544 psp->pr_what == FLTTRACE || psp->pr_what == FLTWATCH))
545 cmd = PCCFAULT;
546 else if (psp->pr_why == PR_SIGNALLED && psp->pr_what == SIGINT)
547 cmd = PCCSIG;
548
549 if (cmd != 0)
550 (void) write(Pctlfd(t->t_pshandle), &cmd, sizeof (cmd));
551 }
552
553 if (Pstate(t->t_pshandle) == PS_UNDEAD)
554 (void) waitpid(Pstatus(t->t_pshandle)->pr_pid, NULL, WNOHANG);
555
556 (void) mdb_tgt_vespec_iter(t, pt_vespec_delete, NULL);
557 mdb_tgt_sespec_idle_all(t, EMDB_NOPROC, clear_matched);
558
559 if (pt->p_fio != pt->p_aout_fio) {
560 pt_close_aout(t);
561 (void) pt_open_aout(t, pt->p_aout_fio);
562 }
563
564 PTL_DTOR(t);
565 pt->p_tdb_ops = NULL;
566 pt->p_ptl_ops = &proc_lwp_ops;
567 pt->p_ptl_hdl = NULL;
568
569 pt->p_rtld = NULL;
570 pt->p_signal = 0;
571 pt->p_rtld_finished = FALSE;
572 pt->p_rdstate = PT_RD_NONE;
573}
574
575static void
576pt_release_parents(mdb_tgt_t *t)
577{
578 struct ps_prochandle *P = t->t_pshandle;
579 pt_data_t *pt = t->t_data;
580
581 mdb_sespec_t *sep;
582 pt_vforkp_t *vfp;
583
584 while ((vfp = mdb_list_next(&pt->p_vforkp)) != NULL) {
585 mdb_dprintf(MDB_DBG_TGT, "releasing vfork parent %d\n",
586 (int)Pstatus(vfp->p_pshandle)->pr_pid);
587
588 /*
589 * To release vfork parents, we must also wipe out any armed
590 * events in the parent by switching t_pshandle and calling
591 * se_disarm(). Do not change states or lose the matched list.
592 */
593 t->t_pshandle = vfp->p_pshandle;
594
595 for (sep = mdb_list_next(&t->t_active); sep != NULL;
596 sep = mdb_list_next(sep)) {
597 if (sep->se_state == MDB_TGT_SPEC_ARMED)
598 (void) sep->se_ops->se_disarm(t, sep);
599 }
600
601 t->t_pshandle = P;
602
603 Prelease(vfp->p_pshandle, PRELEASE_CLEAR);
604 mdb_list_delete(&pt->p_vforkp, vfp);
605 mdb_free(vfp, sizeof (pt_vforkp_t));
606 }
607}
608
609/*ARGSUSED*/
610static void
611pt_fork(mdb_tgt_t *t, int vid, void *private)
612{
613 struct ps_prochandle *P = t->t_pshandle;
614 const lwpstatus_t *psp = &Pstatus(P)->pr_lwp;
615 pt_data_t *pt = t->t_data;
616 mdb_sespec_t *sep;
617
618 int follow_parent = mdb.m_forkmode != MDB_FM_CHILD;
raf657b1f32006-12-13 11:41:29 -0800619 int is_vfork = (psp->pr_what == SYS_vfork ||
620 (psp->pr_what == SYS_forksys && psp->pr_sysarg[0] == 2));
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700621
622 struct ps_prochandle *C;
623 const lwpstatus_t *csp;
624 char sysname[32];
625 int gcode;
626 char c;
627
628 mdb_dprintf(MDB_DBG_TGT, "parent %s: errno=%d rv1=%ld rv2=%ld\n",
629 proc_sysname(psp->pr_what, sysname, sizeof (sysname)),
630 psp->pr_errno, psp->pr_rval1, psp->pr_rval2);
631
632 if (psp->pr_errno != 0) {
633 (void) mdb_tgt_continue(t, NULL);
634 return; /* fork failed */
635 }
636
637 /*
638 * If forkmode is ASK and stdout is a terminal, then ask the user to
639 * explicitly set the fork behavior for this particular fork.
640 */
641 if (mdb.m_forkmode == MDB_FM_ASK && mdb.m_term != NULL) {
642 mdb_iob_printf(mdb.m_err, "%s: %s detected: follow (p)arent "
643 "or (c)hild? ", mdb.m_pname, sysname);
644 mdb_iob_flush(mdb.m_err);
645
646 while (IOP_READ(mdb.m_term, &c, sizeof (c)) == sizeof (c)) {
647 if (c == 'P' || c == 'p') {
648 mdb_iob_printf(mdb.m_err, "%c\n", c);
649 follow_parent = TRUE;
650 break;
651 } else if (c == 'C' || c == 'c') {
652 mdb_iob_printf(mdb.m_err, "%c\n", c);
653 follow_parent = FALSE;
654 break;
655 }
656 }
657 }
658
659 /*
660 * The parent is now stopped on exit from its fork call. We must now
661 * grab the child on its return from fork in order to manipulate it.
662 */
663 if ((C = Pgrab(psp->pr_rval1, PGRAB_RETAIN, &gcode)) == NULL) {
664 warn("failed to grab forked child process %ld: %s\n",
665 psp->pr_rval1, Pgrab_error(gcode));
666 return; /* just stop if we failed to grab the child */
667 }
668
669 /*
670 * We may have grabbed the child and stopped it prematurely before it
671 * stopped on exit from fork. If so, wait up to 1 sec for it to settle.
672 */
673 if (Pstatus(C)->pr_lwp.pr_why != PR_SYSEXIT)
674 (void) Pwait(C, MILLISEC);
675
676 csp = &Pstatus(C)->pr_lwp;
677
raf657b1f32006-12-13 11:41:29 -0800678 if (csp->pr_why != PR_SYSEXIT ||
Roger A. Faulkner8fd04b82010-02-28 18:42:20 -0800679 (csp->pr_what != SYS_vfork && csp->pr_what != SYS_forksys)) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700680 warn("forked child process %ld did not stop on exit from "
681 "fork as expected\n", psp->pr_rval1);
682 }
683
684 warn("target forked child process %ld (debugger following %s)\n",
685 psp->pr_rval1, follow_parent ? "parent" : "child");
686
687 (void) Punsetflags(C, PR_ASYNC); /* require synchronous mode */
688 (void) Psetflags(C, PR_BPTADJ); /* always adjust eip on x86 */
689 (void) Prd_agent(C); /* initialize librtld_db */
690
691 /*
692 * At the time pt_fork() is called, the target event engine has already
693 * disarmed the specifiers on the active list, clearing out events in
694 * the parent process. However, this means that events that change
695 * the address space (e.g. breakpoints) have not been effectively
696 * disarmed in the child since its address space reflects the state of
697 * the process at the time of fork when events were armed. We must
698 * therefore handle this as a special case and re-invoke the disarm
699 * callback of each active specifier to clean out the child process.
700 */
701 if (!is_vfork) {
702 for (t->t_pshandle = C, sep = mdb_list_next(&t->t_active);
703 sep != NULL; sep = mdb_list_next(sep)) {
704 if (sep->se_state == MDB_TGT_SPEC_ACTIVE)
705 (void) sep->se_ops->se_disarm(t, sep);
706 }
707
708 t->t_pshandle = P; /* restore pshandle to parent */
709 }
710
711 /*
712 * If we're following the parent process, we need to temporarily change
713 * t_pshandle to refer to the child handle C so that we can clear out
714 * all the events in the child prior to releasing it below. If we are
715 * tracing a vfork, we also need to explicitly wait for the child to
716 * exec, exit, or die before we can reset and continue the parent. We
717 * avoid having to deal with the vfork child forking again by clearing
718 * PR_FORK and setting PR_RLC; if it does fork it will effectively be
719 * released from our control and we will continue following the parent.
720 */
721 if (follow_parent) {
722 if (is_vfork) {
723 mdb_tgt_status_t status;
724
725 ASSERT(psp->pr_flags & PR_VFORKP);
726 mdb_tgt_sespec_idle_all(t, EBUSY, FALSE);
727 t->t_pshandle = C;
728
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700729 (void) Psysexit(C, SYS_execve, TRUE);
730
731 (void) Punsetflags(C, PR_FORK | PR_KLC);
732 (void) Psetflags(C, PR_RLC);
733
734 do {
735 if (pt_setrun(t, &status, 0) == -1 ||
736 status.st_state == MDB_TGT_UNDEAD ||
737 status.st_state == MDB_TGT_LOST)
738 break; /* failure or process died */
739
740 } while (csp->pr_why != PR_SYSEXIT ||
Roger A. Faulkner8fd04b82010-02-28 18:42:20 -0800741 csp->pr_errno != 0 || csp->pr_what != SYS_execve);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700742 } else
743 t->t_pshandle = C;
744 }
745
746 /*
747 * If we are following the child, destroy any active libthread_db
748 * handle before we release the parent process.
749 */
750 if (!follow_parent) {
751 PTL_DTOR(t);
752 pt->p_tdb_ops = NULL;
753 pt->p_ptl_ops = &proc_lwp_ops;
754 pt->p_ptl_hdl = NULL;
755 }
756
757 /*
758 * Idle all events to make sure the address space and tracing flags are
759 * restored, and then release the process we are not tracing. If we
760 * are following the child of a vfork, we push the parent's pshandle
761 * on to a list of vfork parents to be released when we exec or exit.
762 */
763 if (is_vfork && !follow_parent) {
764 pt_vforkp_t *vfp = mdb_alloc(sizeof (pt_vforkp_t), UM_SLEEP);
765
766 ASSERT(psp->pr_flags & PR_VFORKP);
767 vfp->p_pshandle = P;
768 mdb_list_append(&pt->p_vforkp, vfp);
769 mdb_tgt_sespec_idle_all(t, EBUSY, FALSE);
770
771 } else {
772 mdb_tgt_sespec_idle_all(t, EBUSY, FALSE);
773 Prelease(t->t_pshandle, PRELEASE_CLEAR);
774 if (!follow_parent)
775 pt_release_parents(t);
776 }
777
778 /*
779 * Now that all the hard stuff is done, switch t_pshandle back to the
780 * process we are following and reset our events to the ACTIVE state.
781 * If we are following the child, reset the libthread_db handle as well
782 * as the rtld agent.
783 */
784 if (follow_parent)
785 t->t_pshandle = P;
786 else {
787 t->t_pshandle = C;
788 pt->p_rtld = Prd_agent(C);
Edward Pilatowicz95d62a62008-10-23 14:14:11 -0700789 (void) Pobject_iter(t->t_pshandle, (proc_map_f *)thr_check, t);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700790 }
791
792 (void) mdb_tgt_sespec_activate_all(t);
793 (void) mdb_tgt_continue(t, NULL);
794}
795
796/*ARGSUSED*/
797static void
798pt_exec(mdb_tgt_t *t, int vid, void *private)
799{
800 struct ps_prochandle *P = t->t_pshandle;
801 const pstatus_t *psp = Pstatus(P);
802 pt_data_t *pt = t->t_data;
803 int follow_exec = mdb.m_execmode == MDB_EM_FOLLOW;
804 pid_t pid = psp->pr_pid;
805
806 char execname[MAXPATHLEN];
807 mdb_sespec_t *sep, *nsep;
808 mdb_io_t *io;
809 char c;
810
811 mdb_dprintf(MDB_DBG_TGT, "exit from %s: errno=%d\n", proc_sysname(
812 psp->pr_lwp.pr_what, execname, sizeof (execname)),
813 psp->pr_lwp.pr_errno);
814
815 if (psp->pr_lwp.pr_errno != 0) {
816 (void) mdb_tgt_continue(t, NULL);
817 return; /* exec failed */
818 }
819
820 /*
821 * If execmode is ASK and stdout is a terminal, then ask the user to
822 * explicitly set the exec behavior for this particular exec. If
823 * Pstate() still shows PS_LOST, we are being called from pt_setrun()
824 * directly and therefore we must resume the terminal since it is still
825 * in the suspended state as far as tgt_continue() is concerned.
826 */
827 if (mdb.m_execmode == MDB_EM_ASK && mdb.m_term != NULL) {
828 if (Pstate(P) == PS_LOST)
829 IOP_RESUME(mdb.m_term);
830
831 mdb_iob_printf(mdb.m_err, "%s: %s detected: (f)ollow new "
832 "program or (s)top? ", mdb.m_pname, execname);
833 mdb_iob_flush(mdb.m_err);
834
835 while (IOP_READ(mdb.m_term, &c, sizeof (c)) == sizeof (c)) {
836 if (c == 'F' || c == 'f') {
837 mdb_iob_printf(mdb.m_err, "%c\n", c);
838 follow_exec = TRUE;
839 break;
840 } else if (c == 'S' || c == 's') {
841 mdb_iob_printf(mdb.m_err, "%c\n", c);
842 follow_exec = FALSE;
843 break;
844 }
845 }
846
847 if (Pstate(P) == PS_LOST)
848 IOP_SUSPEND(mdb.m_term);
849 }
850
851 pt_release_parents(t); /* release any waiting vfork parents */
852 pt_pre_detach(t, FALSE); /* remove our breakpoints and idle events */
853 Preset_maps(P); /* libproc must delete mappings and symtabs */
854 pt_close_aout(t); /* free pt symbol tables and GElf file data */
855
856 /*
857 * If we lost control of the process across the exec and are not able
858 * to reopen it, we have no choice but to clear the matched event list
859 * and wait for the user to quit or otherwise release the process.
860 */
861 if (Pstate(P) == PS_LOST && Preopen(P) == -1) {
862 int error = errno;
863
864 warn("lost control of PID %d due to exec of %s executable\n",
865 (int)pid, error == EOVERFLOW ? "64-bit" : "set-id");
866
867 for (sep = t->t_matched; sep != T_SE_END; sep = nsep) {
868 nsep = sep->se_matched;
869 sep->se_matched = NULL;
870 mdb_tgt_sespec_rele(t, sep);
871 }
872
873 if (error != EOVERFLOW)
874 return; /* just stop if we exec'd a set-id executable */
875 }
876
877 if (Pstate(P) != PS_LOST) {
878 if (Pexecname(P, execname, sizeof (execname)) == NULL) {
879 (void) mdb_iob_snprintf(execname, sizeof (execname),
880 "/proc/%d/object/a.out", (int)pid);
881 }
882
883 if (follow_exec == FALSE || psp->pr_dmodel == PR_MODEL_NATIVE)
884 warn("target performed exec of %s\n", execname);
885
886 io = mdb_fdio_create_path(NULL, execname, pt->p_oflags, 0);
887 if (io == NULL) {
888 warn("failed to open %s", execname);
889 warn("a.out symbol tables will not be available\n");
890 } else if (pt_open_aout(t, io) == NULL) {
891 (void) mdb_dis_select(pt_disasm(NULL));
892 mdb_io_destroy(io);
893 } else
894 (void) mdb_dis_select(pt_disasm(&pt->p_file->gf_ehdr));
895 }
896
897 /*
898 * We reset our libthread_db state here, but deliberately do NOT call
899 * PTL_DTOR because we do not want to call libthread_db's td_ta_delete.
900 * This interface is hopelessly broken in that it writes to the process
901 * address space (which we do not want it to do after an exec) and it
902 * doesn't bother deallocating any of its storage anyway.
903 */
904 pt->p_tdb_ops = NULL;
905 pt->p_ptl_ops = &proc_lwp_ops;
906 pt->p_ptl_hdl = NULL;
907
908 if (follow_exec && psp->pr_dmodel != PR_MODEL_NATIVE) {
909 const char *argv[3];
910 char *state, *env;
911 char pidarg[16];
912 size_t envlen;
913
914 if (realpath(getexecname(), execname) == NULL) {
915 warn("cannot follow PID %d -- failed to resolve "
916 "debugger pathname for re-exec", (int)pid);
917 return;
918 }
919
920 warn("restarting debugger to follow PID %d ...\n", (int)pid);
921 mdb_dprintf(MDB_DBG_TGT, "re-exec'ing %s\n", execname);
922
923 (void) mdb_snprintf(pidarg, sizeof (pidarg), "-p%d", (int)pid);
924
925 state = mdb_get_config();
926 envlen = strlen(MDB_CONFIG_ENV_VAR) + 1 + strlen(state) + 1;
927 env = mdb_alloc(envlen, UM_SLEEP);
Surya Prakki80148892009-11-11 21:59:42 -0800928 (void) snprintf(env, envlen,
929 "%s=%s", MDB_CONFIG_ENV_VAR, state);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700930
931 (void) putenv(env);
932
933 argv[0] = mdb.m_pname;
934 argv[1] = pidarg;
935 argv[2] = NULL;
936
937 if (mdb.m_term != NULL)
938 IOP_SUSPEND(mdb.m_term);
939
940 Prelease(P, PRELEASE_CLEAR | PRELEASE_HANG);
941 (void) execv(execname, (char *const *)argv);
942 warn("failed to re-exec debugger");
943
944 if (mdb.m_term != NULL)
945 IOP_RESUME(mdb.m_term);
946
947 t->t_pshandle = pt->p_idlehandle;
948 return;
949 }
950
951 pt_post_attach(t); /* install tracing flags and activate events */
952 pt_activate_common(t); /* initialize librtld_db and libthread_db */
953
954 if (psp->pr_dmodel != PR_MODEL_NATIVE && mdb.m_term != NULL) {
955 warn("loadable dcmds will not operate on non-native %d-bit "
956 "data model\n", psp->pr_dmodel == PR_MODEL_ILP32 ? 32 : 64);
957 warn("use ::release -a and then run mdb -p %d to restart "
958 "debugger\n", (int)pid);
959 }
960
961 if (follow_exec)
962 (void) mdb_tgt_continue(t, NULL);
963}
964
965static int
966pt_setflags(mdb_tgt_t *t, int flags)
967{
968 pt_data_t *pt = t->t_data;
969
970 if ((flags ^ t->t_flags) & MDB_TGT_F_RDWR) {
971 int mode = (flags & MDB_TGT_F_RDWR) ? O_RDWR : O_RDONLY;
972 mdb_io_t *io;
973
974 if (pt->p_fio == NULL)
975 return (set_errno(EMDB_NOEXEC));
976
977 io = mdb_fdio_create_path(NULL, IOP_NAME(pt->p_fio), mode, 0);
978
979 if (io == NULL)
980 return (-1); /* errno is set for us */
981
982 t->t_flags = (t->t_flags & ~MDB_TGT_F_RDWR) |
983 (flags & MDB_TGT_F_RDWR);
984
985 pt->p_fio = mdb_io_hold(io);
986 mdb_io_rele(pt->p_file->gf_io);
987 pt->p_file->gf_io = pt->p_fio;
988 }
989
990 if (flags & MDB_TGT_F_FORCE) {
991 t->t_flags |= MDB_TGT_F_FORCE;
992 pt->p_gflags |= PGRAB_FORCE;
993 }
994
995 return (0);
996}
997
998/*ARGSUSED*/
999static int
1000pt_frame(void *arglim, uintptr_t pc, uint_t argc, const long *argv,
1001 const mdb_tgt_gregset_t *gregs)
1002{
1003 argc = MIN(argc, (uint_t)(uintptr_t)arglim);
1004 mdb_printf("%a(", pc);
1005
1006 if (argc != 0) {
1007 mdb_printf("%lr", *argv++);
1008 for (argc--; argc != 0; argc--)
1009 mdb_printf(", %lr", *argv++);
1010 }
1011
1012 mdb_printf(")\n");
1013 return (0);
1014}
1015
1016static int
1017pt_framev(void *arglim, uintptr_t pc, uint_t argc, const long *argv,
1018 const mdb_tgt_gregset_t *gregs)
1019{
1020 argc = MIN(argc, (uint_t)(uintptr_t)arglim);
1021#if defined(__i386) || defined(__amd64)
1022 mdb_printf("%0?lr %a(", gregs->gregs[R_FP], pc);
1023#else
1024 mdb_printf("%0?lr %a(", gregs->gregs[R_SP], pc);
1025#endif
1026 if (argc != 0) {
1027 mdb_printf("%lr", *argv++);
1028 for (argc--; argc != 0; argc--)
1029 mdb_printf(", %lr", *argv++);
1030 }
1031
1032 mdb_printf(")\n");
1033 return (0);
1034}
1035
1036static int
1037pt_framer(void *arglim, uintptr_t pc, uint_t argc, const long *argv,
1038 const mdb_tgt_gregset_t *gregs)
1039{
1040 if (pt_frameregs(arglim, pc, argc, argv, gregs, pc == PC_FAKE) == -1) {
1041 /*
1042 * Use verbose format if register format is not supported.
1043 */
1044 return (pt_framev(arglim, pc, argc, argv, gregs));
1045 }
1046
1047 return (0);
1048}
1049
1050/*ARGSUSED*/
1051static int
1052pt_stack_common(uintptr_t addr, uint_t flags, int argc,
1053 const mdb_arg_t *argv, mdb_tgt_stack_f *func, prgreg_t saved_pc)
1054{
1055 void *arg = (void *)(uintptr_t)mdb.m_nargs;
1056 mdb_tgt_t *t = mdb.m_target;
1057 mdb_tgt_gregset_t gregs;
1058
1059 if (argc != 0) {
1060 if (argv->a_type == MDB_TYPE_CHAR || argc > 1)
1061 return (DCMD_USAGE);
1062
1063 if (argv->a_type == MDB_TYPE_STRING)
1064 arg = (void *)(uintptr_t)mdb_strtoull(argv->a_un.a_str);
1065 else
1066 arg = (void *)(uintptr_t)argv->a_un.a_val;
1067 }
1068
1069 if (t->t_pshandle == NULL || Pstate(t->t_pshandle) == PS_IDLE) {
1070 mdb_warn("no process active\n");
1071 return (DCMD_ERR);
1072 }
1073
1074 /*
1075 * In the universe of sparcv7, sparcv9, ia32, and amd64 this code can be
1076 * common: <sys/procfs_isa.h> conveniently #defines R_FP to be the
1077 * appropriate register we need to set in order to perform a stack
1078 * traceback from a given frame address.
1079 */
1080 if (flags & DCMD_ADDRSPEC) {
1081 bzero(&gregs, sizeof (gregs));
1082 gregs.gregs[R_FP] = addr;
1083#ifdef __sparc
1084 gregs.gregs[R_I7] = saved_pc;
1085#endif /* __sparc */
1086 } else if (PTL_GETREGS(t, PTL_TID(t), gregs.gregs) != 0) {
1087 mdb_warn("failed to get current register set");
1088 return (DCMD_ERR);
1089 }
1090
1091 (void) mdb_tgt_stack_iter(t, &gregs, func, arg);
1092 return (DCMD_OK);
1093}
1094
1095static int
1096pt_stack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1097{
1098 return (pt_stack_common(addr, flags, argc, argv, pt_frame, 0));
1099}
1100
1101static int
1102pt_stackv(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1103{
1104 return (pt_stack_common(addr, flags, argc, argv, pt_framev, 0));
1105}
1106
1107static int
1108pt_stackr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1109{
1110 /*
1111 * Force printing of first register window, by setting the
1112 * saved pc (%i7) to PC_FAKE.
1113 */
1114 return (pt_stack_common(addr, flags, argc, argv, pt_framer, PC_FAKE));
1115}
1116
1117/*ARGSUSED*/
1118static int
1119pt_ignored(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1120{
1121 struct ps_prochandle *P = mdb.m_target->t_pshandle;
1122 char buf[PRSIGBUFSZ];
1123
1124 if ((flags & DCMD_ADDRSPEC) || argc != 0)
1125 return (DCMD_USAGE);
1126
1127 if (P == NULL) {
1128 mdb_warn("no process is currently active\n");
1129 return (DCMD_ERR);
1130 }
1131
1132 mdb_printf("%s\n", proc_sigset2str(&Pstatus(P)->pr_sigtrace, " ",
1133 FALSE, buf, sizeof (buf)));
1134
1135 return (DCMD_OK);
1136}
1137
1138/*ARGSUSED*/
1139static int
1140pt_lwpid(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1141{
1142 struct ps_prochandle *P = mdb.m_target->t_pshandle;
1143
1144 if ((flags & DCMD_ADDRSPEC) || argc != 0)
1145 return (DCMD_USAGE);
1146
1147 if (P == NULL) {
1148 mdb_warn("no process is currently active\n");
1149 return (DCMD_ERR);
1150 }
1151
1152 mdb_printf("%d\n", Pstatus(P)->pr_lwp.pr_lwpid);
1153 return (DCMD_OK);
1154}
1155
1156static int
1157pt_print_lwpid(int *n, const lwpstatus_t *psp)
1158{
1159 struct ps_prochandle *P = mdb.m_target->t_pshandle;
1160 int nlwp = Pstatus(P)->pr_nlwp;
1161
1162 if (*n == nlwp - 2)
1163 mdb_printf("%d and ", (int)psp->pr_lwpid);
1164 else if (*n == nlwp - 1)
1165 mdb_printf("%d are", (int)psp->pr_lwpid);
1166 else
1167 mdb_printf("%d, ", (int)psp->pr_lwpid);
1168
1169 (*n)++;
1170 return (0);
1171}
1172
1173/*ARGSUSED*/
1174static int
1175pt_lwpids(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1176{
1177 struct ps_prochandle *P = mdb.m_target->t_pshandle;
1178 int n = 0;
1179
1180 if (P == NULL) {
1181 mdb_warn("no process is currently active\n");
1182 return (DCMD_ERR);
1183 }
1184
1185 switch (Pstatus(P)->pr_nlwp) {
1186 case 0:
1187 mdb_printf("no lwps are");
1188 break;
1189 case 1:
1190 mdb_printf("lwpid %d is the only lwp",
1191 Pstatus(P)->pr_lwp.pr_lwpid);
1192 break;
1193 default:
1194 mdb_printf("lwpids ");
1195 (void) Plwp_iter(P, (proc_lwp_f *)pt_print_lwpid, &n);
1196 }
1197
1198 switch (Pstate(P)) {
1199 case PS_DEAD:
1200 mdb_printf(" in core of process %d.\n", Pstatus(P)->pr_pid);
1201 break;
1202 case PS_IDLE:
1203 mdb_printf(" in idle target.\n");
1204 break;
1205 default:
1206 mdb_printf(" in process %d.\n", (int)Pstatus(P)->pr_pid);
1207 break;
1208 }
1209
1210 return (DCMD_OK);
1211}
1212
1213/*ARGSUSED*/
1214static int
1215pt_ignore(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1216{
1217 pt_data_t *pt = mdb.m_target->t_data;
1218
1219 if (!(flags & DCMD_ADDRSPEC) || argc != 0)
1220 return (DCMD_USAGE);
1221
1222 if (addr < 1 || addr > pt->p_maxsig) {
1223 mdb_warn("invalid signal number -- 0t%lu\n", addr);
1224 return (DCMD_ERR);
1225 }
1226
1227 (void) mdb_tgt_vespec_iter(mdb.m_target, pt_ignore_sig, (void *)addr);
1228 return (DCMD_OK);
1229}
1230
1231/*ARGSUSED*/
1232static int
1233pt_attach(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1234{
1235 mdb_tgt_t *t = mdb.m_target;
1236 pt_data_t *pt = t->t_data;
1237 int state, perr;
1238
1239 if (!(flags & DCMD_ADDRSPEC) && argc == 0)
1240 return (DCMD_USAGE);
1241
1242 if (((flags & DCMD_ADDRSPEC) && argc != 0) || argc > 1 ||
1243 (argc != 0 && argv->a_type != MDB_TYPE_STRING))
1244 return (DCMD_USAGE);
1245
1246 if (t->t_pshandle != NULL && Pstate(t->t_pshandle) != PS_IDLE) {
1247 mdb_warn("debugger is already attached to a %s\n",
1248 (Pstate(t->t_pshandle) == PS_DEAD) ? "core" : "process");
1249 return (DCMD_ERR);
1250 }
1251
1252 if (pt->p_fio == NULL) {
1253 mdb_warn("attach requires executable to be specified on "
1254 "command-line (or use -p)\n");
1255 return (DCMD_ERR);
1256 }
1257
1258 if (flags & DCMD_ADDRSPEC)
1259 t->t_pshandle = Pgrab((pid_t)addr, pt->p_gflags, &perr);
1260 else
1261 t->t_pshandle = proc_arg_grab(argv->a_un.a_str,
1262 PR_ARG_ANY, pt->p_gflags, &perr);
1263
1264 if (t->t_pshandle == NULL) {
1265 t->t_pshandle = pt->p_idlehandle;
1266 mdb_warn("cannot attach: %s\n", Pgrab_error(perr));
1267 return (DCMD_ERR);
1268 }
1269
1270 state = Pstate(t->t_pshandle);
1271 if (state != PS_DEAD && state != PS_IDLE) {
1272 (void) Punsetflags(t->t_pshandle, PR_KLC);
1273 (void) Psetflags(t->t_pshandle, PR_RLC);
1274 pt_post_attach(t);
1275 pt_activate_common(t);
1276 }
1277
1278 (void) mdb_tgt_status(t, &t->t_status);
1279 mdb_module_load_all(0);
1280 return (DCMD_OK);
1281}
1282
1283static int
1284pt_regstatus(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1285{
1286 mdb_tgt_t *t = mdb.m_target;
1287
1288 if (t->t_pshandle != NULL) {
1289 const pstatus_t *psp = Pstatus(t->t_pshandle);
1290 int cursig = psp->pr_lwp.pr_cursig;
1291 char signame[SIG2STR_MAX];
1292 int state = Pstate(t->t_pshandle);
1293
1294 if (state != PS_DEAD && state != PS_IDLE)
1295 mdb_printf("process id = %d\n", psp->pr_pid);
1296 else
1297 mdb_printf("no process\n");
1298
1299 if (cursig != 0 && sig2str(cursig, signame) == 0)
1300 mdb_printf("SIG%s: %s\n", signame, strsignal(cursig));
1301 }
1302
1303 return (pt_regs(addr, flags, argc, argv));
1304}
1305
John Levonab618542018-10-08 15:34:11 +01001306static void
1307pt_thread_name(mdb_tgt_t *t, mdb_tgt_tid_t tid, char *buf, size_t bufsize)
1308{
1309 char name[THREAD_NAME_MAX];
1310
1311 buf[0] = '\0';
1312
1313 if (t->t_pshandle == NULL ||
1314 Plwp_getname(t->t_pshandle, tid, name, sizeof (name)) != 0 ||
1315 name[0] == '\0') {
1316 (void) mdb_snprintf(buf, bufsize, "%lu", tid);
1317 return;
1318 }
1319
1320 (void) mdb_snprintf(buf, bufsize, "%lu [%s]", tid, name);
1321}
1322
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001323static int
1324pt_findstack(uintptr_t tid, uint_t flags, int argc, const mdb_arg_t *argv)
1325{
1326 mdb_tgt_t *t = mdb.m_target;
1327 mdb_tgt_gregset_t gregs;
1328 int showargs = 0;
1329 int count;
1330 uintptr_t pc, sp;
John Levonab618542018-10-08 15:34:11 +01001331 char name[128];
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001332
1333 if (!(flags & DCMD_ADDRSPEC))
1334 return (DCMD_USAGE);
1335
1336 count = mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &showargs,
1337 NULL);
1338 argc -= count;
1339 argv += count;
1340
1341 if (argc > 1 || (argc == 1 && argv->a_type != MDB_TYPE_STRING))
1342 return (DCMD_USAGE);
1343
1344 if (PTL_GETREGS(t, tid, gregs.gregs) != 0) {
1345 mdb_warn("failed to get register set for thread %p", tid);
1346 return (DCMD_ERR);
1347 }
1348
1349 pc = gregs.gregs[R_PC];
1350#if defined(__i386) || defined(__amd64)
1351 sp = gregs.gregs[R_FP];
1352#else
1353 sp = gregs.gregs[R_SP];
1354#endif
John Levonab618542018-10-08 15:34:11 +01001355
1356 pt_thread_name(t, tid, name, sizeof (name));
1357
1358 mdb_printf("stack pointer for thread %s: %p\n", name, sp);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001359 if (pc != 0)
1360 mdb_printf("[ %0?lr %a() ]\n", sp, pc);
1361
1362 (void) mdb_inc_indent(2);
1363 mdb_set_dot(sp);
1364
1365 if (argc == 1)
1366 (void) mdb_eval(argv->a_un.a_str);
1367 else if (showargs)
1368 (void) mdb_eval("<.$C");
1369 else
1370 (void) mdb_eval("<.$C0");
1371
1372 (void) mdb_dec_indent(2);
1373 return (DCMD_OK);
1374}
1375
1376/*ARGSUSED*/
1377static int
1378pt_gcore(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1379{
1380 mdb_tgt_t *t = mdb.m_target;
1381 char *prefix = "core";
1382 char *content_str = NULL;
1383 core_content_t content = CC_CONTENT_DEFAULT;
1384 size_t size;
1385 char *fname;
1386 pid_t pid;
1387
1388 if (flags & DCMD_ADDRSPEC)
1389 return (DCMD_USAGE);
1390
1391 if (mdb_getopts(argc, argv,
1392 'o', MDB_OPT_STR, &prefix,
1393 'c', MDB_OPT_STR, &content_str, NULL) != argc)
1394 return (DCMD_USAGE);
1395
1396 if (content_str != NULL &&
1397 (proc_str2content(content_str, &content) != 0 ||
1398 content == CC_CONTENT_INVALID)) {
1399 mdb_warn("invalid content string '%s'\n", content_str);
1400 return (DCMD_ERR);
1401 }
1402
eschrockf723faa2005-12-15 11:30:25 -08001403 if (t->t_pshandle == NULL) {
1404 mdb_warn("no process active\n");
1405 return (DCMD_ERR);
1406 }
1407
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001408 pid = Pstatus(t->t_pshandle)->pr_pid;
1409 size = 1 + mdb_snprintf(NULL, 0, "%s.%d", prefix, (int)pid);
1410 fname = mdb_alloc(size, UM_SLEEP | UM_GC);
1411 (void) mdb_snprintf(fname, size, "%s.%d", prefix, (int)pid);
1412
1413 if (Pgcore(t->t_pshandle, fname, content) != 0) {
Keith M Wesolowski64e4e502014-11-14 15:59:13 -08001414 /*
1415 * Short writes during dumping are specifically described by
1416 * EBADE, just as ZFS uses this otherwise-unused code for
1417 * checksum errors. Translate to and mdb errno.
1418 */
1419 if (errno == EBADE)
1420 (void) set_errno(EMDB_SHORTWRITE);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001421 mdb_warn("couldn't dump core");
1422 return (DCMD_ERR);
1423 }
1424
1425 mdb_warn("%s dumped\n", fname);
1426
1427 return (DCMD_OK);
1428}
1429
1430/*ARGSUSED*/
1431static int
1432pt_kill(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1433{
1434 mdb_tgt_t *t = mdb.m_target;
1435 pt_data_t *pt = t->t_data;
1436 int state;
1437
1438 if ((flags & DCMD_ADDRSPEC) || argc != 0)
1439 return (DCMD_USAGE);
1440
1441 if (t->t_pshandle != NULL &&
1442 (state = Pstate(t->t_pshandle)) != PS_DEAD && state != PS_IDLE) {
1443 mdb_warn("victim process PID %d forcibly terminated\n",
1444 (int)Pstatus(t->t_pshandle)->pr_pid);
1445 pt_pre_detach(t, TRUE);
1446 pt_release_parents(t);
1447 Prelease(t->t_pshandle, PRELEASE_KILL);
1448 t->t_pshandle = pt->p_idlehandle;
1449 (void) mdb_tgt_status(t, &t->t_status);
1450 mdb.m_flags &= ~(MDB_FL_VCREATE | MDB_FL_JOBCTL);
1451 } else
1452 mdb_warn("no victim process is currently under control\n");
1453
1454 return (DCMD_OK);
1455}
1456
1457/*ARGSUSED*/
1458static int
1459pt_detach(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1460{
1461 mdb_tgt_t *t = mdb.m_target;
1462 pt_data_t *pt = t->t_data;
1463 int rflags = pt->p_rflags;
1464
1465 if (argc != 0 && argv->a_type == MDB_TYPE_STRING &&
1466 strcmp(argv->a_un.a_str, "-a") == 0) {
1467 rflags = PRELEASE_HANG | PRELEASE_CLEAR;
1468 argv++;
1469 argc--;
1470 }
1471
1472 if ((flags & DCMD_ADDRSPEC) || argc != 0)
1473 return (DCMD_USAGE);
1474
1475 if (t->t_pshandle == NULL || Pstate(t->t_pshandle) == PS_IDLE) {
1476 mdb_warn("debugger is not currently attached to a process "
1477 "or core file\n");
1478 return (DCMD_ERR);
1479 }
1480
1481 pt_pre_detach(t, TRUE);
1482 pt_release_parents(t);
1483 Prelease(t->t_pshandle, rflags);
1484 t->t_pshandle = pt->p_idlehandle;
1485 (void) mdb_tgt_status(t, &t->t_status);
1486 mdb.m_flags &= ~(MDB_FL_VCREATE | MDB_FL_JOBCTL);
1487
1488 return (DCMD_OK);
1489}
1490
1491static uintmax_t
1492reg_disc_get(const mdb_var_t *v)
1493{
1494 mdb_tgt_t *t = MDB_NV_COOKIE(v);
1495 mdb_tgt_tid_t tid = PTL_TID(t);
1496 mdb_tgt_reg_t r = 0;
1497
1498 if (tid != (mdb_tgt_tid_t)-1L)
1499 (void) mdb_tgt_getareg(t, tid, mdb_nv_get_name(v), &r);
1500
1501 return (r);
1502}
1503
1504static void
1505reg_disc_set(mdb_var_t *v, uintmax_t r)
1506{
1507 mdb_tgt_t *t = MDB_NV_COOKIE(v);
1508 mdb_tgt_tid_t tid = PTL_TID(t);
1509
1510 if (tid != (mdb_tgt_tid_t)-1L && mdb_tgt_putareg(t, tid,
1511 mdb_nv_get_name(v), r) == -1)
1512 mdb_warn("failed to modify %%%s register", mdb_nv_get_name(v));
1513}
1514
1515static void
1516pt_print_reason(const lwpstatus_t *psp)
1517{
1518 char name[SIG2STR_MAX + 4]; /* enough for SIG+name+\0, syscall or flt */
1519 const char *desc;
1520
1521 switch (psp->pr_why) {
1522 case PR_REQUESTED:
1523 mdb_printf("stopped by debugger");
1524 break;
1525 case PR_SIGNALLED:
1526 mdb_printf("stopped on %s (%s)", proc_signame(psp->pr_what,
1527 name, sizeof (name)), strsignal(psp->pr_what));
1528 break;
1529 case PR_SYSENTRY:
1530 mdb_printf("stopped on entry to %s system call",
1531 proc_sysname(psp->pr_what, name, sizeof (name)));
1532 break;
1533 case PR_SYSEXIT:
1534 mdb_printf("stopped on exit from %s system call",
1535 proc_sysname(psp->pr_what, name, sizeof (name)));
1536 break;
1537 case PR_JOBCONTROL:
1538 mdb_printf("stopped by job control");
1539 break;
1540 case PR_FAULTED:
1541 if (psp->pr_what == FLTBPT) {
1542 mdb_printf("stopped on a breakpoint");
1543 } else if (psp->pr_what == FLTWATCH) {
1544 switch (psp->pr_info.si_code) {
1545 case TRAP_RWATCH:
1546 desc = "read";
1547 break;
1548 case TRAP_WWATCH:
1549 desc = "write";
1550 break;
1551 case TRAP_XWATCH:
1552 desc = "execute";
1553 break;
1554 default:
1555 desc = "unknown";
1556 }
1557 mdb_printf("stopped %s a watchpoint (%s access to %p)",
1558 psp->pr_info.si_trapafter ? "after" : "on",
1559 desc, psp->pr_info.si_addr);
1560 } else if (psp->pr_what == FLTTRACE) {
1561 mdb_printf("stopped after a single-step");
1562 } else {
1563 mdb_printf("stopped on a %s fault",
1564 proc_fltname(psp->pr_what, name, sizeof (name)));
1565 }
1566 break;
1567 case PR_SUSPENDED:
1568 case PR_CHECKPOINT:
1569 mdb_printf("suspended by the kernel");
1570 break;
1571 default:
1572 mdb_printf("stopped for unknown reason (%d/%d)",
1573 psp->pr_why, psp->pr_what);
1574 }
1575}
1576
1577/*ARGSUSED*/
1578static int
1579pt_status_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1580{
1581 mdb_tgt_t *t = mdb.m_target;
1582 struct ps_prochandle *P = t->t_pshandle;
1583 pt_data_t *pt = t->t_data;
1584
1585 if (P != NULL) {
1586 const psinfo_t *pip = Ppsinfo(P);
1587 const pstatus_t *psp = Pstatus(P);
1588 int cursig = 0, bits = 0, coredump = 0;
1589 int state;
1590 GElf_Sym sym;
1591 uintptr_t panicstr;
Robert Mustacchif68770e2015-06-09 16:42:36 +02001592 char *panicbuf = mdb_alloc(PANIC_BUFSIZE, UM_SLEEP);
Krishnendu Sadhukhan - Sun Microsystems48fd7012008-09-30 14:29:38 -07001593 const siginfo_t *sip = &(psp->pr_lwp.pr_info);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001594
1595 char execname[MAXPATHLEN], buf[BUFSIZ];
1596 char signame[SIG2STR_MAX + 4]; /* enough for SIG+name+\0 */
1597
1598 mdb_tgt_spec_desc_t desc;
1599 mdb_sespec_t *sep;
1600
1601 struct utsname uts;
1602 prcred_t cred;
1603 psinfo_t pi;
1604
1605 (void) strcpy(uts.nodename, "unknown machine");
1606 (void) Puname(P, &uts);
1607
1608 if (pip != NULL) {
1609 bcopy(pip, &pi, sizeof (psinfo_t));
1610 proc_unctrl_psinfo(&pi);
1611 } else
1612 bzero(&pi, sizeof (psinfo_t));
1613
1614 bits = pi.pr_dmodel == PR_MODEL_ILP32 ? 32 : 64;
1615
1616 state = Pstate(P);
1617 if (psp != NULL && state != PS_UNDEAD && state != PS_IDLE)
1618 cursig = psp->pr_lwp.pr_cursig;
1619
1620 if (state == PS_DEAD && pip != NULL) {
1621 mdb_printf("debugging core file of %s (%d-bit) "
1622 "from %s\n", pi.pr_fname, bits, uts.nodename);
1623
1624 } else if (state == PS_DEAD) {
1625 mdb_printf("debugging core file\n");
1626
1627 } else if (state == PS_IDLE) {
1628 const GElf_Ehdr *ehp = &pt->p_file->gf_ehdr;
1629
1630 mdb_printf("debugging %s file (%d-bit)\n",
1631 ehp->e_type == ET_EXEC ? "executable" : "object",
1632 ehp->e_ident[EI_CLASS] == ELFCLASS32 ? 32 : 64);
1633
1634 } else if (state == PS_UNDEAD && pi.pr_pid == 0) {
1635 mdb_printf("debugging defunct process\n");
1636
1637 } else {
1638 mdb_printf("debugging PID %d (%d-bit)\n",
1639 pi.pr_pid, bits);
1640 }
1641
1642 if (Pexecname(P, execname, sizeof (execname)) != NULL)
1643 mdb_printf("file: %s\n", execname);
1644
1645 if (pip != NULL && state == PS_DEAD)
1646 mdb_printf("initial argv: %s\n", pi.pr_psargs);
1647
1648 if (state != PS_UNDEAD && state != PS_IDLE) {
1649 mdb_printf("threading model: ");
1650 if (pt->p_ptl_ops == &proc_lwp_ops)
1651 mdb_printf("raw lwps\n");
1652 else
1653 mdb_printf("native threads\n");
1654 }
1655
1656 mdb_printf("status: ");
1657 switch (state) {
1658 case PS_RUN:
1659 ASSERT(!(psp->pr_flags & PR_STOPPED));
1660 mdb_printf("process is running");
1661 if (psp->pr_flags & PR_DSTOP)
1662 mdb_printf(", debugger stop directive pending");
1663 mdb_printf("\n");
1664 break;
1665
1666 case PS_STOP:
1667 ASSERT(psp->pr_flags & PR_STOPPED);
1668 pt_print_reason(&psp->pr_lwp);
1669
1670 if (psp->pr_flags & PR_DSTOP)
1671 mdb_printf(", debugger stop directive pending");
1672 if (psp->pr_flags & PR_ASLEEP)
1673 mdb_printf(", sleeping in %s system call",
1674 proc_sysname(psp->pr_lwp.pr_syscall,
1675 signame, sizeof (signame)));
1676
1677 mdb_printf("\n");
1678
1679 for (sep = t->t_matched; sep != T_SE_END;
1680 sep = sep->se_matched) {
1681 mdb_printf("event: %s\n", sep->se_ops->se_info(
1682 t, sep, mdb_list_next(&sep->se_velist),
1683 &desc, buf, sizeof (buf)));
1684 }
1685 break;
1686
1687 case PS_LOST:
1688 mdb_printf("debugger lost control of process\n");
1689 break;
1690
1691 case PS_UNDEAD:
1692 coredump = WIFSIGNALED(pi.pr_wstat) &&
1693 WCOREDUMP(pi.pr_wstat);
1694 /*FALLTHRU*/
1695
1696 case PS_DEAD:
1697 if (cursig == 0 && WIFSIGNALED(pi.pr_wstat))
1698 cursig = WTERMSIG(pi.pr_wstat);
1699 /*
1700 * We can only use pr_wstat == 0 as a test for gcore if
1701 * an NT_PRCRED note is present; these features were
1702 * added at the same time in Solaris 8.
1703 */
1704 if (pi.pr_wstat == 0 && Pstate(P) == PS_DEAD &&
1705 Pcred(P, &cred, 1) == 0) {
1706 mdb_printf("process core file generated "
1707 "with gcore(1)\n");
1708 } else if (cursig != 0) {
1709 mdb_printf("process terminated by %s (%s)",
1710 proc_signame(cursig, signame,
1711 sizeof (signame)), strsignal(cursig));
Krishnendu Sadhukhan - Sun Microsystems48fd7012008-09-30 14:29:38 -07001712
1713 if (sip->si_signo != 0 && SI_FROMUSER(sip) &&
1714 sip->si_pid != 0) {
1715 mdb_printf(", pid=%d uid=%u",
1716 (int)sip->si_pid, sip->si_uid);
1717 if (sip->si_code != 0) {
1718 mdb_printf(" code=%d",
1719 sip->si_code);
1720 }
1721 } else {
1722 switch (sip->si_signo) {
1723 case SIGILL:
1724 case SIGTRAP:
1725 case SIGFPE:
1726 case SIGSEGV:
1727 case SIGBUS:
1728 case SIGEMT:
1729 mdb_printf(", addr=%p",
1730 sip->si_addr);
1731 default:
1732 break;
1733 }
1734 }
1735
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001736 if (coredump)
1737 mdb_printf(" - core file dumped");
1738 mdb_printf("\n");
1739 } else {
1740 mdb_printf("process terminated with exit "
1741 "status %d\n", WEXITSTATUS(pi.pr_wstat));
1742 }
1743
1744 if (Plookup_by_name(t->t_pshandle, "libc.so",
1745 "panicstr", &sym) == 0 &&
1746 Pread(t->t_pshandle, &panicstr, sizeof (panicstr),
1747 sym.st_value) == sizeof (panicstr) &&
1748 Pread_string(t->t_pshandle, panicbuf,
Robert Mustacchif68770e2015-06-09 16:42:36 +02001749 PANIC_BUFSIZE, panicstr) > 0) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001750 mdb_printf("panic message: %s",
1751 panicbuf);
1752 }
1753
1754
1755 break;
1756
1757 case PS_IDLE:
1758 mdb_printf("idle\n");
1759 break;
1760
1761 default:
1762 mdb_printf("unknown libproc Pstate: %d\n", Pstate(P));
1763 }
Robert Mustacchif68770e2015-06-09 16:42:36 +02001764 mdb_free(panicbuf, PANIC_BUFSIZE);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001765
1766 } else if (pt->p_file != NULL) {
1767 const GElf_Ehdr *ehp = &pt->p_file->gf_ehdr;
1768
1769 mdb_printf("debugging %s file (%d-bit)\n",
1770 ehp->e_type == ET_EXEC ? "executable" : "object",
1771 ehp->e_ident[EI_CLASS] == ELFCLASS32 ? 32 : 64);
1772 mdb_printf("executable file: %s\n", IOP_NAME(pt->p_fio));
1773 mdb_printf("status: idle\n");
1774 }
1775
1776 return (DCMD_OK);
1777}
1778
1779static int
1780pt_tls(uintptr_t tid, uint_t flags, int argc, const mdb_arg_t *argv)
1781{
1782 const char *name;
1783 const char *object;
1784 GElf_Sym sym;
1785 mdb_syminfo_t si;
1786 mdb_tgt_t *t = mdb.m_target;
1787
1788 if (!(flags & DCMD_ADDRSPEC) || argc > 1)
1789 return (DCMD_USAGE);
1790
1791 if (argc == 0) {
1792 psaddr_t b;
1793
1794 if (tlsbase(t, tid, PR_LMID_EVERY, MDB_TGT_OBJ_EXEC, &b) != 0) {
1795 mdb_warn("failed to lookup tlsbase for %r", tid);
1796 return (DCMD_ERR);
1797 }
1798
1799 mdb_printf("%lr\n", b);
1800 mdb_set_dot(b);
1801
1802 return (DCMD_OK);
1803 }
1804
1805 name = argv[0].a_un.a_str;
1806 object = MDB_TGT_OBJ_EVERY;
1807
1808 if (pt_lookup_by_name_thr(t, object, name, &sym, &si, tid) != 0) {
1809 mdb_warn("failed to lookup %s", name);
1810 return (DCMD_ABORT); /* avoid repeated failure */
1811 }
1812
1813 if (GELF_ST_TYPE(sym.st_info) != STT_TLS && DCMD_HDRSPEC(flags))
1814 mdb_warn("%s does not refer to thread local storage\n", name);
1815
1816 mdb_printf("%llr\n", sym.st_value);
1817 mdb_set_dot(sym.st_value);
1818
1819 return (DCMD_OK);
1820}
1821
1822/*ARGSUSED*/
1823static int
1824pt_tmodel(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1825{
1826 mdb_tgt_t *t = mdb.m_target;
1827 pt_data_t *pt = t->t_data;
1828 const pt_ptl_ops_t *ptl_ops;
1829
1830 if (argc != 1 || argv->a_type != MDB_TYPE_STRING)
1831 return (DCMD_USAGE);
1832
1833 if (strcmp(argv->a_un.a_str, "thread") == 0)
1834 ptl_ops = &proc_tdb_ops;
1835 else if (strcmp(argv->a_un.a_str, "lwp") == 0)
1836 ptl_ops = &proc_lwp_ops;
1837 else
1838 return (DCMD_USAGE);
1839
1840 if (t->t_pshandle != NULL && pt->p_ptl_ops != ptl_ops) {
1841 PTL_DTOR(t);
1842 pt->p_tdb_ops = NULL;
1843 pt->p_ptl_ops = &proc_lwp_ops;
1844 pt->p_ptl_hdl = NULL;
1845
1846 if (ptl_ops == &proc_tdb_ops) {
Edward Pilatowicz95d62a62008-10-23 14:14:11 -07001847 (void) Pobject_iter(t->t_pshandle, (proc_map_f *)
1848 thr_check, t);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001849 }
1850 }
1851
1852 (void) mdb_tgt_status(t, &t->t_status);
1853 return (DCMD_OK);
1854}
1855
1856static const char *
1857env_match(const char *cmp, const char *nameval)
1858{
1859 const char *loc;
1860 size_t cmplen = strlen(cmp);
1861
1862 loc = strchr(nameval, '=');
1863 if (loc != NULL && (loc - nameval) == cmplen &&
1864 strncmp(nameval, cmp, cmplen) == 0) {
1865 return (loc + 1);
1866 }
1867
1868 return (NULL);
1869}
1870
1871/*ARGSUSED*/
1872static int
1873print_env(void *data, struct ps_prochandle *P, uintptr_t addr,
1874 const char *nameval)
1875{
1876 const char *value;
1877
1878 if (nameval == NULL) {
1879 mdb_printf("<0x%p>\n", addr);
1880 } else {
1881 if (data == NULL)
1882 mdb_printf("%s\n", nameval);
1883 else if ((value = env_match(data, nameval)) != NULL)
1884 mdb_printf("%s\n", value);
1885 }
1886
1887 return (0);
1888}
1889
1890/*ARGSUSED*/
1891static int
1892pt_getenv(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1893{
1894 mdb_tgt_t *t = mdb.m_target;
1895 pt_data_t *pt = t->t_data;
1896 int i;
1897 uint_t opt_t = 0;
1898 mdb_var_t *v;
1899
1900 i = mdb_getopts(argc, argv,
1901 't', MDB_OPT_SETBITS, TRUE, &opt_t, NULL);
1902
1903 argc -= i;
1904 argv += i;
1905
1906 if ((flags & DCMD_ADDRSPEC) || argc > 1)
1907 return (DCMD_USAGE);
1908
1909 if (argc == 1 && argv->a_type != MDB_TYPE_STRING)
1910 return (DCMD_USAGE);
1911
eschrockf723faa2005-12-15 11:30:25 -08001912 if (opt_t && t->t_pshandle == NULL) {
1913 mdb_warn("no process active\n");
1914 return (DCMD_ERR);
1915 }
1916
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001917 if (opt_t && (Pstate(t->t_pshandle) == PS_IDLE ||
1918 Pstate(t->t_pshandle) == PS_UNDEAD)) {
1919 mdb_warn("-t option requires target to be running\n");
1920 return (DCMD_ERR);
1921 }
1922
1923 if (opt_t != 0) {
1924 if (Penv_iter(t->t_pshandle, print_env,
1925 argc == 0 ? NULL : (void *)argv->a_un.a_str) != 0)
1926 return (DCMD_ERR);
1927 } else if (argc == 1) {
1928 if ((v = mdb_nv_lookup(&pt->p_env, argv->a_un.a_str)) == NULL)
1929 return (DCMD_ERR);
1930
1931 ASSERT(strchr(mdb_nv_get_cookie(v), '=') != NULL);
1932 mdb_printf("%s\n", strchr(mdb_nv_get_cookie(v), '=') + 1);
1933 } else {
1934
1935 mdb_nv_rewind(&pt->p_env);
1936 while ((v = mdb_nv_advance(&pt->p_env)) != NULL)
1937 mdb_printf("%s\n", mdb_nv_get_cookie(v));
1938 }
1939
1940 return (DCMD_OK);
1941}
1942
1943/*
1944 * Function to set a variable in the internal environment, which is used when
1945 * creating new processes. Note that it is possible that 'nameval' can refer to
1946 * read-only memory, if mdb calls putenv() on an existing value before calling
1947 * this function. While we should avoid this situation, this function is
1948 * designed to be robust in the face of such changes.
1949 */
1950static void
1951pt_env_set(pt_data_t *pt, const char *nameval)
1952{
1953 mdb_var_t *v;
1954 char *equals, *val;
1955 const char *name;
1956 size_t len;
1957
1958 if ((equals = strchr(nameval, '=')) != NULL) {
1959 val = strdup(nameval);
1960 equals = val + (equals - nameval);
1961 } else {
1962 /*
1963 * nameval doesn't contain an equals character. Convert this to
1964 * be 'nameval='.
1965 */
1966 len = strlen(nameval);
1967 val = mdb_alloc(len + 2, UM_SLEEP);
1968 (void) mdb_snprintf(val, len + 2, "%s=", nameval);
1969 equals = val + len;
1970 }
1971
1972 /* temporary truncate the string for lookup/insert */
1973 *equals = '\0';
1974 v = mdb_nv_lookup(&pt->p_env, val);
1975
1976 if (v != NULL) {
1977 char *old = mdb_nv_get_cookie(v);
1978 mdb_free(old, strlen(old) + 1);
1979 name = mdb_nv_get_name(v);
1980 } else {
1981 /*
1982 * The environment is created using MDB_NV_EXTNAME, so we must
1983 * provide external storage for the variable names.
1984 */
1985 name = strdup(val);
1986 }
1987
1988 *equals = '=';
1989
1990 (void) mdb_nv_insert(&pt->p_env, name, NULL, (uintptr_t)val,
1991 MDB_NV_EXTNAME);
1992
1993 if (equals)
1994 *equals = '=';
1995}
1996
1997/*
1998 * Clears the internal environment.
1999 */
2000static void
2001pt_env_clear(pt_data_t *pt)
2002{
2003 mdb_var_t *v;
2004 char *val, *name;
2005
2006 mdb_nv_rewind(&pt->p_env);
2007 while ((v = mdb_nv_advance(&pt->p_env)) != NULL) {
2008
2009 name = (char *)mdb_nv_get_name(v);
2010 val = mdb_nv_get_cookie(v);
2011
2012 mdb_nv_remove(&pt->p_env, v);
2013
2014 mdb_free(name, strlen(name) + 1);
2015 mdb_free(val, strlen(val) + 1);
2016 }
2017}
2018
2019/*ARGSUSED*/
2020static int
2021pt_setenv(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2022{
2023 mdb_tgt_t *t = mdb.m_target;
2024 pt_data_t *pt = t->t_data;
2025 char *nameval;
2026 size_t len;
2027 int alloc;
2028
2029 if ((flags & DCMD_ADDRSPEC) || argc == 0 || argc > 2)
2030 return (DCMD_USAGE);
2031
2032 if ((argc > 0 && argv[0].a_type != MDB_TYPE_STRING) ||
2033 (argc > 1 && argv[1].a_type != MDB_TYPE_STRING))
2034 return (DCMD_USAGE);
2035
eschrockf723faa2005-12-15 11:30:25 -08002036 if (t->t_pshandle == NULL) {
2037 mdb_warn("no process active\n");
2038 return (DCMD_ERR);
2039 }
2040
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002041 /*
2042 * If the process is in some sort of running state, warn the user that
2043 * changes won't immediately take effect.
2044 */
2045 if (Pstate(t->t_pshandle) == PS_RUN ||
2046 Pstate(t->t_pshandle) == PS_STOP) {
2047 mdb_warn("warning: changes will not take effect until process"
2048 " is restarted\n");
2049 }
2050
2051 /*
2052 * We allow two forms of operation. The first is the usual "name=value"
2053 * parameter. We also allow the user to specify two arguments, where
2054 * the first is the name of the variable, and the second is the value.
2055 */
2056 alloc = 0;
2057 if (argc == 1) {
2058 nameval = (char *)argv->a_un.a_str;
2059 } else {
2060 len = strlen(argv[0].a_un.a_str) +
2061 strlen(argv[1].a_un.a_str) + 2;
2062 nameval = mdb_alloc(len, UM_SLEEP);
2063 (void) mdb_snprintf(nameval, len, "%s=%s", argv[0].a_un.a_str,
2064 argv[1].a_un.a_str);
2065 alloc = 1;
2066 }
2067
2068 pt_env_set(pt, nameval);
2069
2070 if (alloc)
2071 mdb_free(nameval, strlen(nameval) + 1);
2072
2073 return (DCMD_OK);
2074}
2075
2076/*ARGSUSED*/
2077static int
2078pt_unsetenv(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2079{
2080 mdb_tgt_t *t = mdb.m_target;
2081 pt_data_t *pt = t->t_data;
2082 mdb_var_t *v;
2083 char *value, *name;
2084
2085 if ((flags & DCMD_ADDRSPEC) || argc > 1)
2086 return (DCMD_USAGE);
2087
2088 if (argc == 1 && argv->a_type != MDB_TYPE_STRING)
2089 return (DCMD_USAGE);
2090
eschrockf723faa2005-12-15 11:30:25 -08002091 if (t->t_pshandle == NULL) {
2092 mdb_warn("no process active\n");
2093 return (DCMD_ERR);
2094 }
2095
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002096 /*
2097 * If the process is in some sort of running state, warn the user that
2098 * changes won't immediately take effect.
2099 */
2100 if (Pstate(t->t_pshandle) == PS_RUN ||
2101 Pstate(t->t_pshandle) == PS_STOP) {
2102 mdb_warn("warning: changes will not take effect until process"
2103 " is restarted\n");
2104 }
2105
2106 if (argc == 0) {
2107 pt_env_clear(pt);
2108 } else {
2109 if ((v = mdb_nv_lookup(&pt->p_env, argv->a_un.a_str)) != NULL) {
2110 name = (char *)mdb_nv_get_name(v);
2111 value = mdb_nv_get_cookie(v);
2112
2113 mdb_nv_remove(&pt->p_env, v);
2114
2115 mdb_free(name, strlen(name) + 1);
2116 mdb_free(value, strlen(value) + 1);
2117 }
2118 }
2119
2120 return (DCMD_OK);
2121}
2122
johnlevb77e74e2008-02-07 18:43:07 -08002123void
2124getenv_help(void)
2125{
2126 mdb_printf("-t show current process environment"
2127 " instead of initial environment.\n");
2128}
2129
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002130static const mdb_dcmd_t pt_dcmds[] = {
2131 { "$c", "?[cnt]", "print stack backtrace", pt_stack },
2132 { "$C", "?[cnt]", "print stack backtrace", pt_stackv },
2133 { "$i", NULL, "print signals that are ignored", pt_ignored },
2134 { "$l", NULL, "print the representative thread's lwp id", pt_lwpid },
2135 { "$L", NULL, "print list of the active lwp ids", pt_lwpids },
Joshua M. Clulow8f88a512015-01-24 16:32:07 -08002136 { "$r", "?[-u]", "print general-purpose registers", pt_regs },
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002137 { "$x", "?", "print floating point registers", pt_fpregs },
2138 { "$X", "?", "print floating point registers", pt_fpregs },
2139 { "$y", "?", "print floating point registers", pt_fpregs },
2140 { "$Y", "?", "print floating point registers", pt_fpregs },
2141 { "$?", "?", "print status and registers", pt_regstatus },
2142 { ":A", "?[core|pid]", "attach to process or core file", pt_attach },
2143 { ":i", ":", "ignore signal (delete all matching events)", pt_ignore },
2144 { ":k", NULL, "forcibly kill and release target", pt_kill },
2145 { ":R", "[-a]", "release the previously attached process", pt_detach },
2146 { "attach", "?[core|pid]",
2147 "attach to process or core file", pt_attach },
2148 { "findstack", ":[-v]", "find user thread stack", pt_findstack },
2149 { "gcore", "[-o prefix] [-c content]",
2150 "produce a core file for the attached process", pt_gcore },
2151 { "getenv", "[-t] [name]", "display an environment variable",
johnlevb77e74e2008-02-07 18:43:07 -08002152 pt_getenv, getenv_help },
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002153 { "kill", NULL, "forcibly kill and release target", pt_kill },
2154 { "release", "[-a]",
2155 "release the previously attached process", pt_detach },
Joshua M. Clulow8f88a512015-01-24 16:32:07 -08002156 { "regs", "?[-u]", "print general-purpose registers", pt_regs },
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002157 { "fpregs", "?[-dqs]", "print floating point registers", pt_fpregs },
2158 { "setenv", "name=value", "set an environment variable", pt_setenv },
2159 { "stack", "?[cnt]", "print stack backtrace", pt_stack },
2160 { "stackregs", "?", "print stack backtrace and registers", pt_stackr },
2161 { "status", NULL, "print summary of current target", pt_status_dcmd },
2162 { "tls", ":symbol",
2163 "lookup TLS data in the context of a given thread", pt_tls },
2164 { "tmodel", "{thread|lwp}", NULL, pt_tmodel },
2165 { "unsetenv", "[name]", "clear an environment variable", pt_unsetenv },
2166 { NULL }
2167};
2168
2169static void
2170pt_thr_walk_fini(mdb_walk_state_t *wsp)
2171{
2172 mdb_addrvec_destroy(wsp->walk_data);
2173 mdb_free(wsp->walk_data, sizeof (mdb_addrvec_t));
2174}
2175
2176static int
2177pt_thr_walk_init(mdb_walk_state_t *wsp)
2178{
2179 wsp->walk_data = mdb_zalloc(sizeof (mdb_addrvec_t), UM_SLEEP);
2180 mdb_addrvec_create(wsp->walk_data);
2181
2182 if (PTL_ITER(mdb.m_target, wsp->walk_data) == -1) {
2183 mdb_warn("failed to iterate over threads");
2184 pt_thr_walk_fini(wsp);
2185 return (WALK_ERR);
2186 }
2187
2188 return (WALK_NEXT);
2189}
2190
2191static int
2192pt_thr_walk_step(mdb_walk_state_t *wsp)
2193{
2194 if (mdb_addrvec_length(wsp->walk_data) != 0) {
2195 return (wsp->walk_callback(mdb_addrvec_shift(wsp->walk_data),
2196 NULL, wsp->walk_cbdata));
2197 }
2198 return (WALK_DONE);
2199}
2200
2201static const mdb_walker_t pt_walkers[] = {
2202 { "thread", "walk list of valid thread identifiers",
2203 pt_thr_walk_init, pt_thr_walk_step, pt_thr_walk_fini },
2204 { NULL }
2205};
2206
Bryan Cantrill28ea8e02013-04-03 15:58:40 +00002207static int
2208pt_agent_check(boolean_t *agent, const lwpstatus_t *psp)
2209{
2210 if (psp->pr_flags & PR_AGENT)
2211 *agent = B_TRUE;
2212
2213 return (0);
2214}
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002215
2216static void
2217pt_activate_common(mdb_tgt_t *t)
2218{
2219 pt_data_t *pt = t->t_data;
Bryan Cantrill28ea8e02013-04-03 15:58:40 +00002220 boolean_t hasagent = B_FALSE;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002221 GElf_Sym sym;
2222
2223 /*
2224 * If we have a libproc handle and AT_BASE is set, the process or core
2225 * is dynamically linked. We call Prd_agent() to force libproc to
2226 * try to initialize librtld_db, and issue a warning if that fails.
2227 */
2228 if (t->t_pshandle != NULL && Pgetauxval(t->t_pshandle,
2229 AT_BASE) != -1L && Prd_agent(t->t_pshandle) == NULL) {
2230 mdb_warn("warning: librtld_db failed to initialize; shared "
2231 "library information will not be available\n");
2232 }
2233
Bryan Cantrill28ea8e02013-04-03 15:58:40 +00002234 if (t->t_pshandle != NULL) {
2235 (void) Plwp_iter(t->t_pshandle,
2236 (proc_lwp_f *)pt_agent_check, &hasagent);
2237 }
2238
2239 if (hasagent) {
2240 mdb_warn("agent lwp detected; forcing "
2241 "lwp thread model (use ::tmodel to change)\n");
2242 } else if (t->t_pshandle != NULL && Pstate(t->t_pshandle) != PS_IDLE) {
2243 /*
2244 * If we have a libproc handle and we do not have an agent LWP,
2245 * look for the correct thread debugging library. (If we have
2246 * an agent LWP, we leave the model as the raw LWP model to
2247 * allow the agent LWP to be visible to the debugger.)
2248 */
Edward Pilatowicz95d62a62008-10-23 14:14:11 -07002249 (void) Pobject_iter(t->t_pshandle, (proc_map_f *)thr_check, t);
Bryan Cantrill28ea8e02013-04-03 15:58:40 +00002250 }
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002251
2252 /*
2253 * If there's a global object named '_mdb_abort_info', assuming we're
2254 * debugging mdb itself and load the developer support module.
2255 */
2256 if (mdb_gelf_symtab_lookup_by_name(pt->p_symtab, "_mdb_abort_info",
2257 &sym, NULL) == 0 && GELF_ST_TYPE(sym.st_info) == STT_OBJECT) {
2258 if (mdb_module_load("mdb_ds", MDB_MOD_SILENT) < 0)
2259 mdb_warn("warning: failed to load developer support\n");
2260 }
2261
2262 mdb_tgt_elf_export(pt->p_file);
2263}
2264
2265static void
2266pt_activate(mdb_tgt_t *t)
2267{
2268 static const mdb_nv_disc_t reg_disc = { reg_disc_set, reg_disc_get };
2269
2270 pt_data_t *pt = t->t_data;
2271 struct utsname u1, u2;
2272 mdb_var_t *v;
2273 core_content_t content;
2274
2275 if (t->t_pshandle) {
2276 mdb_prop_postmortem = (Pstate(t->t_pshandle) == PS_DEAD);
2277 mdb_prop_kernel = FALSE;
2278 } else
2279 mdb_prop_kernel = mdb_prop_postmortem = FALSE;
2280
2281 mdb_prop_datamodel = MDB_TGT_MODEL_NATIVE;
2282
2283 /*
2284 * If we're examining a core file that doesn't contain program text,
2285 * and uname(2) doesn't match the NT_UTSNAME note recorded in the
2286 * core file, issue a warning.
2287 */
2288 if (mdb_prop_postmortem == TRUE &&
2289 ((content = Pcontent(t->t_pshandle)) == CC_CONTENT_INVALID ||
2290 !(content & CC_CONTENT_TEXT)) &&
2291 uname(&u1) >= 0 && Puname(t->t_pshandle, &u2) == 0 &&
2292 (strcmp(u1.release, u2.release) != 0 ||
2293 strcmp(u1.version, u2.version) != 0)) {
2294 mdb_warn("warning: core file is from %s %s %s; shared text "
2295 "mappings may not match installed libraries\n",
2296 u2.sysname, u2.release, u2.version);
2297 }
2298
2299 /*
2300 * Perform the common initialization tasks -- these are shared with
2301 * the pt_exec() and pt_run() subroutines.
2302 */
2303 pt_activate_common(t);
2304
2305 (void) mdb_tgt_register_dcmds(t, &pt_dcmds[0], MDB_MOD_FORCE);
2306 (void) mdb_tgt_register_walkers(t, &pt_walkers[0], MDB_MOD_FORCE);
2307
2308 /*
2309 * Iterate through our register description list and export
2310 * each register as a named variable.
2311 */
2312 mdb_nv_rewind(&pt->p_regs);
2313 while ((v = mdb_nv_advance(&pt->p_regs)) != NULL) {
2314 ushort_t rd_flags = MDB_TGT_R_FLAGS(mdb_nv_get_value(v));
2315
2316 if (!(rd_flags & MDB_TGT_R_EXPORT))
2317 continue; /* Don't export register as a variable */
2318
2319 (void) mdb_nv_insert(&mdb.m_nv, mdb_nv_get_name(v), &reg_disc,
2320 (uintptr_t)t, MDB_NV_PERSIST);
2321 }
2322}
2323
2324static void
2325pt_deactivate(mdb_tgt_t *t)
2326{
2327 pt_data_t *pt = t->t_data;
2328 const mdb_dcmd_t *dcp;
2329 const mdb_walker_t *wp;
2330 mdb_var_t *v, *w;
2331
2332 mdb_nv_rewind(&pt->p_regs);
2333 while ((v = mdb_nv_advance(&pt->p_regs)) != NULL) {
2334 ushort_t rd_flags = MDB_TGT_R_FLAGS(mdb_nv_get_value(v));
2335
2336 if (!(rd_flags & MDB_TGT_R_EXPORT))
2337 continue; /* Didn't export register as a variable */
2338
2339 if (w = mdb_nv_lookup(&mdb.m_nv, mdb_nv_get_name(v))) {
2340 w->v_flags &= ~MDB_NV_PERSIST;
2341 mdb_nv_remove(&mdb.m_nv, w);
2342 }
2343 }
2344
2345 for (wp = &pt_walkers[0]; wp->walk_name != NULL; wp++) {
2346 if (mdb_module_remove_walker(t->t_module, wp->walk_name) == -1)
2347 warn("failed to remove walk %s", wp->walk_name);
2348 }
2349
2350 for (dcp = &pt_dcmds[0]; dcp->dc_name != NULL; dcp++) {
2351 if (mdb_module_remove_dcmd(t->t_module, dcp->dc_name) == -1)
2352 warn("failed to remove dcmd %s", dcp->dc_name);
2353 }
2354
2355 mdb_prop_postmortem = FALSE;
2356 mdb_prop_kernel = FALSE;
2357 mdb_prop_datamodel = MDB_TGT_MODEL_UNKNOWN;
2358}
2359
2360static void
2361pt_periodic(mdb_tgt_t *t)
2362{
2363 pt_data_t *pt = t->t_data;
2364
2365 if (pt->p_rdstate == PT_RD_CONSIST) {
2366 if (t->t_pshandle != NULL && Pstate(t->t_pshandle) < PS_LOST &&
2367 !(mdb.m_flags & MDB_FL_NOMODS)) {
2368 mdb_printf("%s: You've got symbols!\n", mdb.m_pname);
2369 mdb_module_load_all(0);
2370 }
2371 pt->p_rdstate = PT_RD_NONE;
2372 }
2373}
2374
2375static void
2376pt_destroy(mdb_tgt_t *t)
2377{
2378 pt_data_t *pt = t->t_data;
2379
2380 if (pt->p_idlehandle != NULL && pt->p_idlehandle != t->t_pshandle)
2381 Prelease(pt->p_idlehandle, 0);
2382
2383 if (t->t_pshandle != NULL) {
2384 PTL_DTOR(t);
2385 pt_release_parents(t);
2386 pt_pre_detach(t, TRUE);
2387 Prelease(t->t_pshandle, pt->p_rflags);
2388 }
2389
2390 mdb.m_flags &= ~(MDB_FL_VCREATE | MDB_FL_JOBCTL);
2391 pt_close_aout(t);
2392
2393 if (pt->p_aout_fio != NULL)
2394 mdb_io_rele(pt->p_aout_fio);
2395
2396 pt_env_clear(pt);
2397 mdb_nv_destroy(&pt->p_env);
2398
2399 mdb_nv_destroy(&pt->p_regs);
2400 mdb_free(pt, sizeof (pt_data_t));
2401}
2402
2403/*ARGSUSED*/
2404static const char *
2405pt_name(mdb_tgt_t *t)
2406{
2407 return ("proc");
2408}
2409
2410static const char *
2411pt_platform(mdb_tgt_t *t)
2412{
2413 pt_data_t *pt = t->t_data;
2414
2415 if (t->t_pshandle != NULL &&
2416 Pplatform(t->t_pshandle, pt->p_platform, MAXNAMELEN) != NULL)
2417 return (pt->p_platform);
2418
2419 return (mdb_conf_platform());
2420}
2421
2422static int
2423pt_uname(mdb_tgt_t *t, struct utsname *utsp)
2424{
2425 if (t->t_pshandle != NULL)
2426 return (Puname(t->t_pshandle, utsp));
2427
2428 return (uname(utsp) >= 0 ? 0 : -1);
2429}
2430
2431static int
2432pt_dmodel(mdb_tgt_t *t)
2433{
2434 if (t->t_pshandle == NULL)
2435 return (MDB_TGT_MODEL_NATIVE);
2436
2437 switch (Pstatus(t->t_pshandle)->pr_dmodel) {
2438 case PR_MODEL_ILP32:
2439 return (MDB_TGT_MODEL_ILP32);
2440 case PR_MODEL_LP64:
2441 return (MDB_TGT_MODEL_LP64);
2442 }
2443
2444 return (MDB_TGT_MODEL_UNKNOWN);
2445}
2446
2447static ssize_t
2448pt_vread(mdb_tgt_t *t, void *buf, size_t nbytes, uintptr_t addr)
2449{
2450 ssize_t n;
2451
2452 /*
2453 * If no handle is open yet, reads from virtual addresses are
2454 * allowed to succeed but return zero-filled memory.
2455 */
2456 if (t->t_pshandle == NULL) {
2457 bzero(buf, nbytes);
2458 return (nbytes);
2459 }
2460
2461 if ((n = Pread(t->t_pshandle, buf, nbytes, addr)) <= 0)
2462 return (set_errno(EMDB_NOMAP));
2463
2464 return (n);
2465}
2466
2467static ssize_t
2468pt_vwrite(mdb_tgt_t *t, const void *buf, size_t nbytes, uintptr_t addr)
2469{
2470 ssize_t n;
2471
2472 /*
2473 * If no handle is open yet, writes to virtual addresses are
2474 * allowed to succeed but do not actually modify anything.
2475 */
2476 if (t->t_pshandle == NULL)
2477 return (nbytes);
2478
2479 n = Pwrite(t->t_pshandle, buf, nbytes, addr);
2480
2481 if (n == -1 && errno == EIO)
2482 return (set_errno(EMDB_NOMAP));
2483
2484 return (n);
2485}
2486
2487static ssize_t
2488pt_fread(mdb_tgt_t *t, void *buf, size_t nbytes, uintptr_t addr)
2489{
2490 pt_data_t *pt = t->t_data;
2491
2492 if (pt->p_file != NULL) {
2493 return (mdb_gelf_rw(pt->p_file, buf, nbytes, addr,
2494 IOPF_READ(pt->p_fio), GIO_READ));
2495 }
2496
2497 bzero(buf, nbytes);
2498 return (nbytes);
2499}
2500
2501static ssize_t
2502pt_fwrite(mdb_tgt_t *t, const void *buf, size_t nbytes, uintptr_t addr)
2503{
2504 pt_data_t *pt = t->t_data;
2505
2506 if (pt->p_file != NULL) {
2507 return (mdb_gelf_rw(pt->p_file, (void *)buf, nbytes, addr,
2508 IOPF_WRITE(pt->p_fio), GIO_WRITE));
2509 }
2510
2511 return (nbytes);
2512}
2513
2514static const char *
2515pt_resolve_lmid(const char *object, Lmid_t *lmidp)
2516{
2517 Lmid_t lmid = PR_LMID_EVERY;
2518 const char *p;
2519
2520 if (object == MDB_TGT_OBJ_EVERY || object == MDB_TGT_OBJ_EXEC)
2521 lmid = LM_ID_BASE; /* restrict scope to a.out's link map */
2522 else if (object != MDB_TGT_OBJ_RTLD && strncmp(object, "LM", 2) == 0 &&
2523 (p = strchr(object, '`')) != NULL) {
2524 object += 2; /* skip past initial "LM" prefix */
2525 lmid = strntoul(object, (size_t)(p - object), mdb.m_radix);
2526 object = p + 1; /* skip past link map specifier */
2527 }
2528
2529 *lmidp = lmid;
2530 return (object);
2531}
2532
2533static int
2534tlsbase(mdb_tgt_t *t, mdb_tgt_tid_t tid, Lmid_t lmid, const char *object,
2535 psaddr_t *basep)
2536{
2537 pt_data_t *pt = t->t_data;
2538 const rd_loadobj_t *loadobjp;
2539 td_thrh