Exemplo n.º 1
0
long
powerpc_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
{
    struct reg regs;
    long retval;
    int i;
    int errorp;
    struct syscall *sc;

    if (fsc.name == NULL)
        return (-1);

    cpid = trussinfo->curthread->tid;

    if (ptrace(PT_GETREGS, cpid, (caddr_t)&regs, 0) < 0) {
        fprintf(trussinfo->outfile, "\n");
        return (-1);
    }
    retval = regs.fixreg[3];
    errorp = !!(regs.cr & 0x10000000);

    /*
     * This code, while simpler than the initial versions I used, could
     * stand some significant cleaning.
     */

    sc = fsc.sc;
    if (!sc) {
        for (i = 0; i < fsc.nargs; i++)
            asprintf(&fsc.s_args[i], "0x%lx", fsc.args[i]);
    } else {
        /*
         * On 32-bit big-endian, the low word of a 64-bit return is
         * in the greater address. Switch to this. XXX note that
         * print_syscall_ret can't handle 64-bit return values (llseek)
         */
        if (sc->ret_type == 2)
            retval = regs.fixreg[4];

        /*
         * Here, we only look for arguments that have OUT masked in --
         * otherwise, they were handled in the syscall_entry function.
         */
        for (i = 0; i < sc->nargs; i++) {
            char *temp;
            if (sc->args[i].type & OUT) {
                /*
                 * If an error occurred, than don't bothe getting the data;
                 * it may not be valid.
                 */
                if (errorp)
                    asprintf(&temp, "0x%lx", fsc.args[sc->args[i].offset]);
                else
                    temp = print_arg(&sc->args[i], fsc.args, retval, trussinfo);
                fsc.s_args[i] = temp;
            }
        }
    }

    if (fsc.name != NULL &&
            (!strcmp(fsc.name, "execve") || !strcmp(fsc.name, "exit"))) {
        trussinfo->curthread->in_syscall = 1;
    }


    /*
     * It would probably be a good idea to merge the error handling,
     * but that complicates things considerably.
     */

    print_syscall_ret(trussinfo, fsc.name, fsc.nargs, fsc.s_args, errorp,
                      retval, fsc.sc);
    clear_fsc();

    return (retval);
}
Exemplo n.º 2
0
void
powerpc_syscall_entry(struct trussinfo *trussinfo, int nargs) {
    char buf[32];
    struct reg regs;
    void *args;
    int syscall_num;
    int i;
    unsigned int regargs;
    struct syscall *sc;

    /* Account for a 64-bit argument with corresponding alignment. */
    nargs += 2;

    cpid = trussinfo->curthread->tid;

    clear_fsc();
    if (ptrace(PT_GETREGS, cpid, (caddr_t)&regs, 0) < 0) {
        fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
        return;
    }

    /*
     * FreeBSD has two special kinds of system call redirctions --
     * SYS_syscall, and SYS___syscall.  The former is the old syscall()
     * routine, basically; the latter is for quad-aligned arguments.
     */
    regargs = NARGREG;
    syscall_num = regs.fixreg[0];
    args = &regs.fixreg[3];
    if (syscall_num == SYS_syscall) {
        args = &regs.fixreg[4];
        regargs -= 1;
        syscall_num = regs.fixreg[3];
    } else if (syscall_num == SYS___syscall) {
        args = &regs.fixreg[5];
        regargs -= 2;
        syscall_num = regs.fixreg[4];
    }

    fsc.number = syscall_num;
    fsc.name =
        (syscall_num < 0 || syscall_num >= nsyscalls) ? NULL : syscallnames[syscall_num];
    if (!fsc.name) {
        fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", syscall_num);
    }

    if (fsc.name && (trussinfo->flags & FOLLOWFORKS)
            && ((!strcmp(fsc.name, "fork")
                 || !strcmp(fsc.name, "rfork")
                 || !strcmp(fsc.name, "vfork"))))
    {
        trussinfo->curthread->in_fork = 1;
    }

    if (nargs == 0)
        return;

    fsc.args = malloc((1+nargs) * sizeof(unsigned long));

    if (nargs > regargs) {
        struct ptrace_io_desc iorequest;
        memmove(&fsc.args[0], args, regargs * sizeof(fsc.args[0]));

        iorequest.piod_op = PIOD_READ_D;
        iorequest.piod_offs = (void *)(regs.fixreg[1] + 8);
        iorequest.piod_addr = &fsc.args[regargs];
        iorequest.piod_len = (nargs - regargs) * sizeof(fsc.args[0]);
        ptrace(PT_IO, cpid, (caddr_t)&iorequest, 0);
        if (iorequest.piod_len == 0)
            return;
    } else {
        memmove(&fsc.args[0], args, nargs * sizeof(fsc.args[0]));
    }

    sc = get_syscall(fsc.name);
    if (sc) {
        fsc.nargs = sc->nargs;
    } else {
#if DEBUG
        fprintf(trussinfo->outfile, "unknown syscall %s -- setting args to %d\n",
                fsc.name, nargs);
#endif
        fsc.nargs = nargs;
    }

    fsc.s_args = calloc(1, (1+fsc.nargs) * sizeof(char*));
    fsc.sc = sc;

    /*
     * At this point, we set up the system call arguments.
     * We ignore any OUT ones, however -- those are arguments that
     * are set by the system call, and so are probably meaningless
     * now.  This doesn't currently support arguments that are
     * passed in *and* out, however.
     */

    if (fsc.name) {

#if DEBUG
        fprintf(stderr, "syscall %s(", fsc.name);
#endif
        for (i = 0; i < fsc.nargs; i++) {
#if DEBUG
            fprintf(stderr, "0x%x%s",
                    sc
                    ? fsc.args[sc->args[i].offset]
                    : fsc.args[i],
                    i < (fsc.nargs - 1) ? "," : "");
#endif
            if (sc && !(sc->args[i].type & OUT)) {
                fsc.s_args[i] = print_arg(&sc->args[i], fsc.args, 0, trussinfo);
            }
        }
#if DEBUG
        fprintf(stderr, ")\n");
#endif
    }

#if DEBUG
    fprintf(trussinfo->outfile, "\n");
#endif

    if (fsc.name && (!strcmp(fsc.name, "execve") || !strcmp(fsc.name, "exit"))) {

        /* XXX
         * This could be done in a more general
         * manner but it still wouldn't be very pretty.
         */
        if (!strcmp(fsc.name, "execve")) {
            if ((trussinfo->flags & EXECVEARGS) == 0)
                if (fsc.s_args[1]) {
                    free(fsc.s_args[1]);
                    fsc.s_args[1] = NULL;
                }
            if ((trussinfo->flags & EXECVEENVS) == 0)
                if (fsc.s_args[2]) {
                    free(fsc.s_args[2]);
                    fsc.s_args[2] = NULL;
                }
        }
    }

    return;
}
Exemplo n.º 3
0
long
amd64_linux32_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
{
  struct reg regs;
  long retval;
  int i;
  int errorp;
  struct syscall *sc;

  if (fsc.name == NULL)
	return (-1);

  cpid = trussinfo->curthread->tid;
  if (ptrace(PT_GETREGS, cpid, (caddr_t)&regs, 0) < 0)
  {
    fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
    return (-1);
  }

  retval = regs.r_rax;
  errorp = !!(regs.r_rflags & PSL_C);

  /*
   * This code, while simpler than the initial versions I used, could
   * stand some significant cleaning.
   */

  sc = fsc.sc;
  if (!sc) {
    for (i = 0; i < fsc.nargs; i++)
      asprintf(&fsc.s_args[i], "0x%lx", fsc.args[i]);
  } else {
    /*
     * Here, we only look for arguments that have OUT masked in --
     * otherwise, they were handled in the syscall_entry function.
     */
    for (i = 0; i < sc->nargs; i++) {
      char *temp;
      if (sc->args[i].type & OUT) {
	/*
	 * If an error occurred, than don't bothe getting the data;
	 * it may not be valid.
	 */
	if (errorp)
	  asprintf(&temp, "0x%lx", fsc.args[sc->args[i].offset]);
	else
	  temp = print_arg(&sc->args[i], fsc.args, retval, trussinfo);
	fsc.s_args[i] = temp;
      }
    }
  }

  /*
   * It would probably be a good idea to merge the error handling,
   * but that complicates things considerably.
   */
  if (errorp) {
    for (i = 0; (size_t)i < sizeof(bsd_to_linux_errno) / sizeof(int); i++)
      if (retval == bsd_to_linux_errno[i])
      break;
  }

  if (fsc.name != NULL &&
      (!strcmp(fsc.name, "linux_execve") || !strcmp(fsc.name, "exit"))) {
	trussinfo->curthread->in_syscall = 1;
  }

  print_syscall_ret(trussinfo, fsc.name, fsc.nargs, fsc.s_args, errorp,
                    errorp ? i : retval, fsc.sc);
  clear_fsc();

  return (retval);
}
Exemplo n.º 4
0
void
mips_syscall_entry(struct trussinfo *trussinfo, int nargs) {
    struct reg regs;
    int syscall_num;
    int i;
    struct syscall *sc;
    int indir = 0;	/* indirect system call */
    struct ptrace_io_desc iorequest;

    cpid = trussinfo->curthread->tid;

    clear_fsc();

    if (ptrace(PT_GETREGS, cpid, (caddr_t)&regs, 0) < 0) {
        fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
        return;
    }

    syscall_num = regs.r_regs[V0];
    if (syscall_num == SYS_syscall) {
        indir = 1;
        syscall_num = regs.r_regs[A0];
    }

    fsc.number = syscall_num;
    fsc.name =
        (syscall_num < 0 || syscall_num >= nsyscalls) ? NULL : syscallnames[syscall_num];
    if (!fsc.name) {
        fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", syscall_num);
    }

    if (fsc.name && (trussinfo->flags & FOLLOWFORKS)
            && ((!strcmp(fsc.name, "fork")
                 || !strcmp(fsc.name, "rfork")
                 || !strcmp(fsc.name, "vfork"))))
    {
        trussinfo->curthread->in_fork = 1;
    }

    if (nargs == 0)
        return;

    fsc.args = malloc((1+nargs) * sizeof(unsigned long));
#if 0 // XXX
    iorequest.piod_op = PIOD_READ_D;
    iorequest.piod_offs = (void *)parm_offset;
    iorequest.piod_addr = fsc.args;
    iorequest.piod_len = (1+nargs) * sizeof(unsigned long);
    ptrace(PT_IO, cpid, (caddr_t)&iorequest, 0);
    if (iorequest.piod_len == 0)
        return;
#else
    iorequest.piod_op = PIOD_READ_D;
#endif

    switch (nargs) {
    default:
        /*
         * The OS doesn't seem to allow more than 10 words of
         * parameters (yay!).  So we shouldn't be here.
         */
        warn("More than 10 words (%d) of arguments!\n", nargs);
        break;
    case 10:
    case 9:
    case 8:
    case 7:
    case 6:
    case 5:
        /*
         * If there are 7-10 words of arguments, they are placed
         * on the stack, as is normal for other processors.
         * The fall-through for all of these is deliberate!!!
         */
        // XXX BAD constant used here
        iorequest.piod_op = PIOD_READ_D;
        iorequest.piod_offs = (void *)(regs.r_regs[SP] + 4 * sizeof(uint32_t));
        iorequest.piod_addr = &fsc.args[4];
        iorequest.piod_len = (nargs - 4) * sizeof(fsc.args[0]);
        ptrace(PT_IO, cpid, (caddr_t)&iorequest, 0);
        if (iorequest.piod_len == 0) return;
    case 4:
        fsc.args[3] = regs.r_regs[A3];
    case 3:
        fsc.args[2] = regs.r_regs[A2];
    case 2:
        fsc.args[1] = regs.r_regs[A1];
    case 1:
        fsc.args[0] = regs.r_regs[A0];
    case 0:
        break;
    }
    if (indir) {
        memmove(&fsc.args[0], &fsc.args[1], (nargs-1) * sizeof(fsc.args[0]));
    }

    sc = get_syscall(fsc.name);
    if (sc) {
        fsc.nargs = sc->nargs;
    } else {
#if DEBUG
        fprintf(trussinfo->outfile, "unknown syscall %s -- setting args to %d\n",
                fsc.name, nargs);
#endif
        fsc.nargs = nargs;
    }

    fsc.s_args = calloc(1, (1+fsc.nargs) * sizeof(char*));
    fsc.sc = sc;

    /*
     * At this point, we set up the system call arguments.
     * We ignore any OUT ones, however -- those are arguments that
     * are set by the system call, and so are probably meaningless
     * now.  This doesn't currently support arguments that are
     * passed in *and* out, however.
     */

    if (fsc.name) {

#if DEBUG
        fprintf(stderr, "syscall %s(", fsc.name);
#endif
        for (i = 0; i < fsc.nargs; i++) {
#if DEBUG
            fprintf(stderr, "0x%x%s",
                    sc
                    ? fsc.args[sc->args[i].offset]
                    : fsc.args[i],
                    i < (fsc.nargs - 1) ? "," : "");
#endif
            if (sc && !(sc->args[i].type & OUT)) {
                fsc.s_args[i] = print_arg(&sc->args[i], fsc.args, 0, trussinfo);
            }
        }
#if DEBUG
        fprintf(stderr, ")\n");
#endif
    }

#if DEBUG
    fprintf(trussinfo->outfile, "\n");
#endif

    if (fsc.name != NULL &&
            (!strcmp(fsc.name, "execve") || !strcmp(fsc.name, "exit"))) {

        /* XXX
         * This could be done in a more general
         * manner but it still wouldn't be very pretty.
         */
        if (!strcmp(fsc.name, "execve")) {
            if ((trussinfo->flags & EXECVEARGS) == 0)
                if (fsc.s_args[1]) {
                    free(fsc.s_args[1]);
                    fsc.s_args[1] = NULL;
                }
            if ((trussinfo->flags & EXECVEENVS) == 0)
                if (fsc.s_args[2]) {
                    free(fsc.s_args[2]);
                    fsc.s_args[2] = NULL;
                }
        }
    }

    return;
}
Exemplo n.º 5
0
void
amd64_linux32_syscall_entry(struct trussinfo *trussinfo, int nargs) {
  struct reg regs;
  int syscall_num;
  int i;
  struct syscall *sc;

  cpid = trussinfo->curthread->tid;

  clear_fsc();
  
  if (ptrace(PT_GETREGS, cpid, (caddr_t)&regs, 0) < 0)
  {
    fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
    return;
  } 
  syscall_num = regs.r_rax;

  fsc.number = syscall_num;
  fsc.name =
    (syscall_num < 0 || syscall_num >= nsyscalls) ? NULL : linux32_syscallnames[syscall_num];
  if (!fsc.name) {
    fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", syscall_num);
  }

  if (fsc.name && (trussinfo->flags & FOLLOWFORKS)
   && ((!strcmp(fsc.name, "linux_fork")
    || !strcmp(fsc.name, "linux_vfork"))))
  {
    trussinfo->curthread->in_fork = 1;
  }

  if (nargs == 0)
    return;

  /*
   * Linux passes syscall arguments in registers, not
   * on the stack.  Fortunately, we've got access to the
   * register set.  Note that we don't bother checking the
   * number of arguments.  And what does linux do for syscalls
   * that have more than five arguments?
   */

  fsc.args[0] = regs.r_rbx;
  fsc.args[1] = regs.r_rcx;
  fsc.args[2] = regs.r_rdx;
  fsc.args[3] = regs.r_rsi;
  fsc.args[4] = regs.r_rdi;

  sc = get_syscall(fsc.name);
  if (sc) {
    fsc.nargs = sc->nargs;
  } else {
#if DEBUG
    fprintf(trussinfo->outfile, "unknown syscall %s -- setting args to %d\n",
	   fsc.name, nargs);
#endif
    fsc.nargs = nargs;
  }

  fsc.s_args = calloc(1, (1+fsc.nargs) * sizeof(char*));
  fsc.sc = sc;

  /*
   * At this point, we set up the system call arguments.
   * We ignore any OUT ones, however -- those are arguments that
   * are set by the system call, and so are probably meaningless
   * now.  This doesn't currently support arguments that are
   * passed in *and* out, however.
   */

  if (fsc.name) {

#if DEBUG
    fprintf(stderr, "syscall %s(", fsc.name);
#endif
    for (i = 0; i < fsc.nargs; i++) {
#if DEBUG
      fprintf(stderr, "0x%x%s",
	      sc
	      ? fsc.args[sc->args[i].offset]
	      : fsc.args[i],
	      i < (fsc.nargs - 1) ? "," : "");
#endif
      if (sc && !(sc->args[i].type & OUT)) {
	fsc.s_args[i] = print_arg(&sc->args[i], fsc.args, 0, trussinfo);
      }
    }
#if DEBUG
    fprintf(stderr, ")\n");
#endif
  }

#if DEBUG
  fprintf(trussinfo->outfile, "\n");
#endif

  if (fsc.name != NULL &&
      (!strcmp(fsc.name, "linux_execve") || !strcmp(fsc.name, "exit"))) {

    /* XXX
     * This could be done in a more general
     * manner but it still wouldn't be very pretty.
     */
    if (!strcmp(fsc.name, "linux_execve")) {
        if ((trussinfo->flags & EXECVEARGS) == 0)
          if (fsc.s_args[1]) {
            free(fsc.s_args[1]);
            fsc.s_args[1] = NULL;
          }
        if ((trussinfo->flags & EXECVEENVS) == 0)
          if (fsc.s_args[2]) {
            free(fsc.s_args[2]);
            fsc.s_args[2] = NULL;
          }
    }
  }

  return;
}