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