summaryrefslogtreecommitdiff
path: root/include/libelfu
diff options
context:
space:
mode:
Diffstat (limited to 'include/libelfu')
-rw-r--r--include/libelfu/elfops.h24
-rw-r--r--include/libelfu/generic.h14
-rw-r--r--include/libelfu/modelops.h384
-rw-r--r--include/libelfu/types.h124
4 files changed, 514 insertions, 32 deletions
diff --git a/include/libelfu/elfops.h b/include/libelfu/elfops.h
index 4131f41..dde51bc 100644
--- a/include/libelfu/elfops.h
+++ b/include/libelfu/elfops.h
@@ -1,3 +1,12 @@
+/*!
+ * @file elfops.h
+ * @brief Operations offered by libelfu on libelf handles
+ *
+ * This includes:
+ * - Checks
+ * - Post-processing for ELF specification compliance
+ */
+
#ifndef __LIBELFU_ELFOPS_H_
#define __LIBELFU_ELFOPS_H_
@@ -7,7 +16,22 @@
#include <libelfu/types.h>
+/*!
+ * @brief Perform a large array of sanity checks.
+ * @param e libelf handle to file to be checked.
+ * @result 0 if successful.
+ * Anything else indicates an error.
+ * @note If a file does not pass these checks,
+ * then it cannot be processed by libelfu.
+ */
int elfu_eCheck(Elf *e);
+
+
+
+/*!
+ * @brief Reorder PHDRs to comply with ELF specification.
+ * @param e libelf handle to file to be post-processed.
+ */
void elfu_eReorderPhdrs(Elf *e);
diff --git a/include/libelfu/generic.h b/include/libelfu/generic.h
index 4e3239d..ed774b1 100644
--- a/include/libelfu/generic.h
+++ b/include/libelfu/generic.h
@@ -4,9 +4,17 @@
#include <gelf.h>
-#define MIN(x, y) ((x) < (y) ? (x) : (y))
-#define MAX(x, y) ((x) > (y) ? (x) : (y))
-#define ROUNDUP(x, align) ((x) + ((align) - ((x) % (align))) % (align))
+#ifndef MIN
+ #define MIN(x, y) ((x) < (y) ? (x) : (y))
+#endif
+
+#ifndef MAX
+ #define MAX(x, y) ((x) > (y) ? (x) : (y))
+#endif
+
+#ifndef ROUNDUP
+ #define ROUNDUP(x, align) ((x) + ((align) - ((x) % (align))) % (align))
+#endif
#define OFFS_END(off, sz) ((off) + (sz))
diff --git a/include/libelfu/modelops.h b/include/libelfu/modelops.h
index 538e97a..92f863f 100644
--- a/include/libelfu/modelops.h
+++ b/include/libelfu/modelops.h
@@ -1,3 +1,15 @@
+/*!
+ * @file modelops.h
+ * @brief Operations offered on libelfu's Elfu* models.
+ *
+ * This includes:
+ * - Allocation/initialization, teardown of objects
+ * - Iteration (*Forall)
+ * - Stats (counts, lowest/highest element, ...)
+ * - Lookups (addresses, ...)
+ * - Scripted high-level operations (reladd, detour, ...)
+ */
+
#ifndef __LIBELFU_MODELOPS_H__
#define __LIBELFU_MODELOPS_H__
@@ -7,74 +19,396 @@
#include <libelfu/types.h>
+/*!
+ * @brief Lookup name of a string.
+ * @param symtabscn ElfuScn of symbol table.
+ * @param off Offset in string table at which name starts.
+ * @result Pointer to name.
+ * @result INTERNAL USE ONLY.
+ * See elfu_mSymtabSymToName() for an alternative.
+ *
+ */
#define ELFU_SYMSTR(symtabscn, off) ((symtabscn)->linkptr->databuf + (off))
- int elfu_mSymtabLookupSymToAddr(ElfuElf *me, ElfuScn *msst, ElfuSym *sym, GElf_Addr *result);
- char* elfu_mSymtabSymToName(ElfuScn *msst, ElfuSym *sym);
- ElfuSym* elfu_mSymtabIndexToSym(ElfuScn *msst, GElf_Word entry);
+/*!
+ * @brief Lookup the address a symbol points to.
+ * @param me Entire ELF model.
+ * @param msst ElfuScn containing the symbol table this symbol is in.
+ * @param sym The symbol itself.
+ * @param result Will be set to the calculated address.
+ * @result 0 if *result is valid. Otherwise, *result is undefined and the
+ * address could not be resolved.
+ * @note This is currently for INTERNAL USE in the relocator ONLY.
+ */
+int elfu_mSymtabLookupSymToAddr(ElfuElf *me, ElfuScn *msst, ElfuSym *sym, GElf_Addr *result);
+
+/*!
+ * @brief Lookup name of a symbol.
+ * @param msst ElfuScn containing the symbol table this symbol is in.
+ * @param sym The symbol itself.
+ * @result Pointer to name.
+ */
+char* elfu_mSymtabSymToName(ElfuScn *msst, ElfuSym *sym);
+
+/*!
+ * @brief Lookup a symbol by its index in a symbol table.
+ * @param msst ElfuScn containing the symbol table this symbol is in.
+ * @param entry The symbol's index in the table.
+ * @result Pointer to the symbol.
+ */
+ElfuSym* elfu_mSymtabIndexToSym(ElfuScn *msst, GElf_Word entry);
+
+/*!
+ * @brief Lookup the address a symbol points to, by the symbol name.
+ * @param me Entire ELF model.
+ * @param msst ElfuScn containing the symbol table this symbol is in.
+ * @param name The symbol's name.
+ * @result The address the symbol points to.
+ */
GElf_Addr elfu_mSymtabLookupAddrByName(ElfuElf *me, ElfuScn *msst, char *name);
- void elfu_mSymtabFlatten(ElfuElf *me);
- void elfu_mSymtabAddGlobalDymtabIfNotPresent(ElfuElf *me);
+
+/*!
+ * @brief Serialize an ELF's global symbol table.
+ * @param me Entire ELF model.
+ */
+void elfu_mSymtabFlatten(ElfuElf *me);
+
+/*!
+ * @brief Check if a global symbol table exists, and add it otherwise.
+ * @param me Entire ELF model.
+ */
+void elfu_mSymtabAddGlobalDymtabIfNotPresent(ElfuElf *me);
+
+
+/*!
+ * @brief Callback for elfu_mPhdrForall().
+ * @param me Entire ELF model.
+ * @param mp Current PHDR to process.
+ * @param aux1 User defined.
+ * @param aux2 User defined.
+ * @result NULL if iteration is to continue.
+ * Otherwise it is aborted and the handler's return value is
+ * returned by elfu_mPhdrForall() itself.
+ */
typedef void* (PhdrHandlerFunc)(ElfuElf *me, ElfuPhdr *mp, void *aux1, void *aux2);
- void* elfu_mPhdrForall(ElfuElf *me, PhdrHandlerFunc f, void *aux1, void *aux2);
- size_t elfu_mPhdrCount(ElfuElf *me);
+
+/*!
+ * @brief Iterate over all PHDRs.
+ * @param me Entire ELF model.
+ * @param f Callback function.
+ * @param aux1 User defined.
+ * @param aux2 User defined.
+ * @result NULL if all items have been processed.
+ * Otherwise the return value of the last handler function
+ * call before aborting.
+ */
+void* elfu_mPhdrForall(ElfuElf *me, PhdrHandlerFunc f, void *aux1, void *aux2);
+
+/*!
+ * @brief Calculate number of PHDRs in an ElfuElf.
+ * @param me Entire ELF model.
+ * @result Total number of PHDRs.
+ */
+size_t elfu_mPhdrCount(ElfuElf *me);
+
+/*!
+ * @brief Find a PHDR that covers a memory address.
+ * @param me Entire ELF model.
+ * @param addr A memory address.
+ * @result Pointer to a PHDR containing the given memory address.
+ * NULL if none found.
+ */
ElfuPhdr* elfu_mPhdrByAddr(ElfuElf *me, GElf_Addr addr);
+
+/*!
+ * @brief Find a PHDR that covers a file offset.
+ * @param me Entire ELF model.
+ * @param offset A file offset.
+ * @result Pointer to a PHDR containing the given file offset.
+ * NULL if none found.
+ */
ElfuPhdr* elfu_mPhdrByOffset(ElfuElf *me, GElf_Off offset);
- void elfu_mPhdrLoadLowestHighest(ElfuElf *me,
- ElfuPhdr **lowestAddr,
- ElfuPhdr **highestAddr,
- ElfuPhdr **lowestOffs,
- ElfuPhdr **highestOffsEnd);
- void elfu_mPhdrUpdateChildOffsets(ElfuPhdr *mp);
+
+/*!
+ * @brief Find the ElfuElf's memory address and file offset
+ * extrema in terms of PHDRs.
+ * @param me Entire ELF model.
+ * @param lowestAddr Will be set to PHDR containing the lowest address referenced.
+ * @param highestAddr Will be set to PHDR containing the highest address referenced.
+ * @param lowestOffs Will be set to PHDR containing the lowest offset referenced.
+ * @param highestOffsEnd Will be set to PHDR containing the highest offset referenced.
+ */
+void elfu_mPhdrLoadLowestHighest(ElfuElf *me,
+ ElfuPhdr **lowestAddr,
+ ElfuPhdr **highestAddr,
+ ElfuPhdr **lowestOffs,
+ ElfuPhdr **highestOffsEnd);
+
+/*!
+ * @brief Update child sections' offsets in the file according to parent
+ * PHDR's offset and address.
+ * @param mp Parent PHDR whose children to update.
+ */
+void elfu_mPhdrUpdateChildOffsets(ElfuPhdr *mp);
+
+/*!
+ * @brief Allocate and initialize a PHDR model.
+ * @result Pointer to a fresh ElfuPhdr.
+ * NULL if allocation failed.
+ */
ElfuPhdr* elfu_mPhdrAlloc();
- void elfu_mPhdrDestroy(ElfuPhdr* mp);
+
+/*!
+ * @brief Tear down a PHDR and its children.
+ * @param mp PHDR to delete.
+ */
+void elfu_mPhdrDestroy(ElfuPhdr* mp);
+
+
+/*!
+ * @brief Callback for elfu_mScnForall().
+ * @param me Entire ELF model.
+ * @param ms Current section to process.
+ * @param aux1 User defined.
+ * @param aux2 User defined.
+ * @result NULL if iteration is to continue.
+ * Otherwise it is aborted and the handler's return value is
+ * returned by elfu_mScnForall() itself.
+ */
typedef void* (SectionHandlerFunc)(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2);
- void* elfu_mScnForall(ElfuElf *me, SectionHandlerFunc f, void *aux1, void *aux2);
- size_t elfu_mScnCount(ElfuElf *me);
- size_t elfu_mScnIndex(ElfuElf *me, ElfuScn *ms);
- ElfuScn* elfu_mScnByOldscn(ElfuElf *me, ElfuScn *oldscn);
- char* elfu_mScnName(ElfuElf *me, ElfuScn *ms);
+
+/*!
+ * @brief Iterate over all sections.
+ * @param me Entire ELF model.
+ * @param f Callback function.
+ * @param aux1 User defined.
+ * @param aux2 User defined.
+ * @result NULL if all items have been processed.
+ * Otherwise the return value of the last handler function
+ * call before aborting.
+ */
+void* elfu_mScnForall(ElfuElf *me, SectionHandlerFunc f, void *aux1, void *aux2);
+
+/*!
+ * @brief Calculate number of sections in an ElfuElf.
+ * @param me Entire ELF model.
+ * @result Total number of sections.
+ */
+size_t elfu_mScnCount(ElfuElf *me);
+
+/*!
+ * @brief Calculate index a section would currently have in its ElfuElf.
+ * @param me Entire ELF model.
+ * @param ms A section in *me.
+ * @result Estimated index.
+ */
+size_t elfu_mScnIndex(ElfuElf *me, ElfuScn *ms);
+
+/*!
+ * @brief Find a cloned section by its oldscn value.
+ * @param me Entire ELF model.
+ * @param oldscn Original section to find the clone of.
+ * @result A section that is a clone of *oldscn.
+ * NULL if none found.
+ */
+ElfuScn* elfu_mScnByOldscn(ElfuElf *me, ElfuScn *oldscn);
+
+/*!
+ * @brief Get a section's name.
+ * @param me Entire ELF model.
+ * @param ms A section in *me.
+ * @result Pointer to the section's name in .shstrtab.
+ */
+char* elfu_mScnName(ElfuElf *me, ElfuScn *ms);
+
+/*!
+ * @brief Allocate an array of pointers to all sections,
+ * and sort them by offset.
+ * @param me Entire ELF model.
+ * @param count Where to write total count of sections to.
+ * @result Pointer to the section's name in .shstrtab.
+ * NULL if an error occurred.
+ */
ElfuScn** elfu_mScnSortedByOffset(ElfuElf *me, size_t *count);
- int elfu_mScnAppendData(ElfuScn *ms, void *buf, size_t len);
- ElfuScn* elfu_mScnAlloc();
- void elfu_mScnDestroy(ElfuScn* ms);
+
+/*!
+ * @brief Enlarge a section's buffer and append data to it.
+ * @param ms Section to append to.
+ * @param buf Source buffer with data to append.
+ * @param len Length of source buffer.
+ * @result 0 if successful.
+ * Anything else indicates an error.
+ */
+int elfu_mScnAppendData(ElfuScn *ms, void *buf, size_t len);
+
+/*!
+ * @brief Allocate and initialize a section model.
+ * @result Pointer to a fresh ElfuScn.
+ * NULL if allocation failed.
+ */
+ElfuScn* elfu_mScnAlloc();
+
+/*!
+ * @brief Tear down a section and associated buffers.
+ * @param ms Section to delete.
+ */
+void elfu_mScnDestroy(ElfuScn* ms);
+
+
+/*!
+ * @brief Allocate and initialize an ELF file model.
+ * @result Pointer to a fresh ElfuElf.
+ * NULL if allocation failed.
+ */
ElfuElf* elfu_mElfAlloc();
- void elfu_mElfDestroy(ElfuElf* me);
+
+/*!
+ * @brief Tear down an ELF file model and associated structures.
+ * @param me ElfuElf to destroy.
+ */
+void elfu_mElfDestroy(ElfuElf* me);
+
+
+/*!
+ * @brief Find a LOAD segment to inject into, and expand/create it.
+ * @param me Entire ELF model.
+ * @param size Size of data to inject.
+ * @param align Alignment requirement of new data.
+ * @param w Whether the new data should be writable when loaded.
+ * @param x Whether the new data should be executable when loaded.
+ * @param injPhdr Will be set to the identified target PHDR.
+ * @result The address where the data will be located.
+ */
GElf_Addr elfu_mLayoutGetSpaceInPhdr(ElfuElf *me, GElf_Word size,
GElf_Word align, int w, int x,
ElfuPhdr **injPhdr);
+/*!
+ * @brief Re-layout an ELF file so nothing overlaps that should not.
+ * Also, recalculate various offsets and sizes where necessary.
+ * @param me Entire ELF model.
+ */
int elfu_mLayoutAuto(ElfuElf *me);
+
+
+/*!
+ * @brief Lookup the address of a function in the PLT by its name.
+ * @param me Entire ELF model.
+ * @param name The function's name.
+ * @param result Will be set to the calculated address.
+ * @result 0 if *result is valid. Otherwise, *result is undefined and the
+ * address could not be resolved.
+ */
int elfu_mDynLookupPltAddrByName(ElfuElf *me, char *name, GElf_Addr *result);
+
+/*!
+ * @brief Lookup the address of a dynamically loaded variable by its name.
+ * @param me Entire ELF model.
+ * @param name The variable's name.
+ * @param result Will be set to the calculated address.
+ * @result 0 if *result is valid. Otherwise, *result is undefined and the
+ * address could not be resolved.
+ */
int elfu_mDynLookupReldynAddrByName(ElfuElf *me, char *name, GElf_Addr *result);
+
+
+/*!
+ * @brief Relocate a section.
+ * @param metarget ELF model containing cloned section.
+ * @param mstarget Cloned section to be relocated.
+ * @param msrt Section in original ELF model,
+ * containing relocation table.
+ * @result 0 if successful.
+ * Anything else indicates an error.
+ * @note This is currently for INTERNAL USE in Reladd ONLY.
+ */
int elfu_mRelocate(ElfuElf *metarget, ElfuScn *mstarget, ElfuScn *msrt);
+
+
+/*!
+ * @brief Perform a few sanity checks.
+ * @param me Entire ELF model.
+ * @result 0 if successful.
+ * Anything else indicates an error.
+ */
int elfu_mCheck(ElfuElf *me);
+
+
+/*!
+ * @brief Dump contents of a PHDR to stdout.
+ * @param me Entire ELF model.
+ * @param mp PHDR to dump.
+ */
void elfu_mDumpPhdr(ElfuElf *me, ElfuPhdr *mp);
+
+/*!
+ * @brief Dump details of a section to stdout.
+ * @param me Entire ELF model.
+ * @param ms Section to dump.
+ */
void elfu_mDumpScn(ElfuElf *me, ElfuScn *ms);
+
+/*!
+ * @brief Dump contents of an entire ELF file model to stdout.
+ * @param me Entire ELF model to dump.
+ */
void elfu_mDumpElf(ElfuElf *me);
+
+
+/*!
+ * @brief Parse an ELF file to a libelfu model via libelf.
+ * @param e libelf handle to source file.
+ * @result NULL if an error occurred, a fresh ElfuElf otherwise.
+ */
ElfuElf* elfu_mFromElf(Elf *e);
- void elfu_mToElf(ElfuElf *me, Elf *e);
- int elfu_mReladd(ElfuElf *me, const ElfuElf *mrel);
+/*!
+ * @brief Serialize a libelfu model to an ELF file via libelf.
+ * @param me Entire ELF model.
+ * @param e libelf handle to destination file.
+ */
+void elfu_mToElf(ElfuElf *me, Elf *e);
+
+
+
+/*!
+ * @brief Inject contents of an object file into an executable.
+ * @param me Destination ELF model.
+ * @param mrel Source ELF model.
+ * @result 0 if successful.
+ * Anything else indicates an error.
+ */
+int elfu_mReladd(ElfuElf *me, const ElfuElf *mrel);
+
+
+
+
+/*!
+ * @brief Overwrite a location with an unconditional jump.
+ * @param me Entire ELF model.
+ * @param from Memory address to overwrite at.
+ * @param to Memory address to jump to.
+ */
void elfu_mDetour(ElfuElf *me, GElf_Addr from, GElf_Addr to);
+
#endif
diff --git a/include/libelfu/types.h b/include/libelfu/types.h
index d6a7584..c1fbfda 100644
--- a/include/libelfu/types.h
+++ b/include/libelfu/types.h
@@ -1,3 +1,12 @@
+/*!
+ * @file types.h
+ * @brief libelfu's Elfu* types.
+ *
+ * libelfu provides an abstraction of the data in ELF files
+ * to more closely model the dependencies between them, and
+ * thus to facilitate consistent editing.
+ */
+
#ifndef __LIBELFU_TYPES_H__
#define __LIBELFU_TYPES_H__
@@ -7,46 +16,90 @@
#include <gelf.h>
+/*!
+ * ELFU model of a symbol table entry.
+ */
typedef struct ElfuSym {
+ /*! Offset into linked string table */
GElf_Word name;
+
+ /*! Explicit value */
GElf_Addr value;
+
+ /*! Size of object referenced */
GElf_Word size;
+
+ /*! Binding type (GLOBAL, LOCAL, ...) */
unsigned char bind;
+
+ /*! Type (FUNC, SECTION, ...) */
unsigned char type;
+
+ /*! Always 0, currently meaningless (see ELF spec) */
unsigned char other;
+
+ /*! If non-null, the section referenced. */
struct ElfuScn *scnptr;
+
+ /*! If scnptr is invalid, then this is ABS, COMMON, or UNDEF. */
int shndx;
+
+ /*! Entry in a symbol table */
CIRCLEQ_ENTRY(ElfuSym) elem;
} ElfuSym;
+
+/*!
+ * ELFU model of a symbol table.
+ */
typedef struct ElfuSymtab {
+ /*! All parsed symbols */
CIRCLEQ_HEAD(Syms, ElfuSym) syms;
} ElfuSymtab;
-typedef struct ElfuRel {
- char *name;
+
+/*!
+ * ELFU model of a relocation entry.
+ */
+typedef struct ElfuRel {
+ /*! Location to patch */
GElf_Addr offset;
- GElf_Word info;
+
+ /*! Symbol to calculate value for */
GElf_Word sym;
+
+ /*! Relocation type (machine specific) */
unsigned char type;
+
+ /*! addendUsed == 0: Use addend from relocation destination (REL).
+ * addendUsed != 0: Use explicit addend (RELA). */
int addendUsed;
+
+ /*! Explicit addend in RELA tables */
GElf_Sword addend;
+
+ /*! Element in table */
CIRCLEQ_ENTRY(ElfuRel) elem;
} ElfuRel;
+
+/*!
+ * ELFU model of a relocation table.
+ */
typedef struct ElfuReltab {
+ /*! All parsed relocation entries */
CIRCLEQ_HEAD(Rels, ElfuRel) rels;
} ElfuReltab;
@@ -55,42 +108,105 @@ typedef struct ElfuReltab {
+
+/*!
+ * ELFU model of an ELF section.
+ *
+ * Several members of the SHDR are repeated in abstract form and take
+ * precedence if present. For example, if linkptr is non-NULL then
+ * it points to another section and the SHDR's numeric sh_link member
+ * is to be ignored and recomputed by the layouter.
+ */
typedef struct ElfuScn {
+ /*! SHDR as per ELF specification.
+ * Several values are ignored or recomputed from other members of
+ * ElfuScn. */
GElf_Shdr shdr;
+ /*! malloc()ed buffer containing this section's flat data backbuffer.
+ * Present for all sections that occupy space in the file. */
+ char *databuf;
+
+
+ /*! Pointer to a section, meaning dependent on sh_type.
+ * Preferred over sh_link if non-null. */
struct ElfuScn *linkptr;
+
+ /*! Pointer to a section, meaning dependent on sh_type.
+ * Preferred over sh_info if non-null. */
struct ElfuScn *infoptr;
- char *databuf;
+
+ /*! If this section is a clone of another section, then this
+ * points to that other section.
+ * Used during code injection to facilitate relocation. */
struct ElfuScn *oldptr;
+
+ /*! Translated contents of a symbol table. */
struct ElfuSymtab symtab;
+
+ /*! Translated contents of a relocation table. */
struct ElfuReltab reltab;
+
+ /*! Element linking this section into an ElfuPhdr's childScnList,
+ * or into an ElfuElf's orphanScnList. */
CIRCLEQ_ENTRY(ElfuScn) elemChildScn;
} ElfuScn;
+
+/*!
+ * ELFU model of an ELF PHDR.
+ */
typedef struct ElfuPhdr {
+ /*! PHDR as per ELF specification. */
GElf_Phdr phdr;
+
+ /*! Sections to be shifted in file/memory together with this PHDR */
CIRCLEQ_HEAD(ChildScnList, ElfuScn) childScnList;
+
+ /*! PHDRs to be shifted in file/memory together with this PHDR */
CIRCLEQ_HEAD(ChildPhdrList, ElfuPhdr) childPhdrList;
+
+ /*! Element linking this section into an ElfuPhdr's childPhdrList */
CIRCLEQ_ENTRY(ElfuPhdr) elemChildPhdr;
+
+ /*! Element linking this section into an ElfuElf's phdrList */
CIRCLEQ_ENTRY(ElfuPhdr) elem;
} ElfuPhdr;
+
+/*!
+ * ELFU model of an ELF file header
+ */
typedef struct {
+ /*! The ELF class -- ELFCLASS32/ELFCLASS64 */
int elfclass;
+
+ /*! EHDR as per ELF specification */
GElf_Ehdr ehdr;
+
+ /*! PHDRs that are not dependent on others.
+ * Usually, LOAD and GNU_STACK. */
CIRCLEQ_HEAD(PhdrList, ElfuPhdr) phdrList;
+
+ /*! Sections not in any PHDR, and thus not loaded at runtime.
+ * Usually .symtab, .strtab, .shstrtab, .debug_*, ... */
CIRCLEQ_HEAD(OrphanScnList, ElfuScn) orphanScnList;
+
+ /*! Pointer to ElfuScn containing .shstrtab.
+ * Parsed from EHDR for convenience. */
ElfuScn *shstrtab;
+ /*! Pointer to ElfuScn containing .symtab.
+ * Parsed from list of sections for convenience. */
ElfuScn *symtab;
} ElfuElf;