From 50b85e44529f195bf8156e9c0045d8b017ee26f5 Mon Sep 17 00:00:00 2001 From: norly Date: Fri, 28 Jun 2013 02:35:44 +0100 Subject: [PATCH] Annotate doxygen-style --- include/elfhandle.h | 8 +- include/libelfu/elfops.h | 24 +++ include/libelfu/generic.h | 14 +- include/libelfu/modelops.h | 384 ++++++++++++++++++++++++++++++++++--- include/libelfu/types.h | 124 +++++++++++- 5 files changed, 520 insertions(+), 34 deletions(-) diff --git a/include/elfhandle.h b/include/elfhandle.h index b1a92ea..e948180 100644 --- a/include/elfhandle.h +++ b/include/elfhandle.h @@ -3,9 +3,13 @@ #include +/*! + * A simple pair of a file descriptor and a libelf handle, + * used to simplify elfucli. + */ typedef struct { - int fd; - Elf *e; + int fd; /*!< File handle */ + Elf *e; /*!< libelf handle */ } ELFHandles; 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 +/*! + * @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 -#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 +/*! + * @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 +/*! + * 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; -- 2.30.2