/* * 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; }
/* * 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 }
/* * 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; }
/* * 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 }
/* * 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; }
/* * 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 }
/* * 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; }
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); }
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); }
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); }
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); }