2012-10-15 36 views
8

Tôi đã phát triển một thư viện xử lý tín hiệu SIGILL. Vì tôi muốn tránh sự phụ thuộc của libc, và sử dụng các syscalls Linux trực tiếp. Tôi nhận thấy rằng thư viện của tôi bị treo trên một số hệ thống Linux và sau rất nhiều lần gỡ lỗi, tôi thấy rằng việc sử dụng số sê-ri rt_sigaction thay vì số sigaction giải quyết được sự cố. Tuy nhiên, tôi không tìm thấy một mô tả về sự khác biệt giữa hai syscalls. Có ai trên SO biết các chi tiết cơ bản không?Sự khác biệt giữa tín hiệu và rt_signal syscalls trong Linux là gì?

Cập nhật: Tôi sử dụng trình xử lý tín hiệu để phát hiện hỗ trợ CPU cho một số tiện ích mở rộng hướng dẫn ARM, ví dụ: Hướng dẫn XScale MIATT. Dưới đây là hướng dẫn chức năng thăm dò:

static uint32_t probe_xscale() { 
    register uint32_t retValue asm("r0") = 0; 
    asm volatile (
     // Equivalent of the following code: 
     // ".arch xscale\n" 
     // "MIATT acc0, r0, r0;" 
     // If the next line raises SIGILL, the signal handle will change r0 to 1 and skip the instruction (4 bytes) 
     "MCR P0, 0x1, r0, c15, c0, 0;" 
     : "+r" (retValue) 
     : 
     : 
    ); 
    return retValue; 
} 

Trong xử lý SIGILL tôi thúc đẩy PC đăng ký bởi 4 byte (kích thước của hướng dẫn này), và thay đổi một trong những thanh ghi để cho biết rằng handler SIGILL được gọi. Đây là mã xử lý tín hiệu.

static void probe_signal_handler(int, siginfo_t *, void* ptr) { 
    ucontext_t* ctx = (ucontext_t*)ptr; 
    ctx->uc_mcontext.arm_pc += 4; 
    ctx->uc_mcontext.arm_r0 = 1; 
} 

Dưới đây là cách tôi làm thăm dò (hàm trả về 0 nếu lệnh không gây SIGILL, 1 nếu handler SIGILL được gọi, và 2 nếu sigaction syscall thất bại):

static uint32_t probeInstruction(uint32_t (*ProbeFunction)()) { 
    struct sigaction oldSigillAction; 
    struct sigaction probeSigillAction; 
    memset(&probeSigillAction, 0, sizeof(probeSigillAction)); 
    probeSigillAction.sa_sigaction = &probe_signal_handler; 
    // Needs Linux >= 2.2 
    probeSigillAction.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO; 
    int sigactionResult = _syscall_sigaction(SIGILL, &probeSigillAction, &oldSigillAction); 
    if (sigactionResult == 0) { 
     const uint32_t probeResult = ProbeFunction(); 
     _syscall_sigaction(SIGILL, &oldSigillAction, NULL); 
     return probeResult; 
    } else { 
     return 2; 
    } 
} 

đây là việc tôi triển khai chức năng sigaction syscall stub:

static int _syscall_sigaction(int signum, const struct sigaction *new_action, struct sigaction *old_action) __attribute__((noinline)); 
static int _syscall_sigaction(int signalNumberParameter, const struct sigaction *newActionParameter, struct sigaction *oldActionParameter) { 
    register int result asm ("r0"); 
    register int signalNumber asm ("r0") = signalNumberParameter; 
    register const struct sigaction *newAction asm ("r1") = newActionParameter; 
    register struct sigaction *oldAction asm ("r2") = oldActionParameter; 
    register int syscallNumber asm ("r7") = __NR_rt_sigaction; 
    asm volatile (
     "swi $0;" 
     : "=r" (result) 
     : "r" (signalNumber), "r" (newAction), "r" (oldAction), "r" (syscallNumber) 
     : 
    ); 
    return result; 
} 

Tôi đã thử nghiệm mã này trong trình giả lập từ Android SDK (qemu) và trên Pandaboard chạy Ubuntu. Trong giả lập mã chạy tốt (cả khi mô phỏng CPU ARM9 và Cortex-A8), nhưng trên Pandaboard nó treo trên hướng dẫn MIATT nếu tôi sử dụng __NR_sigaction: có vẻ như sau khi trình xử lý tín hiệu mã không bỏ qua 4 byte, nhưng chạy cùng một hướng dẫn.

+0

Tôi đoán phiên bản 'rt_sigaction' là phiên bản" thời gian thực ". Có nghĩa là nó được thiết kế để có thời gian gọi xác định. –

+0

Đây là gần như chính xác cùng một mã, cả hai đất tại do_sigaction() trong hạt nhân. Nếu bạn đang gặp vấn đề, nó có lẽ sẽ giúp chi tiết chúng. –

+0

Tôi đã thêm chi tiết và phần có liên quan của mã của tôi vào câu hỏi. –

Trả lời

1

Từ man sigaction (link) Tôi xin trích dẫn:

Bản gốc Linux gọi hệ thống được đặt tên sigaction(). Tuy nhiên, với việc thêm tín hiệu thời gian thực trong Linux 2.2, kích thước cố định, loại sigset_t 32 bit được hỗ trợ bởi cuộc gọi hệ thống đó không còn phù hợp với cho mục đích. Do đó, một cuộc gọi hệ thống mới, rt_sigaction(), đã được thêm để hỗ trợ loại sigset_t mở rộng. Cuộc gọi hệ thống mới lấy đối số thứ tư, size_t sigsetsize, chỉ định kích thước theo byte của bộ tín hiệu trong act.sa_mask và oldact.sa_mask.

+0

Cũng từ' man sigaction ', nếu bạn đang sử dụng glibc thì không cần sử dụng rt_sigaction. "Hàm glibc sigaction() bao bọc các chi tiết này từ chúng ta, gọi rt_sigaction() khi hạt nhân cung cấp nó." – cooperised

4

Tôi không có một câu trả lời rõ ràng, nhưng tôi vẫn sẽ cố gắng đóng góp:

Nhìn vào nguồn kernel:

300SYSCALL_DEFINE3(sigaction, int, sig, const struct sigaction __user *, act, 
301  struct sigaction __user *, oact) 
302{ 
303  struct k_sigaction new_ka, old_ka; 
304  int ret; 
305  int err = 0; 
306 
307  if (act) { 
308    old_sigset_t mask; 
309 
310    if (!access_ok(VERIFY_READ, act, sizeof(*act))) 
311      return -EFAULT; 
312    err |= __get_user(new_ka.sa.sa_handler, &act->sa_handler); 
313    err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); 
314    err |= __get_user(mask, &act->sa_mask.sig[0]); 
315    if (err) 
316      return -EFAULT; 
317 
318    siginitset(&new_ka.sa.sa_mask, mask); 
319  } 
320 
321  ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); 
322 
323  if (!ret && oact) { 
324    if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact))) 
325      return -EFAULT; 
326    err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); 
327    err |= __put_user(old_ka.sa.sa_handler, &oact->sa_handler); 
328    err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig); 
329    err |= __put_user(0, &oact->sa_mask.sig[1]); 
330    err |= __put_user(0, &oact->sa_mask.sig[2]); 
331    err |= __put_user(0, &oact->sa_mask.sig[3]); 
332    if (err) 
333      return -EFAULT; 
334  } 
335 
336  return ret; 
337} 
338#endif 

vs

2955SYSCALL_DEFINE4(rt_sigaction, int, sig, 
2956    const struct sigaction __user *, act, 
2957    struct sigaction __user *, oact, 
2958    size_t, sigsetsize) 
2959{ 
2960  struct k_sigaction new_sa, old_sa; 
2961  int ret = -EINVAL; 
2962 
2963  /* XXX: Don't preclude handling different sized sigset_t's. */ 
2964  if (sigsetsize != sizeof(sigset_t)) 
2965    goto out; 
2966 
2967  if (act) { 
2968    if (copy_from_user(&new_sa.sa, act, sizeof(new_sa.sa))) 
2969      return -EFAULT; 
2970  } 
2971 
2972  ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL); 
2973 
2974  if (!ret && oact) { 
2975    if (copy_to_user(oact, &old_sa.sa, sizeof(old_sa.sa))) 
2976      return -EFAULT; 
2977  } 
2978out: 
2979  return ret; 
2980} 

Các khac nhau như Tôi thấy nó là rt_sigaction sao chép toàn bộ cấu trúc sigaction, trong khi sigaction đang nhận và thay đổi nội tuyến bộ nhớ (sử dụng các hàm get/set của người dùng) ... Tôi không chắc, nhưng có lẽ phải mất nhiều thời gian hơn để truy cập bộ nhớ không gian người dùng trực tiếp thay vì làm việc với một bản sao tạm thời.

Các vấn đề liên quan