summaryrefslogtreecommitdiffstats
path: root/tools/isprelinked
diff options
context:
space:
mode:
Diffstat (limited to 'tools/isprelinked')
-rwxr-xr-xtools/isprelinked/Android.mk40
-rw-r--r--tools/isprelinked/common.h28
-rw-r--r--tools/isprelinked/debug.c37
-rw-r--r--tools/isprelinked/debug.h88
-rw-r--r--tools/isprelinked/isprelinked.c89
-rw-r--r--tools/isprelinked/prelink_info.c71
-rw-r--r--tools/isprelinked/prelink_info.h8
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*/