2012-10-15 15 views
8

SIGILL sinyallerini işleyen bir kitaplık geliştirdim. Ben libc bağımlılığını önlemek ve Linux syscalls doğrudan kullanmak istediğim için. Kütüphanemin bazı Linux sistemlerinde asılı olduğunu fark, ve hata ayıklama bir sürü sonra yerine sigaction ait rt_sigaction syscall kullanarak sorunu çözer bulundu. Ancak, iki syscalls arasındaki farkın bir açıklamasını bulamadım. SO'daki herkes temel bilgileri biliyor mu?Linux'ta sinyal ve rt_signal syscalls arasındaki fark nedir?

Güncelleme: Bazı ARM talimat uzantıları, örneğin CPU desteği algılamak için sinyal işleyici kullanın XScale talimatı MIATT. Ben 4 bayt (bu talimat boyutu) tarafından PC kayıt ilerlemek ve SIGILL işleyicisi çağrıldı belirtmek için kayıtlarından birini değiştirmek SIGILL işleyicisi

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; 
} 

: Burada talimat sondalama fonksiyonudur. İşte sinyal işleyici kodu. İşte

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; 
} 

(sigaction syscall başarısız olursa SIGILL işleyicisi çağrıldı eğer talimat SIGILL, 1 neden olmadı IF_FUNCTION 0 döner ve 2) sondalama yaparız: Burada

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; 
    } 
} 

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; 
} 

Ben Android SDK (qemu) den emülatörü Bu kodu test ve Pandaboard Ubuntu çalıştıran: sigaction syscall saplama fonksiyonunun benim uygulamasıdır. emülatörü olarak kod iyi çalışır (hem ARM9 ve Cortex-A8 işlemciler taklit edilirken), ama __NR_sigaction kullanırsanız Pandaboard üzerinde o MIATT talimatı üzerine asılı: sinyal işleyici sonra kod 4 bayt atlamak etmediğini görünüyor ama çalışır aynı talimat.

+0

ben 'rt_sigaction' versiyonu "gerçek zamanlı" sürüm olduğunu tahmin ediyorum. Belirgin arama süresine sahip olması için tasarlandığı anlamına gelir. –

+0

Bunlar hemen hemen aynı kodlardır, her ikisi de çekirdeğindeki do_sigaction() öğesinde. Eğer sorun yaşıyorsanız, muhtemelen onları detaylandırmaya yardımcı olur. –

+0

Daha fazla ayrıntı ve kodumun ilgili bölümüne soruyu ekledim. –

cevap

1

ben alıntı man sigaction (link) Gönderen:

orijinal Linux sistem çağrısı sigaction seçildi(). Ancak, Linux 2.2, sabit boyutlu gerçek zamanlı sinyallerin ilavesi ile, bu sistem çağrısı tarafından desteklenen 32 bit sigset_t tipi artık fit amaç içindi. Sonuç olarak, yeni bir sistem çağrısı, rt_sigaction(), bir genişletilmiş sigset_t türünü desteklemek için eklenmiştir. Yeni sistem çağrısı oldact.sa_mask ve act.sa_mask sinyal setleri boyunu byte belirten dördüncü argümanı, size_t sigsetsize alır.

+0

Ayrıca glibc kullanıyorsanız," man sigaction "dan sonra rt_sigaction kullanmaya gerek yoktur. "Glibc sigaction() sarmalayıcı işlevi, çekirdeği sağladığında rt_sigaction() yöntemini çağırmak suretiyle bu ayrıntıları gizler." – cooperised

4

Ben kesin bir cevap yok, ama yine de katkıda bulunmaya çalışacağız:

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} 

bu farkın olarak:

çekirdek kaynak baktığımızda Görüyorum ki, rt_sigaction tüm sigaction yapısını kopyalarken, sigaction bellek satır içi (get/set kullanıcı işlevlerini kullanarak) alınıyor ve değiştiriyor ... Emin değilim ama belki daha fazla zaman alır geçici bir kopya ile çalışmak yerine doğrudan kullanıcı belleğine erişmek için.

İlgili konular