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) != PS_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) != PS_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 }