blob: 2600ac73b30a5d995a1fb2b599a7dd8e6bb606fa [file] [log] [blame]
#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>
#define RETOUCH_SUFFIX_SIZE 12
typedef struct {
uint32_t mmap_addr;
char tag[4]; /* 'P', 'R', 'E', ' ' */
} __attribute__((packed)) prelink_info_t;
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) == %zd!\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) == %zd!\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);
#ifndef DEBUG
(void)end;
#endif
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;
ssize_t 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((size_t)num_read != sizeof(info),
"read(%d, &info, sizeof(prelink_info_t)): did not read %zd bytes as "
"expected (read %zd)!\n",
fd, sizeof(info), (size_t)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;
}
int check_retouched(const char *fname, int elf_little,
unsigned int *retouch_byte_cnt, char *retouch_buf) {
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-RETOUCH_SUFFIX_SIZE, SEEK_CUR);
ASSERT((long)(end - sz) == (long)(nr+RETOUCH_SUFFIX_SIZE));
FAILIF(sz == (off_t)-1,
"lseek(%d, 0, SEEK_END): %s (%d)!\n",
fd, strerror(errno), errno);
char retouch_meta[RETOUCH_SUFFIX_SIZE];
int num_read = read(fd, &retouch_meta, RETOUCH_SUFFIX_SIZE);
FAILIF(num_read < 0,
"read(%d, &info, sizeof(prelink_info_t)): %s (%d)!\n",
fd, strerror(errno), errno);
FAILIF(num_read != RETOUCH_SUFFIX_SIZE,
"read(%d, &info, sizeof(prelink_info_t)): did not read %d bytes as "
"expected (read %d)!\n",
fd, RETOUCH_SUFFIX_SIZE, num_read);
int retouched = 0;
if (!strncmp(retouch_meta, "RETOUCH ", 8)) {
unsigned int retouch_byte_cnt_meta;
if (!(elf_little ^ is_host_little()))
retouch_byte_cnt_meta = *(unsigned int *)(retouch_meta+8);
else
retouch_byte_cnt_meta =
switch_endianness(*(unsigned int *)(retouch_meta+8));
FAILIF(*retouch_byte_cnt < retouch_byte_cnt_meta,
"Retouch buffer too small at %d bytes (%d needed).",
*retouch_byte_cnt, retouch_byte_cnt_meta);
*retouch_byte_cnt = retouch_byte_cnt_meta;
off_t sz = lseek(fd,
-((long)*retouch_byte_cnt)-RETOUCH_SUFFIX_SIZE-nr,
SEEK_END);
ASSERT((long)(end - sz) ==
(long)(*retouch_byte_cnt+RETOUCH_SUFFIX_SIZE+nr));
FAILIF(sz == (off_t)-1,
"lseek(%d, 0, SEEK_END): %s (%d)!\n",
fd, strerror(errno), errno);
num_read = read(fd, retouch_buf, *retouch_byte_cnt);
FAILIF(num_read < 0,
"read(%d, &info, sizeof(prelink_info_t)): %s (%d)!\n",
fd, strerror(errno), errno);
FAILIF(num_read != *retouch_byte_cnt,
"read(%d, retouch_buf, %u): did not read %d bytes as "
"expected (read %d)!\n",
fd, *retouch_byte_cnt, *retouch_byte_cnt, num_read);
retouched = 1;
}
FAILIF(close(fd) < 0, "close(%d): %s (%d)!\n", fd, strerror(errno), errno);
return retouched;
}
void retouch_dump(const char *fname, int elf_little,
unsigned int retouch_byte_cnt, char *retouch_buf) {
int fd = open(fname, O_WRONLY);
FAILIF(fd < 0,
"open(%s, O_WRONLY): %s (%d)\n",
fname, strerror(errno), errno);
off_t sz = lseek(fd, 0, SEEK_END);
FAILIF(sz == (off_t)-1,
"lseek(%d, 0, SEEK_END): %s (%d)!\n",
fd, strerror(errno), errno);
// The retouch blob ends with "RETOUCH XXXX", where XXXX is the 4-byte
// size of the retouch blob, in target endianness.
strncpy(retouch_buf+retouch_byte_cnt, "RETOUCH ", 8);
if (elf_little ^ is_host_little()) {
*(unsigned int *)(retouch_buf+retouch_byte_cnt+8) =
switch_endianness(retouch_byte_cnt);
} else {
*(unsigned int *)(retouch_buf+retouch_byte_cnt+8) =
retouch_byte_cnt;
}
int num_written = write(fd, retouch_buf, retouch_byte_cnt+12);
FAILIF(num_written < 0,
"write(%d, &info, sizeof(info)): %s (%d)\n",
fd, strerror(errno), errno);
FAILIF((retouch_byte_cnt+12) != num_written,
"Could not write %d bytes as expected (wrote %d bytes instead)!\n",
retouch_byte_cnt, num_written);
FAILIF(close(fd) < 0, "close(%d): %s (%d)!\n", fd, strerror(errno), errno);
}
void setup_prelink_info(const char *fname, int elf_little, long base)
{
FAILIF(sizeof(prelink_info_t) != 8, "Unexpected sizeof(prelink_info_t) == %zd!\n", sizeof(prelink_info_t));
int fd = open(fname, O_WRONLY);
FAILIF(fd < 0,
"open(%s, O_WRONLY): %s (%d)\n" ,
fname, strerror(errno), errno);
prelink_info_t info;
off_t sz = lseek(fd, 0, SEEK_END);
FAILIF(sz == (off_t)-1,
"lseek(%d, 0, SEEK_END): %s (%d)!\n",
fd, strerror(errno), errno);
if (!(elf_little ^ is_host_little())) {
/* Same endianness */
INFO("Host and ELF file [%s] have same endianness.\n", fname);
info.mmap_addr = base;
}
else {
/* Different endianness */
INFO("Host and ELF file [%s] have different endianness.\n", fname);
info.mmap_addr = switch_endianness(base);
}
strncpy(info.tag, "PRE ", 4);
ssize_t num_written = write(fd, &info, sizeof(info));
FAILIF(num_written < 0,
"write(%d, &info, sizeof(info)): %s (%d)\n",
fd, strerror(errno), errno);
FAILIF(sizeof(info) != (size_t)num_written,
"Could not write %zd bytes (wrote only %zd bytes) as expected!\n",
sizeof(info), (size_t)num_written);
FAILIF(close(fd) < 0, "close(%d): %s (%d)!\n", fd, strerror(errno), errno);
}
#endif /*SUPPORT_ANDROID_PRELINK_TAGS*/