非法指令(Illegal Instruction)问题定位

 关键词:Illegal Instruction、SIGILL等。

 

进程在运行过程中会收到SIGILL信号,此类错误是由操作系统发送给进程的。

SIGILL是某个进程中的某一句不能被CPU识别指令,这些指令可能是一些形式错误、未知或者特权指令。

1. SIGILL原因

1.1 错误修改代码段

进程代码段中数据是作为指令运行的,如果不小心代码段被错误覆盖,那么CPU可能无法识别对应的代码,进而造成Illegal Instruction。

同样,如果栈被不小心覆盖了,造成返回地址错误、CPU跳转到错误地址,执行没有意义的内存数据,进而造成Illegal Instruction。

进一步可以认为,任何导致代码段错误的问题都可能带来Illegal Instruction。

1.2 指令集演进

CPU的指令集在不停演进,如果将较新指令集版本的程序在老版本CPU上运行,则老版本CPU运行时会有Illegal Instruction问题。

1.3 工具链Bug

编译器(汇编器或者连接器)自身的bug,有可能生成CPU无法识别的指令。

1.4 内存访问对齐或浮点格式问题

出现错误的指令可能和访存地址指令有关。 另外,浮点数的格式是否符合IEEE的标准也可能会有影响。

2. 错误排查指南

  • 程序中有没有特权指令、或者访问特权寄存器

  • 有没有将在较新CPU上编译得到的可执行文件拿到老CPU上运行------------这种问题是100%复现,只需要查看对应汇编程序即可知道大概。

  • 程序中有没有嵌入式汇编,先检查。-------------------------------------------------编译器bug。

    • 一般编译器很少会生成有这种问题的代码

    • X86平台上要尤其注意64位汇编指令和32位汇编指令的混用问题

  • 程序有在进程代码段空间写数据的机会吗?----------------------------------------下面的分析就是代码段被非法修改。还可能是意见存在问题,DDR中数据正确,从DDR读取的数据经过总线产生数据突变异常。

  • 栈操作够安全吗?--------------------------------------------------------------------------如果异常PC指向栈,那么即是栈被非法修改。

  • 注意程序的ABI是否正确------------------------------------------------------------------100%复现问题,只需要检查ABI说明书即可。

    • 尤其是动态链和静态链是否处理的正确,尽量避免动态链的可执行文件调用错误库的问题(ARM的EABI,MIPS的N32/O32/N64都很可能出这种问题)

  • 用的工具链靠谱吗? 

3. Illegal Instruction处理

CK异常向量VEC_ILLEGAL对应非法指令错误,出现问题的时候内核输出“Illegal instruction Error”,然后输出寄存去、相关代码段、栈等信息;最后发送SIGILL信号给进程。

asmlinkage void trap_c(struct pt_regs *regs)
{
    int sig;
    unsigned long vector;
    siginfo_t info;

    vector = (mfcr("psr") >> 16) & 0xff;

    switch (vector) {
...
        case VEC_ILLEGAL:
#ifndef CONFIG_CPU_NO_USER_BKPT
        if (*(uint16_t *)instruction_pointer(regs) != 0x1464)
#endif
        {
            sig = SIGILL;
            pr_err("Illegal instruction Error\n");
            show_regs(regs);
            break;
        }
...
    }
    send_sig(sig, current, 0);---------------------------------------------发送SIGILL给当前进程。
}

void show_regs(struct pt_regs *fp)
{
    unsigned long   *sp;
    unsigned char   *tp;
    int    i;

    pr_info("\nCURRENT PROCESS:\n\n");
    pr_info("COMM=%s PID=%d\n", current->comm, current->pid);

    if (current->mm) {
        pr_info("TEXT=%08x-%08x DATA=%08x-%08x BSS=%08x-%08x\n",
               (int) current->mm->start_code,
               (int) current->mm->end_code,
               (int) current->mm->start_data,
               (int) current->mm->end_data,
               (int) current->mm->end_data,
               (int) current->mm->brk);
        pr_info("USER-STACK=%08x  KERNEL-STACK=%08x\n\n",
               (int) current->mm->start_stack,
               (int) (((unsigned long) current) + 2 * PAGE_SIZE));
    }

    pr_info("PC: 0x%08lx (%pS)\n", (long)fp->pc, (void *)fp->pc);
    pr_info("LR: 0x%08lx (%pS)\n", (
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值