zoukankan      html  css  js  c++  java
  • 内核工具 – Sparse 简介【转】

    转自:https://www.cnblogs.com/wang_yb/p/3575039.html

    Sparse是内核代码静态分析工具, 能够帮助我们找出代码中的隐患.

    主要内容:

    • Sparse 介绍
    • Sparse 使用方法
    • Sparse 在编译内核中的使用
    • 补充

    1. Sparse 介绍

    Sparse 诞生于 2004 年, 是由linux之父开发的, 目的就是提供一个静态检查代码的工具, 从而减少linux内核的隐患.

    其实在Sparse之前, 已经有了一个不错的代码静态检查工具("SWAT"), 只不过这个工具不是免费软件, 使用上有一些限制.

    所以 linus 还是自己开发了一个静态检查工具.

    具体可以参考这篇文章(2004年的文章了): Finding kernel problems automatically

    Sparse相关的资料非常少, 关于它的使用方法我也是网上查找+自己实验得出来的.

    内核代码中还有一个简略的关于 Sparse的说明文件: Documentation/sparse.txt

    Sparse通过 gcc 的扩展属性 __attribute__ 以及自己定义的 __context__ 来对代码进行静态检查.

    这些属性如下(尽量整理的,可能还有些不全的地方):

    宏名称

    宏定义

    检查点

    __bitwise __attribute__((bitwise)) 确保变量是相同的位方式(比如 bit-endian, little-endiandeng)
    __user __attribute__((noderef, address_space(1))) 指针地址必须在用户地址空间
    __kernel __attribute__((noderef, address_space(0))) 指针地址必须在内核地址空间
    __iomem __attribute__((noderef, address_space(2))) 指针地址必须在设备地址空间
    __safe __attribute__((safe)) 变量可以为空
    __force __attribute__((force)) 变量可以进行强制转换
    __nocast __attribute__((nocast)) 参数类型与实际参数类型必须一致
    __acquires(x) __attribute__((context(x, 0, 1))) 参数x 在执行前引用计数必须是0,执行后,引用计数必须为1
    __releases(x) __attribute__((context(x, 1, 0))) 与 __acquires(x) 相反
    __acquire(x) __context__(x, 1) 参数x 的引用计数 + 1
    __release(x) __context__(x, -1) 与 __acquire(x) 相反
    __cond_lock(x,c) ((c) ? ({ __acquire(x); 1; }) : 0) 参数c 不为0时,引用计数 + 1, 并返回1

    其中 __acquires(x) 和 __releases(x), __acquire(x) 和 __release(x) 必须配对使用, 否则 Sparse 会给出警告

    : 在Fedora系统中通过 rpm 安装的 sparse 存在一个小bug.

    即使用时会报出 error: unable to open ’stddef.h’ 的错误, 最好从自己源码编译安装 sparse.

    参考: http://wangcong.org/blog/archives/504

    2. Sparse 使用方法

    2.1 __bitwise 的使用

    主要作用就是确保内核使用的整数是在同样的位方式下.

    在内核代码根目录下 grep -r '__bitwise', 会发现内核代码中很多地方都使用了这个宏.

    对于使用了这个宏的变量, Sparse 会检查这个变量是否一直在同一种位方式(big-endian, little-endian或其他)下被使用,

    如果此变量在多个位方式下被使用了, Sparse 会给出警告.

    内核代码中的例子:

    /* 内核版本:v2.6.32.61  file:include/sound/core.h 51行 */
    typedef int __bitwise snd_device_type_t;

    2.2 __user 的使用

    如果使用了 __user 宏的指针不在用户地址空间初始化, 或者指向内核地址空间, 设备地址空间等等, Sparse会给出警告.

    内核代码中的例子:

    /* 内核版本:v2.6.32.61  file:arch/score/kernel/signal.c 45行 */
    static int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)

    2.3 __kernel 的使用

    如果使用了 __kernel 宏的指针不在内核地址空间初始化, 或者指向用户地址空间, 设备地址空间等等, Sparse会给出警告.

    内核代码中的例子:

    /* 内核版本:v2.6.32.61  file:arch/s390/lib/uaccess_pt.c 180行 */
    memcpy(to, (void __kernel __force *) from, n);

    2.4 __iomem 的使用

    如果使用了 __iomem 宏的指针不在设备地址空间初始化, 或者指向用户地址空间, 内核地址空间等等, Sparse会给出警告.

    内核代码中的例子:

    /* 内核版本:v2.6.32.61  file:arch/microblaze/include/asm/io.h 22行 */
    static inline unsigned char __raw_readb(const volatile void __iomem *addr)

    2.5 __safe 的使用

    使用了 __safe修饰的变量在使用前没有判断它是否为空(null), Sparse会给出警告.

    我参考的内核版本(v2.6.32.61) 中的所有内核代码都没有使用 __safe, 估计可能是由于随着gcc版本的更新,

    gcc已经会对这种情况给出警告, 所以没有必要用Sparse去检查了.

    2.6 __force 的使用

    使用了__force修饰的变量可以进行强制类型转换, 没有使用 __force修饰的变量进行强制类型转换时, Sparse会给出警告.

    内核代码中的例子:

    /* 内核版本:v2.6.32.61  file:arch/s390/lib/uaccess_pt.c 180行 */
    memcpy(to, (void __kernel __force *) from, n);

    2.7 __nocast 的使用

    使用了__nocast修饰的参数的类型必须和实际传入的参数类型一致才行,否则Sparse会给出警告.

    内核代码中的例子:

    /* 内核版本:v2.6.32.61  file:fs/xfs/support/ktrace.c 55行 */
    ktrace_alloc(int nentries, unsigned int __nocast sleep)

    2.8 __acquires __releases __acquire __release的使用

    这4个宏都是和锁有关的, __acquires 和 __releases 必须成对使用, __acquire 和 __release 必须成对使用, 否则Sparse会给出警告.

    2.9 __cond_lock 的使用

    这个宏有点特别, 因为没有 __cond_unlock 之类的宏和它对应.

    之所以有这个宏的原因可以参见: http://yarchive.net/comp/linux/sparse.html 最后一段.

    这个宏的来源清楚了, 但是为什么这个宏里面还要调用一次 __acquire(x)? 我也不是很清楚, 在网上找了好久也没找到, 谁能指教的话非常感谢!!!

    3. Sparse 在编译内核中的使用

    用 Sparse 对内核进行静态分析非常简单.

    # 检查所有内核代码
    make C=1 检查所有重新编译的代码
    make C=2 检查所有代码, 不管是不是被重新编译

    4. 补充

    Sparse除了能够用在内核代码的静态分析上, 其实也可以用在一般的C语言程序中.

    比如下面的小例子:

    复制代码
    /******************************************************************************
     * @file    : sparse_test.c
     * @author  : wangyubin
     * @date    : Fri Feb 28 16:33:34 2014
     * 
     * @brief   : 测试 sparse 的各个检查点
     * history  : init
     ******************************************************************************/
    
    #include <stdio.h>
    
    #define __acquire(x) __context__(x,1)
    #define __release(x) __context__(x,-1)
    
    int main(int argc, char *argv[])
    {
        int lock = 1;
        __acquire(lock);
        /* TODO something */
        __release(lock);            /* 注释掉这一句 sparse 就会报错 */
        return 0;
    }
    复制代码

    如果安装了 Sparse, 执行静态检查的命令如下:

    $ sparse -a sparse_test.c 
    sparse_test.c:15:5: warning: context imbalance in 'main' - wrong count at exit

    Sparse相关资料可以参考wiki: Sparse wiki

  • 相关阅读:
    SAP S/4HANA extensibility扩展原理介绍
    SAP CRM系统订单模型的设计与实现
    使用nodejs代码在SAP C4C里创建Individual customer
    SAP Cloud for Customer Account和individual customer的区别
    Let the Balloon Rise map一个数组
    How Many Tables 简单并查集
    Heap Operations 优先队列
    Arpa’s obvious problem and Mehrdad’s terrible solution 思维
    Passing the Message 单调栈两次
    The Suspects 并查集
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/14116358.html
Copyright © 2011-2022 走看看