xref: /illumos-gate/usr/src/cmd/sgs/demo_rdb/common/bpt.c (revision 16b76d3cb933ff92018a2a75594449010192eacb)
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 
46 static 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 
63 retc_t
64 set_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 
97 static bptlist_t *
98 find_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 
112 static retc_t
113 delete_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 
133 void
134 list_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 
151 static void
152 set_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 
173 static void
174 clear_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 
187 retc_t
188 delete_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 
206 retc_t
207 delete_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 
222 static void
223 handle_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 
269 unsigned
270 continue_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 
386 ulong_t
387 is_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 
405 retc_t
406 step_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 
509 void
510 step_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