dt_link.c revision 0b38a8bdfd75ac6144f9d462bb38d0c1b3f0ca50
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#define ELF_TARGET_ALL
#include <elf.h>
#include <sys/sysmacros.h>
#include <unistd.h>
#include <strings.h>
#include <alloca.h>
#include <limits.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <wait.h>
#include <assert.h>
#include <dt_impl.h>
#include <dt_provider.h>
#include <dt_string.h>
#define ESHDR_NULL 0
#define ESHDR_SHSTRTAB 1
#define ESHDR_DOF 2
#define ESHDR_STRTAB 3
#define ESHDR_SYMTAB 4
#define ESHDR_REL 5
#define ESHDR_NUM 6
static const char DTRACE_SHSTRTAB32[] = "\0"
".shstrtab\0" /* 1 */
".SUNW_dof\0" /* 11 */
".strtab\0" /* 21 */
".symtab\0" /* 29 */
#ifdef __sparc
".rela.SUNW_dof"; /* 37 */
#else
".rel.SUNW_dof"; /* 37 */
#endif
static const char DTRACE_SHSTRTAB64[] = "\0"
".shstrtab\0" /* 1 */
".SUNW_dof\0" /* 11 */
".strtab\0" /* 21 */
".symtab\0" /* 29 */
".rela.SUNW_dof"; /* 37 */
static const char DOFSTR[] = "__SUNW_dof";
static const char DOFLAZYSTR[] = "___SUNW_dof";
typedef struct dof_elf32 {
#ifdef __sparc
#else
#endif
char *de_strtab; /* string table */
} dof_elf32_t;
static int
{
char *strtab;
int i, j, nrel;
#ifdef __sparc
#else
#endif
/*LINTED*/
/*
* First compute the size of the string table and the number of
* relocations present in the DOF.
*/
for (i = 0; i < dof->dofh_secnum; i++) {
continue;
/*LINTED*/
/*LINTED*/
}
if (dtp->dt_lazyload) {
} else {
}
}
}
}
count = 0;
strtabsz = 1;
/*
* The first symbol table entry must be zeroed and is always ignored.
*/
sym++;
/*
* Take a second pass through the DOF sections filling in the
* memory we allocated.
*/
for (i = 0; i < dof->dofh_secnum; i++) {
continue;
/*LINTED*/
/*LINTED*/
for (j = 0; j < nrel; j++) {
dofr[j].dofr_offset;
R_386_32);
/*
* Add 4 bytes to hit the low half of this 64-bit
* big-endian address.
*/
#else
#endif
rel++;
sym++;
count++;
}
}
/*
* Add a symbol for the DOF itself. We use a different symbol for
* lazily and actively loaded DOF to make them easy to distinguish.
*/
sym++;
if (dtp->dt_lazyload) {
sizeof (DOFLAZYSTR));
strtabsz += sizeof (DOFLAZYSTR);
} else {
}
return (0);
}
typedef struct dof_elf64 {
char *de_strtab;
} dof_elf64_t;
static int
{
char *strtab;
int i, j, nrel;
/*LINTED*/
/*
* First compute the size of the string table and the number of
* relocations present in the DOF.
*/
for (i = 0; i < dof->dofh_secnum; i++) {
continue;
/*LINTED*/
/*LINTED*/
}
if (dtp->dt_lazyload) {
} else {
}
}
}
}
count = 0;
strtabsz = 1;
/*
* The first symbol table entry must be zeroed and is always ignored.
*/
sym++;
/*
* Take a second pass through the DOF sections filling in the
* memory we allocated.
*/
for (i = 0; i < dof->dofh_secnum; i++) {
continue;
/*LINTED*/
/*LINTED*/
for (j = 0; j < nrel; j++) {
dofr[j].dofr_offset;
dofr[j].dofr_offset;
#else
#endif
rel++;
sym++;
count++;
}
}
/*
* Add a symbol for the DOF itself. We use a different symbol for
* lazily and actively loaded DOF to make them easy to distinguish.
*/
sym++;
if (dtp->dt_lazyload) {
sizeof (DOFLAZYSTR));
strtabsz += sizeof (DOFLAZYSTR);
} else {
}
return (0);
}
/*
* Write out an ELF32 file prologue consisting of a header, section headers,
* and a section header string table. The DOF data will follow this prologue
* and complete the contents of the given ELF file.
*/
static int
{
struct {
} elf_file;
int ret = 0;
return (-1); /* errno is set for us */
/*
* If there are no relocations, we only need enough sections for
* the shstrtab and the DOF.
*/
#if defined(_BIG_ENDIAN)
#elif defined(_LITTLE_ENDIAN)
#endif
#if defined(__sparc)
#endif
shp->sh_addralign = sizeof (char);
shp->sh_addralign = sizeof (char);
}
} else {
#ifdef __sparc
#else
#endif
}
}
return (ret);
}
/*
* Write out an ELF64 file prologue consisting of a header, section headers,
* and a section header string table. The DOF data will follow this prologue
* and complete the contents of the given ELF file.
*/
static int
{
struct {
} elf_file;
int ret = 0;
return (-1); /* errno is set for us */
/*
* If there are no relocations, we only need enough sections for
* the shstrtab and the DOF.
*/
#if defined(_BIG_ENDIAN)
#elif defined(_LITTLE_ENDIAN)
#endif
#if defined(__sparc)
#endif
shp->sh_addralign = sizeof (char);
shp->sh_addralign = sizeof (char);
}
} else {
}
}
return (ret);
}
static int
{
int i, ret = -1;
GElf_Sym s;
return (0);
ret = 0;
s = *sym;
}
}
if (ret == 0)
*sym = s;
return (ret);
}
#if defined(__sparc)
#define DT_OP_RET 0x81c7e008
#define DT_OP_NOP 0x01000000
#define DT_OP_CALL 0x40000000
static int
{
return (-1);
/*LINTED*/
/*
* We only know about some specific relocation types.
*/
return (-1);
/*
* We may have already processed this object file in an earlier
*/
return (0);
}
if (DT_IS_RETL(ip[0])) {
return (0);
}
} else {
return (0);
}
}
/*
* We only expect call instructions with a displacement of 0.
*/
if (ip[0] != DT_OP_CALL) {
dt_dprintf("found %x instead of a call instruction at %llx\n",
return (-1);
}
/*
* If the call is followed by a restore, it's a tail call so change
* the call to a ret. If the call if followed by a mov of a register
* into %o7, it's a tail call in leaf context so change the call to
* a retl-like instruction that returns to that register value + 8
* (rather than the typical %o7 + 8). Otherwise we adjust the offset
* to land on what was once the delay slot of the call so we
* correctly get all the arguments.
*/
} else {
}
return (0);
}
#define DT_OP_NOP 0x90
#define DT_OP_CALL 0xe8
static int
{
/*
* On x86, the first byte of the instruction is the call opcode and
* the next four bytes are the 32-bit address; the relocation is for
* the address so we back up one byte to land on the opcode.
*/
(*off) -= 1;
/*
* We only know about some specific relocation types. Luckily
* these types have the same values on both 32-bit and 64-bit
* x86 architectures.
*/
return (-1);
/*
* We may have already processed this object file in an earlier
* linker invocation in which case we'd expect to see a bunch
* of nops; return success in that case.
*/
return (0);
/*
* We only expect a call instrution with a 32-bit displacement.
*/
if (ip[0] != DT_OP_CALL) {
dt_dprintf("found %x instead of a call instruction at %llx\n",
return (-1);
}
return (0);
}
#else
#endif
/*PRINTFLIKE2*/
static int
{
}
static int
{
static const char dt_prefix[] = "__dtrace_";
char *s, *p;
char pname[DTRACE_PROVNAMELEN];
}
elf_errmsg(elf_errno())));
}
case ELF_K_ELF:
break;
case ELF_K_AR:
" use the contents of the archive instead", obj));
default:
}
eclass = ELFCLASS64;
#if defined(__sparc)
#endif
} else {
eclass = ELFCLASS32;
#if defined(__sparc)
#endif
}
"file %s", obj));
"object file %s", obj));
goto err;
continue;
goto err;
goto err;
goto err;
continue;
} else {
continue;
}
goto err;
continue;
goto err;
s += sizeof (dt_prefix) - 1;
p - s >= sizeof (pname))
goto err;
pname[p - s] = '\0';
goto err;
return (dt_link_error(dtp,
"no such provider %s", pname));
}
return (dt_link_error(dtp,
"no such probe %s", p));
}
goto err;
mod = 1;
/*
* This symbol may already have been marked to
* be ignored by another relocation referencing
* the same symbol or if this object file has
* already been processed by an earlier link
* invocation.
*/
}
}
}
goto err;
return (0);
err:
return (dt_link_error(dtp,
"an error was encountered while processing %s", obj));
}
int
{
int ret = 0;
/*
* A NULL program indicates a special use in which we just link
* together a bunch of object files specified in objv and then
* unlink(2) those object files.
*/
const char *fmt = "%s -o %s -r";
for (i = 0; i < objc; i++)
for (i = 0; i < objc; i++)
}
if (WIFSIGNALED(status)) {
return (dt_link_error(dtp,
"failed to link %s: %s failed due to signal %d",
}
if (WEXITSTATUS(status) != 0) {
return (dt_link_error(dtp,
"failed to link %s: %s exited with status %d\n",
}
for (i = 0; i < objc; i++) {
}
return (0);
}
for (i = 0; i < objc; i++) {
return (-1); /* errno is set for us */
}
return (-1); /* errno is set for us */
/*
* Create a temporary file and then unlink it if we're going to
* combine it with drti.o later. We can still refer to it in child
*/
return (dt_link_error(dtp,
}
/*
* If -xlinktype=DOF has been selected, just write out the DOF.
* Otherwise proceed to the default of generating and linking ELF.
*/
switch (dtp->dt_linktype) {
case DT_LTYP_DOF:
if (ret != 0) {
return (dt_link_error(dtp,
}
return (0);
case DT_LTYP_ELF:
break; /* fall through to the rest of dtrace_program_link() */
default:
return (dt_link_error(dtp,
}
if (!dtp->dt_lazyload)
else
return (dt_link_error(dtp,
}
if (!dtp->dt_lazyload) {
"%s/64/drti.o", _dtrace_libdir);
} else {
"%s/drti.o", _dtrace_libdir);
}
drti) + 1;
goto done;
}
if (WIFSIGNALED(status)) {
"failed to link %s: %s failed due to signal %d",
goto done;
}
if (WEXITSTATUS(status) != 0) {
"failed to link %s: %s exited with status %d\n",
goto done;
}
} else {
}
done:
return (ret);
}