summaryrefslogtreecommitdiff
path: root/src/libelfu/modelops/section.c
diff options
context:
space:
mode:
authornorly <ny-git@enpas.org>2013-06-20 01:56:24 +0100
committernorly <ny-git@enpas.org>2013-06-20 22:10:25 +0100
commitb70b3ff9b1679bb1e0a215b7acd9b6d55497a46b (patch)
treed6e95ad143c7e2ec9ca39c1dd32c046fb9006eb9 /src/libelfu/modelops/section.c
parent7f1a29e9e33059dfebdc24bb3ffaa3dac46b58f1 (diff)
Separate library code, build .a/.so
Diffstat (limited to 'src/libelfu/modelops/section.c')
-rw-r--r--src/libelfu/modelops/section.c196
1 files changed, 196 insertions, 0 deletions
diff --git a/src/libelfu/modelops/section.c b/src/libelfu/modelops/section.c
new file mode 100644
index 0000000..2675126
--- /dev/null
+++ b/src/libelfu/modelops/section.c
@@ -0,0 +1,196 @@
+#include <assert.h>
+#include <stdlib.h>
+#include <libelfu/libelfu.h>
+
+
+/* Meta-functions */
+
+void* elfu_mScnForall(ElfuElf *me, SectionHandlerFunc f, void *aux1, void *aux2)
+{
+ ElfuPhdr *mp;
+ ElfuScn *ms;
+
+ // TODO: Sort PHDRs by offset before interating
+
+ CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
+ if (mp->phdr.p_type != PT_LOAD) {
+ continue;
+ }
+
+ CIRCLEQ_FOREACH(ms, &mp->childScnList, elemChildScn) {
+ void *rv = f(me, ms, aux1, aux2);
+
+ if (rv) {
+ return rv;
+ }
+ }
+ }
+
+ CIRCLEQ_FOREACH(ms, &me->orphanScnList, elemChildScn) {
+ void *rv = f(me, ms, aux1, aux2);
+
+ if (rv) {
+ return rv;
+ }
+ }
+
+ return NULL;
+}
+
+
+
+
+/* Counting */
+
+static void* subCounter(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
+{
+ size_t *i = (size_t*)aux1;
+ ElfuScn *otherScn = (ElfuScn*)aux2;
+
+ if (ms == otherScn) {
+ return ms;
+ }
+
+ *i += 1;
+
+ /* Continue */
+ return NULL;
+}
+
+
+size_t elfu_mScnCount(ElfuElf *me)
+{
+ /* NULL section *is not* counted */
+ size_t i = 0;
+
+ assert(me);
+
+ elfu_mScnForall(me, subCounter, &i, NULL);
+
+ return i;
+}
+
+
+/* Returns the index a section would have in the flattened ELF */
+size_t elfu_mScnIndex(ElfuElf *me, ElfuScn *ms)
+{
+ /* NULL section *is* counted */
+ size_t i = 1;
+
+ assert(me);
+ assert(ms);
+
+ elfu_mScnForall(me, subCounter, &i, ms);
+
+ /* If this assertion is broken then ms is not a section in me. */
+ assert(i <= elfu_mScnCount(me));
+ return i;
+}
+
+
+static void* subOldscn(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
+{
+ ElfuScn *otherScn = (ElfuScn*)aux1;
+ (void)aux2;
+
+ if (ms->oldptr == otherScn) {
+ return ms;
+ }
+
+ /* Continue */
+ return NULL;
+}
+
+/* Returns the section with oldscn == oldscn */
+ElfuScn* elfu_mScnByOldscn(ElfuElf *me, ElfuScn *oldscn)
+{
+ assert(me);
+ assert(oldscn);
+
+ return elfu_mScnForall(me, subOldscn, oldscn, NULL);
+}
+
+
+
+
+/* Convenience */
+
+char* elfu_mScnName(ElfuElf *me, ElfuScn *ms)
+{
+ assert(me);
+ assert(ms);
+
+ if (!me->shstrtab) {
+ return NULL;
+ }
+
+ if (!me->shstrtab->data.d_buf) {
+ return NULL;
+ }
+
+ return &((char*)me->shstrtab->data.d_buf)[ms->shdr.sh_name];
+}
+
+
+static void* subScnsToArray(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
+{
+ ElfuScn **arr = (ElfuScn**)aux1;
+ size_t *i = (size_t*)aux2;
+
+ arr[(*i)] = ms;
+ *i += 1;
+
+ /* Continue */
+ return NULL;
+}
+
+static int cmpScnOffs(const void *ms1, const void *ms2)
+{
+ ElfuScn *s1;
+ ElfuScn *s2;
+
+ assert(ms1);
+ assert(ms2);
+
+ s1 = *(ElfuScn**)ms1;
+ s2 = *(ElfuScn**)ms2;
+
+ assert(s1);
+ assert(s2);
+
+
+ if (s1->shdr.sh_offset < s2->shdr.sh_offset) {
+ return -1;
+ } else if (s1->shdr.sh_offset == s2->shdr.sh_offset) {
+ return 0;
+ } else /* if (s1->shdr.sh_offset > s2->shdr.sh_offset) */ {
+ return 1;
+ }
+}
+
+ElfuScn** elfu_mScnSortedByOffset(ElfuElf *me, size_t *count)
+{
+ size_t numSecs;
+ ElfuScn **sortedSecs;
+ size_t i;
+
+ assert(me);
+
+ /* Sort sections by offset in file */
+ numSecs = elfu_mScnCount(me);
+ sortedSecs = malloc(numSecs * sizeof(*sortedSecs));
+ if (!sortedSecs) {
+ ELFU_WARN("elfu_mScnSortedByOffset: Failed to allocate memory.\n");
+ return NULL;
+ }
+
+ i = 0;
+ elfu_mScnForall(me, subScnsToArray, sortedSecs, &i);
+ assert(i == numSecs);
+
+ qsort(sortedSecs, numSecs, sizeof(*sortedSecs), cmpScnOffs);
+
+ *count = numSecs;
+
+ return sortedSecs;
+}