1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
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 */
21
22/*
23 * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26#include <stdio.h>
27#include <stdlib.h>
28#include <unistd.h>
29#include <sys/uio.h>
30#include <fcntl.h>
31#include <string.h>
32#include <errno.h>
33#include <sys/types.h>
34#include <sys/signal.h>
35#include <sys/fault.h>
36#include <sys/syscall.h>
37#include <procfs.h>
38#include <sys/auxv.h>
39#include <libelf.h>
40#include <sys/param.h>
41#include <sys/machelf.h>
42#include <stdarg.h>
43
44#include "rdb.h"
45
46static const char *fault_strings[] = {
47	"<null string>",
48	"illegal instruction",
49	"privileged instruction",
50	"breakpoint instruction",
51	"trace trap (single-step)",
52	"Memory access (e.g., alignment)",
53	"Memory bounds (invalid address)",
54	"Integer overflow",
55	"Integer zero divide"
56	"Floating-point exception",
57	"Irrecoverable stack faul",
58	"Recoverable page fault (no associated sig)"
59};
60
61#define	MAXFAULT	FLTPAGE
62
63retc_t
64set_breakpoint(struct ps_prochandle *ph, ulong_t addr, unsigned flags)
65{
66	bptlist_t	*new, *cur, *prev;
67
68	for (cur = ph->pp_breakpoints, prev = NULL;
69	    (cur && (cur->bl_addr < addr));
70	    prev = cur, cur = cur->bl_next)
71		;
72	if (cur && (cur->bl_addr == addr)) {
73		/*
74		 * already have break point set here.
75		 */
76		cur->bl_flags |= flags;
77		return (RET_OK);
78	}
79
80	new = malloc(sizeof (bptlist_t));
81	new->bl_addr = addr;
82	new->bl_flags = flags;
83	if (prev == NULL) {
84		/*
85		 * insert at head
86		 */
87		new->bl_next = ph->pp_breakpoints;
88		ph->pp_breakpoints = new;
89		return (RET_OK);
90	}
91
92	prev->bl_next = new;
93	new->bl_next = cur;
94	return (RET_OK);
95}
96
97static bptlist_t *
98find_bp(struct ps_prochandle *ph, ulong_t addr)
99{
100	bptlist_t	*cur;
101
102	for (cur = ph->pp_breakpoints;
103	    (cur && (cur->bl_addr != addr));
104	    cur = cur->bl_next)
105		;
106
107	if ((cur == NULL) || (cur->bl_addr != addr))
108		return ((bptlist_t *)-1);
109	return (cur);
110}
111
112static retc_t
113delete_bp(struct ps_prochandle *ph, ulong_t addr)
114{
115	bptlist_t	*cur, *prev;
116
117	for (cur = ph->pp_breakpoints, prev = NULL;
118	    (cur && (cur->bl_addr < addr));
119	    prev = cur, cur = cur->bl_next)
120		;
121	if ((cur == NULL) || (cur->bl_addr != addr))
122		return (RET_FAILED);
123
124	if (prev == NULL)
125		ph->pp_breakpoints = cur->bl_next;
126	else
127		prev->bl_next = cur->bl_next;
128
129	free(cur);
130	return (RET_OK);
131}
132
133void
134list_breakpoints(struct ps_prochandle *ph)
135{
136	bptlist_t	*cur;
137
138	if (ph->pp_breakpoints == NULL) {
139		(void) printf("no active breakpoints.\n");
140		return;
141	}
142
143	(void) printf("active breakpoints:\n");
144	for (cur = ph->pp_breakpoints; cur; cur = cur->bl_next) {
145		(void) printf("\t0x%08lx:0x%04x - %s\n", cur->bl_addr,
146		    cur->bl_flags, print_address_ps(ph, cur->bl_addr,
147		    FLG_PAP_SONAME));
148	}
149}
150
151static void
152set_breaks(struct ps_prochandle *ph)
153{
154	bptlist_t	*cur;
155	bptinstr_t	bpt_instr = BPINSTR;
156
157	for (cur = ph->pp_breakpoints; cur; cur = cur->bl_next) {
158		bptinstr_t	old_inst = 0;
159
160		if (ps_pread(ph, cur->bl_addr, (char *)&old_inst,
161		    sizeof (bptinstr_t)) != PS_OK)
162			perr("sb: error setting breakpoint");
163
164		cur->bl_instr = old_inst;
165
166		if (ps_pwrite(ph, cur->bl_addr, (char *)&bpt_instr,
167		    sizeof (bptinstr_t)) != PS_OK)
168			perr("sb1: error setting breakpoint\n");
169	}
170
171}
172
173static void
174clear_breaks(struct ps_prochandle *ph)
175{
176	bptlist_t	*cur;
177
178	/*
179	 * Restore all the original instructions
180	 */
181	for (cur = ph->pp_breakpoints; cur; cur = cur->bl_next)
182		if (ps_pwrite(ph, cur->bl_addr, (char *)&(cur->bl_instr),
183		    sizeof (bptinstr_t)) != PS_OK)
184			perr("cb: error clearing breakpoint");
185}
186
187retc_t
188delete_all_breakpoints(struct ps_prochandle *ph)
189{
190	bptlist_t	*cur, *prev;
191
192	if (ph->pp_breakpoints == NULL)
193		return (RET_OK);
194
195	for (prev = NULL, cur = ph->pp_breakpoints;
196	    cur; prev = cur, cur = cur->bl_next)
197		if (prev)
198			free(prev);
199	if (prev)
200		free(prev);
201
202	ph->pp_breakpoints = NULL;
203	return (RET_OK);
204}
205
206retc_t
207delete_breakpoint(struct ps_prochandle *ph, ulong_t addr, unsigned flags)
208{
209	bptlist_t	*bpt;
210
211	if (((bpt = find_bp(ph, addr)) == (bptlist_t *)-1) ||
212	    ((bpt->bl_flags & flags) == 0))
213		return (RET_FAILED);
214
215	bpt->bl_flags &= ~flags;
216	if (bpt->bl_flags)
217		return (RET_OK);
218
219	return (delete_bp(ph, addr));
220}
221
222static void
223handle_sp_break(struct ps_prochandle *ph)
224{
225	rd_event_msg_t	emt;
226
227	if (rd_event_getmsg(ph->pp_rap, &emt) != RD_OK) {
228		(void) fprintf(stderr, "hsb: failed rd_event_getmsg()\n");
229		return;
230	}
231
232	if (emt.type == RD_DLACTIVITY) {
233		if (emt.u.state == RD_CONSISTENT)
234			ph->pp_flags |= FLG_PP_LMAPS;
235		else
236			ph->pp_flags &= ~FLG_PP_LMAPS;
237		if ((rdb_flags & RDB_FL_EVENTS) == 0)
238			return;
239
240		(void) printf("dlactivity: state changed to: ");
241		switch (emt.u.state) {
242		case RD_CONSISTENT:
243			(void) printf("RD_CONSISTENT\n");
244			break;
245		case RD_ADD:
246			(void) printf("RD_ADD\n");
247			break;
248		case RD_DELETE:
249			(void) printf("RD_DELETE\n");
250			break;
251		default:
252			(void) printf("unknown: 0x%x\n", emt.u.state);
253		}
254		return;
255	}
256
257	if ((rdb_flags & RDB_FL_EVENTS) == 0)
258		return;
259
260	if (emt.type == RD_PREINIT) {
261		(void) printf("preinit reached\n");
262		return;
263	}
264
265	if (emt.type == RD_POSTINIT)
266		(void) printf("postinit reached\n");
267}
268
269unsigned
270continue_to_break(struct ps_prochandle *ph)
271{
272	bptlist_t	*bpt;
273	pstatus_t	pstatus;
274	struct iovec	piov[5];
275	long		oper1, oper2, oper3, pflags = 0;
276	fltset_t	faults;
277
278	/*
279	 * We step by the first instruction incase their was
280	 * a break-point there.
281	 */
282	(void) step_n(ph, 1, FLG_SN_NONE);
283
284	premptyset(&faults);
285	praddset(&faults, FLTBPT);
286	praddset(&faults, FLTILL);
287	praddset(&faults, FLTPRIV);
288	praddset(&faults, FLTACCESS);
289	praddset(&faults, FLTBOUNDS);
290	praddset(&faults, FLTIZDIV);
291	praddset(&faults, FLTSTACK);
292	praddset(&faults, FLTTRACE);
293
294
295	/* LINTED CONSTANT */
296	while (1) {
297		set_breaks(ph);
298		oper1 = PCSFAULT;
299		piov[0].iov_base = (caddr_t)(&oper1);
300		piov[0].iov_len = sizeof (oper1);
301
302		piov[1].iov_base = (caddr_t)(&faults);
303		piov[1].iov_len = sizeof (faults);
304
305		oper2 = PCRUN;
306		piov[2].iov_base = (caddr_t)(&oper2);
307		piov[2].iov_len = sizeof (oper2);
308		pflags = PRCFAULT;
309		piov[3].iov_base = (caddr_t)(&pflags);
310		piov[3].iov_len = sizeof (pflags);
311
312		oper3 = PCWSTOP;
313		piov[4].iov_base = (caddr_t)(&oper3);
314		piov[4].iov_len = sizeof (oper3);
315
316		if (writev(ph->pp_ctlfd, piov, 5) == -1) {
317			if (errno == ENOENT) {
318				ph->pp_flags &= ~FLG_PP_PACT;
319
320				(void) ps_close(ph);
321				(void) printf("process terminated.\n");
322				return (0);
323			}
324			perr("ctb: PCWSTOP");
325		}
326
327		if (pread(ph->pp_statusfd, &pstatus, sizeof (pstatus), 0) == -1)
328			perr("ctb: reading status");
329
330
331		if ((pstatus.pr_lwp.pr_why != PR_FAULTED) ||
332		    (pstatus.pr_lwp.pr_what != FLTBPT)) {
333			const char	*fltmsg;
334
335			if ((pstatus.pr_lwp.pr_what <= MAXFAULT) &&
336			    (pstatus.pr_lwp.pr_why == PR_FAULTED))
337				fltmsg = fault_strings[pstatus.pr_lwp.pr_what];
338			else
339				fltmsg = "<unknown error>";
340
341			(void) fprintf(stderr, "ctb: bad stop - stopped "
342			    "on why: 0x%x what: %s(0x%x)\n",
343			    pstatus.pr_lwp.pr_why, fltmsg,
344			    pstatus.pr_lwp.pr_what);
345			return (0);
346		}
347
348		oper1 = PCCFAULT;
349		if (writev(ph->pp_ctlfd, piov, 1) == -1)
350			perr("ctb: PCCFAULT");
351
352		if ((bpt = find_bp(ph, pstatus.pr_lwp.pr_reg[R_PC])) ==
353		    (bptlist_t *)-1) {
354			(void) fprintf(stderr,
355			    "stopped at unregistered breakpoint! "
356			    "addr: 0x%x\n",
357			    EC_WORD(pstatus.pr_lwp.pr_reg[R_PC]));
358			break;
359		}
360		clear_breaks(ph);
361
362		/*
363		 * If this was a BP at which we should stop
364		 */
365		if (bpt->bl_flags & MASK_BP_STOP)
366			break;
367
368		(void) step_n(ph, 1, FLG_SN_NONE);
369	}
370
371	if (bpt->bl_flags & FLG_BP_USERDEF)
372		(void) printf("break point reached at addr: 0x%x\n",
373		    EC_WORD(pstatus.pr_lwp.pr_reg[R_PC]));
374
375	if (bpt->bl_flags & MASK_BP_SPECIAL)
376		handle_sp_break(ph);
377
378	if (ph->pp_flags & FLG_PP_LMAPS) {
379		if (get_linkmaps(ph) != RET_OK)
380			(void) fprintf(stderr, "problem loading linkmaps\n");
381	}
382
383	return (bpt->bl_flags);
384}
385
386ulong_t
387is_plt(struct ps_prochandle *ph, ulong_t pc)
388{
389	map_info_t	*mip;
390	ulong_t		pltbase;
391
392	if ((mip = addr_to_map(ph, pc)) == (map_info_t *)0)
393		return ((ulong_t)0);
394
395	pltbase = mip->mi_pltbase;
396	if ((mip->mi_flags & FLG_MI_EXEC) == 0)
397		pltbase += mip->mi_addr;
398
399	if ((pc >= pltbase) && (pc <= (pltbase + mip->mi_pltsize)))
400		return (pltbase);
401
402	return ((ulong_t)0);
403}
404
405retc_t
406step_n(struct ps_prochandle *ph, size_t count, sn_flags_e flgs)
407{
408	pstatus_t	pstatus;
409	fltset_t	faults;
410	int		i;
411	long		oper;
412	long		flags;
413	struct iovec	piov[2];
414
415	if (pread(ph->pp_statusfd, &pstatus, sizeof (pstatus), 0) == -1)
416		perr("stn: reading status");
417
418	piov[0].iov_base = (caddr_t)(&oper);
419	piov[0].iov_len = sizeof (oper);
420
421	premptyset(&faults);
422	praddset(&faults, FLTTRACE);
423
424	flags = PRSTEP | PRCFAULT;
425
426	for (i = 0; i < count; i++) {
427		bptlist_t	*bpt;
428		uintptr_t	pc, pltbase;
429
430		pc = pstatus.pr_lwp.pr_reg[R_PC];
431
432		if ((bpt = find_bp(ph, pc)) != (bptlist_t *)-1) {
433			if (bpt->bl_flags & MASK_BP_SPECIAL)
434				handle_sp_break(ph);
435		}
436
437		if (flgs & FLG_SN_VERBOSE)
438			disasm(ph, 1);
439
440		oper = PCSFAULT;
441		piov[1].iov_base = (caddr_t)(&faults);
442		piov[1].iov_len = sizeof (faults);
443
444		if (writev(ph->pp_ctlfd, piov, 2) == -1)
445			perr("stn: PCSFAULT");
446
447		oper = PCRUN;
448		piov[1].iov_base = (caddr_t)(&flags);
449		piov[1].iov_len = sizeof (flags);
450		if (writev(ph->pp_ctlfd, piov, 2) == -1)
451			perr("stn: PCRUN(PRSETP)");
452
453		oper = PCWSTOP;
454		if (writev(ph->pp_ctlfd, piov, 1) == -1)
455			perr("stn: PCWSTOP stepping");
456
457		if (pread(ph->pp_statusfd, &pstatus, sizeof (pstatus), 0) == -1)
458			perr("stn1: reading status");
459		pc = pstatus.pr_lwp.pr_reg[R_PC];
460
461
462		if ((pstatus.pr_lwp.pr_why != PR_FAULTED) ||
463		    (pstatus.pr_lwp.pr_what != FLTTRACE)) {
464			(void) fprintf(stderr, "sn: bad stop - stopped on "
465			    "why: 0x%x what: 0x%x\n", pstatus.pr_lwp.pr_why,
466			    pstatus.pr_lwp.pr_what);
467			return (RET_FAILED);
468		}
469
470		if ((flgs & FLG_SN_PLTSKIP) &&
471		    ((pltbase = is_plt(ph, pc)) != (ulong_t)0)) {
472			rd_plt_info_t	rp;
473			if (rd_plt_resolution(ph->pp_rap, pc,
474			    pstatus.pr_lwp.pr_lwpid, pltbase, &rp) != RD_OK) {
475				(void) fprintf(stderr,
476				    "sn: rd_plt_resolution failed\n");
477				return (RET_FAILED);
478			}
479			if (rp.pi_skip_method == RD_RESOLVE_TARGET_STEP) {
480				unsigned	bpflags;
481
482				(void) set_breakpoint(ph, rp.pi_target,
483				    FLG_BP_PLTRES);
484				bpflags = continue_to_break(ph);
485
486				(void) delete_breakpoint(ph, rp.pi_target,
487				    FLG_BP_PLTRES);
488
489				if (bpflags & FLG_BP_PLTRES)
490					(void) step_n(ph, rp.pi_nstep,
491					    FLG_SN_NONE);
492			} else if (rp.pi_skip_method == RD_RESOLVE_STEP)
493				(void) step_n(ph, rp.pi_nstep, FLG_SN_NONE);
494		}
495	}
496
497	oper = PRCFAULT;
498	if (writev(ph->pp_ctlfd, piov, 1) == -1)
499		perr("stn: PRCFAULT");
500
501	if ((flgs & FLG_SN_VERBOSE) && (ph->pp_flags & FLG_PP_LMAPS)) {
502		if (get_linkmaps(ph) != RET_OK)
503			(void) fprintf(stderr, "problem loading linkmaps\n");
504	}
505
506	return (RET_OK);
507}
508
509void
510step_to_addr(struct ps_prochandle *ph, ulong_t addr)
511{
512	pstatus_t	pstat;
513	int		count = 0;
514	ulong_t		caddr;
515
516	if (read(ph->pp_statusfd, &pstat, sizeof (pstat)) == -1)
517		perr("sta: reading status");
518
519	caddr = pstat.pr_lwp.pr_reg[R_PC];
520
521	while ((caddr > addr) || ((caddr + 0xff) < addr)) {
522		(void) step_n(ph, 1, FLG_SN_NONE);
523		if (read(ph->pp_statusfd, &pstat, sizeof (pstat)) == -1)
524			perr("sta1: reading status");
525		caddr = pstat.pr_lwp.pr_reg[R_PC];
526		if ((count % 10000) == 0) {
527			(void) printf("%d: ", count);
528			disasm(ph, 1);
529		}
530
531		count++;
532	}
533
534	(void) printf("address found %d instructions in: pc: 0x%lx addr: "
535	    "0x%lx\n", count, caddr, addr);
536}
537