d7ddc19a1f5356b2114dd4a784c8b0786a3141c9
[centaur.git] / src / model / section.c
1 #include <assert.h>
2 #include <stdlib.h>
3 #include <libelf/libelf.h>
4 #include <libelf/gelf.h>
5 #include <libelfu/libelfu.h>
6
7
8 /* Meta-functions */
9
10 int elfu_mScnForall(ElfuElf *me, SectionHandlerFunc f, void *aux1, void *aux2)
11 {
12   ElfuPhdr *mp;
13   ElfuScn *ms;
14
15   // TODO: Sort PHDRs by offset before interating
16
17   CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
18     if (mp->phdr.p_type != PT_LOAD) {
19       continue;
20     }
21
22     CIRCLEQ_FOREACH(ms, &mp->childScnList, elemChildScn) {
23       int rv = f(me, ms, aux1, aux2);
24
25       if (rv) {
26         return rv;
27       }
28     }
29   }
30
31   CIRCLEQ_FOREACH(ms, &me->orphanScnList, elemChildScn) {
32     int rv = f(me, ms, aux1, aux2);
33
34     if (rv) {
35       return rv;
36     }
37   }
38
39   return 0;
40 }
41
42
43
44
45 /* Counting */
46
47 static int subCounter(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
48 {
49   size_t *i = (size_t*)aux1;
50   ElfuScn *otherScn = (ElfuScn*)aux2;
51
52   if (ms == otherScn) {
53     return 1;
54   }
55
56   *i += 1;
57
58   return 0;
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 section index equivalent to the model flattened to 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
93
94 /* Convenience */
95
96 char* elfu_mScnName(ElfuElf *me, ElfuScn *ms)
97 {
98   assert(me);
99   assert(ms);
100
101   if (!me->shstrtab) {
102     return NULL;
103   }
104
105   if (!me->shstrtab->data.d_buf) {
106     return NULL;
107   }
108
109   return &((char*)me->shstrtab->data.d_buf)[ms->shdr.sh_name];
110 }
111
112
113 static int subScnsToArray(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
114 {
115   ElfuScn **arr = (ElfuScn**)aux1;
116   size_t *i = (size_t*)aux2;
117
118   arr[(*i)] = ms;
119   *i += 1;
120
121   return 0;
122 }
123
124 static int cmpScnOffs(const void *ms1, const void *ms2)
125 {
126   assert(ms1);
127   assert(ms2);
128
129   ElfuScn *s1 = *(ElfuScn**)ms1;
130   ElfuScn *s2 = *(ElfuScn**)ms2;
131
132   assert(s1);
133   assert(s2);
134
135
136   if (s1->shdr.sh_offset < s2->shdr.sh_offset) {
137     return -1;
138   } else if (s1->shdr.sh_offset == s2->shdr.sh_offset) {
139     return 0;
140   } else /* if (s1->shdr.sh_offset > s2->shdr.sh_offset) */ {
141     return 1;
142   }
143 }
144
145 ElfuScn** elfu_mScnSortedByOffset(ElfuElf *me, size_t *count)
146 {
147   assert(me);
148
149   size_t numSecs;
150   ElfuScn **sortedSecs;
151   size_t i;
152
153   /* Sort sections by offset in file */
154   numSecs = elfu_mScnCount(me);
155   sortedSecs = malloc(numSecs * sizeof(*sortedSecs));
156   if (!sortedSecs) {
157     ELFU_WARN("elfu_mScnSortedByOffset: Failed to allocate memory.\n");
158     return NULL;
159   }
160
161   i = 0;
162   elfu_mScnForall(me, subScnsToArray, sortedSecs, &i);
163   assert(i == numSecs);
164
165   qsort(sortedSecs, numSecs, sizeof(*sortedSecs), cmpScnOffs);
166
167   *count = numSecs;
168
169   return sortedSecs;
170 }