关闭

Linux内核中的信号机制——信号处理

发表于:2013-2-25 10:02

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:ce123    来源:51Testing软件测试网采编

  get_sigframe()通过用户态空间堆栈的sp-sizeof(struct sigframe)在用户态堆栈的顶部分配了一篇存储空间,将来使用完成后,再通过sp+sizeof(struct sigframe)还原。

  通过上面的讨论,我们再回到do_signal()中来,如果有用户态的信号处理函数,do_signal()会调用handle_signal(),handle_signal()将调用setup_frame()或者setup_rt_frame()来完成实际的工作,这里我们以setup_frame()为例进行进一步讨论。

static int
setup_frame(int usig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *regs)
{
 //在用户态堆栈上分配一个sigframe结构
 struct sigframe __user *frame = get_sigframe(ka, regs, sizeof(*frame));
 int err = 0;

 if (!frame)
  return 1;

 //把相关信息从内核态备份到用户态堆栈的sigframe结构中
 err |= setup_sigcontext(&frame->sc, &frame->aux, regs, set->sig[0]);

 if (_NSIG_WORDS > 1) {
  err |= __copy_to_user(frame->extramask, &set->sig[1],
          sizeof(frame->extramask));
 }

 if (err == 0)
  err = setup_return(regs, ka, &frame->retcode, frame, usig);

 return err;
}

  setup_return()设置返回地址,其定义如下:

static int
setup_return(struct pt_regs *regs, struct k_sigaction *ka,
      unsigned long __user *rc, void __user *frame, int usig)
{
 unsigned long handler = (unsigned long)ka->sa.sa_handler;
 unsigned long retcode;
 int thumb = 0;
 unsigned long cpsr = regs->ARM_cpsr & ~PSR_f;

 /*
  * Maybe we need to deliver a 32-bit signal to a 26-bit task.
  */
 if (ka->sa.sa_flags & SA_THIRTYTWO)
  cpsr = (cpsr & ~MODE_MASK) | USR_MODE;

#ifdef CONFIG_ARM_THUMB
 if (elf_hwcap & HWCAP_THUMB) {
  /*
   * The LSB of the handler determines if we're going to
   * be using THUMB or ARM mode for this signal handler.
   */
  thumb = handler & 1;

  if (thumb)
   cpsr |= PSR_T_BIT;
  else
   cpsr &= ~PSR_T_BIT;
 }
#endif
<SPAN style="WHITE-SPACE: pre"> </SPAN>//这里的retcode就是保存手工构造的sigreturn()代码
 if (ka->sa.sa_flags & SA_RESTORER) {
  retcode = (unsigned long)ka->sa.sa_restorer;
 } else {
  unsigned int idx = thumb;

  if (ka->sa.sa_flags & SA_SIGINFO)
   idx += 2;

  if (__put_user(sigreturn_codes[idx], rc))
   return 1;

  if (cpsr & MODE32_BIT) {
   /*
    * 32-bit code can use the new high-page
    * signal return code support.
    */
   retcode = KERN_SIGRETURN_CODE + (idx << 2) + thumb;
  } else {
   /*
    * Ensure that the instruction cache sees
    * the return code written onto the stack.
    */
   flush_icache_range((unsigned long)rc,
        (unsigned long)(rc + 1));

   retcode = ((unsigned long)rc) + thumb;
  }
 }

 regs->ARM_r0 = usig;
 regs->ARM_sp = (unsigned long)frame;//堆栈
 regs->ARM_lr = retcode;//返回地址,当用户态信号处理函数结束时,就会把这个地址作为返回地址
 regs->ARM_pc = handler;//信号处理函数
 regs->ARM_cpsr = cpsr;

 return 0;
}

  当setup_frame()返回后,一切准备就绪,因此可以从内核态返回了,这样就顺利过渡到用户态的信号处理函数。当这个函数处理结束后,会通过retcode再次进入内核态,现在我们看看retcode是如何处理的,下面的代码选自glibc(2.3.2):

 #include <sysdep.h>

/* If no SA_RESTORER function was specified by the application we use
   one of these.  This avoids the need for the kernel to synthesise a return
   instruction on the stack, which would involve expensive cache flushes. */

ENTRY(__default_sa_restorer)
 swi SYS_ify(sigreturn)

#ifdef __NR_rt_sigreturn

ENTRY(__default_rt_sa_restorer)
 swi SYS_ify(rt_sigreturn)

#define SYS_ify(syscall_name) (__NR_##syscall_name)

54/5<12345>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号