1 /* This file is part of centaur.
3 * centaur is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License 2 as
5 * published by the Free Software Foundation.
7 * centaur is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with centaur. If not, see <http://www.gnu.org/licenses/>.
19 #include <libelfu/libelfu.h>
24 void* elfu_mPhdrForall(ElfuElf *me, PhdrHandlerFunc f, void *aux1, void *aux2)
28 CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
30 void *rv = f(me, mp, aux1, aux2);
35 CIRCLEQ_FOREACH(mp2, &mp->childPhdrList, elemChildPhdr) {
36 void *rv = f(me, mp2, aux1, aux2);
51 static void* subCounter(ElfuElf *me, ElfuPhdr *mp, void *aux1, void *aux2)
53 size_t *i = (size_t*)aux1;
62 size_t elfu_mPhdrCount(ElfuElf *me)
68 elfu_mPhdrForall(me, subCounter, &i, NULL);
76 /* Finding by exact address/offset */
78 static void* subFindLoadByAddr(ElfuElf *me, ElfuPhdr *mp, void *aux1, void *aux2)
80 GElf_Addr addr = *(GElf_Addr*)aux1;
83 if (mp->phdr.p_type == PT_LOAD
84 && FULLY_OVERLAPPING(mp->phdr.p_vaddr, mp->phdr.p_memsz, addr, 1)) {
92 ElfuPhdr* elfu_mPhdrByAddr(ElfuElf *me, GElf_Addr addr)
94 return elfu_mPhdrForall(me, subFindLoadByAddr, &addr, NULL);
98 static void* subFindLoadByOffset(ElfuElf *me, ElfuPhdr *mp, void *aux1, void *aux2)
100 GElf_Off offset = *(GElf_Off*)aux1;
103 if (mp->phdr.p_type == PT_LOAD
104 && FULLY_OVERLAPPING(mp->phdr.p_offset, mp->phdr.p_filesz, offset, 1)) {
112 ElfuPhdr* elfu_mPhdrByOffset(ElfuElf *me, GElf_Off offset)
114 return elfu_mPhdrForall(me, subFindLoadByOffset, &offset, NULL);
120 /* Find lowest/highest address/offset */
122 void elfu_mPhdrLoadLowestHighest(ElfuElf *me,
123 ElfuPhdr **lowestAddr, ElfuPhdr **highestAddr,
124 ElfuPhdr **lowestOffs, ElfuPhdr **highestOffsEnd)
132 assert(highestOffsEnd);
137 *highestOffsEnd = NULL;
139 /* Find first and last LOAD PHDRs.
140 * Don't compare p_memsz - segments don't overlap in memory. */
141 CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
142 if (mp->phdr.p_type != PT_LOAD) {
145 if (!*lowestAddr || mp->phdr.p_vaddr < (*lowestAddr)->phdr.p_vaddr) {
148 if (!*highestAddr || mp->phdr.p_vaddr > (*highestAddr)->phdr.p_vaddr) {
151 if (!*lowestOffs || mp->phdr.p_offset < (*lowestOffs)->phdr.p_offset) {
155 || (OFFS_END(mp->phdr.p_offset,
157 > OFFS_END((*highestOffsEnd)->phdr.p_offset,
158 (*highestOffsEnd)->phdr.p_filesz))) {
159 *highestOffsEnd = mp;
169 void elfu_mPhdrUpdateChildOffsets(ElfuPhdr *mp)
175 assert(mp->phdr.p_type == PT_LOAD);
177 CIRCLEQ_FOREACH(mpc, &mp->childPhdrList, elemChildPhdr) {
178 mpc->phdr.p_offset = mp->phdr.p_offset + (mpc->phdr.p_vaddr - mp->phdr.p_vaddr);
181 CIRCLEQ_FOREACH(ms, &mp->childScnList, elemChildScn) {
182 ms->shdr.sh_offset = mp->phdr.p_offset + (ms->shdr.sh_addr - mp->phdr.p_vaddr);
189 * Allocation, destruction
192 ElfuPhdr* elfu_mPhdrAlloc()
196 mp = malloc(sizeof(ElfuPhdr));
198 ELFU_WARN("mPhdrAlloc: malloc() failed for ElfuPhdr.\n");
202 memset(mp, 0, sizeof(*mp));
204 CIRCLEQ_INIT(&mp->childScnList);
205 CIRCLEQ_INIT(&mp->childPhdrList);
210 void elfu_mPhdrDestroy(ElfuPhdr* mp)
214 if (!CIRCLEQ_EMPTY(&mp->childPhdrList)) {
217 nextmp = CIRCLEQ_FIRST(&mp->childPhdrList);
218 while ((void*)nextmp != (void*)&mp->childPhdrList) {
219 ElfuPhdr *curmp = nextmp;
220 nextmp = CIRCLEQ_NEXT(curmp, elemChildPhdr);
221 CIRCLEQ_REMOVE(&mp->childPhdrList, curmp, elemChildPhdr);
222 elfu_mPhdrDestroy(curmp);
226 if (!CIRCLEQ_EMPTY(&mp->childScnList)) {
229 nextms = CIRCLEQ_FIRST(&mp->childScnList);
230 while ((void*)nextms != (void*)&mp->childScnList) {
231 ElfuScn *curms = nextms;
232 nextms = CIRCLEQ_NEXT(curms, elemChildScn);
233 CIRCLEQ_REMOVE(&mp->childScnList, curms, elemChildScn);
234 elfu_mScnDestroy(curms);