Implement memory management TODOs
[centaur.git] / src / libelfu / model / phdr.c
index d175362d3dd272d6dd9c066598e65d7599e683cf..6f31e6b742567c2ba094161372909bacc2d4c53d 100644 (file)
@@ -58,7 +58,7 @@ size_t elfu_mPhdrCount(ElfuElf *me)
 
 
 
-/* Finding */
+/* Finding by exact address/offset */
 
 static void* subFindLoadByAddr(ElfuElf *me, ElfuPhdr *mp, void *aux1, void *aux2)
 {
@@ -102,6 +102,53 @@ ElfuPhdr* elfu_mPhdrByOffset(ElfuElf *me, GElf_Off offset)
 
 
 
+/* Find lowest/highest address/offset */
+
+void elfu_mPhdrLoadLowestHighest(ElfuElf *me,
+                                 ElfuPhdr **lowestAddr, ElfuPhdr **highestAddr,
+                                 ElfuPhdr **lowestOffs, ElfuPhdr **highestOffsEnd)
+{
+  ElfuPhdr *mp;
+
+  assert(me);
+  assert(lowestAddr);
+  assert(highestAddr);
+  assert(lowestOffs);
+  assert(highestOffsEnd);
+
+  *lowestAddr = NULL;
+  *highestAddr = NULL;
+  *lowestOffs = NULL;
+  *highestOffsEnd = NULL;
+
+  /* Find first and last LOAD PHDRs.
+   * Don't compare p_memsz - segments don't overlap in memory. */
+  CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
+    if (mp->phdr.p_type != PT_LOAD) {
+      continue;
+    }
+    if (!*lowestAddr || mp->phdr.p_vaddr < (*lowestAddr)->phdr.p_vaddr) {
+      *lowestAddr = mp;
+    }
+    if (!*highestAddr || mp->phdr.p_vaddr > (*highestAddr)->phdr.p_vaddr) {
+      *highestAddr = mp;
+    }
+    if (!*lowestOffs || mp->phdr.p_offset < (*lowestOffs)->phdr.p_offset) {
+      *lowestOffs = mp;
+    }
+    if (!*highestOffsEnd
+        || (OFFS_END(mp->phdr.p_offset,
+                     mp->phdr.p_filesz)
+            > OFFS_END((*highestOffsEnd)->phdr.p_offset,
+                       (*highestOffsEnd)->phdr.p_filesz))) {
+      *highestOffsEnd = mp;
+    }
+  }
+}
+
+
+
+
 /* Layout update */
 
 void elfu_mPhdrUpdateChildOffsets(ElfuPhdr *mp)
@@ -147,19 +194,30 @@ ElfuPhdr* elfu_mPhdrAlloc()
 
 void elfu_mPhdrDestroy(ElfuPhdr* mp)
 {
-  ElfuPhdr *mp2;
-  ElfuScn *ms;
-
   assert(mp);
 
-  CIRCLEQ_FOREACH(mp2, &mp->childPhdrList, elem) {
-    CIRCLEQ_REMOVE(&mp->childPhdrList, mp2, elem);
-    elfu_mPhdrDestroy(mp2);
+  if (!CIRCLEQ_EMPTY(&mp->childPhdrList)) {
+    ElfuPhdr *nextmp;
+
+    nextmp = CIRCLEQ_FIRST(&mp->childPhdrList);
+    while ((void*)nextmp != (void*)&mp->childPhdrList) {
+      ElfuPhdr *curmp = nextmp;
+      nextmp = CIRCLEQ_NEXT(curmp, elemChildPhdr);
+      CIRCLEQ_REMOVE(&mp->childPhdrList, curmp, elemChildPhdr);
+      elfu_mPhdrDestroy(curmp);
+    }
   }
 
-  CIRCLEQ_FOREACH(ms, &mp->childScnList, elem) {
-    CIRCLEQ_REMOVE(&mp->childScnList, ms, elem);
-    elfu_mScnDestroy(ms);
+  if (!CIRCLEQ_EMPTY(&mp->childScnList)) {
+    ElfuScn *nextms;
+
+    nextms = CIRCLEQ_FIRST(&mp->childScnList);
+    while ((void*)nextms != (void*)&mp->childScnList) {
+      ElfuScn *curms = nextms;
+      nextms = CIRCLEQ_NEXT(curms, elemChildScn);
+      CIRCLEQ_REMOVE(&mp->childScnList, curms, elemChildScn);
+      elfu_mScnDestroy(curms);
+    }
   }
 
   free(mp);