10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 230Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate #define ELF_TARGET_ALL 300Sstevel@tonic-gate #include <elf.h> 310Sstevel@tonic-gate 320Sstevel@tonic-gate #include <sys/types.h> 330Sstevel@tonic-gate #include <sys/sysmacros.h> 340Sstevel@tonic-gate 350Sstevel@tonic-gate #include <unistd.h> 360Sstevel@tonic-gate #include <strings.h> 370Sstevel@tonic-gate #include <alloca.h> 380Sstevel@tonic-gate #include <limits.h> 390Sstevel@tonic-gate #include <stddef.h> 400Sstevel@tonic-gate #include <stdlib.h> 410Sstevel@tonic-gate #include <stdio.h> 420Sstevel@tonic-gate #include <fcntl.h> 430Sstevel@tonic-gate #include <errno.h> 440Sstevel@tonic-gate #include <wait.h> 450Sstevel@tonic-gate #include <assert.h> 460Sstevel@tonic-gate 470Sstevel@tonic-gate #include <dt_impl.h> 480Sstevel@tonic-gate #include <dt_provider.h> 490Sstevel@tonic-gate #include <dt_string.h> 500Sstevel@tonic-gate 510Sstevel@tonic-gate #define ESHDR_NULL 0 520Sstevel@tonic-gate #define ESHDR_SHSTRTAB 1 530Sstevel@tonic-gate #define ESHDR_DOF 2 540Sstevel@tonic-gate #define ESHDR_STRTAB 3 550Sstevel@tonic-gate #define ESHDR_SYMTAB 4 560Sstevel@tonic-gate #define ESHDR_REL 5 570Sstevel@tonic-gate #define ESHDR_NUM 6 580Sstevel@tonic-gate 590Sstevel@tonic-gate #define PWRITE_SCN(index, data) \ 600Sstevel@tonic-gate (lseek64(fd, (off64_t)elf_file.shdr[(index)].sh_offset, SEEK_SET) != \ 610Sstevel@tonic-gate (off64_t)elf_file.shdr[(index)].sh_offset || \ 620Sstevel@tonic-gate dt_write(dtp, fd, (data), elf_file.shdr[(index)].sh_size) != \ 630Sstevel@tonic-gate elf_file.shdr[(index)].sh_size) 640Sstevel@tonic-gate 650Sstevel@tonic-gate static const char DTRACE_SHSTRTAB32[] = "\0" 660Sstevel@tonic-gate ".shstrtab\0" /* 1 */ 670Sstevel@tonic-gate ".SUNW_dof\0" /* 11 */ 680Sstevel@tonic-gate ".strtab\0" /* 21 */ 690Sstevel@tonic-gate ".symtab\0" /* 29 */ 700Sstevel@tonic-gate #ifdef __sparc 710Sstevel@tonic-gate ".rela.SUNW_dof"; /* 37 */ 720Sstevel@tonic-gate #else 730Sstevel@tonic-gate ".rel.SUNW_dof"; /* 37 */ 740Sstevel@tonic-gate #endif 750Sstevel@tonic-gate 760Sstevel@tonic-gate static const char DTRACE_SHSTRTAB64[] = "\0" 770Sstevel@tonic-gate ".shstrtab\0" /* 1 */ 780Sstevel@tonic-gate ".SUNW_dof\0" /* 11 */ 790Sstevel@tonic-gate ".strtab\0" /* 21 */ 800Sstevel@tonic-gate ".symtab\0" /* 29 */ 810Sstevel@tonic-gate ".rela.SUNW_dof"; /* 37 */ 820Sstevel@tonic-gate 830Sstevel@tonic-gate static const char DOFSTR[] = "__SUNW_dof"; 840Sstevel@tonic-gate static const char DOFLAZYSTR[] = "___SUNW_dof"; 850Sstevel@tonic-gate 860Sstevel@tonic-gate typedef struct dof_elf32 { 870Sstevel@tonic-gate uint32_t de_nrel; /* relocation count */ 880Sstevel@tonic-gate #ifdef __sparc 890Sstevel@tonic-gate Elf32_Rela *de_rel; /* array of relocations for sparc */ 900Sstevel@tonic-gate #else 910Sstevel@tonic-gate Elf32_Rel *de_rel; /* array of relocations for x86 */ 920Sstevel@tonic-gate #endif 930Sstevel@tonic-gate uint32_t de_nsym; /* symbol count */ 940Sstevel@tonic-gate Elf32_Sym *de_sym; /* array of symbols */ 950Sstevel@tonic-gate uint32_t de_strlen; /* size of of string table */ 960Sstevel@tonic-gate char *de_strtab; /* string table */ 970Sstevel@tonic-gate uint32_t de_global; /* index of the first global symbol */ 980Sstevel@tonic-gate } dof_elf32_t; 990Sstevel@tonic-gate 1000Sstevel@tonic-gate static int 1010Sstevel@tonic-gate prepare_elf32(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf32_t *dep) 1020Sstevel@tonic-gate { 1030Sstevel@tonic-gate dof_sec_t *dofs, *s; 1040Sstevel@tonic-gate dof_relohdr_t *dofrh; 1050Sstevel@tonic-gate dof_relodesc_t *dofr; 1060Sstevel@tonic-gate char *strtab; 1070Sstevel@tonic-gate int i, j, nrel; 1080Sstevel@tonic-gate size_t strtabsz = 1; 1090Sstevel@tonic-gate uint32_t count = 0; 1100Sstevel@tonic-gate size_t base; 1110Sstevel@tonic-gate Elf32_Sym *sym; 1120Sstevel@tonic-gate #ifdef __sparc 1130Sstevel@tonic-gate Elf32_Rela *rel; 1140Sstevel@tonic-gate #else 1150Sstevel@tonic-gate Elf32_Rel *rel; 1160Sstevel@tonic-gate #endif 1170Sstevel@tonic-gate 1180Sstevel@tonic-gate /*LINTED*/ 1190Sstevel@tonic-gate dofs = (dof_sec_t *)((char *)dof + dof->dofh_secoff); 1200Sstevel@tonic-gate 1210Sstevel@tonic-gate /* 1220Sstevel@tonic-gate * First compute the size of the string table and the number of 1230Sstevel@tonic-gate * relocations present in the DOF. 1240Sstevel@tonic-gate */ 1250Sstevel@tonic-gate for (i = 0; i < dof->dofh_secnum; i++) { 1260Sstevel@tonic-gate if (dofs[i].dofs_type != DOF_SECT_URELHDR) 1270Sstevel@tonic-gate continue; 1280Sstevel@tonic-gate 1290Sstevel@tonic-gate /*LINTED*/ 1300Sstevel@tonic-gate dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset); 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate s = &dofs[dofrh->dofr_strtab]; 1330Sstevel@tonic-gate strtab = (char *)dof + s->dofs_offset; 1340Sstevel@tonic-gate assert(strtab[0] == '\0'); 1350Sstevel@tonic-gate strtabsz += s->dofs_size - 1; 1360Sstevel@tonic-gate 1370Sstevel@tonic-gate s = &dofs[dofrh->dofr_relsec]; 1380Sstevel@tonic-gate /*LINTED*/ 1390Sstevel@tonic-gate dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset); 1400Sstevel@tonic-gate count += s->dofs_size / s->dofs_entsize; 1410Sstevel@tonic-gate } 1420Sstevel@tonic-gate 1430Sstevel@tonic-gate dep->de_strlen = strtabsz; 1440Sstevel@tonic-gate dep->de_nrel = count; 1450Sstevel@tonic-gate dep->de_nsym = count + 1; /* the first symbol is always null */ 1460Sstevel@tonic-gate 1470Sstevel@tonic-gate if (dtp->dt_lazyload) { 1480Sstevel@tonic-gate dep->de_strlen += sizeof (DOFLAZYSTR); 1490Sstevel@tonic-gate dep->de_nsym++; 1500Sstevel@tonic-gate } else { 1510Sstevel@tonic-gate dep->de_strlen += sizeof (DOFSTR); 1520Sstevel@tonic-gate dep->de_nsym++; 1530Sstevel@tonic-gate } 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate if ((dep->de_rel = calloc(dep->de_nrel, 1560Sstevel@tonic-gate sizeof (dep->de_rel[0]))) == NULL) { 1570Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 1580Sstevel@tonic-gate } 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate if ((dep->de_sym = calloc(dep->de_nsym, sizeof (Elf32_Sym))) == NULL) { 1610Sstevel@tonic-gate free(dep->de_rel); 1620Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 1630Sstevel@tonic-gate } 1640Sstevel@tonic-gate 1650Sstevel@tonic-gate if ((dep->de_strtab = calloc(dep->de_strlen, 1)) == NULL) { 1660Sstevel@tonic-gate free(dep->de_rel); 1670Sstevel@tonic-gate free(dep->de_sym); 1680Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 1690Sstevel@tonic-gate } 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate count = 0; 1720Sstevel@tonic-gate strtabsz = 1; 1730Sstevel@tonic-gate dep->de_strtab[0] = '\0'; 1740Sstevel@tonic-gate rel = dep->de_rel; 1750Sstevel@tonic-gate sym = dep->de_sym; 1760Sstevel@tonic-gate dep->de_global = 1; 1770Sstevel@tonic-gate 1780Sstevel@tonic-gate /* 1790Sstevel@tonic-gate * The first symbol table entry must be zeroed and is always ignored. 1800Sstevel@tonic-gate */ 1810Sstevel@tonic-gate bzero(sym, sizeof (Elf32_Sym)); 1820Sstevel@tonic-gate sym++; 1830Sstevel@tonic-gate 1840Sstevel@tonic-gate /* 1850Sstevel@tonic-gate * Take a second pass through the DOF sections filling in the 1860Sstevel@tonic-gate * memory we allocated. 1870Sstevel@tonic-gate */ 1880Sstevel@tonic-gate for (i = 0; i < dof->dofh_secnum; i++) { 1890Sstevel@tonic-gate if (dofs[i].dofs_type != DOF_SECT_URELHDR) 1900Sstevel@tonic-gate continue; 1910Sstevel@tonic-gate 1920Sstevel@tonic-gate /*LINTED*/ 1930Sstevel@tonic-gate dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset); 1940Sstevel@tonic-gate 1950Sstevel@tonic-gate s = &dofs[dofrh->dofr_strtab]; 1960Sstevel@tonic-gate strtab = (char *)dof + s->dofs_offset; 1970Sstevel@tonic-gate bcopy(strtab + 1, dep->de_strtab + strtabsz, s->dofs_size); 1980Sstevel@tonic-gate base = strtabsz; 1990Sstevel@tonic-gate strtabsz += s->dofs_size - 1; 2000Sstevel@tonic-gate 2010Sstevel@tonic-gate s = &dofs[dofrh->dofr_relsec]; 2020Sstevel@tonic-gate /*LINTED*/ 2030Sstevel@tonic-gate dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset); 2040Sstevel@tonic-gate nrel = s->dofs_size / s->dofs_entsize; 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate s = &dofs[dofrh->dofr_tgtsec]; 2070Sstevel@tonic-gate 2080Sstevel@tonic-gate for (j = 0; j < nrel; j++) { 2090Sstevel@tonic-gate #if defined(__i386) || defined(__amd64) 2100Sstevel@tonic-gate rel->r_offset = s->dofs_offset + 2110Sstevel@tonic-gate dofr[j].dofr_offset; 2120Sstevel@tonic-gate rel->r_info = ELF32_R_INFO(count + dep->de_global, 2130Sstevel@tonic-gate R_386_32); 2140Sstevel@tonic-gate #elif defined(__sparc) 2150Sstevel@tonic-gate /* 2160Sstevel@tonic-gate * Add 4 bytes to hit the low half of this 64-bit 2170Sstevel@tonic-gate * big-endian address. 2180Sstevel@tonic-gate */ 2190Sstevel@tonic-gate rel->r_offset = s->dofs_offset + 2200Sstevel@tonic-gate dofr[j].dofr_offset + 4; 2210Sstevel@tonic-gate rel->r_info = ELF32_R_INFO(count + dep->de_global, 2220Sstevel@tonic-gate R_SPARC_32); 2230Sstevel@tonic-gate #else 2240Sstevel@tonic-gate #error unknown ISA 2250Sstevel@tonic-gate #endif 2260Sstevel@tonic-gate 2270Sstevel@tonic-gate sym->st_name = base + dofr[j].dofr_name - 1; 2280Sstevel@tonic-gate sym->st_value = 0; 2290Sstevel@tonic-gate sym->st_size = 0; 2300Sstevel@tonic-gate sym->st_info = ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE); 2310Sstevel@tonic-gate sym->st_other = 0; 2320Sstevel@tonic-gate sym->st_shndx = SHN_UNDEF; 2330Sstevel@tonic-gate 2340Sstevel@tonic-gate rel++; 2350Sstevel@tonic-gate sym++; 2360Sstevel@tonic-gate count++; 2370Sstevel@tonic-gate } 2380Sstevel@tonic-gate } 2390Sstevel@tonic-gate 2400Sstevel@tonic-gate /* 2410Sstevel@tonic-gate * Add a symbol for the DOF itself. We use a different symbol for 2420Sstevel@tonic-gate * lazily and actively loaded DOF to make them easy to distinguish. 2430Sstevel@tonic-gate */ 2440Sstevel@tonic-gate sym->st_name = strtabsz; 2450Sstevel@tonic-gate sym->st_value = 0; 2460Sstevel@tonic-gate sym->st_size = dof->dofh_filesz; 2470Sstevel@tonic-gate sym->st_info = ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT); 2480Sstevel@tonic-gate sym->st_other = 0; 2490Sstevel@tonic-gate sym->st_shndx = ESHDR_DOF; 2500Sstevel@tonic-gate sym++; 2510Sstevel@tonic-gate 2520Sstevel@tonic-gate if (dtp->dt_lazyload) { 2530Sstevel@tonic-gate bcopy(DOFLAZYSTR, dep->de_strtab + strtabsz, 2540Sstevel@tonic-gate sizeof (DOFLAZYSTR)); 2550Sstevel@tonic-gate strtabsz += sizeof (DOFLAZYSTR); 2560Sstevel@tonic-gate } else { 2570Sstevel@tonic-gate bcopy(DOFSTR, dep->de_strtab + strtabsz, sizeof (DOFSTR)); 2580Sstevel@tonic-gate strtabsz += sizeof (DOFSTR); 2590Sstevel@tonic-gate } 2600Sstevel@tonic-gate 2610Sstevel@tonic-gate assert(count == dep->de_nrel); 2620Sstevel@tonic-gate assert(strtabsz == dep->de_strlen); 2630Sstevel@tonic-gate 2640Sstevel@tonic-gate return (0); 2650Sstevel@tonic-gate } 2660Sstevel@tonic-gate 2670Sstevel@tonic-gate 2680Sstevel@tonic-gate typedef struct dof_elf64 { 2690Sstevel@tonic-gate uint32_t de_nrel; 2700Sstevel@tonic-gate Elf64_Rela *de_rel; 2710Sstevel@tonic-gate uint32_t de_nsym; 2720Sstevel@tonic-gate Elf64_Sym *de_sym; 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate uint32_t de_strlen; 2750Sstevel@tonic-gate char *de_strtab; 2760Sstevel@tonic-gate 2770Sstevel@tonic-gate uint32_t de_global; 2780Sstevel@tonic-gate } dof_elf64_t; 2790Sstevel@tonic-gate 2800Sstevel@tonic-gate static int 2810Sstevel@tonic-gate prepare_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf64_t *dep) 2820Sstevel@tonic-gate { 2830Sstevel@tonic-gate dof_sec_t *dofs, *s; 2840Sstevel@tonic-gate dof_relohdr_t *dofrh; 2850Sstevel@tonic-gate dof_relodesc_t *dofr; 2860Sstevel@tonic-gate char *strtab; 2870Sstevel@tonic-gate int i, j, nrel; 2880Sstevel@tonic-gate size_t strtabsz = 1; 2890Sstevel@tonic-gate uint32_t count = 0; 2900Sstevel@tonic-gate size_t base; 2910Sstevel@tonic-gate Elf64_Sym *sym; 2920Sstevel@tonic-gate Elf64_Rela *rel; 2930Sstevel@tonic-gate 2940Sstevel@tonic-gate /*LINTED*/ 2950Sstevel@tonic-gate dofs = (dof_sec_t *)((char *)dof + dof->dofh_secoff); 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate /* 2980Sstevel@tonic-gate * First compute the size of the string table and the number of 2990Sstevel@tonic-gate * relocations present in the DOF. 3000Sstevel@tonic-gate */ 3010Sstevel@tonic-gate for (i = 0; i < dof->dofh_secnum; i++) { 3020Sstevel@tonic-gate if (dofs[i].dofs_type != DOF_SECT_URELHDR) 3030Sstevel@tonic-gate continue; 3040Sstevel@tonic-gate 3050Sstevel@tonic-gate /*LINTED*/ 3060Sstevel@tonic-gate dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset); 3070Sstevel@tonic-gate 3080Sstevel@tonic-gate s = &dofs[dofrh->dofr_strtab]; 3090Sstevel@tonic-gate strtab = (char *)dof + s->dofs_offset; 3100Sstevel@tonic-gate assert(strtab[0] == '\0'); 3110Sstevel@tonic-gate strtabsz += s->dofs_size - 1; 3120Sstevel@tonic-gate 3130Sstevel@tonic-gate s = &dofs[dofrh->dofr_relsec]; 3140Sstevel@tonic-gate /*LINTED*/ 3150Sstevel@tonic-gate dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset); 3160Sstevel@tonic-gate count += s->dofs_size / s->dofs_entsize; 3170Sstevel@tonic-gate } 3180Sstevel@tonic-gate 3190Sstevel@tonic-gate dep->de_strlen = strtabsz; 3200Sstevel@tonic-gate dep->de_nrel = count; 3210Sstevel@tonic-gate dep->de_nsym = count + 1; /* the first symbol is always null */ 3220Sstevel@tonic-gate 3230Sstevel@tonic-gate if (dtp->dt_lazyload) { 3240Sstevel@tonic-gate dep->de_strlen += sizeof (DOFLAZYSTR); 3250Sstevel@tonic-gate dep->de_nsym++; 3260Sstevel@tonic-gate } else { 3270Sstevel@tonic-gate dep->de_strlen += sizeof (DOFSTR); 3280Sstevel@tonic-gate dep->de_nsym++; 3290Sstevel@tonic-gate } 3300Sstevel@tonic-gate 3310Sstevel@tonic-gate if ((dep->de_rel = calloc(dep->de_nrel, 3320Sstevel@tonic-gate sizeof (dep->de_rel[0]))) == NULL) { 3330Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 3340Sstevel@tonic-gate } 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate if ((dep->de_sym = calloc(dep->de_nsym, sizeof (Elf64_Sym))) == NULL) { 3370Sstevel@tonic-gate free(dep->de_rel); 3380Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 3390Sstevel@tonic-gate } 3400Sstevel@tonic-gate 3410Sstevel@tonic-gate if ((dep->de_strtab = calloc(dep->de_strlen, 1)) == NULL) { 3420Sstevel@tonic-gate free(dep->de_rel); 3430Sstevel@tonic-gate free(dep->de_sym); 3440Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 3450Sstevel@tonic-gate } 3460Sstevel@tonic-gate 3470Sstevel@tonic-gate count = 0; 3480Sstevel@tonic-gate strtabsz = 1; 3490Sstevel@tonic-gate dep->de_strtab[0] = '\0'; 3500Sstevel@tonic-gate rel = dep->de_rel; 3510Sstevel@tonic-gate sym = dep->de_sym; 3520Sstevel@tonic-gate dep->de_global = 1; 3530Sstevel@tonic-gate 3540Sstevel@tonic-gate /* 3550Sstevel@tonic-gate * The first symbol table entry must be zeroed and is always ignored. 3560Sstevel@tonic-gate */ 3570Sstevel@tonic-gate bzero(sym, sizeof (Elf64_Sym)); 3580Sstevel@tonic-gate sym++; 3590Sstevel@tonic-gate 3600Sstevel@tonic-gate /* 3610Sstevel@tonic-gate * Take a second pass through the DOF sections filling in the 3620Sstevel@tonic-gate * memory we allocated. 3630Sstevel@tonic-gate */ 3640Sstevel@tonic-gate for (i = 0; i < dof->dofh_secnum; i++) { 3650Sstevel@tonic-gate if (dofs[i].dofs_type != DOF_SECT_URELHDR) 3660Sstevel@tonic-gate continue; 3670Sstevel@tonic-gate 3680Sstevel@tonic-gate /*LINTED*/ 3690Sstevel@tonic-gate dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset); 3700Sstevel@tonic-gate 3710Sstevel@tonic-gate s = &dofs[dofrh->dofr_strtab]; 3720Sstevel@tonic-gate strtab = (char *)dof + s->dofs_offset; 3730Sstevel@tonic-gate bcopy(strtab + 1, dep->de_strtab + strtabsz, s->dofs_size); 3740Sstevel@tonic-gate base = strtabsz; 3750Sstevel@tonic-gate strtabsz += s->dofs_size - 1; 3760Sstevel@tonic-gate 3770Sstevel@tonic-gate s = &dofs[dofrh->dofr_relsec]; 3780Sstevel@tonic-gate /*LINTED*/ 3790Sstevel@tonic-gate dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset); 3800Sstevel@tonic-gate nrel = s->dofs_size / s->dofs_entsize; 3810Sstevel@tonic-gate 3820Sstevel@tonic-gate s = &dofs[dofrh->dofr_tgtsec]; 3830Sstevel@tonic-gate 3840Sstevel@tonic-gate for (j = 0; j < nrel; j++) { 3850Sstevel@tonic-gate #if defined(__i386) || defined(__amd64) 3860Sstevel@tonic-gate rel->r_offset = s->dofs_offset + 3870Sstevel@tonic-gate dofr[j].dofr_offset; 3880Sstevel@tonic-gate rel->r_info = ELF64_R_INFO(count + dep->de_global, 3890Sstevel@tonic-gate R_AMD64_64); 3900Sstevel@tonic-gate #elif defined(__sparc) 3910Sstevel@tonic-gate rel->r_offset = s->dofs_offset + 3920Sstevel@tonic-gate dofr[j].dofr_offset; 3930Sstevel@tonic-gate rel->r_info = ELF64_R_INFO(count + dep->de_global, 3940Sstevel@tonic-gate R_SPARC_64); 3950Sstevel@tonic-gate #else 3960Sstevel@tonic-gate #error unknown ISA 3970Sstevel@tonic-gate #endif 3980Sstevel@tonic-gate 3990Sstevel@tonic-gate sym->st_name = base + dofr[j].dofr_name - 1; 4000Sstevel@tonic-gate sym->st_value = 0; 4010Sstevel@tonic-gate sym->st_size = 0; 4020Sstevel@tonic-gate sym->st_info = ELF64_ST_INFO(STB_GLOBAL, STT_NOTYPE); 4030Sstevel@tonic-gate sym->st_other = 0; 4040Sstevel@tonic-gate sym->st_shndx = SHN_UNDEF; 4050Sstevel@tonic-gate 4060Sstevel@tonic-gate rel++; 4070Sstevel@tonic-gate sym++; 4080Sstevel@tonic-gate count++; 4090Sstevel@tonic-gate } 4100Sstevel@tonic-gate } 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate /* 4130Sstevel@tonic-gate * Add a symbol for the DOF itself. We use a different symbol for 4140Sstevel@tonic-gate * lazily and actively loaded DOF to make them easy to distinguish. 4150Sstevel@tonic-gate */ 4160Sstevel@tonic-gate sym->st_name = strtabsz; 4170Sstevel@tonic-gate sym->st_value = 0; 4180Sstevel@tonic-gate sym->st_size = dof->dofh_filesz; 4190Sstevel@tonic-gate sym->st_info = ELF64_ST_INFO(STB_GLOBAL, STT_OBJECT); 4200Sstevel@tonic-gate sym->st_other = 0; 4210Sstevel@tonic-gate sym->st_shndx = ESHDR_DOF; 4220Sstevel@tonic-gate sym++; 4230Sstevel@tonic-gate 4240Sstevel@tonic-gate if (dtp->dt_lazyload) { 4250Sstevel@tonic-gate bcopy(DOFLAZYSTR, dep->de_strtab + strtabsz, 4260Sstevel@tonic-gate sizeof (DOFLAZYSTR)); 4270Sstevel@tonic-gate strtabsz += sizeof (DOFLAZYSTR); 4280Sstevel@tonic-gate } else { 4290Sstevel@tonic-gate bcopy(DOFSTR, dep->de_strtab + strtabsz, sizeof (DOFSTR)); 4300Sstevel@tonic-gate strtabsz += sizeof (DOFSTR); 4310Sstevel@tonic-gate } 4320Sstevel@tonic-gate 4330Sstevel@tonic-gate assert(count == dep->de_nrel); 4340Sstevel@tonic-gate assert(strtabsz == dep->de_strlen); 4350Sstevel@tonic-gate 4360Sstevel@tonic-gate return (0); 4370Sstevel@tonic-gate } 4380Sstevel@tonic-gate 4390Sstevel@tonic-gate /* 4400Sstevel@tonic-gate * Write out an ELF32 file prologue consisting of a header, section headers, 4410Sstevel@tonic-gate * and a section header string table. The DOF data will follow this prologue 4420Sstevel@tonic-gate * and complete the contents of the given ELF file. 4430Sstevel@tonic-gate */ 4440Sstevel@tonic-gate static int 4450Sstevel@tonic-gate dump_elf32(dtrace_hdl_t *dtp, const dof_hdr_t *dof, int fd) 4460Sstevel@tonic-gate { 4470Sstevel@tonic-gate struct { 4480Sstevel@tonic-gate Elf32_Ehdr ehdr; 4490Sstevel@tonic-gate Elf32_Shdr shdr[ESHDR_NUM]; 4500Sstevel@tonic-gate } elf_file; 4510Sstevel@tonic-gate 4520Sstevel@tonic-gate Elf32_Shdr *shp; 4530Sstevel@tonic-gate Elf32_Off off; 4540Sstevel@tonic-gate dof_elf32_t de; 4550Sstevel@tonic-gate int ret = 0; 4560Sstevel@tonic-gate uint_t nshdr; 4570Sstevel@tonic-gate 4580Sstevel@tonic-gate if (prepare_elf32(dtp, dof, &de) != 0) 4590Sstevel@tonic-gate return (-1); /* errno is set for us */ 4600Sstevel@tonic-gate 4610Sstevel@tonic-gate /* 4620Sstevel@tonic-gate * If there are no relocations, we only need enough sections for 4630Sstevel@tonic-gate * the shstrtab and the DOF. 4640Sstevel@tonic-gate */ 4650Sstevel@tonic-gate nshdr = de.de_nrel == 0 ? ESHDR_SYMTAB + 1 : ESHDR_NUM; 4660Sstevel@tonic-gate 4670Sstevel@tonic-gate bzero(&elf_file, sizeof (elf_file)); 4680Sstevel@tonic-gate 4690Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_MAG0] = ELFMAG0; 4700Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_MAG1] = ELFMAG1; 4710Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_MAG2] = ELFMAG2; 4720Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_MAG3] = ELFMAG3; 4730Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_VERSION] = EV_CURRENT; 4740Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_CLASS] = ELFCLASS32; 4750Sstevel@tonic-gate #if defined(_BIG_ENDIAN) 4760Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2MSB; 4770Sstevel@tonic-gate #elif defined(_LITTLE_ENDIAN) 4780Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2LSB; 4790Sstevel@tonic-gate #endif 4800Sstevel@tonic-gate elf_file.ehdr.e_type = ET_REL; 4810Sstevel@tonic-gate #if defined(__sparc) 4820Sstevel@tonic-gate elf_file.ehdr.e_machine = EM_SPARC; 4830Sstevel@tonic-gate #elif defined(__i386) || defined(__amd64) 4840Sstevel@tonic-gate elf_file.ehdr.e_machine = EM_386; 4850Sstevel@tonic-gate #endif 4860Sstevel@tonic-gate elf_file.ehdr.e_version = EV_CURRENT; 4870Sstevel@tonic-gate elf_file.ehdr.e_shoff = sizeof (Elf32_Ehdr); 4880Sstevel@tonic-gate elf_file.ehdr.e_ehsize = sizeof (Elf32_Ehdr); 4890Sstevel@tonic-gate elf_file.ehdr.e_phentsize = sizeof (Elf32_Phdr); 4900Sstevel@tonic-gate elf_file.ehdr.e_shentsize = sizeof (Elf32_Shdr); 4910Sstevel@tonic-gate elf_file.ehdr.e_shnum = nshdr; 4920Sstevel@tonic-gate elf_file.ehdr.e_shstrndx = ESHDR_SHSTRTAB; 4930Sstevel@tonic-gate off = sizeof (elf_file) + nshdr * sizeof (Elf32_Shdr); 4940Sstevel@tonic-gate 4950Sstevel@tonic-gate shp = &elf_file.shdr[ESHDR_SHSTRTAB]; 4960Sstevel@tonic-gate shp->sh_name = 1; /* DTRACE_SHSTRTAB32[1] = ".shstrtab" */ 4970Sstevel@tonic-gate shp->sh_type = SHT_STRTAB; 4980Sstevel@tonic-gate shp->sh_offset = off; 4990Sstevel@tonic-gate shp->sh_size = sizeof (DTRACE_SHSTRTAB32); 5000Sstevel@tonic-gate shp->sh_addralign = sizeof (char); 5010Sstevel@tonic-gate off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8); 5020Sstevel@tonic-gate 5030Sstevel@tonic-gate shp = &elf_file.shdr[ESHDR_DOF]; 5040Sstevel@tonic-gate shp->sh_name = 11; /* DTRACE_SHSTRTAB32[11] = ".SUNW_dof" */ 5050Sstevel@tonic-gate shp->sh_flags = SHF_ALLOC; 5060Sstevel@tonic-gate shp->sh_type = SHT_SUNW_dof; 5070Sstevel@tonic-gate shp->sh_offset = off; 5080Sstevel@tonic-gate shp->sh_size = dof->dofh_filesz; 5090Sstevel@tonic-gate shp->sh_addralign = 8; 5100Sstevel@tonic-gate off = shp->sh_offset + shp->sh_size; 5110Sstevel@tonic-gate 5120Sstevel@tonic-gate shp = &elf_file.shdr[ESHDR_STRTAB]; 5130Sstevel@tonic-gate shp->sh_name = 21; /* DTRACE_SHSTRTAB32[21] = ".strtab" */ 5140Sstevel@tonic-gate shp->sh_flags = SHF_ALLOC; 5150Sstevel@tonic-gate shp->sh_type = SHT_STRTAB; 5160Sstevel@tonic-gate shp->sh_offset = off; 5170Sstevel@tonic-gate shp->sh_size = de.de_strlen; 5180Sstevel@tonic-gate shp->sh_addralign = sizeof (char); 5190Sstevel@tonic-gate off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 4); 5200Sstevel@tonic-gate 5210Sstevel@tonic-gate shp = &elf_file.shdr[ESHDR_SYMTAB]; 5220Sstevel@tonic-gate shp->sh_name = 29; /* DTRACE_SHSTRTAB32[29] = ".symtab" */ 5230Sstevel@tonic-gate shp->sh_flags = SHF_ALLOC; 5240Sstevel@tonic-gate shp->sh_type = SHT_SYMTAB; 5250Sstevel@tonic-gate shp->sh_entsize = sizeof (Elf32_Sym); 5260Sstevel@tonic-gate shp->sh_link = ESHDR_STRTAB; 5270Sstevel@tonic-gate shp->sh_offset = off; 5280Sstevel@tonic-gate shp->sh_info = de.de_global; 5290Sstevel@tonic-gate shp->sh_size = de.de_nsym * sizeof (Elf32_Sym); 5300Sstevel@tonic-gate shp->sh_addralign = 4; 5310Sstevel@tonic-gate off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 4); 5320Sstevel@tonic-gate 5330Sstevel@tonic-gate if (de.de_nrel == 0) { 5340Sstevel@tonic-gate if (dt_write(dtp, fd, &elf_file, 5350Sstevel@tonic-gate sizeof (elf_file)) != sizeof (elf_file) || 5360Sstevel@tonic-gate PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB32) || 5370Sstevel@tonic-gate PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || 5380Sstevel@tonic-gate PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || 5390Sstevel@tonic-gate PWRITE_SCN(ESHDR_DOF, dof)) { 5400Sstevel@tonic-gate ret = dt_set_errno(dtp, errno); 5410Sstevel@tonic-gate } 5420Sstevel@tonic-gate } else { 5430Sstevel@tonic-gate shp = &elf_file.shdr[ESHDR_REL]; 5440Sstevel@tonic-gate shp->sh_name = 37; /* DTRACE_SHSTRTAB32[37] = ".rel.SUNW_dof" */ 5450Sstevel@tonic-gate shp->sh_flags = SHF_ALLOC; 5460Sstevel@tonic-gate #ifdef __sparc 5470Sstevel@tonic-gate shp->sh_type = SHT_RELA; 5480Sstevel@tonic-gate #else 5490Sstevel@tonic-gate shp->sh_type = SHT_REL; 5500Sstevel@tonic-gate #endif 5510Sstevel@tonic-gate shp->sh_entsize = sizeof (de.de_rel[0]); 5520Sstevel@tonic-gate shp->sh_link = ESHDR_SYMTAB; 5530Sstevel@tonic-gate shp->sh_info = ESHDR_DOF; 5540Sstevel@tonic-gate shp->sh_offset = off; 5550Sstevel@tonic-gate shp->sh_size = de.de_nrel * sizeof (de.de_rel[0]); 5560Sstevel@tonic-gate shp->sh_addralign = 4; 5570Sstevel@tonic-gate 5580Sstevel@tonic-gate if (dt_write(dtp, fd, &elf_file, 5590Sstevel@tonic-gate sizeof (elf_file)) != sizeof (elf_file) || 5600Sstevel@tonic-gate PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB32) || 5610Sstevel@tonic-gate PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || 5620Sstevel@tonic-gate PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || 5630Sstevel@tonic-gate PWRITE_SCN(ESHDR_REL, de.de_rel) || 5640Sstevel@tonic-gate PWRITE_SCN(ESHDR_DOF, dof)) { 5650Sstevel@tonic-gate ret = dt_set_errno(dtp, errno); 5660Sstevel@tonic-gate } 5670Sstevel@tonic-gate } 5680Sstevel@tonic-gate 5690Sstevel@tonic-gate free(de.de_strtab); 5700Sstevel@tonic-gate free(de.de_sym); 5710Sstevel@tonic-gate free(de.de_rel); 5720Sstevel@tonic-gate 5730Sstevel@tonic-gate return (ret); 5740Sstevel@tonic-gate } 5750Sstevel@tonic-gate 5760Sstevel@tonic-gate /* 5770Sstevel@tonic-gate * Write out an ELF64 file prologue consisting of a header, section headers, 5780Sstevel@tonic-gate * and a section header string table. The DOF data will follow this prologue 5790Sstevel@tonic-gate * and complete the contents of the given ELF file. 5800Sstevel@tonic-gate */ 5810Sstevel@tonic-gate static int 5820Sstevel@tonic-gate dump_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, int fd) 5830Sstevel@tonic-gate { 5840Sstevel@tonic-gate struct { 5850Sstevel@tonic-gate Elf64_Ehdr ehdr; 5860Sstevel@tonic-gate Elf64_Shdr shdr[ESHDR_NUM]; 5870Sstevel@tonic-gate } elf_file; 5880Sstevel@tonic-gate 5890Sstevel@tonic-gate Elf64_Shdr *shp; 5900Sstevel@tonic-gate Elf64_Off off; 5910Sstevel@tonic-gate dof_elf64_t de; 5920Sstevel@tonic-gate int ret = 0; 5930Sstevel@tonic-gate uint_t nshdr; 5940Sstevel@tonic-gate 5950Sstevel@tonic-gate if (prepare_elf64(dtp, dof, &de) != 0) 5960Sstevel@tonic-gate return (-1); /* errno is set for us */ 5970Sstevel@tonic-gate 5980Sstevel@tonic-gate /* 5990Sstevel@tonic-gate * If there are no relocations, we only need enough sections for 6000Sstevel@tonic-gate * the shstrtab and the DOF. 6010Sstevel@tonic-gate */ 6020Sstevel@tonic-gate nshdr = de.de_nrel == 0 ? ESHDR_SYMTAB + 1 : ESHDR_NUM; 6030Sstevel@tonic-gate 6040Sstevel@tonic-gate bzero(&elf_file, sizeof (elf_file)); 6050Sstevel@tonic-gate 6060Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_MAG0] = ELFMAG0; 6070Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_MAG1] = ELFMAG1; 6080Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_MAG2] = ELFMAG2; 6090Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_MAG3] = ELFMAG3; 6100Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_VERSION] = EV_CURRENT; 6110Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_CLASS] = ELFCLASS64; 6120Sstevel@tonic-gate #if defined(_BIG_ENDIAN) 6130Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2MSB; 6140Sstevel@tonic-gate #elif defined(_LITTLE_ENDIAN) 6150Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2LSB; 6160Sstevel@tonic-gate #endif 6170Sstevel@tonic-gate elf_file.ehdr.e_type = ET_REL; 6180Sstevel@tonic-gate #if defined(__sparc) 6190Sstevel@tonic-gate elf_file.ehdr.e_machine = EM_SPARCV9; 6200Sstevel@tonic-gate #elif defined(__i386) || defined(__amd64) 6210Sstevel@tonic-gate elf_file.ehdr.e_machine = EM_AMD64; 6220Sstevel@tonic-gate #endif 6230Sstevel@tonic-gate elf_file.ehdr.e_version = EV_CURRENT; 6240Sstevel@tonic-gate elf_file.ehdr.e_shoff = sizeof (Elf64_Ehdr); 6250Sstevel@tonic-gate elf_file.ehdr.e_ehsize = sizeof (Elf64_Ehdr); 6260Sstevel@tonic-gate elf_file.ehdr.e_phentsize = sizeof (Elf64_Phdr); 6270Sstevel@tonic-gate elf_file.ehdr.e_shentsize = sizeof (Elf64_Shdr); 6280Sstevel@tonic-gate elf_file.ehdr.e_shnum = nshdr; 6290Sstevel@tonic-gate elf_file.ehdr.e_shstrndx = ESHDR_SHSTRTAB; 6300Sstevel@tonic-gate off = sizeof (elf_file) + nshdr * sizeof (Elf64_Shdr); 6310Sstevel@tonic-gate 6320Sstevel@tonic-gate shp = &elf_file.shdr[ESHDR_SHSTRTAB]; 6330Sstevel@tonic-gate shp->sh_name = 1; /* DTRACE_SHSTRTAB64[1] = ".shstrtab" */ 6340Sstevel@tonic-gate shp->sh_type = SHT_STRTAB; 6350Sstevel@tonic-gate shp->sh_offset = off; 6360Sstevel@tonic-gate shp->sh_size = sizeof (DTRACE_SHSTRTAB64); 6370Sstevel@tonic-gate shp->sh_addralign = sizeof (char); 6380Sstevel@tonic-gate off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8); 6390Sstevel@tonic-gate 6400Sstevel@tonic-gate shp = &elf_file.shdr[ESHDR_DOF]; 6410Sstevel@tonic-gate shp->sh_name = 11; /* DTRACE_SHSTRTAB64[11] = ".SUNW_dof" */ 6420Sstevel@tonic-gate shp->sh_flags = SHF_ALLOC; 6430Sstevel@tonic-gate shp->sh_type = SHT_SUNW_dof; 6440Sstevel@tonic-gate shp->sh_offset = off; 6450Sstevel@tonic-gate shp->sh_size = dof->dofh_filesz; 6460Sstevel@tonic-gate shp->sh_addralign = 8; 6470Sstevel@tonic-gate off = shp->sh_offset + shp->sh_size; 6480Sstevel@tonic-gate 6490Sstevel@tonic-gate shp = &elf_file.shdr[ESHDR_STRTAB]; 6500Sstevel@tonic-gate shp->sh_name = 21; /* DTRACE_SHSTRTAB64[21] = ".strtab" */ 6510Sstevel@tonic-gate shp->sh_flags = SHF_ALLOC; 6520Sstevel@tonic-gate shp->sh_type = SHT_STRTAB; 6530Sstevel@tonic-gate shp->sh_offset = off; 6540Sstevel@tonic-gate shp->sh_size = de.de_strlen; 6550Sstevel@tonic-gate shp->sh_addralign = sizeof (char); 6560Sstevel@tonic-gate off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8); 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate shp = &elf_file.shdr[ESHDR_SYMTAB]; 6590Sstevel@tonic-gate shp->sh_name = 29; /* DTRACE_SHSTRTAB64[29] = ".symtab" */ 6600Sstevel@tonic-gate shp->sh_flags = SHF_ALLOC; 6610Sstevel@tonic-gate shp->sh_type = SHT_SYMTAB; 6620Sstevel@tonic-gate shp->sh_entsize = sizeof (Elf64_Sym); 6630Sstevel@tonic-gate shp->sh_link = ESHDR_STRTAB; 6640Sstevel@tonic-gate shp->sh_offset = off; 6650Sstevel@tonic-gate shp->sh_info = de.de_global; 6660Sstevel@tonic-gate shp->sh_size = de.de_nsym * sizeof (Elf64_Sym); 6670Sstevel@tonic-gate shp->sh_addralign = 8; 6680Sstevel@tonic-gate off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8); 6690Sstevel@tonic-gate 6700Sstevel@tonic-gate if (de.de_nrel == 0) { 6710Sstevel@tonic-gate if (dt_write(dtp, fd, &elf_file, 6720Sstevel@tonic-gate sizeof (elf_file)) != sizeof (elf_file) || 6730Sstevel@tonic-gate PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB64) || 6740Sstevel@tonic-gate PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || 6750Sstevel@tonic-gate PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || 6760Sstevel@tonic-gate PWRITE_SCN(ESHDR_DOF, dof)) { 6770Sstevel@tonic-gate ret = dt_set_errno(dtp, errno); 6780Sstevel@tonic-gate } 6790Sstevel@tonic-gate } else { 6800Sstevel@tonic-gate shp = &elf_file.shdr[ESHDR_REL]; 6810Sstevel@tonic-gate shp->sh_name = 37; /* DTRACE_SHSTRTAB64[37] = ".rel.SUNW_dof" */ 6820Sstevel@tonic-gate shp->sh_flags = SHF_ALLOC; 6830Sstevel@tonic-gate shp->sh_type = SHT_RELA; 6840Sstevel@tonic-gate shp->sh_entsize = sizeof (de.de_rel[0]); 6850Sstevel@tonic-gate shp->sh_link = ESHDR_SYMTAB; 6860Sstevel@tonic-gate shp->sh_info = ESHDR_DOF; 6870Sstevel@tonic-gate shp->sh_offset = off; 6880Sstevel@tonic-gate shp->sh_size = de.de_nrel * sizeof (de.de_rel[0]); 6890Sstevel@tonic-gate shp->sh_addralign = 8; 6900Sstevel@tonic-gate 6910Sstevel@tonic-gate if (dt_write(dtp, fd, &elf_file, 6920Sstevel@tonic-gate sizeof (elf_file)) != sizeof (elf_file) || 6930Sstevel@tonic-gate PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB64) || 6940Sstevel@tonic-gate PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || 6950Sstevel@tonic-gate PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || 6960Sstevel@tonic-gate PWRITE_SCN(ESHDR_REL, de.de_rel) || 6970Sstevel@tonic-gate PWRITE_SCN(ESHDR_DOF, dof)) { 6980Sstevel@tonic-gate ret = dt_set_errno(dtp, errno); 6990Sstevel@tonic-gate } 7000Sstevel@tonic-gate } 7010Sstevel@tonic-gate 7020Sstevel@tonic-gate free(de.de_strtab); 7030Sstevel@tonic-gate free(de.de_sym); 7040Sstevel@tonic-gate free(de.de_rel); 7050Sstevel@tonic-gate 7060Sstevel@tonic-gate return (ret); 7070Sstevel@tonic-gate } 7080Sstevel@tonic-gate 7090Sstevel@tonic-gate static int 7100Sstevel@tonic-gate dt_symtab_lookup(Elf_Data *data_sym, uintptr_t addr, uint_t shn, GElf_Sym *sym) 7110Sstevel@tonic-gate { 7120Sstevel@tonic-gate int i, ret = -1; 7130Sstevel@tonic-gate GElf_Sym s; 7140Sstevel@tonic-gate 7150Sstevel@tonic-gate for (i = 0; gelf_getsym(data_sym, i, sym) != NULL; i++) { 7160Sstevel@tonic-gate if (GELF_ST_TYPE(sym->st_info) == STT_FUNC && 7170Sstevel@tonic-gate shn == sym->st_shndx && 7180Sstevel@tonic-gate sym->st_value <= addr && 7190Sstevel@tonic-gate addr < sym->st_value + sym->st_size) { 7200Sstevel@tonic-gate if (GELF_ST_BIND(sym->st_info) == STB_GLOBAL) 7210Sstevel@tonic-gate return (0); 7220Sstevel@tonic-gate 7230Sstevel@tonic-gate ret = 0; 7240Sstevel@tonic-gate s = *sym; 7250Sstevel@tonic-gate } 7260Sstevel@tonic-gate } 7270Sstevel@tonic-gate 7280Sstevel@tonic-gate if (ret == 0) 7290Sstevel@tonic-gate *sym = s; 7300Sstevel@tonic-gate return (ret); 7310Sstevel@tonic-gate } 7320Sstevel@tonic-gate 7330Sstevel@tonic-gate #if defined(__sparc) 7340Sstevel@tonic-gate 7350Sstevel@tonic-gate #define DT_OP_RET 0x81c7e008 7360Sstevel@tonic-gate #define DT_OP_NOP 0x01000000 7370Sstevel@tonic-gate #define DT_OP_CALL 0x40000000 7380Sstevel@tonic-gate 7390Sstevel@tonic-gate #define DT_IS_MOV_O7(inst) (((inst) & 0xffffe000) == 0x9e100000) 7400Sstevel@tonic-gate #define DT_IS_RESTORE(inst) (((inst) & 0xc1f80000) == 0x81e80000) 7410Sstevel@tonic-gate #define DT_IS_RETL(inst) (((inst) & 0xfff83fff) == 0x81c02008) 7420Sstevel@tonic-gate 7430Sstevel@tonic-gate #define DT_RS2(inst) ((inst) & 0x1f) 7440Sstevel@tonic-gate #define DT_MAKE_RETL(reg) (0x81c02008 | ((reg) << 14)) 7450Sstevel@tonic-gate 7460Sstevel@tonic-gate static int 7470Sstevel@tonic-gate dt_modtext(char *p, GElf_Rela *rela, uint32_t *off) 7480Sstevel@tonic-gate { 7490Sstevel@tonic-gate uint32_t *ip; 7500Sstevel@tonic-gate 7510Sstevel@tonic-gate if ((rela->r_offset & (sizeof (uint32_t) - 1)) != 0) 7520Sstevel@tonic-gate return (-1); 7530Sstevel@tonic-gate 7540Sstevel@tonic-gate /*LINTED*/ 7550Sstevel@tonic-gate ip = (uint32_t *)(p + rela->r_offset); 7560Sstevel@tonic-gate 7570Sstevel@tonic-gate /* 7580Sstevel@tonic-gate * We only know about some specific relocation types. 7590Sstevel@tonic-gate */ 7600Sstevel@tonic-gate if (GELF_R_TYPE(rela->r_info) != R_SPARC_WDISP30 && 7610Sstevel@tonic-gate GELF_R_TYPE(rela->r_info) != R_SPARC_WPLT30) 7620Sstevel@tonic-gate return (-1); 7630Sstevel@tonic-gate 7640Sstevel@tonic-gate /* 7650Sstevel@tonic-gate * We may have already processed this object file in an earlier 7660Sstevel@tonic-gate * linker invocation in which case we'd expect to see a ret/restore 7670Sstevel@tonic-gate * pair, a retl-like/mov pair or a nop; return success in that case. 7680Sstevel@tonic-gate */ 7690Sstevel@tonic-gate if (DT_IS_RESTORE(ip[1])) { 7700Sstevel@tonic-gate if (ip[0] == DT_OP_RET) { 7710Sstevel@tonic-gate return (0); 7720Sstevel@tonic-gate } 7730Sstevel@tonic-gate } else if (DT_IS_MOV_O7(ip[1])) { 7740Sstevel@tonic-gate if (DT_IS_RETL(ip[0])) { 7750Sstevel@tonic-gate return (0); 7760Sstevel@tonic-gate } 7770Sstevel@tonic-gate } else { 7780Sstevel@tonic-gate if (ip[0] == DT_OP_NOP) { 7790Sstevel@tonic-gate (*off) += sizeof (ip[0]); 7800Sstevel@tonic-gate return (0); 7810Sstevel@tonic-gate } 7820Sstevel@tonic-gate } 7830Sstevel@tonic-gate 7840Sstevel@tonic-gate /* 7850Sstevel@tonic-gate * We only expect call instructions with a displacement of 0. 7860Sstevel@tonic-gate */ 7870Sstevel@tonic-gate if (ip[0] != DT_OP_CALL) { 7880Sstevel@tonic-gate dt_dprintf("found %x instead of a call instruction at %llx\n", 7890Sstevel@tonic-gate ip[0], (u_longlong_t)rela->r_offset); 7900Sstevel@tonic-gate return (-1); 7910Sstevel@tonic-gate } 7920Sstevel@tonic-gate 7930Sstevel@tonic-gate /* 7940Sstevel@tonic-gate * If the call is followed by a restore, it's a tail call so change 7950Sstevel@tonic-gate * the call to a ret. If the call if followed by a mov of a register 7960Sstevel@tonic-gate * into %o7, it's a tail call in leaf context so change the call to 7970Sstevel@tonic-gate * a retl-like instruction that returns to that register value + 8 7980Sstevel@tonic-gate * (rather than the typical %o7 + 8). Otherwise we adjust the offset 7990Sstevel@tonic-gate * to land on what was once the delay slot of the call so we 8000Sstevel@tonic-gate * correctly get all the arguments. 8010Sstevel@tonic-gate */ 8020Sstevel@tonic-gate if (DT_IS_RESTORE(ip[1])) { 8030Sstevel@tonic-gate ip[0] = DT_OP_RET; 8040Sstevel@tonic-gate } else if (DT_IS_MOV_O7(ip[1])) { 8050Sstevel@tonic-gate ip[0] = DT_MAKE_RETL(DT_RS2(ip[1])); 8060Sstevel@tonic-gate } else { 8070Sstevel@tonic-gate ip[0] = DT_OP_NOP; 8080Sstevel@tonic-gate (*off) += sizeof (ip[0]); 8090Sstevel@tonic-gate } 8100Sstevel@tonic-gate 8110Sstevel@tonic-gate return (0); 8120Sstevel@tonic-gate } 8130Sstevel@tonic-gate 8140Sstevel@tonic-gate #elif defined(__i386) || defined(__amd64) 8150Sstevel@tonic-gate 8160Sstevel@tonic-gate #define DT_OP_NOP 0x90 8170Sstevel@tonic-gate #define DT_OP_CALL 0xe8 8180Sstevel@tonic-gate 8190Sstevel@tonic-gate static int 8200Sstevel@tonic-gate dt_modtext(char *p, GElf_Rela *rela, uint32_t *off) 8210Sstevel@tonic-gate { 8220Sstevel@tonic-gate uint8_t *ip = (uint8_t *)(p + rela->r_offset - 1); 8230Sstevel@tonic-gate 8240Sstevel@tonic-gate /* 8250Sstevel@tonic-gate * On x86, the first byte of the instruction is the call opcode and 8260Sstevel@tonic-gate * the next four bytes are the 32-bit address; the relocation is for 8270Sstevel@tonic-gate * the address so we back up one byte to land on the opcode. 8280Sstevel@tonic-gate */ 8290Sstevel@tonic-gate (*off) -= 1; 8300Sstevel@tonic-gate 8310Sstevel@tonic-gate /* 8320Sstevel@tonic-gate * We only know about some specific relocation types. Luckily 8330Sstevel@tonic-gate * these types have the same values on both 32-bit and 64-bit 8340Sstevel@tonic-gate * x86 architectures. 8350Sstevel@tonic-gate */ 8360Sstevel@tonic-gate if (GELF_R_TYPE(rela->r_info) != R_386_PC32 && 8370Sstevel@tonic-gate GELF_R_TYPE(rela->r_info) != R_386_PLT32) 8380Sstevel@tonic-gate return (-1); 8390Sstevel@tonic-gate 8400Sstevel@tonic-gate /* 8410Sstevel@tonic-gate * We may have already processed this object file in an earlier 8420Sstevel@tonic-gate * linker invocation in which case we'd expect to see a bunch 8430Sstevel@tonic-gate * of nops; return success in that case. 8440Sstevel@tonic-gate */ 8450Sstevel@tonic-gate if (ip[0] == DT_OP_NOP && ip[1] == DT_OP_NOP && ip[2] == DT_OP_NOP && 8460Sstevel@tonic-gate ip[3] == DT_OP_NOP && ip[4] == DT_OP_NOP) 8470Sstevel@tonic-gate return (0); 8480Sstevel@tonic-gate 8490Sstevel@tonic-gate /* 8500Sstevel@tonic-gate * We only expect a call instrution with a 32-bit displacement. 8510Sstevel@tonic-gate */ 8520Sstevel@tonic-gate if (ip[0] != DT_OP_CALL) { 8530Sstevel@tonic-gate dt_dprintf("found %x instead of a call instruction at %llx\n", 8540Sstevel@tonic-gate ip[0], (u_longlong_t)rela->r_offset); 8550Sstevel@tonic-gate return (-1); 8560Sstevel@tonic-gate } 8570Sstevel@tonic-gate 8580Sstevel@tonic-gate ip[0] = DT_OP_NOP; 8590Sstevel@tonic-gate ip[1] = DT_OP_NOP; 8600Sstevel@tonic-gate ip[2] = DT_OP_NOP; 8610Sstevel@tonic-gate ip[3] = DT_OP_NOP; 8620Sstevel@tonic-gate ip[4] = DT_OP_NOP; 8630Sstevel@tonic-gate 8640Sstevel@tonic-gate return (0); 8650Sstevel@tonic-gate } 8660Sstevel@tonic-gate 8670Sstevel@tonic-gate #else 8680Sstevel@tonic-gate #error unknown ISA 8690Sstevel@tonic-gate #endif 8700Sstevel@tonic-gate 871*265Smws /*PRINTFLIKE3*/ 8720Sstevel@tonic-gate static int 873*265Smws dt_link_error(dtrace_hdl_t *dtp, Elf *elf, const char *format, ...) 8740Sstevel@tonic-gate { 8750Sstevel@tonic-gate va_list ap; 8760Sstevel@tonic-gate 8770Sstevel@tonic-gate va_start(ap, format); 8780Sstevel@tonic-gate dt_set_errmsg(dtp, NULL, NULL, NULL, 0, format, ap); 8790Sstevel@tonic-gate va_end(ap); 8800Sstevel@tonic-gate 881*265Smws if (elf != NULL) 882*265Smws (void) elf_end(elf); 883*265Smws 8840Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_COMPILER)); 8850Sstevel@tonic-gate } 8860Sstevel@tonic-gate 8870Sstevel@tonic-gate static int 8880Sstevel@tonic-gate process_obj(dtrace_hdl_t *dtp, const char *obj) 8890Sstevel@tonic-gate { 8900Sstevel@tonic-gate static const char dt_prefix[] = "__dtrace_"; 8910Sstevel@tonic-gate int fd, i, ndx, mod = 0; 892*265Smws Elf *elf = NULL; 8930Sstevel@tonic-gate GElf_Ehdr ehdr; 8940Sstevel@tonic-gate Elf_Scn *scn_rel, *scn_sym, *scn_tgt; 8950Sstevel@tonic-gate Elf_Data *data_rel, *data_sym, *data_tgt; 8960Sstevel@tonic-gate GElf_Shdr shdr_rel, shdr_sym, shdr_tgt; 8970Sstevel@tonic-gate GElf_Sym rsym, fsym; 8980Sstevel@tonic-gate GElf_Rela rela; 8990Sstevel@tonic-gate GElf_Rel rel; 9000Sstevel@tonic-gate char *s, *p; 9010Sstevel@tonic-gate char pname[DTRACE_PROVNAMELEN]; 9020Sstevel@tonic-gate dt_provider_t *pvp; 9030Sstevel@tonic-gate dt_probe_t *prp; 9040Sstevel@tonic-gate uint32_t off, eclass, emachine1, emachine2; 9050Sstevel@tonic-gate 9060Sstevel@tonic-gate if ((fd = open64(obj, O_RDWR)) == -1) { 907*265Smws return (dt_link_error(dtp, elf, "failed to open %s: %s", obj, 9080Sstevel@tonic-gate strerror(errno))); 9090Sstevel@tonic-gate } 9100Sstevel@tonic-gate 911*265Smws if ((elf = elf_begin(fd, ELF_C_RDWR, NULL)) == NULL) { 912*265Smws return (dt_link_error(dtp, elf, "failed to process %s: %s", obj, 9130Sstevel@tonic-gate elf_errmsg(elf_errno()))); 9140Sstevel@tonic-gate } 9150Sstevel@tonic-gate 9160Sstevel@tonic-gate switch (elf_kind(elf)) { 9170Sstevel@tonic-gate case ELF_K_ELF: 9180Sstevel@tonic-gate break; 9190Sstevel@tonic-gate case ELF_K_AR: 920*265Smws return (dt_link_error(dtp, elf, "archives are not permitted;" 921*265Smws " use the contents of the archive instead: %s", obj)); 9220Sstevel@tonic-gate default: 923*265Smws return (dt_link_error(dtp, elf, "invalid file type: %s", obj)); 9240Sstevel@tonic-gate } 9250Sstevel@tonic-gate 9260Sstevel@tonic-gate if (gelf_getehdr(elf, &ehdr) == NULL) 927*265Smws return (dt_link_error(dtp, elf, "corrupt file: %s", obj)); 9280Sstevel@tonic-gate 9290Sstevel@tonic-gate if (dtp->dt_oflags & DTRACE_O_LP64) { 9300Sstevel@tonic-gate eclass = ELFCLASS64; 9310Sstevel@tonic-gate #if defined(__sparc) 9320Sstevel@tonic-gate emachine1 = emachine2 = EM_SPARCV9; 9330Sstevel@tonic-gate #elif defined(__i386) || defined(__amd64) 9340Sstevel@tonic-gate emachine1 = emachine2 = EM_AMD64; 9350Sstevel@tonic-gate #endif 9360Sstevel@tonic-gate } else { 9370Sstevel@tonic-gate eclass = ELFCLASS32; 9380Sstevel@tonic-gate #if defined(__sparc) 9390Sstevel@tonic-gate emachine1 = EM_SPARC; 9400Sstevel@tonic-gate emachine2 = EM_SPARC32PLUS; 9410Sstevel@tonic-gate #elif defined(__i386) || defined(__amd64) 9420Sstevel@tonic-gate emachine1 = emachine2 = EM_386; 9430Sstevel@tonic-gate #endif 9440Sstevel@tonic-gate } 9450Sstevel@tonic-gate 946*265Smws if (ehdr.e_ident[EI_CLASS] != eclass) { 947*265Smws return (dt_link_error(dtp, elf, 948*265Smws "incorrect ELF class for object file: %s", obj)); 949*265Smws } 9500Sstevel@tonic-gate 9510Sstevel@tonic-gate if (ehdr.e_machine != emachine1 && ehdr.e_machine != emachine2) 952*265Smws return (dt_link_error(dtp, elf, "incorrect ELF machine type " 953*265Smws "for object file: %s", obj)); 9540Sstevel@tonic-gate 9550Sstevel@tonic-gate scn_rel = NULL; 9560Sstevel@tonic-gate while ((scn_rel = elf_nextscn(elf, scn_rel)) != NULL) { 9570Sstevel@tonic-gate if (gelf_getshdr(scn_rel, &shdr_rel) == NULL) 9580Sstevel@tonic-gate goto err; 9590Sstevel@tonic-gate 9600Sstevel@tonic-gate if (shdr_rel.sh_type != SHT_RELA && shdr_rel.sh_type != SHT_REL) 9610Sstevel@tonic-gate continue; 9620Sstevel@tonic-gate 9630Sstevel@tonic-gate if ((data_rel = elf_getdata(scn_rel, NULL)) == NULL) 9640Sstevel@tonic-gate goto err; 9650Sstevel@tonic-gate 9660Sstevel@tonic-gate if ((scn_sym = elf_getscn(elf, shdr_rel.sh_link)) == NULL || 9670Sstevel@tonic-gate gelf_getshdr(scn_sym, &shdr_sym) == NULL || 9680Sstevel@tonic-gate (data_sym = elf_getdata(scn_sym, NULL)) == NULL) 9690Sstevel@tonic-gate goto err; 9700Sstevel@tonic-gate 9710Sstevel@tonic-gate if ((scn_tgt = elf_getscn(elf, shdr_rel.sh_info)) == NULL || 9720Sstevel@tonic-gate gelf_getshdr(scn_tgt, &shdr_tgt) == NULL || 9730Sstevel@tonic-gate (data_tgt = elf_getdata(scn_tgt, NULL)) == NULL) 9740Sstevel@tonic-gate goto err; 9750Sstevel@tonic-gate 9760Sstevel@tonic-gate for (i = 0; i < shdr_rel.sh_size / shdr_rel.sh_entsize; i++) { 9770Sstevel@tonic-gate 9780Sstevel@tonic-gate if (shdr_rel.sh_type == SHT_RELA) { 9790Sstevel@tonic-gate if (gelf_getrela(data_rel, i, &rela) == NULL) 9800Sstevel@tonic-gate continue; 9810Sstevel@tonic-gate } else { 9820Sstevel@tonic-gate if (gelf_getrel(data_rel, i, &rel) == NULL) 9830Sstevel@tonic-gate continue; 9840Sstevel@tonic-gate rela.r_offset = rel.r_offset; 9850Sstevel@tonic-gate rela.r_info = rel.r_info; 9860Sstevel@tonic-gate rela.r_addend = 0; 9870Sstevel@tonic-gate } 9880Sstevel@tonic-gate 9890Sstevel@tonic-gate ndx = GELF_R_SYM(rela.r_info); 9900Sstevel@tonic-gate 9910Sstevel@tonic-gate if (gelf_getsym(data_sym, ndx, &rsym) == NULL || 9920Sstevel@tonic-gate (s = elf_strptr(elf, shdr_sym.sh_link, 9930Sstevel@tonic-gate rsym.st_name)) == NULL) 9940Sstevel@tonic-gate goto err; 9950Sstevel@tonic-gate 9960Sstevel@tonic-gate if (strncmp(s, dt_prefix, sizeof (dt_prefix) - 1) != 0) 9970Sstevel@tonic-gate continue; 9980Sstevel@tonic-gate 9990Sstevel@tonic-gate if (dt_symtab_lookup(data_sym, rela.r_offset, 10000Sstevel@tonic-gate shdr_rel.sh_info, &fsym) != 0) 10010Sstevel@tonic-gate goto err; 10020Sstevel@tonic-gate 10030Sstevel@tonic-gate s += sizeof (dt_prefix) - 1; 10040Sstevel@tonic-gate if ((p = strstr(s, "___")) == NULL || 10050Sstevel@tonic-gate p - s >= sizeof (pname)) 10060Sstevel@tonic-gate goto err; 10070Sstevel@tonic-gate 10080Sstevel@tonic-gate (void) memcpy(pname, s, p - s); 10090Sstevel@tonic-gate pname[p - s] = '\0'; 10100Sstevel@tonic-gate 10110Sstevel@tonic-gate p = strhyphenate(p + 3); /* strlen("___") */ 10120Sstevel@tonic-gate 10130Sstevel@tonic-gate if ((s = elf_strptr(elf, shdr_sym.sh_link, 10140Sstevel@tonic-gate fsym.st_name)) == NULL) 10150Sstevel@tonic-gate goto err; 10160Sstevel@tonic-gate 10170Sstevel@tonic-gate if ((pvp = dt_provider_lookup(dtp, pname)) == NULL) { 1018*265Smws return (dt_link_error(dtp, elf, 10190Sstevel@tonic-gate "no such provider %s", pname)); 10200Sstevel@tonic-gate } 10210Sstevel@tonic-gate 10220Sstevel@tonic-gate if ((prp = dt_probe_lookup(pvp, p)) == NULL) { 1023*265Smws return (dt_link_error(dtp, elf, 10240Sstevel@tonic-gate "no such probe %s", p)); 10250Sstevel@tonic-gate } 10260Sstevel@tonic-gate 10270Sstevel@tonic-gate assert(fsym.st_value <= rela.r_offset); 10280Sstevel@tonic-gate 10290Sstevel@tonic-gate off = rela.r_offset - fsym.st_value; 10300Sstevel@tonic-gate if (dt_modtext(data_tgt->d_buf, &rela, &off) != 0) 10310Sstevel@tonic-gate goto err; 10320Sstevel@tonic-gate 10330Sstevel@tonic-gate if (dt_probe_define(pvp, prp, s, off) != 0) 10340Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 10350Sstevel@tonic-gate 10360Sstevel@tonic-gate mod = 1; 10370Sstevel@tonic-gate 10380Sstevel@tonic-gate /* 10390Sstevel@tonic-gate * This symbol may already have been marked to 10400Sstevel@tonic-gate * be ignored by another relocation referencing 10410Sstevel@tonic-gate * the same symbol or if this object file has 10420Sstevel@tonic-gate * already been processed by an earlier link 10430Sstevel@tonic-gate * invocation. 10440Sstevel@tonic-gate */ 10450Sstevel@tonic-gate if (rsym.st_shndx != SHN_SUNW_IGNORE) { 10460Sstevel@tonic-gate rsym.st_shndx = SHN_SUNW_IGNORE; 10470Sstevel@tonic-gate (void) gelf_update_sym(data_sym, ndx, &rsym); 10480Sstevel@tonic-gate } 10490Sstevel@tonic-gate } 10500Sstevel@tonic-gate } 10510Sstevel@tonic-gate 10520Sstevel@tonic-gate if (mod && elf_update(elf, ELF_C_WRITE) == -1) 10530Sstevel@tonic-gate goto err; 10540Sstevel@tonic-gate 1055*265Smws (void) elf_end(elf); 10560Sstevel@tonic-gate return (0); 10570Sstevel@tonic-gate 10580Sstevel@tonic-gate err: 1059*265Smws return (dt_link_error(dtp, elf, 10600Sstevel@tonic-gate "an error was encountered while processing %s", obj)); 10610Sstevel@tonic-gate } 10620Sstevel@tonic-gate 10630Sstevel@tonic-gate int 10640Sstevel@tonic-gate dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags, 10650Sstevel@tonic-gate const char *file, int objc, char *const objv[]) 10660Sstevel@tonic-gate { 10670Sstevel@tonic-gate char drti[PATH_MAX]; 10680Sstevel@tonic-gate dof_hdr_t *dof; 1069191Sahl int fd, status, i, cur; 10700Sstevel@tonic-gate char *cmd, tmp; 10710Sstevel@tonic-gate size_t len; 10720Sstevel@tonic-gate int ret = 0; 10730Sstevel@tonic-gate 1074191Sahl /* 1075191Sahl * A NULL program indicates a special use in which we just link 1076191Sahl * together a bunch of object files specified in objv and then 1077191Sahl * unlink(2) those object files. 1078191Sahl */ 1079191Sahl if (pgp == NULL) { 1080191Sahl const char *fmt = "%s -o %s -r"; 1081191Sahl 1082191Sahl len = snprintf(&tmp, 1, fmt, dtp->dt_ld_path, file) + 1; 1083191Sahl 1084191Sahl for (i = 0; i < objc; i++) 1085191Sahl len += strlen(objv[i]) + 1; 1086191Sahl 1087191Sahl cmd = alloca(len); 1088191Sahl 1089191Sahl cur = snprintf(cmd, len, fmt, dtp->dt_ld_path, file); 1090191Sahl 1091191Sahl for (i = 0; i < objc; i++) 1092191Sahl cur += snprintf(cmd + cur, len - cur, " %s", objv[i]); 1093191Sahl 1094191Sahl if ((status = system(cmd)) == -1) { 1095*265Smws return (dt_link_error(dtp, NULL, "failed to run %s: %s", 1096191Sahl dtp->dt_ld_path, strerror(errno))); 1097191Sahl } 1098191Sahl 1099191Sahl if (WIFSIGNALED(status)) { 1100*265Smws return (dt_link_error(dtp, NULL, 1101191Sahl "failed to link %s: %s failed due to signal %d", 1102191Sahl file, dtp->dt_ld_path, WTERMSIG(status))); 1103191Sahl } 1104191Sahl 1105191Sahl if (WEXITSTATUS(status) != 0) { 1106*265Smws return (dt_link_error(dtp, NULL, 1107191Sahl "failed to link %s: %s exited with status %d\n", 1108191Sahl file, dtp->dt_ld_path, WEXITSTATUS(status))); 1109191Sahl } 1110191Sahl 1111191Sahl for (i = 0; i < objc; i++) { 1112191Sahl if (strcmp(objv[i], file) != 0) 1113191Sahl (void) unlink(objv[i]); 1114191Sahl } 1115191Sahl 1116191Sahl return (0); 1117191Sahl } 1118191Sahl 11190Sstevel@tonic-gate for (i = 0; i < objc; i++) { 11200Sstevel@tonic-gate if (process_obj(dtp, objv[i]) != 0) 11210Sstevel@tonic-gate return (-1); /* errno is set for us */ 11220Sstevel@tonic-gate } 11230Sstevel@tonic-gate 11240Sstevel@tonic-gate if ((dof = dtrace_dof_create(dtp, pgp, dflags)) == NULL) 11250Sstevel@tonic-gate return (-1); /* errno is set for us */ 11260Sstevel@tonic-gate 11270Sstevel@tonic-gate /* 11280Sstevel@tonic-gate * Create a temporary file and then unlink it if we're going to 11290Sstevel@tonic-gate * combine it with drti.o later. We can still refer to it in child 11300Sstevel@tonic-gate * processes as /dev/fd/<fd>. 11310Sstevel@tonic-gate */ 11320Sstevel@tonic-gate if ((fd = open64(file, O_RDWR | O_CREAT | O_TRUNC, 0666)) == -1) { 1133*265Smws return (dt_link_error(dtp, NULL, 11340Sstevel@tonic-gate "failed to open %s: %s", file, strerror(errno))); 11350Sstevel@tonic-gate } 11360Sstevel@tonic-gate 11370Sstevel@tonic-gate /* 11380Sstevel@tonic-gate * If -xlinktype=DOF has been selected, just write out the DOF. 11390Sstevel@tonic-gate * Otherwise proceed to the default of generating and linking ELF. 11400Sstevel@tonic-gate */ 11410Sstevel@tonic-gate switch (dtp->dt_linktype) { 11420Sstevel@tonic-gate case DT_LTYP_DOF: 11430Sstevel@tonic-gate if (dt_write(dtp, fd, dof, dof->dofh_filesz) < dof->dofh_filesz) 11440Sstevel@tonic-gate ret = errno; 11450Sstevel@tonic-gate 11460Sstevel@tonic-gate if (close(fd) != 0 && ret == 0) 11470Sstevel@tonic-gate ret = errno; 11480Sstevel@tonic-gate 11490Sstevel@tonic-gate if (ret != 0) { 1150*265Smws return (dt_link_error(dtp, NULL, 11510Sstevel@tonic-gate "failed to write %s: %s", file, strerror(ret))); 11520Sstevel@tonic-gate } 11530Sstevel@tonic-gate 11540Sstevel@tonic-gate return (0); 11550Sstevel@tonic-gate 11560Sstevel@tonic-gate case DT_LTYP_ELF: 11570Sstevel@tonic-gate break; /* fall through to the rest of dtrace_program_link() */ 11580Sstevel@tonic-gate 11590Sstevel@tonic-gate default: 1160*265Smws return (dt_link_error(dtp, NULL, 11610Sstevel@tonic-gate "invalid link type %u\n", dtp->dt_linktype)); 11620Sstevel@tonic-gate } 11630Sstevel@tonic-gate 11640Sstevel@tonic-gate 11650Sstevel@tonic-gate if (!dtp->dt_lazyload) 11660Sstevel@tonic-gate (void) unlink(file); 11670Sstevel@tonic-gate 11680Sstevel@tonic-gate if (dtp->dt_oflags & DTRACE_O_LP64) 11690Sstevel@tonic-gate status = dump_elf64(dtp, dof, fd); 11700Sstevel@tonic-gate else 11710Sstevel@tonic-gate status = dump_elf32(dtp, dof, fd); 11720Sstevel@tonic-gate 11730Sstevel@tonic-gate if (status != 0 || lseek(fd, 0, SEEK_SET) != 0) { 1174*265Smws return (dt_link_error(dtp, NULL, 11750Sstevel@tonic-gate "failed to write %s: %s", file, strerror(errno))); 11760Sstevel@tonic-gate } 11770Sstevel@tonic-gate 11780Sstevel@tonic-gate if (!dtp->dt_lazyload) { 1179191Sahl const char *fmt = "%s -o %s -r -Blocal -Breduce /dev/fd/%d %s"; 1180191Sahl 11810Sstevel@tonic-gate if (dtp->dt_oflags & DTRACE_O_LP64) { 11820Sstevel@tonic-gate (void) snprintf(drti, sizeof (drti), 11830Sstevel@tonic-gate "%s/64/drti.o", _dtrace_libdir); 11840Sstevel@tonic-gate } else { 11850Sstevel@tonic-gate (void) snprintf(drti, sizeof (drti), 11860Sstevel@tonic-gate "%s/drti.o", _dtrace_libdir); 11870Sstevel@tonic-gate } 11880Sstevel@tonic-gate 1189191Sahl len = snprintf(&tmp, 1, fmt, dtp->dt_ld_path, file, fd, 1190191Sahl drti) + 1; 11910Sstevel@tonic-gate 11920Sstevel@tonic-gate cmd = alloca(len); 11930Sstevel@tonic-gate 1194191Sahl (void) snprintf(cmd, len, fmt, dtp->dt_ld_path, file, fd, drti); 11950Sstevel@tonic-gate 11960Sstevel@tonic-gate if ((status = system(cmd)) == -1) { 1197*265Smws ret = dt_link_error(dtp, NULL, "failed to run %s: %s", 11980Sstevel@tonic-gate dtp->dt_ld_path, strerror(errno)); 11990Sstevel@tonic-gate goto done; 12000Sstevel@tonic-gate } 12010Sstevel@tonic-gate 12020Sstevel@tonic-gate (void) close(fd); /* release temporary file */ 12030Sstevel@tonic-gate 12040Sstevel@tonic-gate if (WIFSIGNALED(status)) { 1205*265Smws ret = dt_link_error(dtp, NULL, 12060Sstevel@tonic-gate "failed to link %s: %s failed due to signal %d", 12070Sstevel@tonic-gate file, dtp->dt_ld_path, WTERMSIG(status)); 12080Sstevel@tonic-gate goto done; 12090Sstevel@tonic-gate } 12100Sstevel@tonic-gate 12110Sstevel@tonic-gate if (WEXITSTATUS(status) != 0) { 1212*265Smws ret = dt_link_error(dtp, NULL, 12130Sstevel@tonic-gate "failed to link %s: %s exited with status %d\n", 12140Sstevel@tonic-gate file, dtp->dt_ld_path, WEXITSTATUS(status)); 12150Sstevel@tonic-gate goto done; 12160Sstevel@tonic-gate } 12170Sstevel@tonic-gate } else { 12180Sstevel@tonic-gate (void) close(fd); 12190Sstevel@tonic-gate } 12200Sstevel@tonic-gate 12210Sstevel@tonic-gate done: 12220Sstevel@tonic-gate dtrace_dof_destroy(dtp, dof); 12230Sstevel@tonic-gate return (ret); 12240Sstevel@tonic-gate } 1225