diff options
Diffstat (limited to 'tools/isprelinked')
-rwxr-xr-x | tools/isprelinked/Android.mk | 40 | ||||
-rw-r--r-- | tools/isprelinked/common.h | 28 | ||||
-rw-r--r-- | tools/isprelinked/debug.c | 37 | ||||
-rw-r--r-- | tools/isprelinked/debug.h | 88 | ||||
-rw-r--r-- | tools/isprelinked/isprelinked.c | 89 | ||||
-rw-r--r-- | tools/isprelinked/prelink_info.c | 71 | ||||
-rw-r--r-- | tools/isprelinked/prelink_info.h | 8 |
7 files changed, 361 insertions, 0 deletions
diff --git a/tools/isprelinked/Android.mk b/tools/isprelinked/Android.mk new file mode 100755 index 0000000..e085f29 --- /dev/null +++ b/tools/isprelinked/Android.mk @@ -0,0 +1,40 @@ +# Copyright 2005 The Android Open Source Project +# +# Android.mk for apriori +# + +LOCAL_PATH:= $(call my-dir) + +ifeq ($(TARGET_ARCH),arm) +include $(CLEAR_VARS) + +LOCAL_LDLIBS += -ldl +LOCAL_CFLAGS += -O2 -g +LOCAL_CFLAGS += -fno-function-sections -fno-data-sections -fno-inline +LOCAL_CFLAGS += -Wall -Wno-unused-function #-Werror +LOCAL_CFLAGS += -DSUPPORT_ANDROID_PRELINK_TAGS +LOCAL_CFLAGS += -DARM_SPECIFIC_HACKS +LOCAL_CFLAGS += -DDEBUG + +ifeq ($(HOST_OS),windows) +LOCAL_LDLIBS += -lintl +endif + +LOCAL_SRC_FILES := \ + isprelinked.c \ + debug.c \ + prelink_info.c + +LOCAL_C_INCLUDES:= \ + $(LOCAL_PATH)/ \ + external/elfutils/lib/ \ + external/elfutils/libelf/ \ + external/elfutils/libebl/ \ + external/elfcopy/ + +LOCAL_STATIC_LIBRARIES := libelfcopy libelf libebl libebl_arm #dl + +LOCAL_MODULE := isprelinked + +include $(BUILD_HOST_EXECUTABLE) +endif #TARGET_ARCH==arm diff --git a/tools/isprelinked/common.h b/tools/isprelinked/common.h new file mode 100644 index 0000000..f5d9d2e --- /dev/null +++ b/tools/isprelinked/common.h @@ -0,0 +1,28 @@ +#ifndef COMMON_H +#define COMMON_H + +#include <libelf.h> +#include <elf.h> + +#define unlikely(expr) __builtin_expect (expr, 0) +#define likely(expr) __builtin_expect (expr, 1) + +#define MIN(a,b) ((a)<(b)?(a):(b)) /* no side effects in arguments allowed! */ + +static inline int is_host_little(void) +{ + short val = 0x10; + return ((char *)&val)[0] != 0; +} + +static inline long switch_endianness(long val) +{ + long newval; + ((char *)&newval)[3] = ((char *)&val)[0]; + ((char *)&newval)[2] = ((char *)&val)[1]; + ((char *)&newval)[1] = ((char *)&val)[2]; + ((char *)&newval)[0] = ((char *)&val)[3]; + return newval; +} + +#endif/*COMMON_H*/ diff --git a/tools/isprelinked/debug.c b/tools/isprelinked/debug.c new file mode 100644 index 0000000..6066543 --- /dev/null +++ b/tools/isprelinked/debug.c @@ -0,0 +1,37 @@ +#include <debug.h> +#include <stdio.h> +#include <ctype.h> + +#define NUM_COLS (32) + +int dump_hex_buffer(FILE *s, void *b, size_t len, size_t elsize) { + int num_nonprintable = 0; + int i, last; + char *pchr = (char *)b; + fputc('\n', s); + for (i = last = 0; i < len; i++) { + if (!elsize) { + if (i && !(i % 4)) fprintf(s, " "); + if (i && !(i % 8)) fprintf(s, " "); + } else { + if (i && !(i % elsize)) fprintf(s, " "); + } + + if (i && !(i % NUM_COLS)) { + while (last < i) { + if (isprint(pchr[last])) + fputc(pchr[last], s); + else { + fputc('.', s); + num_nonprintable++; + } + last++; + } + fprintf(s, " (%d)\n", i); + } + fprintf(s, "%02x", (unsigned char)pchr[i]); + } + if (i && (i % NUM_COLS)) fputs("\n", s); + return num_nonprintable; +} + diff --git a/tools/isprelinked/debug.h b/tools/isprelinked/debug.h new file mode 100644 index 0000000..3996898 --- /dev/null +++ b/tools/isprelinked/debug.h @@ -0,0 +1,88 @@ +#ifndef DEBUG_H +#define DEBUG_H + +#include <stdlib.h> +#include <stdio.h> +#include <common.h> + +#ifdef DEBUG + + #define FAILIF(cond, msg...) do { \ + if (unlikely(cond)) { \ + fprintf(stderr, "%s(%d): ", __FILE__, __LINE__); \ + fprintf(stderr, ##msg); \ + exit(1); \ + } \ +} while(0) + +/* Debug enabled */ + #define ASSERT(x) do { \ + if (unlikely(!(x))) { \ + fprintf(stderr, \ + "ASSERTION FAILURE %s:%d: [%s]\n", \ + __FILE__, __LINE__, #x); \ + exit(1); \ + } \ +} while(0) + +#else + + #define FAILIF(cond, msg...) do { \ + if (unlikely(cond)) { \ + fprintf(stderr, ##msg); \ + exit(1); \ + } \ +} while(0) + +/* No debug */ + #define ASSERT(x) do { } while(0) + +#endif/* DEBUG */ + +#define FAILIF_LIBELF(cond, function) \ + FAILIF(cond, "%s(): %s\n", #function, elf_errmsg(elf_errno())); + +static inline void *MALLOC(unsigned int size) { + void *m = malloc(size); + FAILIF(NULL == m, "malloc(%d) failed!\n", size); + return m; +} + +static inline void *CALLOC(unsigned int num_entries, unsigned int entry_size) { + void *m = calloc(num_entries, entry_size); + FAILIF(NULL == m, "calloc(%d, %d) failed!\n", num_entries, entry_size); + return m; +} + +static inline void *REALLOC(void *ptr, unsigned int size) { + void *m = realloc(ptr, size); + FAILIF(NULL == m, "realloc(%p, %d) failed!\n", ptr, size); + return m; +} + +static inline void FREE(void *ptr) { + free(ptr); +} + +static inline void FREEIF(void *ptr) { + if (ptr) FREE(ptr); +} + +#define PRINT(x...) do { \ + extern int quiet_flag; \ + if(likely(!quiet_flag)) \ + fprintf(stdout, ##x); \ +} while(0) + +#define ERROR PRINT + +#define INFO(x...) do { \ + extern int verbose_flag; \ + if(unlikely(verbose_flag)) \ + fprintf(stdout, ##x); \ +} while(0) + +/* Prints a hex and ASCII dump of the selected buffer to the selected stream. */ +int dump_hex_buffer(FILE *s, void *b, size_t l, size_t elsize); + +#endif/*DEBUG_H*/ diff --git a/tools/isprelinked/isprelinked.c b/tools/isprelinked/isprelinked.c new file mode 100644 index 0000000..c677e39 --- /dev/null +++ b/tools/isprelinked/isprelinked.c @@ -0,0 +1,89 @@ +/* TODO: + 1. check the ARM EABI version--this works for versions 1 and 2. + 2. use a more-intelligent approach to finding the symbol table, symbol-string + table, and the .dynamic section. + 3. fix the determination of the host and ELF-file endianness + 4. write the help screen +*/ + +#include <stdio.h> +#include <common.h> +#include <debug.h> +#include <libelf.h> +#include <libebl.h> +#ifdef ARM_SPECIFIC_HACKS + #include <libebl_arm.h> +#endif/*ARM_SPECIFIC_HACKS*/ +#include <elf.h> +#include <gelf.h> +#include <string.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <rangesort.h> +#include <prelink_info.h> +#include <libgen.h> + + +/* Flag set by --verbose. This variable is global as it is accessed by the + macro INFO() in multiple compilation unites. */ +int verbose_flag = 0; +/* Flag set by --quiet. This variable is global as it is accessed by the + macro PRINT() in multiple compilation unites. */ +int quiet_flag = 0; + +int main(int argc, char **argv) { + + argc--, argv++; + if (!argc) + return 0; + + /* Check to see whether the ELF library is current. */ + FAILIF (elf_version(EV_CURRENT) == EV_NONE, "libelf is out of date!\n"); + + const char *filename; + for (; argc; argc--) { + filename = *argv++; + + Elf *elf; + GElf_Ehdr elf_hdr; + int fd; + int prelinked; + long prelink_addr = 0; + + INFO("Processing file [%s]\n", filename); + + fd = open(filename, O_RDONLY); + FAILIF(fd < 0, "open(%d): %s (%d).\n", + filename, + strerror(errno), + errno); + + elf = elf_begin(fd, ELF_C_READ_MMAP_PRIVATE, NULL); + FAILIF_LIBELF(elf == NULL, elf_begin); + + FAILIF_LIBELF(0 == gelf_getehdr(elf, &elf_hdr), + gelf_getehdr); + +#ifdef SUPPORT_ANDROID_PRELINK_TAGS + prelinked = check_prelinked(filename, elf_hdr.e_ident[EI_DATA] == ELFDATA2LSB, + &prelink_addr); +#else + #error 'SUPPORT_ANDROID_PRELINK_TAGS is not defined!' +#endif + + if (prelinked) + PRINT("%s: 0x%08x\n", filename, prelink_addr); + else + PRINT("%s: not prelinked\n", filename); + + FAILIF_LIBELF(elf_end(elf), elf_end); + close(fd); + } + + return 0; +} + diff --git a/tools/isprelinked/prelink_info.c b/tools/isprelinked/prelink_info.c new file mode 100644 index 0000000..21b1519 --- /dev/null +++ b/tools/isprelinked/prelink_info.c @@ -0,0 +1,71 @@ +#ifdef SUPPORT_ANDROID_PRELINK_TAGS + +#include <sys/types.h> +#include <fcntl.h> +#include <sys/types.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include <prelink_info.h> +#include <debug.h> +#include <common.h> + +typedef struct { + long mmap_addr; + char tag[4]; /* 'P', 'R', 'E', ' ' */ +} prelink_info_t __attribute__((packed)); + +static inline void set_prelink(long *prelink_addr, + int elf_little, + prelink_info_t *info) +{ + FAILIF(sizeof(prelink_info_t) != 8, "Unexpected sizeof(prelink_info_t) == %d!\n", sizeof(prelink_info_t)); + if (prelink_addr) { + if (!(elf_little ^ is_host_little())) { + /* Same endianness */ + *prelink_addr = info->mmap_addr; + } + else { + /* Different endianness */ + *prelink_addr = switch_endianness(info->mmap_addr); + } + } +} + +int check_prelinked(const char *fname, int elf_little, long *prelink_addr) +{ + FAILIF(sizeof(prelink_info_t) != 8, "Unexpected sizeof(prelink_info_t) == %d!\n", sizeof(prelink_info_t)); + int fd = open(fname, O_RDONLY); + FAILIF(fd < 0, "open(%s, O_RDONLY): %s (%d)!\n", + fname, strerror(errno), errno); + off_t end = lseek(fd, 0, SEEK_END); + + int nr = sizeof(prelink_info_t); + + off_t sz = lseek(fd, -nr, SEEK_CUR); + ASSERT((long)(end - sz) == (long)nr); + FAILIF(sz == (off_t)-1, + "lseek(%d, 0, SEEK_END): %s (%d)!\n", + fd, strerror(errno), errno); + + prelink_info_t info; + int num_read = read(fd, &info, nr); + FAILIF(num_read < 0, + "read(%d, &info, sizeof(prelink_info_t)): %s (%d)!\n", + fd, strerror(errno), errno); + FAILIF(num_read != sizeof(info), + "read(%d, &info, sizeof(prelink_info_t)): did not read %d bytes as " + "expected (read %d)!\n", + fd, sizeof(info), num_read); + + int prelinked = 0; + if (!strncmp(info.tag, "PRE ", 4)) { + set_prelink(prelink_addr, elf_little, &info); + prelinked = 1; + } + FAILIF(close(fd) < 0, "close(%d): %s (%d)!\n", fd, strerror(errno), errno); + return prelinked; +} + +#endif /*SUPPORT_ANDROID_PRELINK_TAGS*/ diff --git a/tools/isprelinked/prelink_info.h b/tools/isprelinked/prelink_info.h new file mode 100644 index 0000000..afc03e9 --- /dev/null +++ b/tools/isprelinked/prelink_info.h @@ -0,0 +1,8 @@ +#ifndef PRELINK_INFO_H +#define PRELINK_INFO_H +#ifdef SUPPORT_ANDROID_PRELINK_TAGS + +int check_prelinked(const char *fname, int elf_little, long *prelink_addr); + +#endif +#endif/*PRELINK_INFO_H*/ |