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
set_breakpoint(struct ps_prochandle * ph,ulong_t addr,unsigned flags)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 *
find_bp(struct ps_prochandle * ph,ulong_t addr)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
delete_bp(struct ps_prochandle * ph,ulong_t addr)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
list_breakpoints(struct ps_prochandle * ph)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
set_breaks(struct ps_prochandle * ph)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
clear_breaks(struct ps_prochandle * ph)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
delete_all_breakpoints(struct ps_prochandle * ph)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
delete_breakpoint(struct ps_prochandle * ph,ulong_t addr,unsigned flags)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
handle_sp_break(struct ps_prochandle * ph)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
continue_to_break(struct ps_prochandle * ph)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
is_plt(struct ps_prochandle * ph,ulong_t pc)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
step_n(struct ps_prochandle * ph,size_t count,sn_flags_e flgs)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
step_to_addr(struct ps_prochandle * ph,ulong_t addr)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