freebsd-skq/sys/powerpc/powerpc/elf_machdep.c
marcel fbbaea5f90 Add __elfN(dump_thread). This function is called from __elfN(coredump)
to allow dumping per-thread machine specific notes. On ia64 we use this
function to flush the dirty registers onto the backingstore before we
write out the PRSTATUS notes.

Tested on: alpha, amd64, i386, ia64 & sparc64
Not tested on: arm, powerpc
2004-08-11 02:35:06 +00:00

233 lines
5.5 KiB
C

/*-
* Copyright 1996-1998 John D. Polstra.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/exec.h>
#include <sys/imgact.h>
#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/namei.h>
#include <sys/fcntl.h>
#include <sys/sysent.h>
#include <sys/imgact_elf.h>
#include <sys/syscall.h>
#include <sys/signalvar.h>
#include <sys/vnode.h>
#include <sys/linker.h>
#include <vm/vm.h>
#include <vm/vm_param.h>
#include <machine/cpu.h>
#include <machine/elf.h>
#include <machine/md_var.h>
struct sysentvec elf32_freebsd_sysvec = {
SYS_MAXSYSCALL,
sysent,
0,
0,
NULL,
0,
NULL,
NULL,
__elfN(freebsd_fixup),
sendsig,
sigcode,
&szsigcode,
NULL,
"FreeBSD ELF32",
__elfN(coredump),
NULL,
MINSIGSTKSZ,
PAGE_SIZE,
VM_MIN_ADDRESS,
VM_MAXUSER_ADDRESS,
USRSTACK,
PS_STRINGS,
VM_PROT_ALL,
exec_copyout_strings,
exec_setregs,
NULL
};
static Elf32_Brandinfo freebsd_brand_info = {
ELFOSABI_FREEBSD,
EM_PPC,
"FreeBSD",
NULL,
"/libexec/ld-elf.so.1",
&elf32_freebsd_sysvec,
NULL,
};
SYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_ANY,
(sysinit_cfunc_t) elf32_insert_brand_entry,
&freebsd_brand_info);
static Elf32_Brandinfo freebsd_brand_oinfo = {
ELFOSABI_FREEBSD,
EM_PPC,
"FreeBSD",
NULL,
"/usr/libexec/ld-elf.so.1",
&elf32_freebsd_sysvec,
NULL,
};
SYSINIT(oelf32, SI_SUB_EXEC, SI_ORDER_ANY,
(sysinit_cfunc_t) elf32_insert_brand_entry,
&freebsd_brand_oinfo);
void
elf32_dump_thread(struct thread *td __unused, void *dst __unused,
size_t *off __unused)
{
}
/* Process one elf relocation with addend. */
static int
elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
int type, int local, elf_lookup_fn lookup)
{
Elf_Addr *where;
Elf_Half *hwhere;
Elf_Addr addr;
Elf_Addr addend;
Elf_Word rtype, symidx;
const Elf_Rela *rela;
switch (type) {
case ELF_RELOC_REL:
panic("PPC only supports RELA relocations");
break;
case ELF_RELOC_RELA:
rela = (const Elf_Rela *)data;
where = (Elf_Addr *) (relocbase + rela->r_offset);
hwhere = (Elf_Half *) (relocbase + rela->r_offset);
addend = rela->r_addend;
rtype = ELF_R_TYPE(rela->r_info);
symidx = ELF_R_SYM(rela->r_info);
break;
default:
panic("elf_reloc: unknown relocation mode %d\n", type);
}
switch (rtype) {
case R_PPC_NONE:
break;
case R_PPC_ADDR32: /* word32 S + A */
addr = lookup(lf, symidx, 1);
if (addr == 0)
return -1;
addr += addend;
*where = addr;
break;
case R_PPC_ADDR16_LO: /* #lo(S) */
addr = lookup(lf, symidx, 1);
if (addr == 0)
return -1;
/*
* addend values are sometimes relative to sections
* (i.e. .rodata) in rela, where in reality they
* are relative to relocbase. Detect this condition.
*/
if (addr > relocbase && addr <= (relocbase + addend))
addr = relocbase + addend;
else
addr += addend;
*hwhere = addr & 0xffff;
break;
case R_PPC_ADDR16_HA: /* #ha(S) */
addr = lookup(lf, symidx, 1);
if (addr == 0)
return -1;
/*
* addend values are sometimes relative to sections
* (i.e. .rodata) in rela, where in reality they
* are relative to relocbase. Detect this condition.
*/
if (addr > relocbase && addr <= (relocbase + addend))
addr = relocbase + addend;
else
addr += addend;
*hwhere = ((addr >> 16) + ((addr & 0x8000) ? 1 : 0))
& 0xffff;
break;
case R_PPC_RELATIVE: /* word32 B + A */
*where = relocbase + addend;
break;
default:
printf("kldload: unexpected relocation type %d\n",
(int) rtype);
return -1;
}
return(0);
}
int
elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type,
elf_lookup_fn lookup)
{
return (elf_reloc_internal(lf, relocbase, data, type, 0, lookup));
}
int
elf_reloc_local(linker_file_t lf, Elf_Addr relocbase, const void *data,
int type, elf_lookup_fn lookup)
{
return (elf_reloc_internal(lf, relocbase, data, type, 1, lookup));
}
int
elf_cpu_load_file(linker_file_t lf)
{
/* Only sync the cache for non-kernel modules */
if (lf->id != 1)
__syncicache(lf->address, lf->size);
return (0);
}
int
elf_cpu_unload_file(linker_file_t lf __unused)
{
return (0);
}