Browse Source

Make ldd and readelf work even with byte swapped binaries

Eric Andersen 22 years ago
parent
commit
776eae6153
2 changed files with 105 additions and 33 deletions
  1. 55 18
      ldso/util/ldd.c
  2. 50 15
      ldso/util/readelf.c

+ 55 - 18
ldso/util/ldd.c

@@ -2,9 +2,8 @@
 /*
  * A small little ldd implementation for uClibc
  *
- * Copyright (C) 2000 by Lineo, inc.
- * Copyright (C) 2000,2001 Erik Andersen <andersee@debian.org>
- * Written by Erik Andersen <andersee@debian.org>
+ * Copyright (C) 2000 by Lineo, inc and Erik Andersen
+ * Copyright (C) 2000-2002 Erik Andersen <andersee@debian.org>
  *
  * Several functions in this file (specifically, elf_find_section_type(),
  * elf_find_phdr_type(), and elf_find_dynamic(), were stolen from elflib.c from
@@ -39,6 +38,8 @@
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <endian.h>
+#include <byteswap.h>
 #include "elf.h"
 #ifdef DMALLOC
 #include <dmalloc.h>
@@ -52,15 +53,26 @@ struct library {
 };
 struct library *lib_list = NULL;
 char not_found[] = "not found";
+int byteswap;
+
+inline uint32_t byteswap32_to_host(uint32_t value)
+{
+	if (byteswap==1) {
+		return(bswap_32(value));
+	} else {
+		return(value);
+	}
+}
 
 
 
 Elf32_Shdr * elf_find_section_type( int key, Elf32_Ehdr *ehdr)
 {
 	int j;
-	Elf32_Shdr *shdr = (Elf32_Shdr *)(ehdr->e_shoff + (char *)ehdr);
+	Elf32_Shdr *shdr;
+	shdr = (Elf32_Shdr *)(ehdr->e_shoff + (char *)ehdr);
 	for (j = ehdr->e_shnum; --j>=0; ++shdr) {
-		if (shdr->sh_type == key) {
+		if (key==byteswap32_to_host(shdr->sh_type)) {
 			return shdr;
 		}
 	}
@@ -72,7 +84,7 @@ Elf32_Phdr * elf_find_phdr_type( int type, Elf32_Ehdr *ehdr)
 	int j;
 	Elf32_Phdr *phdr = (Elf32_Phdr *)(ehdr->e_phoff + (char *)ehdr);
 	for (j = ehdr->e_phnum; --j>=0; ++phdr) {
-		if (type==phdr->p_type) {
+		if (type==byteswap32_to_host(phdr->p_type)) {
 			return phdr;
 		}
 	}
@@ -84,19 +96,19 @@ void * elf_find_dynamic(int const key, Elf32_Dyn *dynp,
 	Elf32_Ehdr *ehdr, int return_val)
 {
 	Elf32_Phdr *pt_text = elf_find_phdr_type(PT_LOAD, ehdr);
-	unsigned tx_reloc = pt_text->p_vaddr - pt_text->p_offset;
-	for (; DT_NULL!=dynp->d_tag; ++dynp) {
-		if (dynp->d_tag == key) {
+	unsigned tx_reloc = byteswap32_to_host(pt_text->p_vaddr) - byteswap32_to_host(pt_text->p_offset);
+	for (; DT_NULL!=byteswap32_to_host(dynp->d_tag); ++dynp) {
+		if (key == byteswap32_to_host(dynp->d_tag)) {
 			if (return_val == 1)
-				return (void *)dynp->d_un.d_val;
+				return (void *)byteswap32_to_host(dynp->d_un.d_val);
 			else
-				return (void *)(dynp->d_un.d_val - tx_reloc + (char *)ehdr );
+				return (void *)(byteswap32_to_host(dynp->d_un.d_val) - tx_reloc + (char *)ehdr );
 		}
 	}
 	return NULL;
 }
 
-int check_elf_header(Elf32_Ehdr const *const ehdr)
+int check_elf_header(Elf32_Ehdr *const ehdr)
 {
 	if (! ehdr || strncmp((void *)ehdr, ELFMAG, SELFMAG) != 0 ||  
 			ehdr->e_ident[EI_CLASS] != ELFCLASS32 ||
@@ -104,6 +116,30 @@ int check_elf_header(Elf32_Ehdr const *const ehdr)
 	{
 		return 1;
 	}
+
+	/* Check if the target endianness matches the host's endianness */
+	byteswap = 0;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+	if (ehdr->e_ident[5] == ELFDATA2MSB) {
+		/* Ick -- we will have to byte-swap everything */
+		byteswap = 1;
+	}
+#elif __BYTE_ORDER == __BIG_ENDIAN
+	if (ehdr->e_ident[5] == ELFDATA2LSB) {
+		byteswap = 1;
+	}
+#else
+#error Unknown host byte order!
+#endif
+	/* Be vary lazy, and only byteswap the stuff we use */
+	if (byteswap==1) {
+		ehdr->e_type=bswap_16(ehdr->e_type);
+		ehdr->e_phoff=bswap_32(ehdr->e_phoff);
+		ehdr->e_shoff=bswap_32(ehdr->e_shoff);
+		ehdr->e_phnum=bswap_16(ehdr->e_phnum);
+		ehdr->e_shnum=bswap_16(ehdr->e_shnum);
+	}
+
 	return 0;
 }
 
@@ -295,13 +331,14 @@ static void find_needed_libraries(Elf32_Ehdr* ehdr, Elf32_Dyn* dynamic, char *st
 	/* Find the path where the shared lib loader lives */
 	phdr = elf_find_phdr_type(PT_INTERP, ehdr);
 	if (phdr) {
-		ldpath = strdup((char*)ehdr + phdr->p_offset);
+		ldpath = strdup((char*)ehdr + byteswap32_to_host(phdr->p_offset));
 		ldpath = basename(ldpath);
 	}
 
-	for (dyns=dynamic; dyns->d_tag!=DT_NULL; ++dyns) {
-		if (dyns->d_tag == DT_NEEDED) {
-			add_library(ehdr, dynamic, strtab, is_setuid, (char*)strtab + dyns->d_un.d_val, ldpath);
+	for (dyns=dynamic; byteswap32_to_host(dyns->d_tag)!=DT_NULL; ++dyns) {
+		if (DT_NEEDED == byteswap32_to_host(dyns->d_tag)) {
+			add_library(ehdr, dynamic, strtab, is_setuid, (char*)strtab + 
+					byteswap32_to_host(dyns->d_un.d_val), ldpath);
 		}
 	}
 }
@@ -317,7 +354,7 @@ static void find_elf_interpreter(Elf32_Ehdr* ehdr, Elf32_Dyn* dynamic, char *str
 	phdr = elf_find_phdr_type(PT_INTERP, ehdr);
 	if (phdr) {
 		struct library *cur, *newlib=NULL;
-		char *s = (char*)ehdr + phdr->p_offset;
+		char *s = (char*)ehdr + byteswap32_to_host(phdr->p_offset);
 	
 		char *tmp, *tmp1;
 		tmp1 = tmp = s;
@@ -413,7 +450,7 @@ foo:
 
 	dynsec = elf_find_section_type(SHT_DYNAMIC, ehdr);
 	if (dynsec) {
-		dynamic = (Elf32_Dyn*)(dynsec->sh_offset + (int)ehdr);
+		dynamic = (Elf32_Dyn*)(byteswap32_to_host(dynsec->sh_offset) + (int)ehdr);
 		dynstr = (char *)elf_find_dynamic(DT_STRTAB, dynamic, ehdr, 0);
 		find_needed_libraries(ehdr, dynamic, dynstr, is_suid);
 	}

+ 50 - 15
ldso/util/readelf.c

@@ -2,9 +2,8 @@
 /*
  * A small little readelf implementation for uClibc
  *
- * Copyright (C) 2000 by Lineo, inc.
- * Copyright (C) 2000,2001 Erik Andersen <andersee@debian.org>
- * Written by Erik Andersen <andersee@debian.org>
+ * Copyright (C) 2000 by Lineo, inc and Erik Andersen
+ * Copyright (C) 2000-2002 Erik Andersen <andersee@debian.org>
  *
  * Several functions in this file (specifically, elf_find_section_type(),
  * elf_find_phdr_type(), and elf_find_dynamic(), were stolen from elflib.c from
@@ -37,16 +36,27 @@
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <endian.h>
+#include <byteswap.h>
 #include "elf.h"
 
 
+int byteswap;
+inline uint32_t byteswap32_to_host(uint32_t value)
+{
+	if (byteswap==1) {
+		return(bswap_32(value));
+	} else {
+		return(value);
+	}
+}
 
 Elf32_Shdr * elf_find_section_type( int key, Elf32_Ehdr *ehdr)
 {
 	int j;
 	Elf32_Shdr *shdr = (Elf32_Shdr *)(ehdr->e_shoff + (char *)ehdr);
 	for (j = ehdr->e_shnum; --j>=0; ++shdr) {
-		if (shdr->sh_type == key) {
+		if (key==byteswap32_to_host(shdr->sh_type)) {
 			return shdr;
 		}
 	}
@@ -58,7 +68,7 @@ Elf32_Phdr * elf_find_phdr_type( int type, Elf32_Ehdr *ehdr)
 	int j;
 	Elf32_Phdr *phdr = (Elf32_Phdr *)(ehdr->e_phoff + (char *)ehdr);
 	for (j = ehdr->e_phnum; --j>=0; ++phdr) {
-		if (type==phdr->p_type) {
+		if (type==byteswap32_to_host(phdr->p_type)) {
 			return phdr;
 		}
 	}
@@ -70,19 +80,19 @@ void * elf_find_dynamic(int const key, Elf32_Dyn *dynp,
 	Elf32_Ehdr *ehdr, int return_val)
 {
 	Elf32_Phdr *pt_text = elf_find_phdr_type(PT_LOAD, ehdr);
-	unsigned tx_reloc = pt_text->p_vaddr - pt_text->p_offset;
-	for (; DT_NULL!=dynp->d_tag; ++dynp) {
-		if (dynp->d_tag == key) {
+	unsigned tx_reloc = byteswap32_to_host(pt_text->p_vaddr) - byteswap32_to_host(pt_text->p_offset);
+	for (; DT_NULL!=byteswap32_to_host(dynp->d_tag); ++dynp) {
+		if (key == byteswap32_to_host(dynp->d_tag)) {
 			if (return_val == 1)
-				return (void *)dynp->d_un.d_val;
+				return (void *)byteswap32_to_host(dynp->d_un.d_val);
 			else
-				return (void *)(dynp->d_un.d_val - tx_reloc + (char *)ehdr );
+				return (void *)(byteswap32_to_host(dynp->d_un.d_val) - tx_reloc + (char *)ehdr );
 		}
 	}
 	return NULL;
 }
 
-int check_elf_header(Elf32_Ehdr const *const ehdr)
+int check_elf_header(Elf32_Ehdr *const ehdr)
 {
 	if (! ehdr || strncmp((void *)ehdr, ELFMAG, SELFMAG) != 0 ||  
 			ehdr->e_ident[EI_CLASS] != ELFCLASS32 ||
@@ -90,9 +100,34 @@ int check_elf_header(Elf32_Ehdr const *const ehdr)
 	{
 		return 1;
 	}
+
+	/* Check if the target endianness matches the host's endianness */
+	byteswap = 0;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+	if (ehdr->e_ident[5] == ELFDATA2MSB) {
+		/* Ick -- we will have to byte-swap everything */
+		byteswap = 1;
+	}
+#elif __BYTE_ORDER == __BIG_ENDIAN
+	if (ehdr->e_ident[5] == ELFDATA2LSB) {
+		byteswap = 1;
+	}
+#else
+#error Unknown host byte order!
+#endif
+	/* Be vary lazy, and only byteswap the stuff we use */
+	if (byteswap==1) {
+		ehdr->e_type=bswap_16(ehdr->e_type);
+		ehdr->e_machine=bswap_16(ehdr->e_machine);
+		ehdr->e_phoff=bswap_32(ehdr->e_phoff);
+		ehdr->e_shoff=bswap_32(ehdr->e_shoff);
+		ehdr->e_phnum=bswap_16(ehdr->e_phnum);
+		ehdr->e_shnum=bswap_16(ehdr->e_shnum);
+	}
 	return 0;
 }
 
+
 #define ELFOSABI_NONE   0       /* UNIX System V ABI */
 #define ELFOSABI_HPUX   1       /* HP-UX operating system */
 #define ELFOSABI_NETBSD 2       /* NetBSD */
@@ -245,9 +280,9 @@ static void list_needed_libraries(Elf32_Dyn* dynamic, char *strtab)
 	Elf32_Dyn  *dyns;
 
 	printf("Dependancies:\n");
-	for (dyns=dynamic; dyns->d_tag!=DT_NULL; ++dyns) {
+	for (dyns=dynamic; byteswap32_to_host(dyns->d_tag)!=DT_NULL; ++dyns) {
 		if (dyns->d_tag == DT_NEEDED) {
-			printf("\t%s\n", (char*)strtab + dyns->d_un.d_val);
+			printf("\t%s\n", (char*)strtab + byteswap32_to_host(dyns->d_un.d_val));
 		}
 	}
 }
@@ -257,7 +292,7 @@ static void describe_elf_interpreter(Elf32_Ehdr* ehdr)
 	Elf32_Phdr *phdr;
 	phdr = elf_find_phdr_type(PT_INTERP, ehdr);
 	if (phdr) {
-		printf("Interpreter:\t%s\n", (char*)ehdr + phdr->p_offset);
+		printf("Interpreter:\t%s\n", (char*)ehdr + byteswap32_to_host(phdr->p_offset));
 	}
 }
 
@@ -304,7 +339,7 @@ foo:
 
 	dynsec = elf_find_section_type(SHT_DYNAMIC, ehdr);
 	if (dynsec) {
-		dynamic = (Elf32_Dyn*)(dynsec->sh_offset + (int)ehdr);
+		dynamic = (Elf32_Dyn*)(byteswap32_to_host(dynsec->sh_offset) + (int)ehdr);
 		dynstr = (char *)elf_find_dynamic(DT_STRTAB, dynamic, ehdr, 0);
 		list_needed_libraries(dynamic, dynstr);
 	}