linux内核的idr学习(二)

本文深入解析了IDR(Identifier Resource)的数据结构及其操作方法,包括初始化、分配ID、构建32叉树等过程,并详细解释了相关函数的工作原理。

  一、idr构建的结构可以看成是32叉树, 它需要用到2个结构体:

struct idr {
    struct idr_layer __rcu *top;    /*根节点*/
    struct idr_layer *id_free;         /*空闲节点*/
    int          layers;                 /*树的高度*/
    int          id_free_cnt;        /*空闲节点数*/
    spinlock_t      lock;
};

struct idr_layer {
    unsigned long         bitmap;     /*位图*/
    struct idr_layer __rcu    *ary[1<<IDR_BITS];    /*孩子节点或者地址数据*/
    int             count;     /*ary已存放数*/
    int             layer;     /* 相对叶子节点的高度 */
    struct rcu_head         rcu_head;
};

  

  二、idr初始化:

1 #define IDR_INIT(name)      \  
2 {               \  
3     .top        = NULL, \  
4     .id_free        = NULL, \  
5     .layers         = 0,    \  
6     .id_free_cnt    = 0,    \  
7     .lock       = __SPIN_LOCK_UNLOCKED(name.lock),  \  
8 }  
9 #define DEFINE_IDR(name)    struct idr name = IDR_INIT(name)
View Code

  

 

  三、分配空闲节点

 1 /*创建多个idr_layer结构,组成一条链,存入idr->id_free区域, 区域含有
 2   *IDR_FREE_MAX个这样的结构, id_free_cnt = IDR_FREE_MAX
 3   */
 4 
 5 int idr_pre_get(struct idr *idp, gfp_t gfp_mask)
 6 {
 7     while (idp->id_free_cnt < IDR_FREE_MAX) {
 8         struct idr_layer *new;
 9         new = kmem_cache_zalloc(idr_layer_cache, gfp_mask);
10         if (new == NULL)
11             return (0);
12         move_to_free_list(idp, new);
13     }
14     return 1;
15 }
16 
17 static void move_to_free_list(struct idr *idp, struct idr_layer *p)
18 {
19     unsigned long flags;
20 
21     /*
22      * Depends on the return element being zeroed.
23      */
24     spin_lock_irqsave(&idp->lock, flags);
25     __move_to_free_list(idp, p);
26     spin_unlock_irqrestore(&idp->lock, flags);
27 }
28 
29 static void __move_to_free_list(struct idr *idp, struct idr_layer *p)
30 {
31     p->ary[0] = idp->id_free;
32     idp->id_free = p;
33     idp->id_free_cnt++;
34 }
View Code

  第一次循环结果

  

  第二次循环结果

        

  接着

  

  最后得到一条链(循环IDR_FREE_MAX次)

  

 

  四、构建树并申请ID, 绑定地址

  idr_get_new和idr_get_new_above函数

/* 申请0~0x7fffffff之间的id */
int idr_get_new(struct idr *idp, void *ptr, int *id)
{
    int rv;

    rv = idr_get_new_above_int(idp, ptr, 0);
    /*
     * This is a cheap hack until the IDR code can be fixed to
     * return proper error values.
     */
    if (rv < 0)
        return _idr_rc_to_errno(rv);
    *id = rv;
    return 0;
}

/* 申请starting_id~0x7fffffff之间的id  */
int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id)
{
    int rv;

    rv = idr_get_new_above_int(idp, ptr, starting_id);
    /*
     * This is a cheap hack until the IDR code can be fixed to
     * return proper error values.
     */
    if (rv < 0)
        return _idr_rc_to_errno(rv);
    *id = rv;
    return 0;
}
View Code

  为什么只能到0x7fffffff呢, 到后面就知道了.

  idr_get_new和idr_get_new_above两个函数都是调用idr_get_new_above_int函数:

 1 static int idr_get_new_above_int(struct idr *idp, void *ptr, int starting_id)
 2 {
 3         /* MAX_LEVEL = 7 */
 4     struct idr_layer *pa[MAX_LEVEL];
 5     int id;
 6 
 7     /* 从idr->top中寻找可用的最小ID */
 8     id = idr_get_empty_slot(idp, starting_id, pa);
 9     if (id >= 0) {
10         /*
11          *  将ID与对象地址ptr绑定, 并且标记
12                  *  pa[0]->ary[id & IDR_MASK] =(struct idr_layer *)ptr; 
13          */
14         rcu_assign_pointer(pa[0]->ary[id & IDR_MASK],
15                 (struct idr_layer *)ptr);
16         pa[0]->count++;
17         idr_mark_full(pa, id);
18     }
19 
20     return id;
21 }
View Code

  idr_get_empty_slot函数.

 1 static int idr_get_empty_slot(struct idr *idp, int starting_id,
 2                   struct idr_layer **pa)
 3 {
 4     struct idr_layer *p, *new;
 5     int layers, v, id;
 6     unsigned long flags;
 7 
 8     id = starting_id;
 9 build_up:
10     p = idp->top;
11     layers = idp->layers;
12     /* 第一次申请ID时,p都为null,看图A */
13     if (unlikely(!p)) {
14         if (!(p = get_from_free_list(idp)))
15             return -1;
16         p->layer = 0;
17         layers = 1;
18     }
19     /*
20      * 当申请ID比目前分配的空间数还大时,开辟新层
21      * 比如目前是2层结构, 可以分配的空间数为32^2=1024,最大ID为1023, 现在需要申请的ID为1050,
22      * 则需要开辟1层变成3层结构,这样可以分配的空间数为32^3, 最大ID变为32^3 - 1
23      * 看图B
24      */
25     while ((layers < (MAX_LEVEL - 1)) && (id >= (1 << (layers*IDR_BITS)))) {
26         layers++;
27         if (!p->count) {
28             /* 
29                          *这里不知道怎么进去的
30                         */
31             p->layer++;
32             continue;
33         }
34         /* 从idp->id_free中取出一个idr_layer结构失败 */
35         if (!(new = get_from_free_list(idp))) {
36             /*
37              * The allocation failed.  If we built part of
38              * the structure tear it down.
39              */
40             spin_lock_irqsave(&idp->lock, flags);
41             for (new = p; p && p != idp->top; new = p) {
42                 p = p->ary[0];
43                 new->ary[0] = NULL;
44                 new->bitmap = new->count = 0;
45                 __move_to_free_list(idp, new);
46             }
47             spin_unlock_irqrestore(&idp->lock, flags);
48             return -1;
49         }
50         new->ary[0] = p;
51         new->count = 1;
52         new->layer = layers-1;
53         if (p->bitmap == IDR_FULL)
54             __set_bit(0, &new->bitmap);
55         p = new;
56     }
57     /* idp->top = p */
58     rcu_assign_pointer(idp->top, p); 
59     idp->layers = layers;
60         /* 以上部分主要处理layer相关,以下部分主要处理id相关 */
61     v = sub_alloc(idp, &id, pa);
62     if (v == IDR_NEED_TO_GROW)
63         goto build_up;
64     return(v);
65 }
View Code

  图a:

  图b:

  

  get_from_free_list函数.

 1 static struct idr_layer *get_from_free_list(struct idr *idp)
 2 {
 3     struct idr_layer *p;
 4     unsigned long flags;
 5 
 6     spin_lock_irqsave(&idp->lock, flags);
 7     /* 从空闲节点链中取出1个节点 */
 8     if ((p = idp->id_free)) {
 9         idp->id_free = p->ary[0];
10         idp->id_free_cnt--;
11         p->ary[0] = NULL;
12     }
13     spin_unlock_irqrestore(&idp->lock, flags);
14     return(p);
15 }
View Code

  sub_alloc函数, 里面就有判断如果id>=0x80000000是无法申请的.

 1 static int sub_alloc(struct idr *idp, int *starting_id, struct idr_layer **pa)
 2 {
 3     int n, m, sh;
 4     struct idr_layer *p, *new;
 5     int l, id, oid;
 6     unsigned long bm;
 7 
 8     id = *starting_id;
 9  restart:
10     p = idp->top;
11     l = idp->layers;
12     pa[l--] = NULL;
13     while (1) {
14         /*
15          *  从根节点开始寻找直到到达叶子节点
16          */
17          
18         /* n = 0~31 */
19         n = (id >> (IDR_BITS*l)) & IDR_MASK; 
20         
21         bm = ~p->bitmap;
22         m = find_next_bit(&bm, IDR_SIZE, n);
23         /* 顶层位图已满,需要再开辟1层 */
24         if (m == IDR_SIZE) {
25             l++;
26             oid = id;
27             id = (id | ((1 << (IDR_BITS * l)) - 1)) + 1;
28 
29             if (id >= 1 << (idp->layers * IDR_BITS)) {
30                 *starting_id = id;
31                 return IDR_NEED_TO_GROW;
32             }
33             p = pa[l];
34             BUG_ON(!p);
35 
36             /* If we need to go up one layer, continue the
37              * loop; otherwise, restart from the top.
38              */
39             sh = IDR_BITS * (l + 1);
40             if (oid >> sh == id >> sh)
41                 continue;
42             else
43                 goto restart;
44         }
45         /* 改变ID */
46         if (m != n) {
47             sh = IDR_BITS*l;
48             id = ((id >> sh) ^ n ^ m) << sh;
49         }
50         /* 如果id>=0x80000000,无法申请 */
51         if ((id >= MAX_ID_BIT) || (id < 0))
52             return IDR_NOMORE_SPACE;
53         if (l == 0)
54             break;
55         /*
56          * Create the layer below if it is missing.
57          */
58         if (!p->ary[m]) {
59             new = get_from_free_list(idp);
60             if (!new)
61                 return -1;
62             new->layer = l-1;
63             rcu_assign_pointer(p->ary[m], new);
64             p->count++;
65         }
66         pa[l--] = p;
67         p = p->ary[m];
68     }
69 
70     pa[l] = p;
71     return id;
72 }
View Code

  find_next_bit函数.

 1 /* find_next_bit就是从地址addr处的size位2进制数据中,从第offset位向左开始寻找下一个置1位
 2  */
 3 unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
 4                 unsigned long offset)
 5 {
 6     const unsigned long *p = addr + BITOP_WORD(offset);
 7     /* result 是32的倍数 */
 8     unsigned long result = offset & ~(BITS_PER_LONG-1);
 9     unsigned long tmp;
10     
11 
12     if (offset >= size)
13         return size;
14     size -= result;
15     /* offset =0~31, 这个offset 加上 result 等于 输入参数的offset */
16     offset %= BITS_PER_LONG; 
17     /* 查找低32位 */
18     if (offset) {
19         tmp = *(p++);
20         tmp &= (~0UL << offset);
21         if (size < BITS_PER_LONG)
22             goto found_first;
23         if (tmp)
24             goto found_middle;
25         size -= BITS_PER_LONG;
26         result += BITS_PER_LONG;
27     }
28     
29     /* size是32的倍正整数, 32位一次寻找置1位 */
30     while (size & ~(BITS_PER_LONG-1)) {
31         if ((tmp = *(p++)))
32             goto found_middle;
33         result += BITS_PER_LONG;
34         size -= BITS_PER_LONG;
35     }
36     /* 走到这里就是整个数已无置1位, 返回最开始的size值 */
37     if (!size)
38         return result;
39 
40     /* 走到这里size一开始就不是32的倍数, 比如是37位数, 低32位已无置1位, 后面寻找高5位的置1位 */
41     tmp = *p;
42 
43 found_first:
44     tmp &= (~0UL >> (BITS_PER_LONG - size));
45     if (tmp == 0UL)        /* Are any bits set? */
46         return result + size;    /* Nope. */
47 found_middle:
48     return result + __ffs(tmp);
49 }
View Code

  

  五、利用ID寻找地址

  idr_find函数.

 1 void *idr_find(struct idr *idp, int id)
 2 {
 3     int n;
 4     struct idr_layer *p;
 5 
 6     p = rcu_dereference_raw(idp->top);
 7     if (!p)
 8         return NULL;
 9     n = (p->layer+1) * IDR_BITS;
10 
11     /* id最大为0x7fffffff */
12     id &= MAX_ID_MASK;
13 
14     if (id >= (1 << n))
15         return NULL;
16     BUG_ON(n == 0);
17 
18     /* 一直到叶子节点 */
19     while (n > 0 && p) {
20         n -= IDR_BITS;
21         BUG_ON(n != p->layer*IDR_BITS);
22         p = rcu_dereference_raw(p->ary[(id >> n) & IDR_MASK]);
23     }
24     return((void *)p);
25 }
View Code

 

转载于:https://www.cnblogs.com/zero-jh/p/5184946.html

News 26.03.2015 Knowledge base file for Delphi XE3 freely available. 23.03.2015 Knowledge base file for Delphi XE and Delphi XE2 freely available. 16.03.2015 Latest version is available for download. What is IDR? IDR (Interactive Delphi Reconstructor) – a decompiler of executable files (EXE) and dynamic libraries (DLL), written in Delphi and executed in Windows32 environment. The program firstly is intended for the companies, engaged by development of anti-virus software. It can also help programmers to recover lost source code of programs appreciably. The current version of the program can process files (GUI and console applications), compiled by Delphi compilers of versions Delphi2 – Delphi XE3. Final project goal is development of the program capable to restore the most part of initial Delphi source codes from the compiled file but IDR, as well as others Delphi decompilers, cannot do it yet. Nevertheless, IDR is in a status considerably to facilitate such process. In comparison with other well known Delphi decompilers the result of IDR analysis has the greatest completeness and reliability. Moreover interactivity does work with the program comfortable and (we shall not be afraid of this word) pleasant. IDR make static analysis (analyzed file is not loaded to memory and executed) that allows to safely investigate viruses, trojans and other malware applications, those which executing is dangerous or is not desirable. The program does not require any installation activity and does not do any records in Windows registry. Below screenshot of IDR main window is shown. You can find examples of IDR working results on separate page. For detailed acquaintance with opportunities IDR there is a help file in format CHM which can be downloaded on page of download or directly from this link.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值