Beispiel #1
0
/*
 * Document-method: PinkTrace::StringArray.decode
 * call-seq:
 *   PinkTrace::StringArray.decode(pid, arg, index, [[maxlen=-1], [bitness=PinkTrace::Bitness::DEFAULT]]) -> String or nil
 *
 * This function decodes the member of the string array pointed by the address
 * +arg+. The +index+ argument specifies the index of the member in the string
 * array.
 *
 * Note: If the string array member was NULL, this function returns nil.
 */
VALUE
pinkrb_decode_strarray(int argc, VALUE *argv, VALUE mod)
{
    bool nil;
    pid_t pid;
    unsigned bit, ind;
    long arg;
    int maxlen;
    char *str;
    VALUE vpid, varg, vind, vmax, vbit, vret;

    switch (rb_scan_args(argc, argv, "32", &vpid, &varg, &vind, &vmax, &vbit)) {
    case 3:
        maxlen = -1;
        bit = PINKTRACE_BITNESS_DEFAULT;
        break;
    case 4:
        maxlen = NUM2INT(vmax);
        bit = PINKTRACE_BITNESS_DEFAULT;
        break;
    case 5:
        maxlen = NUM2INT(vmax);
        bit = FIX2UINT(vbit);
        break;
    default:
        abort();
    }
    pid = NUM2PIDT(vpid);
    arg = NUM2LONG(varg);
    ind = FIX2UINT(vind);

    if (maxlen < 0) {
        /* Use pink_decode_string_array_member_persistent() */
        errno = 0;
        str = pink_decode_string_array_member_persistent(pid, bit, arg, ind);
        if (!str) {
            if (errno)
                rb_sys_fail("pink_decode_string_array_member_persistent()");
            return Qnil;
        }

        vret = rb_str_new2(str);
        free(str);
        return vret;
    }

    /* Use pink_decode_string_array_member() */
    str = ALLOC_N(char, maxlen);
    if (!pink_decode_string_array_member(pid, bit, arg, ind, str, maxlen, &nil))
        rb_sys_fail("pink_decode_string_array_member()");
    if (nil) {
        free(str);
        return Qnil;
    }

    vret = rb_str_new2(str);
    if (str)
        free(str);
    return vret;
}
Beispiel #2
0
/*
 * Document-method: PinkTrace::Trace.setup
 * call-seq:
 *   PinkTrace::Trace.setup(pid, [options=0]) -> nil
 *
 * Sets the tracing options.
 *
 * Availability: Linux
 */
VALUE
pinkrb_trace_setup(int argc, VALUE *argv, VALUE mod)
{
#ifdef PINKTRACE_LINUX
	pid_t pid;
	int opts;
	VALUE vpid, vopts;

	switch (rb_scan_args(argc, argv, "11", &vpid, &vopts)) {
	case 1:
		opts = 0;
		break;
	case 2:
		opts = NUM2INT(vopts);
		break;
	default:
		abort();
	}
	pid = NUM2PIDT(vpid);

	if (!pink_trace_setup(pid, opts))
		rb_sys_fail("pink_trace_setup()");

	return Qnil;
#else
	rb_raise(rb_eNotImpError, "Not implemented");
#endif
}
Beispiel #3
0
/*
 * Document-method: PinkTrace::Trace.cont
 * call-seq:
 *   PinkTrace::Trace.cont(pid, [[sig=0], [addr=1]]) -> nil
 *
 * Restarts the stopped child process.
 *
 * If +sig+ argument is non-zero and not SIGSTOP, it is interpreted as the
 * signal to be delivered to the child; otherwise, no signal is delivered.
 * Thus, for example, the parent can control whether a signal sent to the child
 * is delivered or not.
 *
 * On FreeBSD +addr+ is an address specifying the place where execution
 * is to be resumed (a new value for the program counter), or 1 to indicate
 * that execution is to pick up where it left off.
 * On Linux, this argument is not used.
 */
VALUE
pinkrb_trace_cont(int argc, VALUE *argv, VALUE mod)
{
	pid_t pid;
	long sig, addr;
	VALUE vpid, vsig, vaddr;

	switch (rb_scan_args(argc, argv, "12", &vpid, &vsig, &vaddr)) {
	case 1:
		addr = 1;
		sig = 0;
		break;
	case 2:
		addr = 1;
		sig = NUM2LONG(vsig);
		break;
	case 3:
		addr = NUM2LONG(vaddr);
		sig = NUM2LONG(vsig);
		break;
	default:
		abort();
	}
	pid = NUM2PIDT(vpid);

	if (!pink_trace_cont(pid, sig, (char *)addr))
		rb_sys_fail("pink_trace_cont()");

	return Qnil;
}
Beispiel #4
0
/*
 * Document-method: PinkTrace::Trace.sysemu_singlestep
 * call-seq:
 *   PinkTrace::Trace.sysemu_singlestep(pid, [sig=0]) -> nil
 *
 * Restarts the stopped child process PinkTrace::Trace.sysemu but also
 * singlesteps if not a system call.
 *
 * The +sig+ argument is treated as the same way as the +sig+ argument of
 * PinkTrace::Trace.cont.
 *
 * Availability: Linux
 */
VALUE
pinkrb_trace_sysemu_singlestep(int argc, VALUE *argv, VALUE mod)
{
#ifdef PINKTRACE_LINUX
	pid_t pid;
	long sig;
	VALUE vpid, vsig;

	switch (rb_scan_args(argc, argv, "11", &vpid, &vsig)) {
	case 1:
		sig = 0;
		break;
	case 2:
		sig = NUM2LONG(vsig);
		break;
	default:
		abort();
	}
	pid = NUM2PIDT(vpid);

	if (!pink_trace_sysemu_singlestep(pid, sig))
		rb_sys_fail("pink_trace_sysemu_singlestep()");

	return Qnil;
#else
	rb_raise(rb_eNotImpError, "Not implemented");
#endif
}
Beispiel #5
0
/*
 * Document-method: PinkTrace::Trace.attach
 * call-seq:
 *   PinkTrace::Trace.attach(pid) -> nil
 *
 * Attaches to the process specified in pid, making it a traced "child" of the
 * calling process; the behaviour of the child is as if it had done a
 * PinkTrace::Trace.me. The child is sent a SIGSTOP, but will not necessarily have
 * stopped by the completion of this call; use Process.waitpid to wait for the
 * child to stop.
 */
VALUE
pinkrb_trace_attach(VALUE mod, VALUE vpid)
{
	pid_t pid;

	pid = NUM2PIDT(vpid);
	if (!pink_trace_attach(pid))
		rb_sys_fail("pink_trace_attach()");

	return Qnil;
}
Beispiel #6
0
/*
 * Document-method: PinkTrace::Trace.geteventmsg
 * call-seq:
 *   PinkTrace::Trace.geteventmsg(pid) -> fixnum
 *
 * Returns a message (as a <tt>fixnum</tt>) about the trace event that just
 * happened, For *EXIT* event this is the child's exit status. For *FORK*,
 * *VFORK*, *CLONE* and *VFORK_DONE* events this is the process ID of the new
 * process.
 *
 * Availability: Linux
 */
VALUE
pinkrb_trace_geteventmsg(VALUE mod, VALUE vpid)
{
#ifdef PINKTRACE_LINUX
	pid_t pid;
	unsigned long data;

	pid = NUM2PIDT(vpid);
	if (!pink_trace_geteventmsg(pid, &data))
		rb_sys_fail("pink_trace_geteventmsg()");

	return ULONG2NUM(data);
#else
	rb_raise(rb_eNotImpError, "Not implemented");
#endif
}
Beispiel #7
0
/*
 * Document-method: PinkTrace::Trace.detach
 * call-seq:
 *   PinkTrace::Trace.detach(pid, [sig=0]) -> nil
 *
 * Restarts the stopped child as for PinkTrace::Trace.cont, but first detaches
 * from the process, undoing the reparenting effect of PinkTrace::Trace.attach.
 *
 * The +sig+ argument is treated as the same way as the +sig+ argument of
 * PinkTrace::Trace.cont.
 */
VALUE
pinkrb_trace_detach(int argc, VALUE *argv, VALUE mod)
{
	pid_t pid;
	long sig;
	VALUE vpid, vsig;

	switch (rb_scan_args(argc, argv, "11", &vpid, &vsig)) {
	case 1:
		sig = 0;
		break;
	case 2:
		sig = NUM2LONG(vsig);
		break;
	default:
		abort();
	}
	pid = NUM2PIDT(vpid);

	if (!pink_trace_detach(pid, sig))
		rb_sys_fail("pink_trace_detach()");

	return Qnil;
}
Beispiel #8
0
VALUE
rb_f_kill(int argc, const VALUE *argv)
{
#ifndef HAVE_KILLPG
#define killpg(pg, sig) kill(-(pg), (sig))
#endif
    int negative = 0;
    int sig;
    int i;
    VALUE str;
    const char *s;

    rb_secure(2);
    rb_check_arity(argc, 2, UNLIMITED_ARGUMENTS);

    switch (TYPE(argv[0])) {
      case T_FIXNUM:
	sig = FIX2INT(argv[0]);
	break;

      case T_SYMBOL:
	str = rb_sym2str(argv[0]);
	goto str_signal;

      case T_STRING:
	str = argv[0];
      str_signal:
	s = RSTRING_PTR(str);
	if (s[0] == '-') {
	    negative++;
	    s++;
	}
	if (strncmp(signame_prefix, s, sizeof(signame_prefix)) == 0)
	    s += 3;
	if ((sig = signm2signo(s)) == 0) {
	    long ofs = s - RSTRING_PTR(str);
	    if (ofs) str = rb_str_subseq(str, ofs, RSTRING_LEN(str)-ofs);
	    rb_raise(rb_eArgError, "unsupported name `SIG%"PRIsVALUE"'", str);
	}

	if (negative)
	    sig = -sig;
	break;

      default:
	str = rb_check_string_type(argv[0]);
	if (!NIL_P(str)) {
	    goto str_signal;
	}
	rb_raise(rb_eArgError, "bad signal type %s",
		 rb_obj_classname(argv[0]));
	break;
    }

    if (argc <= 1) return INT2FIX(0);

    if (sig < 0) {
	sig = -sig;
	for (i=1; i<argc; i++) {
	    if (killpg(NUM2PIDT(argv[i]), sig) < 0)
		rb_sys_fail(0);
	}
    }
    else {
	const rb_pid_t self = (GET_THREAD() == GET_VM()->main_thread) ? getpid() : -1;
	int wakeup = 0;

	for (i=1; i<argc; i++) {
	    rb_pid_t pid = NUM2PIDT(argv[i]);

	    if ((sig != 0) && (self != -1) && (pid == self)) {
		int t;
		/*
		 * When target pid is self, many caller assume signal will be
		 * delivered immediately and synchronously.
		 */
		switch (sig) {
		  case SIGSEGV:
#ifdef SIGBUS
		  case SIGBUS:
#endif
#ifdef SIGKILL
		  case SIGKILL:
#endif
#ifdef SIGSTOP
		  case SIGSTOP:
#endif
		    ruby_kill(pid, sig);
		    break;
		  default:
		    t = signal_ignored(sig);
		    if (t) {
			if (t < 0 && kill(pid, sig))
			    rb_sys_fail(0);
			break;
		    }
		    signal_enque(sig);
		    wakeup = 1;
		}
	    }
	    else if (kill(pid, sig) < 0) {
		rb_sys_fail(0);
	    }
	}
	if (wakeup) {
	    rb_threadptr_check_signal(GET_VM()->main_thread);
	}
    }
    rb_thread_execute_interrupts(rb_thread_current());

    return INT2FIX(i-1);
}
Beispiel #9
0
VALUE
rb_f_kill(int argc, VALUE *argv)
{
#ifndef HAS_KILLPG
#define killpg(pg, sig) kill(-(pg), sig)
#endif
    int negative = 0;
    int sig;
    int i;
    const char *s;

    rb_secure(2);
    if (argc < 2)
	rb_raise(rb_eArgError, "wrong number of arguments -- kill(sig, pid...)");
    switch (TYPE(argv[0])) {
      case T_FIXNUM:
	sig = FIX2INT(argv[0]);
	break;

      case T_SYMBOL:
	s = rb_id2name(SYM2ID(argv[0]));
	if (!s) rb_raise(rb_eArgError, "bad signal");
	goto str_signal;

      case T_STRING:
	s = RSTRING_PTR(argv[0]);
	if (s[0] == '-') {
	    negative++;
	    s++;
	}
      str_signal:
	if (strncmp("SIG", s, 3) == 0)
	    s += 3;
	if((sig = signm2signo(s)) == 0)
	    rb_raise(rb_eArgError, "unsupported name `SIG%s'", s);

	if (negative)
	    sig = -sig;
	break;

      default:
        {
	    VALUE str;

	    str = rb_check_string_type(argv[0]);
	    if (!NIL_P(str)) {
		s = RSTRING_PTR(str);
		goto str_signal;
	    }
	    rb_raise(rb_eArgError, "bad signal type %s",
		     rb_obj_classname(argv[0]));
	}
	break;
    }

    if (sig < 0) {
	sig = -sig;
	for (i=1; i<argc; i++) {
	    if (killpg(NUM2PIDT(argv[i]), sig) < 0)
		rb_sys_fail(0);
	}
    }
    else {
	for (i=1; i<argc; i++) {
	    if (kill(NUM2PIDT(argv[i]), sig) < 0)
		rb_sys_fail(0);
	}
    }
    rb_thread_polling();
    return INT2FIX(i-1);
}
Beispiel #10
0
VALUE
rb_f_kill(VALUE self, SEL sel, int argc, VALUE *argv)
{
    int negative = 0;
    int sig;
    int i;
    int type;
    const char *s = NULL;

    rb_secure(2);
    if (argc < 2)
	rb_raise(rb_eArgError, "wrong number of arguments -- kill(sig, pid...)");

    type = TYPE(argv[0]);
    if (type == T_FIXNUM) {
	sig = FIX2INT(argv[0]);
    }
    else {
	if (type == T_SYMBOL) {
	    s = rb_sym2name(argv[0]);
	    if (!s)
		rb_raise(rb_eArgError, "bad signal");
	}
	else if (type == T_STRING) {
	    s = RSTRING_PTR(argv[0]);
	    if (s[0] == '-') {
		negative++;
		s++;
	    }
	}
	else {
	    VALUE str;
	    str = rb_check_string_type(argv[0]);
	    if (!NIL_P(str)) {
		s = RSTRING_PTR(str);
	    }
	}
	if (s == NULL)
	    rb_raise(rb_eArgError, "bad signal type %s", rb_obj_classname(argv[0]));

	if (strncmp("SIG", s, 3) == 0)
	    s += 3;
	if ((sig = signm2signo(s)) == 0)
	    rb_raise(rb_eArgError, "unsupported name `SIG%s'", s);
	if (negative)
	    sig = -sig;
    }

    if (sig < 0) {
	sig = -sig;
	for (i = 1; i < argc; i++) {
	    if (killpg(NUM2PIDT(argv[i]), sig) < 0)
		rb_sys_fail(0);
	}
    }
    else {
	for (i = 1; i < argc; i++) {
	    if (kill(NUM2PIDT(argv[i]), sig) < 0)
		rb_sys_fail(0);
	}
    }
    rb_thread_polling();
    return INT2FIX(i - 1);
}
Beispiel #11
0
VALUE
rb_f_kill(int argc, VALUE *argv)
{
#ifndef HAVE_KILLPG
#define killpg(pg, sig) kill(-(pg), (sig))
#endif
    int negative = 0;
    int sig;
    int i;
    volatile VALUE str;
    const char *s;

    rb_secure(2);
    rb_check_arity(argc, 2, UNLIMITED_ARGUMENTS);

    switch (TYPE(argv[0])) {
      case T_FIXNUM:
	sig = FIX2INT(argv[0]);
	break;

      case T_SYMBOL:
	s = rb_id2name(SYM2ID(argv[0]));
	if (!s) rb_raise(rb_eArgError, "bad signal");
	goto str_signal;

      case T_STRING:
	s = RSTRING_PTR(argv[0]);
      str_signal:
	if (s[0] == '-') {
	    negative++;
	    s++;
	}
	if (strncmp("SIG", s, 3) == 0)
	    s += 3;
	if ((sig = signm2signo(s)) == 0)
	    rb_raise(rb_eArgError, "unsupported name `SIG%s'", s);

	if (negative)
	    sig = -sig;
	break;

      default:
	str = rb_check_string_type(argv[0]);
	if (!NIL_P(str)) {
	    s = RSTRING_PTR(str);
	    goto str_signal;
	}
	rb_raise(rb_eArgError, "bad signal type %s",
		 rb_obj_classname(argv[0]));
	break;
    }

    if (sig < 0) {
	sig = -sig;
	for (i=1; i<argc; i++) {
	    if (killpg(NUM2PIDT(argv[i]), sig) < 0)
		rb_sys_fail(0);
	}
    }
    else {
	for (i=1; i<argc; i++) {
	    ruby_kill(NUM2PIDT(argv[i]), sig);
	}
    }
    rb_thread_execute_interrupts(rb_thread_current());

    return INT2FIX(i-1);
}