• 内核工具 – Sparse 简介【转】


    转自:http://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

  • 相关阅读:
    戏说程序猿之荒唐的需求
    戏说程序猿之过年--二叔,我真不会修电脑
    深入理解设计模式(17):迭代器模式
    深入理解设计模式(16):备忘录模式
    我的2018
    Java高级篇(一)——线程
    Java进阶篇(六)——Swing程序设计(下)
    Java进阶篇(六)——Swing程序设计(上)
    Java进阶篇(五)——Java的I/O技术
    Java进阶篇(四)——Java异常处理
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/8520929.html
Copyright © 2020-2023  润新知