Implement memory management TODOs
[centaur.git] / src / libelfu / model / section.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_mScnForall(ElfuElf *me, SectionHandlerFunc f, void *aux1, void *aux2)
10 {
11   ElfuPhdr *mp;
12   ElfuScn *ms;
13
14   CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
15     if (mp->phdr.p_type != PT_LOAD) {
16       continue;
17     }
18
19     CIRCLEQ_FOREACH(ms, &mp->childScnList, elemChildScn) {
20       void *rv = f(me, ms, aux1, aux2);
21
22       if (rv) {
23         return rv;
24       }
25     }
26   }
27
28   CIRCLEQ_FOREACH(ms, &me->orphanScnList, elemChildScn) {
29     void *rv = f(me, ms, aux1, aux2);
30
31     if (rv) {
32       return rv;
33     }
34   }
35
36   return NULL;
37 }
38
39
40
41
42 /* Counting */
43
44 static void* subCounter(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
45 {
46   size_t *i = (size_t*)aux1;
47   ElfuScn *otherScn = (ElfuScn*)aux2;
48
49   if (ms == otherScn) {
50     return ms;
51   }
52
53   *i += 1;
54
55   /* Continue */
56   return NULL;
57 }
58
59
60 size_t elfu_mScnCount(ElfuElf *me)
61 {
62   /* NULL section *is not* counted */
63   size_t i = 0;
64
65   assert(me);
66
67   elfu_mScnForall(me, subCounter, &i, NULL);
68
69   return i;
70 }
71
72
73 /* Returns the index a section would have in the flattened ELF */
74 size_t elfu_mScnIndex(ElfuElf *me, ElfuScn *ms)
75 {
76   /* NULL section *is* counted */
77   size_t i = 1;
78
79   assert(me);
80   assert(ms);
81
82   elfu_mScnForall(me, subCounter, &i, ms);
83
84   /* If this assertion is broken then ms is not a section in me. */
85   assert(i <= elfu_mScnCount(me));
86   return i;
87 }
88
89
90 static void* subOldscn(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
91 {
92   ElfuScn *otherScn = (ElfuScn*)aux1;
93   (void)aux2;
94
95   if (ms->oldptr == otherScn) {
96     return ms;
97   }
98
99   /* Continue */
100   return NULL;
101 }
102
103 /* Returns the section with oldscn == oldscn */
104 ElfuScn* elfu_mScnByOldscn(ElfuElf *me, ElfuScn *oldscn)
105 {
106   assert(me);
107   assert(oldscn);
108
109   return elfu_mScnForall(me, subOldscn, oldscn, NULL);
110 }
111
112
113
114
115 /* Convenience */
116
117 char* elfu_mScnName(ElfuElf *me, ElfuScn *ms)
118 {
119   assert(me);
120   assert(ms);
121
122   if (!me->shstrtab) {
123     return NULL;
124   }
125
126   if (!me->shstrtab->databuf) {
127     return NULL;
128   }
129
130   return &me->shstrtab->databuf[ms->shdr.sh_name];
131 }
132
133
134 static void* subScnsToArray(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
135 {
136   ElfuScn **arr = (ElfuScn**)aux1;
137   size_t *i = (size_t*)aux2;
138
139   arr[(*i)] = ms;
140   *i += 1;
141
142   /* Continue */
143   return NULL;
144 }
145
146 static int cmpScnOffs(const void *ms1, const void *ms2)
147 {
148   ElfuScn *s1;
149   ElfuScn *s2;
150
151   assert(ms1);
152   assert(ms2);
153
154   s1 = *(ElfuScn**)ms1;
155   s2 = *(ElfuScn**)ms2;
156
157   assert(s1);
158   assert(s2);
159
160
161   if (s1->shdr.sh_offset < s2->shdr.sh_offset) {
162     return -1;
163   } else if (s1->shdr.sh_offset == s2->shdr.sh_offset) {
164     return 0;
165   } else /* if (s1->shdr.sh_offset > s2->shdr.sh_offset) */ {
166     return 1;
167   }
168 }
169
170 ElfuScn** elfu_mScnSortedByOffset(ElfuElf *me, size_t *count)
171 {
172   size_t numSecs;
173   ElfuScn **sortedSecs;
174   size_t i;
175
176   assert(me);
177
178   /* Sort sections by offset in file */
179   numSecs = elfu_mScnCount(me);
180   sortedSecs = malloc(numSecs * sizeof(*sortedSecs));
181   if (!sortedSecs) {
182     ELFU_WARN("elfu_mScnSortedByOffset: Failed to allocate memory.\n");
183     return NULL;
184   }
185
186   i = 0;
187   elfu_mScnForall(me, subScnsToArray, sortedSecs, &i);
188   assert(i == numSecs);
189
190   qsort(sortedSecs, numSecs, sizeof(*sortedSecs), cmpScnOffs);
191
192   *count = numSecs;
193
194   return sortedSecs;
195 }
196
197
198
199 int elfu_mScnAppendData(ElfuScn *ms, void *buf, size_t len)
200 {
201   char *newbuf;
202
203   assert(ms);
204   assert(ms->shdr.sh_type != SHT_NOBITS);
205   assert(ms->databuf);
206
207   newbuf = realloc(ms->databuf, ms->shdr.sh_size + len);
208   if (!newbuf) {
209     ELFU_WARN("elfu_mScnAppendData: malloc() failed for newbuf.\n");
210     return -1;
211   }
212
213   ms->databuf = newbuf;
214   memcpy(newbuf + ms->shdr.sh_size, buf, len);
215   ms->shdr.sh_size += len;
216   assert(ms->shdr.sh_size == ms->shdr.sh_size);
217
218   return 0;
219 }
220
221
222
223 /*
224  * Allocation, destruction
225  */
226
227 ElfuScn* elfu_mScnAlloc()
228 {
229   ElfuScn *ms;
230
231   ms = malloc(sizeof(ElfuScn));
232   if (!ms) {
233     ELFU_WARN("mScnCreate: malloc() failed for ElfuScn.\n");
234     return NULL;
235   }
236
237   memset(ms, 0, sizeof(*ms));
238
239   CIRCLEQ_INIT(&ms->symtab.syms);
240   CIRCLEQ_INIT(&ms->reltab.rels);
241
242   return ms;
243 }
244
245 void elfu_mScnDestroy(ElfuScn* ms)
246 {
247   assert(ms);
248
249   if (!CIRCLEQ_EMPTY(&ms->symtab.syms)) {
250     ElfuSym *nextsym;
251
252     nextsym = CIRCLEQ_FIRST(&ms->symtab.syms);
253     while ((void*)nextsym != (void*)&ms->symtab.syms) {
254       ElfuSym *cursym = nextsym;
255       nextsym = CIRCLEQ_NEXT(cursym, elem);
256       CIRCLEQ_REMOVE(&ms->symtab.syms, cursym, elem);
257       free(cursym);
258     }
259   }
260
261   if (!CIRCLEQ_EMPTY(&ms->reltab.rels)) {
262     ElfuRel *nextrel;
263
264     nextrel = CIRCLEQ_FIRST(&ms->reltab.rels);
265     while ((void*)nextrel != (void*)&ms->reltab.rels) {
266       ElfuRel *currel = nextrel;
267       nextrel = CIRCLEQ_NEXT(currel, elem);
268       CIRCLEQ_REMOVE(&ms->reltab.rels, currel, elem);
269       free(currel);
270     }
271   }
272
273   if (ms->databuf) {
274     free(ms->databuf);
275   }
276
277   free(ms);
278 }