181 lines
4.0 KiB
C
181 lines
4.0 KiB
C
|
#include <sys/stat.h>
|
||
|
#include <elf.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <sys/mman.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <unistd.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdarg.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
#include "elfconfig.h"
|
||
|
|
||
|
#if KERNEL_ELFCLASS == ELFCLASS32
|
||
|
|
||
|
#define Elf_Ehdr Elf32_Ehdr
|
||
|
#define Elf_Shdr Elf32_Shdr
|
||
|
#define Elf_Sym Elf32_Sym
|
||
|
#define Elf_Addr Elf32_Addr
|
||
|
#define Elf_Section Elf32_Section
|
||
|
#define ELF_ST_BIND ELF32_ST_BIND
|
||
|
#define ELF_ST_TYPE ELF32_ST_TYPE
|
||
|
|
||
|
#define Elf_Rel Elf32_Rel
|
||
|
#define Elf_Rela Elf32_Rela
|
||
|
#define ELF_R_SYM ELF32_R_SYM
|
||
|
#define ELF_R_TYPE ELF32_R_TYPE
|
||
|
|
||
|
/* It needs to match sizeof within kernel
|
||
|
* as defined in include/linux/module.h
|
||
|
*/
|
||
|
#define ksym_t uint32_t
|
||
|
#define kstr_t uint32_t
|
||
|
#define ksym_hash_t uint32_t
|
||
|
#else
|
||
|
|
||
|
#define Elf_Ehdr Elf64_Ehdr
|
||
|
#define Elf_Shdr Elf64_Shdr
|
||
|
#define Elf_Sym Elf64_Sym
|
||
|
#define Elf_Addr Elf64_Addr
|
||
|
#define Elf_Section Elf64_Section
|
||
|
#define ELF_ST_BIND ELF64_ST_BIND
|
||
|
#define ELF_ST_TYPE ELF64_ST_TYPE
|
||
|
|
||
|
#define Elf_Rel Elf64_Rel
|
||
|
#define Elf_Rela Elf64_Rela
|
||
|
#define ELF_R_SYM ELF64_R_SYM
|
||
|
#define ELF_R_TYPE ELF64_R_TYPE
|
||
|
|
||
|
/* It needs to match sizeof within kernel
|
||
|
* as defined in include/linux/module.h
|
||
|
*/
|
||
|
#define ksym_t uint64_t
|
||
|
#define kstr_t uint64_t
|
||
|
#define ksym_hash_t uint64_t
|
||
|
#endif
|
||
|
|
||
|
/* The 64-bit MIPS ELF ABI uses an unusual reloc format. */
|
||
|
typedef struct
|
||
|
{
|
||
|
Elf32_Word r_sym; /* Symbol index */
|
||
|
unsigned char r_ssym; /* Special symbol for 2nd relocation */
|
||
|
unsigned char r_type3; /* 3rd relocation type */
|
||
|
unsigned char r_type2; /* 2nd relocation type */
|
||
|
unsigned char r_type1; /* 1st relocation type */
|
||
|
} _Elf64_Mips_R_Info;
|
||
|
|
||
|
typedef union
|
||
|
{
|
||
|
Elf64_Xword r_info_number;
|
||
|
_Elf64_Mips_R_Info r_info_fields;
|
||
|
} _Elf64_Mips_R_Info_union;
|
||
|
|
||
|
#define ELF64_MIPS_R_SYM(i) \
|
||
|
((__extension__ (_Elf64_Mips_R_Info_union)(i)).r_info_fields.r_sym)
|
||
|
|
||
|
#define ELF64_MIPS_R_TYPE(i) \
|
||
|
((__extension__ (_Elf64_Mips_R_Info_union)(i)).r_info_fields.r_type1)
|
||
|
|
||
|
#if KERNEL_ELFDATA != HOST_ELFDATA
|
||
|
|
||
|
static inline void __endian(const void *src, void *dest, unsigned int size)
|
||
|
{
|
||
|
unsigned int i;
|
||
|
for (i = 0; i < size; i++)
|
||
|
((unsigned char *)dest)[i] =
|
||
|
((unsigned char *)src)[size - i - 1];
|
||
|
}
|
||
|
|
||
|
#define TO_NATIVE(x) \
|
||
|
({ \
|
||
|
typeof(x) __x; \
|
||
|
__endian(&(x), &(__x), sizeof(__x)); \
|
||
|
__x; \
|
||
|
})
|
||
|
|
||
|
#else /* endianness matches */
|
||
|
|
||
|
#define TO_NATIVE(x) (x)
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#define GET_KSTRING(__ksym, __offset) (unsigned char *)(__ksym->name + __offset)
|
||
|
|
||
|
/* We have no more than 5 kernel symbol tables
|
||
|
__ksymtab
|
||
|
__ksymtab_gpl
|
||
|
__ksymtab_unused
|
||
|
__ksymtab_unused_gpl
|
||
|
__ksymtab_gpl_future
|
||
|
*/
|
||
|
|
||
|
enum ksymtab_type {
|
||
|
KSYMTAB = 0,
|
||
|
KSYMTAB_GPL,
|
||
|
KSYMTAB_UNUSED,
|
||
|
KSYMTAB_UNUSED_GPL,
|
||
|
KSYMTAB_GPL_FUTURE,
|
||
|
KSYMTAB_ALL,
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
* This maps the ELF hash table
|
||
|
* The entries in the .hash table always have a size of 32 bits.
|
||
|
*/
|
||
|
struct elf_htable {
|
||
|
uint32_t nbucket;
|
||
|
uint32_t nchain;
|
||
|
uint32_t *elf_buckets;
|
||
|
uint32_t *chains;
|
||
|
};
|
||
|
|
||
|
/* as defined in include/linux/module.h */
|
||
|
struct kernel_symbol {
|
||
|
ksym_t value;
|
||
|
kstr_t name;
|
||
|
ksym_hash_t hash_value;
|
||
|
};
|
||
|
|
||
|
struct kernel_symtab {
|
||
|
const char *name;
|
||
|
struct kernel_symbol *start;
|
||
|
struct kernel_symbol *stop;
|
||
|
Elf_Section sec;
|
||
|
};
|
||
|
|
||
|
struct elf_info {
|
||
|
unsigned long size;
|
||
|
Elf_Ehdr *hdr;
|
||
|
Elf_Shdr *sechdrs;
|
||
|
Elf_Sym *symtab_start;
|
||
|
Elf_Sym *symtab_stop;
|
||
|
long kstr_offset;
|
||
|
unsigned long base_addr;
|
||
|
|
||
|
struct {
|
||
|
ksym_hash_t *start;
|
||
|
ksym_hash_t *stop;
|
||
|
} undef_hash;
|
||
|
|
||
|
struct kernel_symtab ksym_tables[KSYMTAB_ALL];
|
||
|
Elf_Section markers_strings_sec;
|
||
|
const char *strtab;
|
||
|
const char *kstrings;
|
||
|
char *modinfo;
|
||
|
unsigned int modinfo_len;
|
||
|
};
|
||
|
|
||
|
/* from elflib.c */
|
||
|
void fatal(const char *fmt, ...);
|
||
|
void warn(const char *fmt, ...);
|
||
|
void merror(const char *fmt, ...);
|
||
|
|
||
|
ksym_hash_t gnu_hash(const unsigned char *name);
|
||
|
void *grab_file(const char *filename, unsigned long *size);
|
||
|
void release_file(void *file, unsigned long size);
|
||
|
int parse_elf(struct elf_info *info, const char *filename);
|
||
|
int parse_writable_elf(struct elf_info *info, const char *filename);
|
||
|
void parse_elf_finish(struct elf_info *info);
|
||
|
|
||
|
|