PHDR: find by addr/offset
[centaur.git] / src / libelfu / model / phdr.c
1 #include <assert.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <libelfu/libelfu.h>
5
6
7 /* Meta-functions */
8
9 void* elfu_mPhdrForall(ElfuElf *me, PhdrHandlerFunc f, void *aux1, void *aux2)
10 {
11   ElfuPhdr *mp;
12
13   CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
14     ElfuPhdr *mp2;
15     void *rv = f(me, mp, aux1, aux2);
16     if (rv) {
17       return rv;
18     }
19
20     CIRCLEQ_FOREACH(mp2, &mp->childPhdrList, elemChildPhdr) {
21       void *rv = f(me, mp2, aux1, aux2);
22       if (rv) {
23         return rv;
24       }
25     }
26   }
27
28   return NULL;
29 }
30
31
32
33
34 /* Counting */
35
36 static void* subCounter(ElfuElf *me, ElfuPhdr *mp, void *aux1, void *aux2)
37 {
38   size_t *i = (size_t*)aux1;
39   (void)aux2;
40
41   *i += 1;
42
43   /* Continue */
44   return NULL;
45 }
46
47 size_t elfu_mPhdrCount(ElfuElf *me)
48 {
49   size_t i = 0;
50
51   assert(me);
52
53   elfu_mPhdrForall(me, subCounter, &i, NULL);
54
55   return i;
56 }
57
58
59
60
61 /* Finding */
62
63 static void* subFindLoadByAddr(ElfuElf *me, ElfuPhdr *mp, void *aux1, void *aux2)
64 {
65   GElf_Addr addr = *(GElf_Addr*)aux1;
66   (void)aux2;
67
68   if (mp->phdr.p_type == PT_LOAD
69       && FULLY_OVERLAPPING(mp->phdr.p_vaddr, mp->phdr.p_memsz, addr, 1)) {
70     return mp;
71   }
72
73   /* Continue */
74   return NULL;
75 }
76
77 ElfuPhdr* elfu_mPhdrByAddr(ElfuElf *me, GElf_Addr addr)
78 {
79   return elfu_mPhdrForall(me, subFindLoadByAddr, &addr, NULL);
80 }
81
82
83 static void* subFindLoadByOffset(ElfuElf *me, ElfuPhdr *mp, void *aux1, void *aux2)
84 {
85   GElf_Off offset = *(GElf_Off*)aux1;
86   (void)aux2;
87
88   if (mp->phdr.p_type == PT_LOAD
89       && FULLY_OVERLAPPING(mp->phdr.p_offset, mp->phdr.p_filesz, offset, 1)) {
90     return mp;
91   }
92
93   /* Continue */
94   return NULL;
95 }
96
97 ElfuPhdr* elfu_mPhdrByOffset(ElfuElf *me, GElf_Off offset)
98 {
99   return elfu_mPhdrForall(me, subFindLoadByOffset, &offset, NULL);
100 }
101
102
103
104
105 /* Layout update */
106
107 void elfu_mPhdrUpdateChildOffsets(ElfuPhdr *mp)
108 {
109   ElfuScn *ms;
110   ElfuPhdr *mpc;
111
112   assert(mp);
113   assert(mp->phdr.p_type == PT_LOAD);
114
115   CIRCLEQ_FOREACH(mpc, &mp->childPhdrList, elemChildPhdr) {
116     mpc->phdr.p_offset = mp->phdr.p_offset + (mpc->phdr.p_vaddr - mp->phdr.p_vaddr);
117   }
118
119   CIRCLEQ_FOREACH(ms, &mp->childScnList, elemChildScn) {
120     ms->shdr.sh_offset = mp->phdr.p_offset + (ms->shdr.sh_addr - mp->phdr.p_vaddr);
121   }
122 }
123
124
125
126 /*
127  * Allocation, destruction
128  */
129
130 ElfuPhdr* elfu_mPhdrAlloc()
131 {
132   ElfuPhdr *mp;
133
134   mp = malloc(sizeof(ElfuPhdr));
135   if (!mp) {
136     ELFU_WARN("mPhdrAlloc: malloc() failed for ElfuPhdr.\n");
137     return NULL;
138   }
139
140   memset(mp, 0, sizeof(*mp));
141
142   CIRCLEQ_INIT(&mp->childScnList);
143   CIRCLEQ_INIT(&mp->childPhdrList);
144
145   return mp;
146 }
147
148 void elfu_mPhdrDestroy(ElfuPhdr* mp)
149 {
150   ElfuPhdr *mp2;
151   ElfuScn *ms;
152
153   assert(mp);
154
155   CIRCLEQ_FOREACH(mp2, &mp->childPhdrList, elem) {
156     CIRCLEQ_REMOVE(&mp->childPhdrList, mp2, elem);
157     elfu_mPhdrDestroy(mp2);
158   }
159
160   CIRCLEQ_FOREACH(ms, &mp->childScnList, elem) {
161     CIRCLEQ_REMOVE(&mp->childScnList, ms, elem);
162     elfu_mScnDestroy(ms);
163   }
164
165   free(mp);
166 }