#include <sys/sysmacros.h>
#include <sys/types.h>
#include <sys/exechdr.h>
#include <sys/elf.h>
#include <sys/elf_notes.h>
#include <sys/bootconf.h>
#include <sys/reboot.h>
#include <sys/fcntl.h>
#include <sys/stat.h>
#include <sys/modctl.h>
#include <sys/link.h>
#include <sys/auxv.h>
#include <sys/salib.h>
#include <sys/bootvfs.h>
#include <sys/platnames.h>
#include "util.h"
union {
struct exec X;
Elf32_Ehdr Elfhdr;
Elf64_Ehdr Elfhdr64;
} ex;
#define x ex.X
#define elfhdr ex.Elfhdr
#define elfhdr64 ex.Elfhdr64
typedef int (*func_t)();
#define FAIL ((func_t)-1)
#define ALIGN(x, a) \
((a) == 0 ? (uintptr_t)(x) : (((uintptr_t)(x) + (a) - 1) & ~((a) - 1)))
#define __BOOT_NAUXV_IMPL 22
int use_align = 0;
int npagesize = 0;
uint_t icache_flush = 0;
char *cpulist = NULL;
char *mmulist = NULL;
extern char *module_path;
#ifdef _ELF64_SUPPORT
Elf32_Boot *elfbootvecELF32_64;
Elf64_Boot *elfbootvecELF64;
#define OK ((func_t)0)
#define FAIL_READELF64 ((uint64_t)0)
#define FAIL_ILOAD64 ((Elf64_Addr)-1)
#endif
Elf32_Boot *elfbootvec;
#ifdef DEBUG
static int debug = 1;
#else
static int debug = 0;
#endif
#define dprintf if (debug) printf
#ifdef _ELF64_SUPPORT
typedef struct {
uint_t a_type;
union {
uint64_t a_val;
uint64_t a_ptr;
void (*a_fcn)();
} a_un;
} auxv64_t;
#if defined(__sparcv9)
extern int client_isLP64;
#endif
static uint64_t read_elf64(int, int, Elf64_Ehdr *);
static Elf64_Addr iload64(char *, Elf64_Phdr *, Elf64_Phdr *, auxv64_t **);
#endif
static func_t read_elf32(int, int, Elf32_Ehdr *);
static func_t iload32(char *, Elf32_Phdr *, Elf32_Phdr *, auxv32_t **);
static caddr_t segbrk(caddr_t *, size_t, size_t);
static int openpath(char *, char *, int);
static char *getmodpath(char *);
extern void setup_aux(void);
extern void *kmem_alloc(size_t, int);
extern void kmem_free(void *, size_t);
extern int cons_gets(char *, int);
extern void sync_instruction_memory(caddr_t v, size_t len);
extern int verbosemode;
extern int boothowto;
extern int pagesize;
extern char filename[];
ssize_t
xread(int fd, char *p, size_t nbytes)
{
size_t bytesread = 0;
int errorcount = 0;
ssize_t i;
while (bytesread < nbytes) {
i = read(fd, p, nbytes - bytesread);
if (i < 0) {
++errorcount;
if (verbosemode)
printf("read error (0x%x times)\n", errorcount);
continue;
}
bytesread += i;
p += i;
}
return (bytesread);
}
func_t
readfile(int fd, int print)
{
#ifdef _ELF64_SUPPORT
uint64_t elf64_go2;
#endif
ssize_t i;
int shared = 0;
if (verbosemode) {
dprintf("fd = %x\n", fd);
}
i = xread(fd, (char *)&elfhdr, sizeof (Elf64_Ehdr));
if (x.a_magic == ZMAGIC || x.a_magic == NMAGIC)
shared = 1;
if (i != sizeof (Elf64_Ehdr)) {
printf("Error reading ELF header.\n");
return (FAIL);
}
if (!shared && x.a_magic != OMAGIC) {
if (*(int *)&elfhdr.e_ident == *(int *)(ELFMAG)) {
if (verbosemode) {
int is64 = (elfhdr.e_ident[EI_CLASS] ==
ELFCLASS64);
dprintf("calling readelf, elfheader is:\n");
dprintf("e_ident\t0x%x, 0x%x, 0x%x, 0x%x\n",
*(int *)&elfhdr.e_ident[0],
*(int *)&elfhdr.e_ident[4],
*(int *)&elfhdr.e_ident[8],
*(int *)&elfhdr.e_ident[12]);
dprintf("e_machine\t0x%x\n", elfhdr.e_machine);
dprintf("e_entry\t\t0x%llx\n", (is64 ?
elfhdr64.e_entry :
(u_longlong_t)elfhdr.e_entry));
dprintf("e_shoff\t\t0x%llx\n", (is64 ?
elfhdr64.e_shoff :
(u_longlong_t)elfhdr.e_shoff));
dprintf("e_shnentsize\t%d\n", (is64 ?
elfhdr64.e_shentsize : elfhdr.e_shentsize));
dprintf("e_shnum\t\t%d\n", (is64 ?
elfhdr64.e_shnum : elfhdr.e_shnum));
dprintf("e_shstrndx\t%d\n", (is64 ?
elfhdr64.e_shstrndx : elfhdr.e_shstrndx));
}
#ifdef _ELF64_SUPPORT
dprintf("ELF file CLASS 0x%x 32 is %x 64 is %x\n",
elfhdr.e_ident[EI_CLASS], ELFCLASS32, ELFCLASS64);
if (elfhdr.e_ident[EI_CLASS] == ELFCLASS64) {
elf64_go2 = read_elf64(fd, print,
(Elf64_Ehdr *)&elfhdr);
return ((elf64_go2 == FAIL_READELF64) ? FAIL :
(func_t)elf64_go2);
} else
#endif
return (read_elf32(fd, print, &elfhdr));
} else {
printf("File not executable.\n");
return (FAIL);
}
}
return (FAIL);
}
#define AUX(p, a, v) { (p)->a_type = (a); \
((p)++)->a_un.a_val = (int32_t)(uintptr_t)(v); }
#define EBV(p, a, v) { (p)->eb_tag = (a); \
((p)++)->eb_un.eb_val = (Elf32_Word)(uintptr_t)(v); }
static func_t
read_elf32(int fd, int print, Elf32_Ehdr *elfhdrp)
{
Elf32_Phdr *phdr;
Elf32_Nhdr *nhdr;
int nphdrs, phdrsize;
caddr_t allphdrs;
caddr_t namep, descp;
Elf32_Addr loadaddr, base;
size_t offset = 0;
size_t size;
uintptr_t off;
int i;
int bss_seen = 0;
int interp = 0;
static char dlname[MAXPATHLEN];
uint_t dynamic;
Elf32_Phdr *thdr;
Elf32_Phdr *dhdr;
func_t entrypt;
allphdrs = NULL;
nhdr = NULL;
#ifdef _ELF64_SUPPORT
if (verbosemode)
printf("Elf32 client\n");
#endif
if (elfhdrp->e_phnum == 0 || elfhdrp->e_phoff == 0)
goto elferror;
entrypt = (func_t)(uintptr_t)elfhdrp->e_entry;
if (verbosemode)
dprintf("Entry point: %p\n", (void *)entrypt);
nphdrs = elfhdrp->e_phnum;
phdrsize = nphdrs * elfhdrp->e_phentsize;
allphdrs = (caddr_t)kmem_alloc(phdrsize, 0);
if (allphdrs == NULL)
goto elferror;
if (verbosemode)
dprintf("lseek: args = %x %x %x\n", fd, elfhdrp->e_phoff, 0);
if (lseek(fd, elfhdrp->e_phoff, 0) == -1)
goto elferror;
if (xread(fd, allphdrs, phdrsize) != phdrsize)
goto elferror;
npagesize = 0;
for (i = 0; i < nphdrs; i++) {
void *note_buf;
phdr = (Elf32_Phdr *)(allphdrs + elfhdrp->e_phentsize * i);
if (phdr->p_type != PT_NOTE)
continue;
if (verbosemode) {
dprintf("allocating 0x%x bytes for note hdr\n",
phdr->p_filesz);
}
if ((note_buf = kmem_alloc(phdr->p_filesz, 0)) == NULL)
goto elferror;
if (verbosemode)
dprintf("seeking to 0x%x\n", phdr->p_offset);
if (lseek(fd, phdr->p_offset, 0) == -1)
goto elferror;
if (verbosemode) {
dprintf("reading 0x%x bytes into %p\n",
phdr->p_filesz, (void *)nhdr);
}
nhdr = (Elf32_Nhdr *)note_buf;
if (xread(fd, (caddr_t)nhdr, phdr->p_filesz) != phdr->p_filesz)
goto elferror;
if (verbosemode) {
dprintf("p_note namesz %x descsz %x type %x\n",
nhdr->n_namesz, nhdr->n_descsz, nhdr->n_type);
}
do {
namep = (caddr_t)(nhdr + 1);
if (nhdr->n_namesz == strlen(ELF_NOTE_SOLARIS) + 1 &&
strcmp(namep, ELF_NOTE_SOLARIS) == 0 &&
nhdr->n_type == ELF_NOTE_PAGESIZE_HINT) {
descp = namep + roundup(nhdr->n_namesz, 4);
npagesize = *(int *)descp;
if (verbosemode)
dprintf("pagesize is %x\n", npagesize);
}
offset += sizeof (Elf32_Nhdr) + roundup(nhdr->n_namesz,
4) + roundup(nhdr->n_descsz, 4);
nhdr = (Elf32_Nhdr *)((char *)note_buf + offset);
} while (offset < phdr->p_filesz);
kmem_free(note_buf, phdr->p_filesz);
nhdr = NULL;
}
if (print)
printf("Size: ");
for (i = 0; i < nphdrs; i++) {
phdr = (Elf32_Phdr *)(allphdrs + elfhdrp->e_phentsize * i);
if (verbosemode) {
dprintf("Doing header 0x%x\n", i);
dprintf("phdr\n");
dprintf("\tp_offset = %x, p_vaddr = %x\n",
phdr->p_offset, phdr->p_vaddr);
dprintf("\tp_memsz = %x, p_filesz = %x\n",
phdr->p_memsz, phdr->p_filesz);
}
if (phdr->p_type == PT_LOAD) {
if (verbosemode)
dprintf("seeking to 0x%x\n", phdr->p_offset);
if (lseek(fd, phdr->p_offset, 0) == -1)
goto elferror;
if (phdr->p_flags == (PF_R | PF_W) &&
phdr->p_vaddr == 0) {
if ((loadaddr = (uintptr_t)
kmem_alloc(phdr->p_memsz, 0)) == 0)
goto elferror;
phdr->p_vaddr = (Elf32_Addr)loadaddr;
} else {
if (print)
printf("0x%x+", phdr->p_filesz);
loadaddr = phdr->p_vaddr;
if (use_align && npagesize != 0) {
off = loadaddr & (npagesize - 1);
size = roundup(phdr->p_memsz + off,
npagesize);
base = loadaddr - off;
} else {
npagesize = 0;
size = phdr->p_memsz;
base = loadaddr;
}
if (phdr->p_flags & PF_W)
dhdr = phdr;
else
thdr = phdr;
if (size == 0)
continue;
if (verbosemode)
dprintf("allocating memory: %x %lx "
"%x\n", base, size, npagesize);
if (get_progmemory((caddr_t)(uintptr_t)base,
size, npagesize))
goto elferror;
}
if (verbosemode) {
dprintf("reading 0x%x bytes into 0x%x\n",
phdr->p_filesz, loadaddr);
}
if (xread(fd, (caddr_t)(uintptr_t)loadaddr,
phdr->p_filesz) != phdr->p_filesz)
goto elferror;
if (phdr->p_memsz > phdr->p_filesz) {
loadaddr += phdr->p_filesz;
if (verbosemode) {
dprintf("bss from 0x%x size 0x%x\n",
loadaddr,
phdr->p_memsz - phdr->p_filesz);
}
bzero((void *)(uintptr_t)loadaddr,
phdr->p_memsz - phdr->p_filesz);
bss_seen++;
if (print)
printf("0x%x Bytes\n",
phdr->p_memsz - phdr->p_filesz);
}
if (phdr->p_flags & PF_X) {
sync_instruction_memory(
(caddr_t)(uintptr_t)phdr->p_vaddr,
phdr->p_memsz);
}
} else if (phdr->p_type == PT_INTERP) {
interp = 1;
if (lseek(fd, phdr->p_offset, 0) == -1) {
goto elferror;
}
if (xread(fd, dlname, phdr->p_filesz) !=
phdr->p_filesz ||
dlname[phdr->p_filesz - 1] != '\0')
goto elferror;
} else if (phdr->p_type == PT_DYNAMIC) {
dynamic = phdr->p_vaddr;
}
}
if (!bss_seen && print)
printf("0 Bytes\n");
if (interp) {
Elf32_Boot bootv[EB_MAX];
auxv32_t auxv[__BOOT_NAUXV_IMPL];
Elf32_Boot *bv = bootv;
auxv32_t *av = auxv;
size_t vsize;
if ((entrypt = iload32(dlname, thdr, dhdr, &av)) == FAIL)
goto elferror;
setup_aux();
EBV(bv, EB_AUXV, 0);
EBV(bv, EB_PAGESIZE, pagesize);
EBV(bv, EB_DYNAMIC, dynamic);
EBV(bv, EB_NULL, 0);
AUX(av, AT_BASE, entrypt);
AUX(av, AT_ENTRY, elfhdrp->e_entry);
AUX(av, AT_PAGESZ, pagesize);
AUX(av, AT_PHDR, allphdrs);
AUX(av, AT_PHNUM, elfhdrp->e_phnum);
AUX(av, AT_PHENT, elfhdrp->e_phentsize);
if (use_align)
AUX(av, AT_SUN_LPAGESZ, npagesize);
AUX(av, AT_SUN_IFLUSH, icache_flush);
if (cpulist != NULL)
AUX(av, AT_SUN_CPU, cpulist);
if (mmulist != NULL)
AUX(av, AT_SUN_MMU, mmulist);
AUX(av, AT_NULL, 0);
vsize = (caddr_t)bv - (caddr_t)bootv;
if ((elfbootvec = (Elf32_Boot *)kmem_alloc(vsize, 0)) == NULL)
goto elferror;
bcopy((char *)bootv, (char *)elfbootvec, vsize);
size = (caddr_t)av - (caddr_t)auxv;
if (size > sizeof (auxv)) {
printf("readelf: overrun of available aux vectors\n");
kmem_free(elfbootvec, vsize);
goto elferror;
}
if ((elfbootvec->eb_un.eb_ptr =
(Elf32_Addr)(uintptr_t)kmem_alloc(size, 0)) == 0) {
kmem_free(elfbootvec, vsize);
goto elferror;
}
bcopy(auxv,
(void *)(uintptr_t)(elfbootvec->eb_un.eb_ptr), size);
#if defined(_ELF64_SUPPORT)
if ((elfbootvecELF32_64 = (Elf32_Boot *)kmem_alloc(vsize, 0))
== NULL)
goto elferror;
bcopy(bootv, elfbootvecELF32_64, vsize);
size = (av - auxv) * sizeof (auxv64_t);
if ((elfbootvecELF32_64->eb_un.eb_ptr =
(Elf32_Addr)(uintptr_t)kmem_alloc(size, 0)) == 0) {
kmem_free(elfbootvecELF32_64, vsize);
goto elferror;
} else {
auxv64_t *a64 =
(auxv64_t *)(uintptr_t)
elfbootvecELF32_64->eb_un.eb_ptr;
auxv32_t *a = auxv;
for (a = auxv; a < av; a++) {
a64->a_type = a->a_type;
a64->a_un.a_val = a->a_un.a_val;
a64++;
}
}
#endif
} else {
kmem_free(allphdrs, phdrsize);
}
return (entrypt);
elferror:
if (allphdrs != NULL)
kmem_free(allphdrs, phdrsize);
if (nhdr != NULL)
kmem_free(nhdr, phdr->p_filesz);
printf("Elf32 read error.\n");
return (FAIL);
}
#ifdef _ELF64_SUPPORT
#define AUX64(p, a, v) { (p)->a_type = (a); \
((p)++)->a_un.a_val = (uint64_t)(v); }
#define EBV64(p, a, v) { (p)->eb_tag = (a); \
((p)++)->eb_un.eb_val = (Elf64_Xword)(v); }
static uint64_t
read_elf64(int fd, int print, Elf64_Ehdr *elfhdrp)
{
Elf64_Phdr *phdr;
Elf64_Nhdr *nhdr;
int nphdrs, phdrsize;
caddr_t allphdrs;
caddr_t namep, descp;
Elf64_Addr loadaddr, base;
size_t offset = 0;
size_t size;
int i;
uintptr_t off;
int bss_seen = 0;
int interp = 0;
static char dlname[MAXPATHLEN];
uintptr_t dynamic;
Elf64_Phdr *thdr;
Elf64_Phdr *dhdr;
Elf64_Addr entrypt;
allphdrs = NULL;
nhdr = NULL;
#if defined(__sparcv9)
client_isLP64 = 1;
#endif
if (verbosemode)
printf("Elf64 client\n");
if (elfhdrp->e_phnum == 0 || elfhdrp->e_phoff == 0)
goto elf64error;
entrypt = elfhdrp->e_entry;
if (verbosemode)
dprintf("Entry point: 0x%llx\n", (u_longlong_t)entrypt);
nphdrs = elfhdrp->e_phnum;
phdrsize = nphdrs * elfhdrp->e_phentsize;
allphdrs = (caddr_t)kmem_alloc(phdrsize, 0);
if (allphdrs == NULL)
goto elf64error;
if (verbosemode)
dprintf("lseek: args = %x %llx %x\n", fd,
(u_longlong_t)elfhdrp->e_phoff, 0);
if (lseek(fd, elfhdrp->e_phoff, 0) == -1)
goto elf64error;
if (xread(fd, allphdrs, phdrsize) != phdrsize)
goto elf64error;
npagesize = 0;
for (i = 0; i < nphdrs; i++) {
void *note_buf;
phdr = (Elf64_Phdr *)(allphdrs + elfhdrp->e_phentsize * i);
if (phdr->p_type != PT_NOTE)
continue;
if (verbosemode) {
dprintf("allocating 0x%llx bytes for note hdr\n",
(u_longlong_t)phdr->p_filesz);
}
if ((note_buf = kmem_alloc(phdr->p_filesz, 0)) == NULL)
goto elf64error;
if (verbosemode)
dprintf("seeking to 0x%llx\n",
(u_longlong_t)phdr->p_offset);
if (lseek(fd, phdr->p_offset, 0) == -1)
goto elf64error;
if (verbosemode) {
dprintf("reading 0x%llx bytes into 0x%p\n",
(u_longlong_t)phdr->p_filesz, (void *)nhdr);
}
nhdr = (Elf64_Nhdr *)note_buf;
if (xread(fd, (caddr_t)nhdr, phdr->p_filesz) != phdr->p_filesz)
goto elf64error;
if (verbosemode) {
dprintf("p_note namesz %x descsz %x type %x\n",
nhdr->n_namesz, nhdr->n_descsz, nhdr->n_type);
}
do {
namep = (caddr_t)(nhdr + 1);
if (nhdr->n_namesz == strlen(ELF_NOTE_SOLARIS) + 1 &&
strcmp(namep, ELF_NOTE_SOLARIS) == 0 &&
nhdr->n_type == ELF_NOTE_PAGESIZE_HINT) {
descp = namep + roundup(nhdr->n_namesz, 4);
npagesize = *(int *)descp;
if (verbosemode)
dprintf("pagesize is %x\n", npagesize);
}
offset += sizeof (Elf64_Nhdr) + roundup(nhdr->n_namesz,
4) + roundup(nhdr->n_descsz, 4);
nhdr = (Elf64_Nhdr *)((char *)note_buf + offset);
} while (offset < phdr->p_filesz);
kmem_free(note_buf, phdr->p_filesz);
nhdr = NULL;
}
if (print)
printf("Size: ");
for (i = 0; i < nphdrs; i++) {
phdr = (Elf64_Phdr *)(allphdrs + elfhdrp->e_phentsize * i);
if (verbosemode) {
dprintf("Doing header 0x%x\n", i);
dprintf("phdr\n");
dprintf("\tp_offset = %llx, p_vaddr = %llx\n",
(u_longlong_t)phdr->p_offset,
(u_longlong_t)phdr->p_vaddr);
dprintf("\tp_memsz = %llx, p_filesz = %llx\n",
(u_longlong_t)phdr->p_memsz,
(u_longlong_t)phdr->p_filesz);
dprintf("\tp_type = %x, p_flags = %x\n",
phdr->p_type, phdr->p_flags);
}
if (phdr->p_type == PT_LOAD) {
if (verbosemode)
dprintf("seeking to 0x%llx\n",
(u_longlong_t)phdr->p_offset);
if (lseek(fd, phdr->p_offset, 0) == -1)
goto elf64error;
if (phdr->p_flags == (PF_R | PF_W) &&
phdr->p_vaddr == 0) {
if ((loadaddr = (Elf64_Addr)(uintptr_t)
kmem_alloc(phdr->p_memsz, 0)) == 0)
goto elf64error;
phdr->p_vaddr = loadaddr;
} else {
if (print)
printf("0x%llx+",
(u_longlong_t)phdr->p_filesz);
loadaddr = phdr->p_vaddr;
if (use_align && npagesize != 0) {
off = loadaddr & (npagesize - 1);
size = roundup(phdr->p_memsz + off,
npagesize);
base = loadaddr - off;
} else {
npagesize = 0;
size = phdr->p_memsz;
base = loadaddr;
}
if (phdr->p_flags & PF_W)
dhdr = phdr;
else
thdr = phdr;
if (verbosemode)
dprintf(
"allocating memory: %llx %lx %x\n",
(u_longlong_t)base,
size, npagesize);
if (size == 0)
continue;
if (get_progmemory((caddr_t)(uintptr_t)base,
size, npagesize))
goto elf64error;
}
if (verbosemode) {
dprintf("reading 0x%llx bytes into 0x%llx\n",
(u_longlong_t)phdr->p_filesz,
(u_longlong_t)loadaddr);
}
if (xread(fd, (caddr_t)(uintptr_t)
loadaddr, phdr->p_filesz) != phdr->p_filesz)
goto elf64error;
if (phdr->p_memsz > phdr->p_filesz) {
loadaddr += phdr->p_filesz;
if (verbosemode) {
dprintf("bss from 0x%llx size 0x%llx\n",
(u_longlong_t)loadaddr,
(u_longlong_t)(phdr->p_memsz -
phdr->p_filesz));
}
bzero((caddr_t)(uintptr_t)loadaddr,
phdr->p_memsz - phdr->p_filesz);
bss_seen++;
if (print)
printf("0x%llx Bytes\n",
(u_longlong_t)(phdr->p_memsz -
phdr->p_filesz));
}
if (phdr->p_flags & PF_X)
sync_instruction_memory((caddr_t)(uintptr_t)
phdr->p_vaddr, phdr->p_memsz);
} else if (phdr->p_type == PT_INTERP) {
interp = 1;
if (lseek(fd, phdr->p_offset, 0) == -1) {
goto elf64error;
}
if (xread(fd, dlname, phdr->p_filesz) !=
phdr->p_filesz ||
dlname[phdr->p_filesz - 1] != '\0')
goto elf64error;
} else if (phdr->p_type == PT_DYNAMIC) {
dynamic = phdr->p_vaddr;
}
}
if (!bss_seen && print)
printf("0 Bytes\n");
if (interp) {
Elf64_Boot bootv[EB_MAX];
auxv64_t auxv[__BOOT_NAUXV_IMPL];
Elf64_Boot *bv = bootv;
auxv64_t *av = auxv;
size_t vsize;
if ((entrypt = iload64(dlname, thdr, dhdr, &av)) ==
FAIL_ILOAD64)
goto elf64error;
setup_aux();
EBV64(bv, EB_AUXV, 0);
EBV64(bv, EB_PAGESIZE, pagesize);
EBV64(bv, EB_DYNAMIC, dynamic);
EBV64(bv, EB_NULL, 0);
AUX64(av, AT_BASE, entrypt);
AUX64(av, AT_ENTRY, elfhdrp->e_entry);
AUX64(av, AT_PAGESZ, pagesize);
AUX64(av, AT_PHDR, (uintptr_t)allphdrs);
AUX64(av, AT_PHNUM, elfhdrp->e_phnum);
AUX64(av, AT_PHENT, elfhdrp->e_phentsize);
if (npagesize)
AUX64(av, AT_SUN_LPAGESZ, npagesize);
AUX64(av, AT_SUN_IFLUSH, icache_flush);
if (cpulist != NULL)
AUX64(av, AT_SUN_CPU, (uintptr_t)cpulist);
AUX64(av, AT_NULL, 0);
vsize = (caddr_t)bv - (caddr_t)bootv;
if ((elfbootvecELF64 =
(Elf64_Boot *)kmem_alloc(vsize, 0)) == NULL)
goto elf64error;
bcopy((char *)bootv, (char *)elfbootvecELF64, vsize);
size = (caddr_t)av - (caddr_t)auxv;
if (size > sizeof (auxv)) {
printf("readelf: overrun of available aux vectors\n");
kmem_free(elfbootvecELF64, vsize);
goto elf64error;
}
if ((elfbootvecELF64->eb_un.eb_ptr =
(Elf64_Addr)kmem_alloc(size, 0)) == 0) {
kmem_free(elfbootvecELF64, vsize);
goto elf64error;
}
bcopy((char *)auxv, (char *)(elfbootvecELF64->eb_un.eb_ptr),
size);
} else {
kmem_free(allphdrs, phdrsize);
}
return ((uint64_t)entrypt);
elf64error:
if (allphdrs != NULL)
kmem_free(allphdrs, phdrsize);
if (nhdr != NULL)
kmem_free(nhdr, phdr->p_filesz);
printf("Elf64 read error.\n");
return (FAIL_READELF64);
}
#endif
static func_t
iload32(char *rtld, Elf32_Phdr *thdr, Elf32_Phdr *dhdr, auxv32_t **avp)
{
Elf32_Ehdr *ehdr = NULL;
uintptr_t dl_entry = 0;
uint_t i;
int fd;
int size;
caddr_t shdrs = NULL;
caddr_t etext, edata;
etext = (caddr_t)(uintptr_t)thdr->p_vaddr + thdr->p_memsz;
edata = (caddr_t)(uintptr_t)dhdr->p_vaddr + dhdr->p_memsz;
module_path = getmodpath(filename);
if ((fd = openpath(module_path, rtld, O_RDONLY)) < 0) {
printf("boot: cannot find %s\n", rtld);
goto errorx;
}
dprintf("Opened %s OK\n", rtld);
AUX(*avp, AT_SUN_LDNAME, rtld);
if ((ehdr = (Elf32_Ehdr *)kmem_alloc(sizeof (Elf32_Ehdr), 0)) == NULL) {
printf("boot: alloc error reading ELF header (%s).\n", rtld);
goto error;
}
if (xread(fd, (char *)ehdr, sizeof (*ehdr)) != sizeof (*ehdr)) {
printf("boot: error reading ELF header (%s).\n", rtld);
goto error;
}
size = ehdr->e_shentsize * ehdr->e_shnum;
if ((shdrs = (caddr_t)kmem_alloc(size, 0)) == NULL) {
printf("boot: alloc error reading ELF header (%s).\n", rtld);
goto error;
}
if (lseek(fd, ehdr->e_shoff, 0) == -1 ||
xread(fd, shdrs, size) != size) {
printf("boot: error reading section headers\n");
goto error;
}
AUX(*avp, AT_SUN_LDELF, ehdr);
AUX(*avp, AT_SUN_LDSHDR, shdrs);
for (i = 1; i < ehdr->e_shnum; i++) {
Elf32_Shdr *sp;
caddr_t *spp;
caddr_t load;
sp = (Elf32_Shdr *)(shdrs + (i*ehdr->e_shentsize));
if (!(sp->sh_flags & SHF_ALLOC) &&
sp->sh_type != SHT_RELA &&
sp->sh_type != SHT_SYMTAB &&
sp->sh_type != SHT_STRTAB)
continue;
spp = (sp->sh_flags & SHF_WRITE)? &edata: &etext;
load = segbrk(spp, sp->sh_size, sp->sh_addralign);
if (load == NULL) {
printf("boot: allocating memory for sections failed\n");
goto error;
}
if (dl_entry == 0 &&
!(sp->sh_flags & SHF_WRITE) &&
(sp->sh_flags & SHF_EXECINSTR)) {
dl_entry = (uintptr_t)load + ehdr->e_entry;
}
if (sp->sh_type == SHT_NOBITS) {
bzero(load, sp->sh_size);
} else {
if (lseek(fd, sp->sh_offset, 0) == -1 ||
xread(fd, load, sp->sh_size) != sp->sh_size) {
printf("boot: error reading sections\n");
goto error;
}
}
sp->sh_addr = (Elf32_Off)(uintptr_t)load;
if (sp->sh_flags & SHF_EXECINSTR)
sync_instruction_memory((caddr_t)(uintptr_t)sp->sh_addr,
sp->sh_size);
}
thdr->p_memsz = (Elf32_Word)((uintptr_t)etext - thdr->p_vaddr);
dhdr->p_memsz = (Elf32_Word)((uintptr_t)edata - dhdr->p_vaddr);
(void) close(fd);
return ((func_t)dl_entry);
error:
(void) close(fd);
errorx:
if (ehdr)
kmem_free(ehdr, sizeof (Elf32_Ehdr));
if (shdrs)
kmem_free(shdrs, size);
printf("boot: error loading interpreter (%s)\n", rtld);
return (FAIL);
}
#ifdef _ELF64_SUPPORT
static Elf64_Addr
iload64(char *rtld, Elf64_Phdr *thdr, Elf64_Phdr *dhdr, auxv64_t **avp)
{
Elf64_Ehdr *ehdr = NULL;
Elf64_Addr dl_entry = (Elf64_Addr)0;
Elf64_Addr etext, edata;
uint_t i;
int fd;
int size;
caddr_t shdrs = NULL;
etext = thdr->p_vaddr + thdr->p_memsz;
edata = dhdr->p_vaddr + dhdr->p_memsz;
module_path = getmodpath(filename);
if ((fd = openpath(module_path, rtld, O_RDONLY)) < 0) {
printf("boot: cannot find %s\n", rtld);
goto errorx;
}
dprintf("Opened %s OK\n", rtld);
AUX64(*avp, AT_SUN_LDNAME, (uintptr_t)rtld);
if ((ehdr = (Elf64_Ehdr *)kmem_alloc(sizeof (Elf64_Ehdr), 0)) == NULL) {
printf("boot: alloc error reading ELF header (%s).\n", rtld);
goto error;
}
if (xread(fd, (char *)ehdr, sizeof (*ehdr)) != sizeof (*ehdr)) {
printf("boot: error reading ELF header (%s).\n", rtld);
goto error;
}
size = ehdr->e_shentsize * ehdr->e_shnum;
if ((shdrs = (caddr_t)kmem_alloc(size, 0)) == NULL) {
printf("boot: alloc error reading ELF header (%s).\n", rtld);
goto error;
}
if (lseek(fd, ehdr->e_shoff, 0) == -1 ||
xread(fd, shdrs, size) != size) {
printf("boot: error reading section headers\n");
goto error;
}
AUX64(*avp, AT_SUN_LDELF, ehdr);
AUX64(*avp, AT_SUN_LDSHDR, shdrs);
for (i = 1; i < ehdr->e_shnum; i++) {
Elf64_Shdr *sp;
Elf64_Addr *spp, load;
sp = (Elf64_Shdr *)(shdrs + (i*ehdr->e_shentsize));
if (!(sp->sh_flags & SHF_ALLOC) &&
sp->sh_type != SHT_SYMTAB &&
sp->sh_type != SHT_STRTAB &&
sp->sh_type != SHT_RELA)
continue;
spp = (sp->sh_flags & SHF_WRITE)? &edata: &etext;
load = (Elf64_Addr)segbrk((caddr_t *)spp, sp->sh_size,
sp->sh_addralign);
if (load == 0) {
printf("boot: allocating memory for section %d "
"failed\n", i);
goto error;
}
if (dl_entry == 0 &&
!(sp->sh_flags & SHF_WRITE) &&
(sp->sh_flags & SHF_EXECINSTR)) {
dl_entry = load + ehdr->e_entry;
if (verbosemode)
dprintf("boot: loading linker @ 0x%llx\n",
(u_longlong_t)dl_entry);
}
if (sp->sh_type == SHT_NOBITS) {
bzero((caddr_t)(uintptr_t)load, sp->sh_size);
} else {
if (lseek(fd, sp->sh_offset, 0) == -1 ||
xread(fd, (caddr_t)(uintptr_t)load, sp->sh_size) !=
sp->sh_size) {
printf("boot: error reading section %d\n", i);
goto error;
}
}
sp->sh_addr = load;
if (verbosemode)
dprintf("boot: section %d, type %d, loaded @ 0x%llx, "
"size 0x%llx\n", i, sp->sh_type, (u_longlong_t)load,
(u_longlong_t)sp->sh_size);
if (sp->sh_flags & SHF_EXECINSTR)
sync_instruction_memory((caddr_t)(uintptr_t)sp->sh_addr,
sp->sh_size);
}
thdr->p_memsz = etext - thdr->p_vaddr;
dhdr->p_memsz = edata - dhdr->p_vaddr;
(void) close(fd);
return (dl_entry);
error:
(void) close(fd);
errorx:
if (ehdr)
kmem_free((caddr_t)ehdr, sizeof (Elf64_Ehdr));
if (shdrs)
kmem_free(shdrs, size);
printf("boot: error loading interpreter (%s)\n", rtld);
return (FAIL_ILOAD64);
}
#endif
static caddr_t
segbrk(caddr_t *spp, size_t bytes, size_t align)
{
caddr_t va, pva;
size_t size = 0;
unsigned int alloc_pagesize = pagesize;
unsigned int alloc_align = 0;
if (npagesize) {
alloc_align = npagesize;
alloc_pagesize = npagesize;
}
va = (caddr_t)ALIGN(*spp, align);
pva = (caddr_t)roundup((uintptr_t)*spp, alloc_pagesize);
if (va + bytes > pva) {
size = roundup((bytes - (pva - va)), alloc_pagesize);
if (get_progmemory(pva, size, alloc_align)) {
printf("boot: segbrk allocation failed, "
"0x%lx bytes @ %p\n", bytes, (void *)pva);
return (NULL);
}
}
*spp = va + bytes;
return (va);
}
static int
openpath(char *path, char *fname, int flags)
{
register char *p, *q;
char buf[MAXPATHLEN];
int fd;
if (fname[0] == '/')
return (open(fname, flags));
q = NULL;
for (p = path; ; p = q) {
while (*p == ' ' || *p == '\t' || *p == ':')
p++;
if (*p == '\0')
break;
q = p;
while (*q && *q != ' ' && *q != '\t' && *q != ':')
q++;
(void) strncpy(buf, p, q - p);
if (q[-1] != '/') {
buf[q - p] = '/';
(void) strcpy(&buf[q - p + 1], fname);
} else {
(void) strcpy(&buf[q - p], fname);
}
if ((fd = open(buf, flags)) > 0)
return (fd);
}
return (-1);
}
static char *
getmodpath(char *fname)
{
register char *p = strrchr(fname, '/');
static char mod_path[MOD_MAXPATH];
size_t len;
extern char *impl_arch_name;
#if defined(__sparcv9)
char *isastr = "/sparcv9";
size_t isalen = strlen(isastr);
#endif
if (p == NULL) {
printf("%s is not a legal kernel pathname", fname);
return (NULL);
}
while (p > fname && *(p - 1) == '/')
p--;
if (p == fname)
p++;
len = p - fname;
(void) strncpy(mod_path, fname, len);
mod_path[len] = 0;
#if defined(__sparcv9)
len = strlen(mod_path);
if ((len > isalen) && (strcmp(&mod_path[len - isalen], isastr) == 0)) {
mod_path[len - isalen] = '\0';
if ((client_isLP64 == 0) && verbosemode)
printf("Assuming LP64 %s client.\n", isastr);
client_isLP64 = 1;
}
#endif
mod_path_uname_m(mod_path, impl_arch_name);
(void) strcat(mod_path, " ");
(void) strcat(mod_path, MOD_DEFPATH);
if (boothowto & RB_ASKNAME) {
char buf[MOD_MAXPATH];
printf("Enter default directory for modules [%s]: ", mod_path);
(void) cons_gets(buf, sizeof (buf));
if (buf[0] != '\0')
(void) strcpy(mod_path, buf);
}
if (verbosemode)
printf("modpath: %s\n", mod_path);
return (mod_path);
}