8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / sgs / librtld_db / demo / common / bpt.c
blob2906467576cf7c78447e8bf0a442f516faaca896
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
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>
44 #include "rdb.h"
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)"
61 #define MAXFAULT FLTPAGE
63 retc_t
64 set_breakpoint(struct ps_prochandle *ph, ulong_t addr, unsigned flags)
66 bptlist_t *new, *cur, *prev;
68 for (cur = ph->pp_breakpoints, prev = NULL;
69 (cur && (cur->bl_addr < addr));
70 prev = cur, cur = cur->bl_next)
72 if (cur && (cur->bl_addr == addr)) {
74 * already have break point set here.
76 cur->bl_flags |= flags;
77 return (RET_OK);
80 new = malloc(sizeof (bptlist_t));
81 new->bl_addr = addr;
82 new->bl_flags = flags;
83 if (prev == NULL) {
85 * insert at head
87 new->bl_next = ph->pp_breakpoints;
88 ph->pp_breakpoints = new;
89 return (RET_OK);
92 prev->bl_next = new;
93 new->bl_next = cur;
94 return (RET_OK);
97 static bptlist_t *
98 find_bp(struct ps_prochandle *ph, ulong_t addr)
100 bptlist_t *cur;
102 for (cur = ph->pp_breakpoints;
103 (cur && (cur->bl_addr != addr));
104 cur = cur->bl_next)
107 if ((cur == NULL) || (cur->bl_addr != addr))
108 return ((bptlist_t *)-1);
109 return (cur);
112 static retc_t
113 delete_bp(struct ps_prochandle *ph, ulong_t addr)
115 bptlist_t *cur, *prev;
117 for (cur = ph->pp_breakpoints, prev = NULL;
118 (cur && (cur->bl_addr < addr));
119 prev = cur, cur = cur->bl_next)
121 if ((cur == NULL) || (cur->bl_addr != addr))
122 return (RET_FAILED);
124 if (prev == NULL)
125 ph->pp_breakpoints = cur->bl_next;
126 else
127 prev->bl_next = cur->bl_next;
129 free(cur);
130 return (RET_OK);
133 void
134 list_breakpoints(struct ps_prochandle *ph)
136 bptlist_t *cur;
138 if (ph->pp_breakpoints == NULL) {
139 (void) printf("no active breakpoints.\n");
140 return;
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));
151 static void
152 set_breaks(struct ps_prochandle *ph)
154 bptlist_t *cur;
155 bptinstr_t bpt_instr = BPINSTR;
157 for (cur = ph->pp_breakpoints; cur; cur = cur->bl_next) {
158 bptinstr_t old_inst = 0;
160 if (ps_pread(ph, cur->bl_addr, (char *)&old_inst,
161 sizeof (bptinstr_t)) != PS_OK)
162 perr("sb: error setting breakpoint");
164 cur->bl_instr = old_inst;
166 if (ps_pwrite(ph, cur->bl_addr, (char *)&bpt_instr,
167 sizeof (bptinstr_t)) != PS_OK)
168 perr("sb1: error setting breakpoint\n");
173 static void
174 clear_breaks(struct ps_prochandle *ph)
176 bptlist_t *cur;
179 * Restore all the original instructions
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");
187 retc_t
188 delete_all_breakpoints(struct ps_prochandle *ph)
190 bptlist_t *cur, *prev;
192 if (ph->pp_breakpoints == NULL)
193 return (RET_OK);
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);
202 ph->pp_breakpoints = NULL;
203 return (RET_OK);
206 retc_t
207 delete_breakpoint(struct ps_prochandle *ph, ulong_t addr, unsigned flags)
209 bptlist_t *bpt;
211 if (((bpt = find_bp(ph, addr)) == (bptlist_t *)-1) ||
212 ((bpt->bl_flags & flags) == 0))
213 return (RET_FAILED);
215 bpt->bl_flags &= ~flags;
216 if (bpt->bl_flags)
217 return (RET_OK);
219 return (delete_bp(ph, addr));
222 static void
223 handle_sp_break(struct ps_prochandle *ph)
225 rd_event_msg_t emt;
227 if (rd_event_getmsg(ph->pp_rap, &emt) != RD_OK) {
228 (void) fprintf(stderr, "hsb: failed rd_event_getmsg()\n");
229 return;
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;
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);
254 return;
257 if ((rdb_flags & RDB_FL_EVENTS) == 0)
258 return;
260 if (emt.type == RD_PREINIT) {
261 (void) printf("preinit reached\n");
262 return;
265 if (emt.type == RD_POSTINIT)
266 (void) printf("postinit reached\n");
269 unsigned
270 continue_to_break(struct ps_prochandle *ph)
272 bptlist_t *bpt;
273 pstatus_t pstatus;
274 struct iovec piov[5];
275 long oper1, oper2, oper3, pflags = 0;
276 fltset_t faults;
279 * We step by the first instruction incase their was
280 * a break-point there.
282 (void) step_n(ph, 1, FLG_SN_NONE);
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);
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);
302 piov[1].iov_base = (caddr_t)(&faults);
303 piov[1].iov_len = sizeof (faults);
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);
312 oper3 = PCWSTOP;
313 piov[4].iov_base = (caddr_t)(&oper3);
314 piov[4].iov_len = sizeof (oper3);
316 if (writev(ph->pp_ctlfd, piov, 5) == -1) {
317 if (errno == ENOENT) {
318 ph->pp_flags &= ~FLG_PP_PACT;
320 (void) ps_close(ph);
321 (void) printf("process terminated.\n");
322 return (0);
324 perr("ctb: PCWSTOP");
327 if (pread(ph->pp_statusfd, &pstatus, sizeof (pstatus), 0) == -1)
328 perr("ctb: reading status");
331 if ((pstatus.pr_lwp.pr_why != PR_FAULTED) ||
332 (pstatus.pr_lwp.pr_what != FLTBPT)) {
333 const char *fltmsg;
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>";
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);
348 oper1 = PCCFAULT;
349 if (writev(ph->pp_ctlfd, piov, 1) == -1)
350 perr("ctb: PCCFAULT");
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;
360 clear_breaks(ph);
363 * If this was a BP at which we should stop
365 if (bpt->bl_flags & MASK_BP_STOP)
366 break;
368 (void) step_n(ph, 1, FLG_SN_NONE);
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]));
375 if (bpt->bl_flags & MASK_BP_SPECIAL)
376 handle_sp_break(ph);
378 if (ph->pp_flags & FLG_PP_LMAPS) {
379 if (get_linkmaps(ph) != PS_OK)
380 (void) fprintf(stderr, "problem loading linkmaps\n");
383 return (bpt->bl_flags);
386 ulong_t
387 is_plt(struct ps_prochandle *ph, ulong_t pc)
389 map_info_t *mip;
390 ulong_t pltbase;
392 if ((mip = addr_to_map(ph, pc)) == (map_info_t *)0)
393 return ((ulong_t)0);
395 pltbase = mip->mi_pltbase;
396 if ((mip->mi_flags & FLG_MI_EXEC) == 0)
397 pltbase += mip->mi_addr;
399 if ((pc >= pltbase) && (pc <= (pltbase + mip->mi_pltsize)))
400 return (pltbase);
402 return ((ulong_t)0);
405 retc_t
406 step_n(struct ps_prochandle *ph, size_t count, sn_flags_e flgs)
408 pstatus_t pstatus;
409 fltset_t faults;
410 int i;
411 long oper;
412 long flags;
413 struct iovec piov[2];
415 if (pread(ph->pp_statusfd, &pstatus, sizeof (pstatus), 0) == -1)
416 perr("stn: reading status");
418 piov[0].iov_base = (caddr_t)(&oper);
419 piov[0].iov_len = sizeof (oper);
421 premptyset(&faults);
422 praddset(&faults, FLTTRACE);
424 flags = PRSTEP | PRCFAULT;
426 for (i = 0; i < count; i++) {
427 bptlist_t *bpt;
428 uintptr_t pc, pltbase;
430 pc = pstatus.pr_lwp.pr_reg[R_PC];
432 if ((bpt = find_bp(ph, pc)) != (bptlist_t *)-1) {
433 if (bpt->bl_flags & MASK_BP_SPECIAL)
434 handle_sp_break(ph);
437 if (flgs & FLG_SN_VERBOSE)
438 disasm(ph, 1);
440 oper = PCSFAULT;
441 piov[1].iov_base = (caddr_t)(&faults);
442 piov[1].iov_len = sizeof (faults);
444 if (writev(ph->pp_ctlfd, piov, 2) == -1)
445 perr("stn: PCSFAULT");
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)");
453 oper = PCWSTOP;
454 if (writev(ph->pp_ctlfd, piov, 1) == -1)
455 perr("stn: PCWSTOP stepping");
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];
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);
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);
479 if (rp.pi_skip_method == RD_RESOLVE_TARGET_STEP) {
480 unsigned bpflags;
482 (void) set_breakpoint(ph, rp.pi_target,
483 FLG_BP_PLTRES);
484 bpflags = continue_to_break(ph);
486 (void) delete_breakpoint(ph, rp.pi_target,
487 FLG_BP_PLTRES);
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);
497 oper = PRCFAULT;
498 if (writev(ph->pp_ctlfd, piov, 1) == -1)
499 perr("stn: PRCFAULT");
501 if ((flgs & FLG_SN_VERBOSE) && (ph->pp_flags & FLG_PP_LMAPS)) {
502 if (get_linkmaps(ph) != PS_OK)
503 (void) fprintf(stderr, "problem loading linkmaps\n");
506 return (RET_OK);
509 void
510 step_to_addr(struct ps_prochandle *ph, ulong_t addr)
512 pstatus_t pstat;
513 int count = 0;
514 ulong_t caddr;
516 if (read(ph->pp_statusfd, &pstat, sizeof (pstat)) == -1)
517 perr("sta: reading status");
519 caddr = pstat.pr_lwp.pr_reg[R_PC];
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);
531 count++;
534 (void) printf("address found %d instructions in: pc: 0x%lx addr: "
535 "0x%lx\n", count, caddr, addr);