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 51710Sahl * Common Development and Distribution License (the "License"). 61710Sahl * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 211710Sahl 220Sstevel@tonic-gate /* 23*6390Sahl * Copyright 2008 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> 461239Sahl #include <sys/ipc.h> 470Sstevel@tonic-gate 480Sstevel@tonic-gate #include <dt_impl.h> 490Sstevel@tonic-gate #include <dt_provider.h> 501710Sahl #include <dt_program.h> 510Sstevel@tonic-gate #include <dt_string.h> 520Sstevel@tonic-gate 530Sstevel@tonic-gate #define ESHDR_NULL 0 540Sstevel@tonic-gate #define ESHDR_SHSTRTAB 1 550Sstevel@tonic-gate #define ESHDR_DOF 2 560Sstevel@tonic-gate #define ESHDR_STRTAB 3 570Sstevel@tonic-gate #define ESHDR_SYMTAB 4 580Sstevel@tonic-gate #define ESHDR_REL 5 590Sstevel@tonic-gate #define ESHDR_NUM 6 600Sstevel@tonic-gate 610Sstevel@tonic-gate #define PWRITE_SCN(index, data) \ 620Sstevel@tonic-gate (lseek64(fd, (off64_t)elf_file.shdr[(index)].sh_offset, SEEK_SET) != \ 630Sstevel@tonic-gate (off64_t)elf_file.shdr[(index)].sh_offset || \ 640Sstevel@tonic-gate dt_write(dtp, fd, (data), elf_file.shdr[(index)].sh_size) != \ 650Sstevel@tonic-gate elf_file.shdr[(index)].sh_size) 660Sstevel@tonic-gate 670Sstevel@tonic-gate static const char DTRACE_SHSTRTAB32[] = "\0" 680Sstevel@tonic-gate ".shstrtab\0" /* 1 */ 690Sstevel@tonic-gate ".SUNW_dof\0" /* 11 */ 700Sstevel@tonic-gate ".strtab\0" /* 21 */ 710Sstevel@tonic-gate ".symtab\0" /* 29 */ 720Sstevel@tonic-gate #ifdef __sparc 730Sstevel@tonic-gate ".rela.SUNW_dof"; /* 37 */ 740Sstevel@tonic-gate #else 750Sstevel@tonic-gate ".rel.SUNW_dof"; /* 37 */ 760Sstevel@tonic-gate #endif 770Sstevel@tonic-gate 780Sstevel@tonic-gate static const char DTRACE_SHSTRTAB64[] = "\0" 790Sstevel@tonic-gate ".shstrtab\0" /* 1 */ 800Sstevel@tonic-gate ".SUNW_dof\0" /* 11 */ 810Sstevel@tonic-gate ".strtab\0" /* 21 */ 820Sstevel@tonic-gate ".symtab\0" /* 29 */ 830Sstevel@tonic-gate ".rela.SUNW_dof"; /* 37 */ 840Sstevel@tonic-gate 850Sstevel@tonic-gate static const char DOFSTR[] = "__SUNW_dof"; 860Sstevel@tonic-gate static const char DOFLAZYSTR[] = "___SUNW_dof"; 870Sstevel@tonic-gate 881239Sahl typedef struct dt_link_pair { 892769Sahl struct dt_link_pair *dlp_next; /* next pair in linked list */ 902769Sahl void *dlp_str; /* buffer for string table */ 912769Sahl void *dlp_sym; /* buffer for symbol table */ 921239Sahl } dt_link_pair_t; 931239Sahl 940Sstevel@tonic-gate typedef struct dof_elf32 { 952769Sahl uint32_t de_nrel; /* relocation count */ 960Sstevel@tonic-gate #ifdef __sparc 972769Sahl Elf32_Rela *de_rel; /* array of relocations for sparc */ 980Sstevel@tonic-gate #else 992769Sahl Elf32_Rel *de_rel; /* array of relocations for x86 */ 1000Sstevel@tonic-gate #endif 1012769Sahl uint32_t de_nsym; /* symbol count */ 1022769Sahl Elf32_Sym *de_sym; /* array of symbols */ 1032769Sahl uint32_t de_strlen; /* size of of string table */ 1042769Sahl char *de_strtab; /* string table */ 1052769Sahl uint32_t de_global; /* index of the first global symbol */ 1060Sstevel@tonic-gate } dof_elf32_t; 1070Sstevel@tonic-gate 1080Sstevel@tonic-gate static int 1090Sstevel@tonic-gate prepare_elf32(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf32_t *dep) 1100Sstevel@tonic-gate { 1110Sstevel@tonic-gate dof_sec_t *dofs, *s; 1120Sstevel@tonic-gate dof_relohdr_t *dofrh; 1130Sstevel@tonic-gate dof_relodesc_t *dofr; 1140Sstevel@tonic-gate char *strtab; 1150Sstevel@tonic-gate int i, j, nrel; 1160Sstevel@tonic-gate size_t strtabsz = 1; 1170Sstevel@tonic-gate uint32_t count = 0; 1180Sstevel@tonic-gate size_t base; 1190Sstevel@tonic-gate Elf32_Sym *sym; 1200Sstevel@tonic-gate #ifdef __sparc 1210Sstevel@tonic-gate Elf32_Rela *rel; 1220Sstevel@tonic-gate #else 1230Sstevel@tonic-gate Elf32_Rel *rel; 1240Sstevel@tonic-gate #endif 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate /*LINTED*/ 1270Sstevel@tonic-gate dofs = (dof_sec_t *)((char *)dof + dof->dofh_secoff); 1280Sstevel@tonic-gate 1290Sstevel@tonic-gate /* 1300Sstevel@tonic-gate * First compute the size of the string table and the number of 1310Sstevel@tonic-gate * relocations present in the DOF. 1320Sstevel@tonic-gate */ 1330Sstevel@tonic-gate for (i = 0; i < dof->dofh_secnum; i++) { 1340Sstevel@tonic-gate if (dofs[i].dofs_type != DOF_SECT_URELHDR) 1350Sstevel@tonic-gate continue; 1360Sstevel@tonic-gate 1370Sstevel@tonic-gate /*LINTED*/ 1380Sstevel@tonic-gate dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset); 1390Sstevel@tonic-gate 1400Sstevel@tonic-gate s = &dofs[dofrh->dofr_strtab]; 1410Sstevel@tonic-gate strtab = (char *)dof + s->dofs_offset; 1420Sstevel@tonic-gate assert(strtab[0] == '\0'); 1430Sstevel@tonic-gate strtabsz += s->dofs_size - 1; 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate s = &dofs[dofrh->dofr_relsec]; 1460Sstevel@tonic-gate /*LINTED*/ 1470Sstevel@tonic-gate dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset); 1480Sstevel@tonic-gate count += s->dofs_size / s->dofs_entsize; 1490Sstevel@tonic-gate } 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate dep->de_strlen = strtabsz; 1520Sstevel@tonic-gate dep->de_nrel = count; 1530Sstevel@tonic-gate dep->de_nsym = count + 1; /* the first symbol is always null */ 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate if (dtp->dt_lazyload) { 1560Sstevel@tonic-gate dep->de_strlen += sizeof (DOFLAZYSTR); 1570Sstevel@tonic-gate dep->de_nsym++; 1580Sstevel@tonic-gate } else { 1590Sstevel@tonic-gate dep->de_strlen += sizeof (DOFSTR); 1600Sstevel@tonic-gate dep->de_nsym++; 1610Sstevel@tonic-gate } 1620Sstevel@tonic-gate 1630Sstevel@tonic-gate if ((dep->de_rel = calloc(dep->de_nrel, 1640Sstevel@tonic-gate sizeof (dep->de_rel[0]))) == NULL) { 1650Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 1660Sstevel@tonic-gate } 1670Sstevel@tonic-gate 1680Sstevel@tonic-gate if ((dep->de_sym = calloc(dep->de_nsym, sizeof (Elf32_Sym))) == NULL) { 1690Sstevel@tonic-gate free(dep->de_rel); 1700Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 1710Sstevel@tonic-gate } 1720Sstevel@tonic-gate 1730Sstevel@tonic-gate if ((dep->de_strtab = calloc(dep->de_strlen, 1)) == NULL) { 1740Sstevel@tonic-gate free(dep->de_rel); 1750Sstevel@tonic-gate free(dep->de_sym); 1760Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 1770Sstevel@tonic-gate } 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate count = 0; 1800Sstevel@tonic-gate strtabsz = 1; 1810Sstevel@tonic-gate dep->de_strtab[0] = '\0'; 1820Sstevel@tonic-gate rel = dep->de_rel; 1830Sstevel@tonic-gate sym = dep->de_sym; 1840Sstevel@tonic-gate dep->de_global = 1; 1850Sstevel@tonic-gate 1860Sstevel@tonic-gate /* 1870Sstevel@tonic-gate * The first symbol table entry must be zeroed and is always ignored. 1880Sstevel@tonic-gate */ 1890Sstevel@tonic-gate bzero(sym, sizeof (Elf32_Sym)); 1900Sstevel@tonic-gate sym++; 1910Sstevel@tonic-gate 1920Sstevel@tonic-gate /* 1930Sstevel@tonic-gate * Take a second pass through the DOF sections filling in the 1940Sstevel@tonic-gate * memory we allocated. 1950Sstevel@tonic-gate */ 1960Sstevel@tonic-gate for (i = 0; i < dof->dofh_secnum; i++) { 1970Sstevel@tonic-gate if (dofs[i].dofs_type != DOF_SECT_URELHDR) 1980Sstevel@tonic-gate continue; 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate /*LINTED*/ 2010Sstevel@tonic-gate dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset); 2020Sstevel@tonic-gate 2030Sstevel@tonic-gate s = &dofs[dofrh->dofr_strtab]; 2040Sstevel@tonic-gate strtab = (char *)dof + s->dofs_offset; 2050Sstevel@tonic-gate bcopy(strtab + 1, dep->de_strtab + strtabsz, s->dofs_size); 2060Sstevel@tonic-gate base = strtabsz; 2070Sstevel@tonic-gate strtabsz += s->dofs_size - 1; 2080Sstevel@tonic-gate 2090Sstevel@tonic-gate s = &dofs[dofrh->dofr_relsec]; 2100Sstevel@tonic-gate /*LINTED*/ 2110Sstevel@tonic-gate dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset); 2120Sstevel@tonic-gate nrel = s->dofs_size / s->dofs_entsize; 2130Sstevel@tonic-gate 2140Sstevel@tonic-gate s = &dofs[dofrh->dofr_tgtsec]; 2150Sstevel@tonic-gate 2160Sstevel@tonic-gate for (j = 0; j < nrel; j++) { 2170Sstevel@tonic-gate #if defined(__i386) || defined(__amd64) 2180Sstevel@tonic-gate rel->r_offset = s->dofs_offset + 2190Sstevel@tonic-gate dofr[j].dofr_offset; 2200Sstevel@tonic-gate rel->r_info = ELF32_R_INFO(count + dep->de_global, 2210Sstevel@tonic-gate R_386_32); 2220Sstevel@tonic-gate #elif defined(__sparc) 2230Sstevel@tonic-gate /* 2240Sstevel@tonic-gate * Add 4 bytes to hit the low half of this 64-bit 2250Sstevel@tonic-gate * big-endian address. 2260Sstevel@tonic-gate */ 2270Sstevel@tonic-gate rel->r_offset = s->dofs_offset + 2280Sstevel@tonic-gate dofr[j].dofr_offset + 4; 2290Sstevel@tonic-gate rel->r_info = ELF32_R_INFO(count + dep->de_global, 2300Sstevel@tonic-gate R_SPARC_32); 2310Sstevel@tonic-gate #else 2320Sstevel@tonic-gate #error unknown ISA 2330Sstevel@tonic-gate #endif 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate sym->st_name = base + dofr[j].dofr_name - 1; 2360Sstevel@tonic-gate sym->st_value = 0; 2370Sstevel@tonic-gate sym->st_size = 0; 2381239Sahl sym->st_info = ELF32_ST_INFO(STB_GLOBAL, STT_FUNC); 2390Sstevel@tonic-gate sym->st_other = 0; 2400Sstevel@tonic-gate sym->st_shndx = SHN_UNDEF; 2410Sstevel@tonic-gate 2420Sstevel@tonic-gate rel++; 2430Sstevel@tonic-gate sym++; 2440Sstevel@tonic-gate count++; 2450Sstevel@tonic-gate } 2460Sstevel@tonic-gate } 2470Sstevel@tonic-gate 2480Sstevel@tonic-gate /* 2490Sstevel@tonic-gate * Add a symbol for the DOF itself. We use a different symbol for 2500Sstevel@tonic-gate * lazily and actively loaded DOF to make them easy to distinguish. 2510Sstevel@tonic-gate */ 2520Sstevel@tonic-gate sym->st_name = strtabsz; 2530Sstevel@tonic-gate sym->st_value = 0; 2540Sstevel@tonic-gate sym->st_size = dof->dofh_filesz; 2550Sstevel@tonic-gate sym->st_info = ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT); 2560Sstevel@tonic-gate sym->st_other = 0; 2570Sstevel@tonic-gate sym->st_shndx = ESHDR_DOF; 2580Sstevel@tonic-gate sym++; 2590Sstevel@tonic-gate 2600Sstevel@tonic-gate if (dtp->dt_lazyload) { 2610Sstevel@tonic-gate bcopy(DOFLAZYSTR, dep->de_strtab + strtabsz, 2620Sstevel@tonic-gate sizeof (DOFLAZYSTR)); 2630Sstevel@tonic-gate strtabsz += sizeof (DOFLAZYSTR); 2640Sstevel@tonic-gate } else { 2650Sstevel@tonic-gate bcopy(DOFSTR, dep->de_strtab + strtabsz, sizeof (DOFSTR)); 2660Sstevel@tonic-gate strtabsz += sizeof (DOFSTR); 2670Sstevel@tonic-gate } 2680Sstevel@tonic-gate 2690Sstevel@tonic-gate assert(count == dep->de_nrel); 2700Sstevel@tonic-gate assert(strtabsz == dep->de_strlen); 2710Sstevel@tonic-gate 2720Sstevel@tonic-gate return (0); 2730Sstevel@tonic-gate } 2740Sstevel@tonic-gate 2750Sstevel@tonic-gate 2760Sstevel@tonic-gate typedef struct dof_elf64 { 2770Sstevel@tonic-gate uint32_t de_nrel; 2780Sstevel@tonic-gate Elf64_Rela *de_rel; 2790Sstevel@tonic-gate uint32_t de_nsym; 2800Sstevel@tonic-gate Elf64_Sym *de_sym; 2810Sstevel@tonic-gate 2820Sstevel@tonic-gate uint32_t de_strlen; 2830Sstevel@tonic-gate char *de_strtab; 2840Sstevel@tonic-gate 2850Sstevel@tonic-gate uint32_t de_global; 2860Sstevel@tonic-gate } dof_elf64_t; 2870Sstevel@tonic-gate 2880Sstevel@tonic-gate static int 2890Sstevel@tonic-gate prepare_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf64_t *dep) 2900Sstevel@tonic-gate { 2910Sstevel@tonic-gate dof_sec_t *dofs, *s; 2920Sstevel@tonic-gate dof_relohdr_t *dofrh; 2930Sstevel@tonic-gate dof_relodesc_t *dofr; 2940Sstevel@tonic-gate char *strtab; 2950Sstevel@tonic-gate int i, j, nrel; 2960Sstevel@tonic-gate size_t strtabsz = 1; 2970Sstevel@tonic-gate uint32_t count = 0; 2980Sstevel@tonic-gate size_t base; 2990Sstevel@tonic-gate Elf64_Sym *sym; 3000Sstevel@tonic-gate Elf64_Rela *rel; 3010Sstevel@tonic-gate 3020Sstevel@tonic-gate /*LINTED*/ 3030Sstevel@tonic-gate dofs = (dof_sec_t *)((char *)dof + dof->dofh_secoff); 3040Sstevel@tonic-gate 3050Sstevel@tonic-gate /* 3060Sstevel@tonic-gate * First compute the size of the string table and the number of 3070Sstevel@tonic-gate * relocations present in the DOF. 3080Sstevel@tonic-gate */ 3090Sstevel@tonic-gate for (i = 0; i < dof->dofh_secnum; i++) { 3100Sstevel@tonic-gate if (dofs[i].dofs_type != DOF_SECT_URELHDR) 3110Sstevel@tonic-gate continue; 3120Sstevel@tonic-gate 3130Sstevel@tonic-gate /*LINTED*/ 3140Sstevel@tonic-gate dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset); 3150Sstevel@tonic-gate 3160Sstevel@tonic-gate s = &dofs[dofrh->dofr_strtab]; 3170Sstevel@tonic-gate strtab = (char *)dof + s->dofs_offset; 3180Sstevel@tonic-gate assert(strtab[0] == '\0'); 3190Sstevel@tonic-gate strtabsz += s->dofs_size - 1; 3200Sstevel@tonic-gate 3210Sstevel@tonic-gate s = &dofs[dofrh->dofr_relsec]; 3220Sstevel@tonic-gate /*LINTED*/ 3230Sstevel@tonic-gate dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset); 3240Sstevel@tonic-gate count += s->dofs_size / s->dofs_entsize; 3250Sstevel@tonic-gate } 3260Sstevel@tonic-gate 3270Sstevel@tonic-gate dep->de_strlen = strtabsz; 3280Sstevel@tonic-gate dep->de_nrel = count; 3290Sstevel@tonic-gate dep->de_nsym = count + 1; /* the first symbol is always null */ 3300Sstevel@tonic-gate 3310Sstevel@tonic-gate if (dtp->dt_lazyload) { 3320Sstevel@tonic-gate dep->de_strlen += sizeof (DOFLAZYSTR); 3330Sstevel@tonic-gate dep->de_nsym++; 3340Sstevel@tonic-gate } else { 3350Sstevel@tonic-gate dep->de_strlen += sizeof (DOFSTR); 3360Sstevel@tonic-gate dep->de_nsym++; 3370Sstevel@tonic-gate } 3380Sstevel@tonic-gate 3390Sstevel@tonic-gate if ((dep->de_rel = calloc(dep->de_nrel, 3400Sstevel@tonic-gate sizeof (dep->de_rel[0]))) == NULL) { 3410Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 3420Sstevel@tonic-gate } 3430Sstevel@tonic-gate 3440Sstevel@tonic-gate if ((dep->de_sym = calloc(dep->de_nsym, sizeof (Elf64_Sym))) == NULL) { 3450Sstevel@tonic-gate free(dep->de_rel); 3460Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 3470Sstevel@tonic-gate } 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate if ((dep->de_strtab = calloc(dep->de_strlen, 1)) == NULL) { 3500Sstevel@tonic-gate free(dep->de_rel); 3510Sstevel@tonic-gate free(dep->de_sym); 3520Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 3530Sstevel@tonic-gate } 3540Sstevel@tonic-gate 3550Sstevel@tonic-gate count = 0; 3560Sstevel@tonic-gate strtabsz = 1; 3570Sstevel@tonic-gate dep->de_strtab[0] = '\0'; 3580Sstevel@tonic-gate rel = dep->de_rel; 3590Sstevel@tonic-gate sym = dep->de_sym; 3600Sstevel@tonic-gate dep->de_global = 1; 3610Sstevel@tonic-gate 3620Sstevel@tonic-gate /* 3630Sstevel@tonic-gate * The first symbol table entry must be zeroed and is always ignored. 3640Sstevel@tonic-gate */ 3650Sstevel@tonic-gate bzero(sym, sizeof (Elf64_Sym)); 3660Sstevel@tonic-gate sym++; 3670Sstevel@tonic-gate 3680Sstevel@tonic-gate /* 3690Sstevel@tonic-gate * Take a second pass through the DOF sections filling in the 3700Sstevel@tonic-gate * memory we allocated. 3710Sstevel@tonic-gate */ 3720Sstevel@tonic-gate for (i = 0; i < dof->dofh_secnum; i++) { 3730Sstevel@tonic-gate if (dofs[i].dofs_type != DOF_SECT_URELHDR) 3740Sstevel@tonic-gate continue; 3750Sstevel@tonic-gate 3760Sstevel@tonic-gate /*LINTED*/ 3770Sstevel@tonic-gate dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset); 3780Sstevel@tonic-gate 3790Sstevel@tonic-gate s = &dofs[dofrh->dofr_strtab]; 3800Sstevel@tonic-gate strtab = (char *)dof + s->dofs_offset; 3810Sstevel@tonic-gate bcopy(strtab + 1, dep->de_strtab + strtabsz, s->dofs_size); 3820Sstevel@tonic-gate base = strtabsz; 3830Sstevel@tonic-gate strtabsz += s->dofs_size - 1; 3840Sstevel@tonic-gate 3850Sstevel@tonic-gate s = &dofs[dofrh->dofr_relsec]; 3860Sstevel@tonic-gate /*LINTED*/ 3870Sstevel@tonic-gate dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset); 3880Sstevel@tonic-gate nrel = s->dofs_size / s->dofs_entsize; 3890Sstevel@tonic-gate 3900Sstevel@tonic-gate s = &dofs[dofrh->dofr_tgtsec]; 3910Sstevel@tonic-gate 3920Sstevel@tonic-gate for (j = 0; j < nrel; j++) { 3930Sstevel@tonic-gate #if defined(__i386) || defined(__amd64) 3940Sstevel@tonic-gate rel->r_offset = s->dofs_offset + 3950Sstevel@tonic-gate dofr[j].dofr_offset; 3960Sstevel@tonic-gate rel->r_info = ELF64_R_INFO(count + dep->de_global, 3970Sstevel@tonic-gate R_AMD64_64); 3980Sstevel@tonic-gate #elif defined(__sparc) 3990Sstevel@tonic-gate rel->r_offset = s->dofs_offset + 4000Sstevel@tonic-gate dofr[j].dofr_offset; 4010Sstevel@tonic-gate rel->r_info = ELF64_R_INFO(count + dep->de_global, 4020Sstevel@tonic-gate R_SPARC_64); 4030Sstevel@tonic-gate #else 4040Sstevel@tonic-gate #error unknown ISA 4050Sstevel@tonic-gate #endif 4060Sstevel@tonic-gate 4070Sstevel@tonic-gate sym->st_name = base + dofr[j].dofr_name - 1; 4080Sstevel@tonic-gate sym->st_value = 0; 4090Sstevel@tonic-gate sym->st_size = 0; 4101239Sahl sym->st_info = GELF_ST_INFO(STB_GLOBAL, STT_FUNC); 4110Sstevel@tonic-gate sym->st_other = 0; 4120Sstevel@tonic-gate sym->st_shndx = SHN_UNDEF; 4130Sstevel@tonic-gate 4140Sstevel@tonic-gate rel++; 4150Sstevel@tonic-gate sym++; 4160Sstevel@tonic-gate count++; 4170Sstevel@tonic-gate } 4180Sstevel@tonic-gate } 4190Sstevel@tonic-gate 4200Sstevel@tonic-gate /* 4210Sstevel@tonic-gate * Add a symbol for the DOF itself. We use a different symbol for 4220Sstevel@tonic-gate * lazily and actively loaded DOF to make them easy to distinguish. 4230Sstevel@tonic-gate */ 4240Sstevel@tonic-gate sym->st_name = strtabsz; 4250Sstevel@tonic-gate sym->st_value = 0; 4260Sstevel@tonic-gate sym->st_size = dof->dofh_filesz; 4271239Sahl sym->st_info = GELF_ST_INFO(STB_GLOBAL, STT_OBJECT); 4280Sstevel@tonic-gate sym->st_other = 0; 4290Sstevel@tonic-gate sym->st_shndx = ESHDR_DOF; 4300Sstevel@tonic-gate sym++; 4310Sstevel@tonic-gate 4320Sstevel@tonic-gate if (dtp->dt_lazyload) { 4330Sstevel@tonic-gate bcopy(DOFLAZYSTR, dep->de_strtab + strtabsz, 4340Sstevel@tonic-gate sizeof (DOFLAZYSTR)); 4350Sstevel@tonic-gate strtabsz += sizeof (DOFLAZYSTR); 4360Sstevel@tonic-gate } else { 4370Sstevel@tonic-gate bcopy(DOFSTR, dep->de_strtab + strtabsz, sizeof (DOFSTR)); 4380Sstevel@tonic-gate strtabsz += sizeof (DOFSTR); 4390Sstevel@tonic-gate } 4400Sstevel@tonic-gate 4410Sstevel@tonic-gate assert(count == dep->de_nrel); 4420Sstevel@tonic-gate assert(strtabsz == dep->de_strlen); 4430Sstevel@tonic-gate 4440Sstevel@tonic-gate return (0); 4450Sstevel@tonic-gate } 4460Sstevel@tonic-gate 4470Sstevel@tonic-gate /* 4480Sstevel@tonic-gate * Write out an ELF32 file prologue consisting of a header, section headers, 4490Sstevel@tonic-gate * and a section header string table. The DOF data will follow this prologue 4500Sstevel@tonic-gate * and complete the contents of the given ELF file. 4510Sstevel@tonic-gate */ 4520Sstevel@tonic-gate static int 4530Sstevel@tonic-gate dump_elf32(dtrace_hdl_t *dtp, const dof_hdr_t *dof, int fd) 4540Sstevel@tonic-gate { 4550Sstevel@tonic-gate struct { 4560Sstevel@tonic-gate Elf32_Ehdr ehdr; 4570Sstevel@tonic-gate Elf32_Shdr shdr[ESHDR_NUM]; 4580Sstevel@tonic-gate } elf_file; 4590Sstevel@tonic-gate 4600Sstevel@tonic-gate Elf32_Shdr *shp; 4610Sstevel@tonic-gate Elf32_Off off; 4620Sstevel@tonic-gate dof_elf32_t de; 4630Sstevel@tonic-gate int ret = 0; 4640Sstevel@tonic-gate uint_t nshdr; 4650Sstevel@tonic-gate 4660Sstevel@tonic-gate if (prepare_elf32(dtp, dof, &de) != 0) 4670Sstevel@tonic-gate return (-1); /* errno is set for us */ 4680Sstevel@tonic-gate 4690Sstevel@tonic-gate /* 4700Sstevel@tonic-gate * If there are no relocations, we only need enough sections for 4710Sstevel@tonic-gate * the shstrtab and the DOF. 4720Sstevel@tonic-gate */ 4730Sstevel@tonic-gate nshdr = de.de_nrel == 0 ? ESHDR_SYMTAB + 1 : ESHDR_NUM; 4740Sstevel@tonic-gate 4750Sstevel@tonic-gate bzero(&elf_file, sizeof (elf_file)); 4760Sstevel@tonic-gate 4770Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_MAG0] = ELFMAG0; 4780Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_MAG1] = ELFMAG1; 4790Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_MAG2] = ELFMAG2; 4800Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_MAG3] = ELFMAG3; 4810Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_VERSION] = EV_CURRENT; 4820Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_CLASS] = ELFCLASS32; 4830Sstevel@tonic-gate #if defined(_BIG_ENDIAN) 4840Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2MSB; 4850Sstevel@tonic-gate #elif defined(_LITTLE_ENDIAN) 4860Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2LSB; 4870Sstevel@tonic-gate #endif 4880Sstevel@tonic-gate elf_file.ehdr.e_type = ET_REL; 4890Sstevel@tonic-gate #if defined(__sparc) 4900Sstevel@tonic-gate elf_file.ehdr.e_machine = EM_SPARC; 4910Sstevel@tonic-gate #elif defined(__i386) || defined(__amd64) 4920Sstevel@tonic-gate elf_file.ehdr.e_machine = EM_386; 4930Sstevel@tonic-gate #endif 4940Sstevel@tonic-gate elf_file.ehdr.e_version = EV_CURRENT; 4950Sstevel@tonic-gate elf_file.ehdr.e_shoff = sizeof (Elf32_Ehdr); 4960Sstevel@tonic-gate elf_file.ehdr.e_ehsize = sizeof (Elf32_Ehdr); 4970Sstevel@tonic-gate elf_file.ehdr.e_phentsize = sizeof (Elf32_Phdr); 4980Sstevel@tonic-gate elf_file.ehdr.e_shentsize = sizeof (Elf32_Shdr); 4990Sstevel@tonic-gate elf_file.ehdr.e_shnum = nshdr; 5000Sstevel@tonic-gate elf_file.ehdr.e_shstrndx = ESHDR_SHSTRTAB; 5010Sstevel@tonic-gate off = sizeof (elf_file) + nshdr * sizeof (Elf32_Shdr); 5020Sstevel@tonic-gate 5030Sstevel@tonic-gate shp = &elf_file.shdr[ESHDR_SHSTRTAB]; 5040Sstevel@tonic-gate shp->sh_name = 1; /* DTRACE_SHSTRTAB32[1] = ".shstrtab" */ 5050Sstevel@tonic-gate shp->sh_type = SHT_STRTAB; 5060Sstevel@tonic-gate shp->sh_offset = off; 5070Sstevel@tonic-gate shp->sh_size = sizeof (DTRACE_SHSTRTAB32); 5080Sstevel@tonic-gate shp->sh_addralign = sizeof (char); 5090Sstevel@tonic-gate off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8); 5100Sstevel@tonic-gate 5110Sstevel@tonic-gate shp = &elf_file.shdr[ESHDR_DOF]; 5120Sstevel@tonic-gate shp->sh_name = 11; /* DTRACE_SHSTRTAB32[11] = ".SUNW_dof" */ 5130Sstevel@tonic-gate shp->sh_flags = SHF_ALLOC; 5140Sstevel@tonic-gate shp->sh_type = SHT_SUNW_dof; 5150Sstevel@tonic-gate shp->sh_offset = off; 5160Sstevel@tonic-gate shp->sh_size = dof->dofh_filesz; 5170Sstevel@tonic-gate shp->sh_addralign = 8; 5180Sstevel@tonic-gate off = shp->sh_offset + shp->sh_size; 5190Sstevel@tonic-gate 5200Sstevel@tonic-gate shp = &elf_file.shdr[ESHDR_STRTAB]; 5210Sstevel@tonic-gate shp->sh_name = 21; /* DTRACE_SHSTRTAB32[21] = ".strtab" */ 5220Sstevel@tonic-gate shp->sh_flags = SHF_ALLOC; 5230Sstevel@tonic-gate shp->sh_type = SHT_STRTAB; 5240Sstevel@tonic-gate shp->sh_offset = off; 5250Sstevel@tonic-gate shp->sh_size = de.de_strlen; 5260Sstevel@tonic-gate shp->sh_addralign = sizeof (char); 5270Sstevel@tonic-gate off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 4); 5280Sstevel@tonic-gate 5290Sstevel@tonic-gate shp = &elf_file.shdr[ESHDR_SYMTAB]; 5300Sstevel@tonic-gate shp->sh_name = 29; /* DTRACE_SHSTRTAB32[29] = ".symtab" */ 5310Sstevel@tonic-gate shp->sh_flags = SHF_ALLOC; 5320Sstevel@tonic-gate shp->sh_type = SHT_SYMTAB; 5330Sstevel@tonic-gate shp->sh_entsize = sizeof (Elf32_Sym); 5340Sstevel@tonic-gate shp->sh_link = ESHDR_STRTAB; 5350Sstevel@tonic-gate shp->sh_offset = off; 5360Sstevel@tonic-gate shp->sh_info = de.de_global; 5370Sstevel@tonic-gate shp->sh_size = de.de_nsym * sizeof (Elf32_Sym); 5380Sstevel@tonic-gate shp->sh_addralign = 4; 5390Sstevel@tonic-gate off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 4); 5400Sstevel@tonic-gate 5410Sstevel@tonic-gate if (de.de_nrel == 0) { 5420Sstevel@tonic-gate if (dt_write(dtp, fd, &elf_file, 5430Sstevel@tonic-gate sizeof (elf_file)) != sizeof (elf_file) || 5440Sstevel@tonic-gate PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB32) || 5450Sstevel@tonic-gate PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || 5460Sstevel@tonic-gate PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || 5470Sstevel@tonic-gate PWRITE_SCN(ESHDR_DOF, dof)) { 5480Sstevel@tonic-gate ret = dt_set_errno(dtp, errno); 5490Sstevel@tonic-gate } 5500Sstevel@tonic-gate } else { 5510Sstevel@tonic-gate shp = &elf_file.shdr[ESHDR_REL]; 5520Sstevel@tonic-gate shp->sh_name = 37; /* DTRACE_SHSTRTAB32[37] = ".rel.SUNW_dof" */ 5530Sstevel@tonic-gate shp->sh_flags = SHF_ALLOC; 5540Sstevel@tonic-gate #ifdef __sparc 5550Sstevel@tonic-gate shp->sh_type = SHT_RELA; 5560Sstevel@tonic-gate #else 5570Sstevel@tonic-gate shp->sh_type = SHT_REL; 5580Sstevel@tonic-gate #endif 5590Sstevel@tonic-gate shp->sh_entsize = sizeof (de.de_rel[0]); 5600Sstevel@tonic-gate shp->sh_link = ESHDR_SYMTAB; 5610Sstevel@tonic-gate shp->sh_info = ESHDR_DOF; 5620Sstevel@tonic-gate shp->sh_offset = off; 5630Sstevel@tonic-gate shp->sh_size = de.de_nrel * sizeof (de.de_rel[0]); 5640Sstevel@tonic-gate shp->sh_addralign = 4; 5650Sstevel@tonic-gate 5660Sstevel@tonic-gate if (dt_write(dtp, fd, &elf_file, 5670Sstevel@tonic-gate sizeof (elf_file)) != sizeof (elf_file) || 5680Sstevel@tonic-gate PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB32) || 5690Sstevel@tonic-gate PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || 5700Sstevel@tonic-gate PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || 5710Sstevel@tonic-gate PWRITE_SCN(ESHDR_REL, de.de_rel) || 5720Sstevel@tonic-gate PWRITE_SCN(ESHDR_DOF, dof)) { 5730Sstevel@tonic-gate ret = dt_set_errno(dtp, errno); 5740Sstevel@tonic-gate } 5750Sstevel@tonic-gate } 5760Sstevel@tonic-gate 5770Sstevel@tonic-gate free(de.de_strtab); 5780Sstevel@tonic-gate free(de.de_sym); 5790Sstevel@tonic-gate free(de.de_rel); 5800Sstevel@tonic-gate 5810Sstevel@tonic-gate return (ret); 5820Sstevel@tonic-gate } 5830Sstevel@tonic-gate 5840Sstevel@tonic-gate /* 5850Sstevel@tonic-gate * Write out an ELF64 file prologue consisting of a header, section headers, 5860Sstevel@tonic-gate * and a section header string table. The DOF data will follow this prologue 5870Sstevel@tonic-gate * and complete the contents of the given ELF file. 5880Sstevel@tonic-gate */ 5890Sstevel@tonic-gate static int 5900Sstevel@tonic-gate dump_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, int fd) 5910Sstevel@tonic-gate { 5920Sstevel@tonic-gate struct { 5930Sstevel@tonic-gate Elf64_Ehdr ehdr; 5940Sstevel@tonic-gate Elf64_Shdr shdr[ESHDR_NUM]; 5950Sstevel@tonic-gate } elf_file; 5960Sstevel@tonic-gate 5970Sstevel@tonic-gate Elf64_Shdr *shp; 5980Sstevel@tonic-gate Elf64_Off off; 5990Sstevel@tonic-gate dof_elf64_t de; 6000Sstevel@tonic-gate int ret = 0; 6010Sstevel@tonic-gate uint_t nshdr; 6020Sstevel@tonic-gate 6030Sstevel@tonic-gate if (prepare_elf64(dtp, dof, &de) != 0) 6040Sstevel@tonic-gate return (-1); /* errno is set for us */ 6050Sstevel@tonic-gate 6060Sstevel@tonic-gate /* 6070Sstevel@tonic-gate * If there are no relocations, we only need enough sections for 6080Sstevel@tonic-gate * the shstrtab and the DOF. 6090Sstevel@tonic-gate */ 6100Sstevel@tonic-gate nshdr = de.de_nrel == 0 ? ESHDR_SYMTAB + 1 : ESHDR_NUM; 6110Sstevel@tonic-gate 6120Sstevel@tonic-gate bzero(&elf_file, sizeof (elf_file)); 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_MAG0] = ELFMAG0; 6150Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_MAG1] = ELFMAG1; 6160Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_MAG2] = ELFMAG2; 6170Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_MAG3] = ELFMAG3; 6180Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_VERSION] = EV_CURRENT; 6190Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_CLASS] = ELFCLASS64; 6200Sstevel@tonic-gate #if defined(_BIG_ENDIAN) 6210Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2MSB; 6220Sstevel@tonic-gate #elif defined(_LITTLE_ENDIAN) 6230Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2LSB; 6240Sstevel@tonic-gate #endif 6250Sstevel@tonic-gate elf_file.ehdr.e_type = ET_REL; 6260Sstevel@tonic-gate #if defined(__sparc) 6270Sstevel@tonic-gate elf_file.ehdr.e_machine = EM_SPARCV9; 6280Sstevel@tonic-gate #elif defined(__i386) || defined(__amd64) 6290Sstevel@tonic-gate elf_file.ehdr.e_machine = EM_AMD64; 6300Sstevel@tonic-gate #endif 6310Sstevel@tonic-gate elf_file.ehdr.e_version = EV_CURRENT; 6320Sstevel@tonic-gate elf_file.ehdr.e_shoff = sizeof (Elf64_Ehdr); 6330Sstevel@tonic-gate elf_file.ehdr.e_ehsize = sizeof (Elf64_Ehdr); 6340Sstevel@tonic-gate elf_file.ehdr.e_phentsize = sizeof (Elf64_Phdr); 6350Sstevel@tonic-gate elf_file.ehdr.e_shentsize = sizeof (Elf64_Shdr); 6360Sstevel@tonic-gate elf_file.ehdr.e_shnum = nshdr; 6370Sstevel@tonic-gate elf_file.ehdr.e_shstrndx = ESHDR_SHSTRTAB; 6380Sstevel@tonic-gate off = sizeof (elf_file) + nshdr * sizeof (Elf64_Shdr); 6390Sstevel@tonic-gate 6400Sstevel@tonic-gate shp = &elf_file.shdr[ESHDR_SHSTRTAB]; 6410Sstevel@tonic-gate shp->sh_name = 1; /* DTRACE_SHSTRTAB64[1] = ".shstrtab" */ 6420Sstevel@tonic-gate shp->sh_type = SHT_STRTAB; 6430Sstevel@tonic-gate shp->sh_offset = off; 6440Sstevel@tonic-gate shp->sh_size = sizeof (DTRACE_SHSTRTAB64); 6450Sstevel@tonic-gate shp->sh_addralign = sizeof (char); 6460Sstevel@tonic-gate off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8); 6470Sstevel@tonic-gate 6480Sstevel@tonic-gate shp = &elf_file.shdr[ESHDR_DOF]; 6490Sstevel@tonic-gate shp->sh_name = 11; /* DTRACE_SHSTRTAB64[11] = ".SUNW_dof" */ 6500Sstevel@tonic-gate shp->sh_flags = SHF_ALLOC; 6510Sstevel@tonic-gate shp->sh_type = SHT_SUNW_dof; 6520Sstevel@tonic-gate shp->sh_offset = off; 6530Sstevel@tonic-gate shp->sh_size = dof->dofh_filesz; 6540Sstevel@tonic-gate shp->sh_addralign = 8; 6550Sstevel@tonic-gate off = shp->sh_offset + shp->sh_size; 6560Sstevel@tonic-gate 6570Sstevel@tonic-gate shp = &elf_file.shdr[ESHDR_STRTAB]; 6580Sstevel@tonic-gate shp->sh_name = 21; /* DTRACE_SHSTRTAB64[21] = ".strtab" */ 6590Sstevel@tonic-gate shp->sh_flags = SHF_ALLOC; 6600Sstevel@tonic-gate shp->sh_type = SHT_STRTAB; 6610Sstevel@tonic-gate shp->sh_offset = off; 6620Sstevel@tonic-gate shp->sh_size = de.de_strlen; 6630Sstevel@tonic-gate shp->sh_addralign = sizeof (char); 6640Sstevel@tonic-gate off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8); 6650Sstevel@tonic-gate 6660Sstevel@tonic-gate shp = &elf_file.shdr[ESHDR_SYMTAB]; 6670Sstevel@tonic-gate shp->sh_name = 29; /* DTRACE_SHSTRTAB64[29] = ".symtab" */ 6680Sstevel@tonic-gate shp->sh_flags = SHF_ALLOC; 6690Sstevel@tonic-gate shp->sh_type = SHT_SYMTAB; 6700Sstevel@tonic-gate shp->sh_entsize = sizeof (Elf64_Sym); 6710Sstevel@tonic-gate shp->sh_link = ESHDR_STRTAB; 6720Sstevel@tonic-gate shp->sh_offset = off; 6730Sstevel@tonic-gate shp->sh_info = de.de_global; 6740Sstevel@tonic-gate shp->sh_size = de.de_nsym * sizeof (Elf64_Sym); 6750Sstevel@tonic-gate shp->sh_addralign = 8; 6760Sstevel@tonic-gate off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8); 6770Sstevel@tonic-gate 6780Sstevel@tonic-gate if (de.de_nrel == 0) { 6790Sstevel@tonic-gate if (dt_write(dtp, fd, &elf_file, 6800Sstevel@tonic-gate sizeof (elf_file)) != sizeof (elf_file) || 6810Sstevel@tonic-gate PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB64) || 6820Sstevel@tonic-gate PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || 6830Sstevel@tonic-gate PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || 6840Sstevel@tonic-gate PWRITE_SCN(ESHDR_DOF, dof)) { 6850Sstevel@tonic-gate ret = dt_set_errno(dtp, errno); 6860Sstevel@tonic-gate } 6870Sstevel@tonic-gate } else { 6880Sstevel@tonic-gate shp = &elf_file.shdr[ESHDR_REL]; 6890Sstevel@tonic-gate shp->sh_name = 37; /* DTRACE_SHSTRTAB64[37] = ".rel.SUNW_dof" */ 6900Sstevel@tonic-gate shp->sh_flags = SHF_ALLOC; 6910Sstevel@tonic-gate shp->sh_type = SHT_RELA; 6920Sstevel@tonic-gate shp->sh_entsize = sizeof (de.de_rel[0]); 6930Sstevel@tonic-gate shp->sh_link = ESHDR_SYMTAB; 6940Sstevel@tonic-gate shp->sh_info = ESHDR_DOF; 6950Sstevel@tonic-gate shp->sh_offset = off; 6960Sstevel@tonic-gate shp->sh_size = de.de_nrel * sizeof (de.de_rel[0]); 6970Sstevel@tonic-gate shp->sh_addralign = 8; 6980Sstevel@tonic-gate 6990Sstevel@tonic-gate if (dt_write(dtp, fd, &elf_file, 7000Sstevel@tonic-gate sizeof (elf_file)) != sizeof (elf_file) || 7010Sstevel@tonic-gate PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB64) || 7020Sstevel@tonic-gate PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || 7030Sstevel@tonic-gate PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || 7040Sstevel@tonic-gate PWRITE_SCN(ESHDR_REL, de.de_rel) || 7050Sstevel@tonic-gate PWRITE_SCN(ESHDR_DOF, dof)) { 7060Sstevel@tonic-gate ret = dt_set_errno(dtp, errno); 7070Sstevel@tonic-gate } 7080Sstevel@tonic-gate } 7090Sstevel@tonic-gate 7100Sstevel@tonic-gate free(de.de_strtab); 7110Sstevel@tonic-gate free(de.de_sym); 7120Sstevel@tonic-gate free(de.de_rel); 7130Sstevel@tonic-gate 7140Sstevel@tonic-gate return (ret); 7150Sstevel@tonic-gate } 7160Sstevel@tonic-gate 7170Sstevel@tonic-gate static int 7183944Sahl dt_symtab_lookup(Elf_Data *data_sym, int nsym, uintptr_t addr, uint_t shn, 7193944Sahl GElf_Sym *sym) 7200Sstevel@tonic-gate { 7210Sstevel@tonic-gate int i, ret = -1; 7220Sstevel@tonic-gate GElf_Sym s; 7230Sstevel@tonic-gate 7243944Sahl for (i = 0; i < nsym && gelf_getsym(data_sym, i, sym) != NULL; i++) { 7250Sstevel@tonic-gate if (GELF_ST_TYPE(sym->st_info) == STT_FUNC && 7260Sstevel@tonic-gate shn == sym->st_shndx && 7270Sstevel@tonic-gate sym->st_value <= addr && 7280Sstevel@tonic-gate addr < sym->st_value + sym->st_size) { 7290Sstevel@tonic-gate if (GELF_ST_BIND(sym->st_info) == STB_GLOBAL) 7300Sstevel@tonic-gate return (0); 7310Sstevel@tonic-gate 7320Sstevel@tonic-gate ret = 0; 7330Sstevel@tonic-gate s = *sym; 7340Sstevel@tonic-gate } 7350Sstevel@tonic-gate } 7360Sstevel@tonic-gate 7370Sstevel@tonic-gate if (ret == 0) 7380Sstevel@tonic-gate *sym = s; 7390Sstevel@tonic-gate return (ret); 7400Sstevel@tonic-gate } 7410Sstevel@tonic-gate 7420Sstevel@tonic-gate #if defined(__sparc) 7430Sstevel@tonic-gate 7440Sstevel@tonic-gate #define DT_OP_RET 0x81c7e008 7450Sstevel@tonic-gate #define DT_OP_NOP 0x01000000 7460Sstevel@tonic-gate #define DT_OP_CALL 0x40000000 7471710Sahl #define DT_OP_CLR_O0 0x90102000 7480Sstevel@tonic-gate 7490Sstevel@tonic-gate #define DT_IS_MOV_O7(inst) (((inst) & 0xffffe000) == 0x9e100000) 7500Sstevel@tonic-gate #define DT_IS_RESTORE(inst) (((inst) & 0xc1f80000) == 0x81e80000) 7510Sstevel@tonic-gate #define DT_IS_RETL(inst) (((inst) & 0xfff83fff) == 0x81c02008) 7520Sstevel@tonic-gate 7530Sstevel@tonic-gate #define DT_RS2(inst) ((inst) & 0x1f) 7540Sstevel@tonic-gate #define DT_MAKE_RETL(reg) (0x81c02008 | ((reg) << 14)) 7550Sstevel@tonic-gate 7561710Sahl /*ARGSUSED*/ 7570Sstevel@tonic-gate static int 7581710Sahl dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, 7591710Sahl uint32_t *off) 7600Sstevel@tonic-gate { 7610Sstevel@tonic-gate uint32_t *ip; 7620Sstevel@tonic-gate 7630Sstevel@tonic-gate if ((rela->r_offset & (sizeof (uint32_t) - 1)) != 0) 7640Sstevel@tonic-gate return (-1); 7650Sstevel@tonic-gate 7660Sstevel@tonic-gate /*LINTED*/ 7670Sstevel@tonic-gate ip = (uint32_t *)(p + rela->r_offset); 7680Sstevel@tonic-gate 7690Sstevel@tonic-gate /* 7700Sstevel@tonic-gate * We only know about some specific relocation types. 7710Sstevel@tonic-gate */ 7720Sstevel@tonic-gate if (GELF_R_TYPE(rela->r_info) != R_SPARC_WDISP30 && 7730Sstevel@tonic-gate GELF_R_TYPE(rela->r_info) != R_SPARC_WPLT30) 7740Sstevel@tonic-gate return (-1); 7750Sstevel@tonic-gate 7760Sstevel@tonic-gate /* 7771710Sahl * We may have already processed this object file in an earlier linker 7781710Sahl * invocation. Check to see if the present instruction sequence matches 7791710Sahl * the one we would install. 7800Sstevel@tonic-gate */ 7811710Sahl if (isenabled) { 7821710Sahl if (ip[0] == DT_OP_CLR_O0) 7830Sstevel@tonic-gate return (0); 7840Sstevel@tonic-gate } else { 7851710Sahl if (DT_IS_RESTORE(ip[1])) { 7861710Sahl if (ip[0] == DT_OP_RET) 7871710Sahl return (0); 7881710Sahl } else if (DT_IS_MOV_O7(ip[1])) { 7891710Sahl if (DT_IS_RETL(ip[0])) 7901710Sahl return (0); 7911710Sahl } else { 7921710Sahl if (ip[0] == DT_OP_NOP) { 7931710Sahl (*off) += sizeof (ip[0]); 7941710Sahl return (0); 7951710Sahl } 7960Sstevel@tonic-gate } 7970Sstevel@tonic-gate } 7980Sstevel@tonic-gate 7990Sstevel@tonic-gate /* 8000Sstevel@tonic-gate * We only expect call instructions with a displacement of 0. 8010Sstevel@tonic-gate */ 8020Sstevel@tonic-gate if (ip[0] != DT_OP_CALL) { 8030Sstevel@tonic-gate dt_dprintf("found %x instead of a call instruction at %llx\n", 8040Sstevel@tonic-gate ip[0], (u_longlong_t)rela->r_offset); 8050Sstevel@tonic-gate return (-1); 8060Sstevel@tonic-gate } 8070Sstevel@tonic-gate 8081710Sahl if (isenabled) { 8091710Sahl /* 8101710Sahl * It would necessarily indicate incorrect usage if an is- 8111710Sahl * enabled probe were tail-called so flag that as an error. 8121710Sahl * It's also potentially (very) tricky to handle gracefully, 8131710Sahl * but could be done if this were a desired use scenario. 8141710Sahl */ 8151710Sahl if (DT_IS_RESTORE(ip[1]) || DT_IS_MOV_O7(ip[1])) { 8161710Sahl dt_dprintf("tail call to is-enabled probe at %llx\n", 8171710Sahl (u_longlong_t)rela->r_offset); 8181710Sahl return (-1); 8191710Sahl } 8201710Sahl 8211710Sahl ip[0] = DT_OP_CLR_O0; 8220Sstevel@tonic-gate } else { 8231710Sahl /* 8241710Sahl * If the call is followed by a restore, it's a tail call so 8251710Sahl * change the call to a ret. If the call if followed by a mov 8261710Sahl * of a register into %o7, it's a tail call in leaf context 8271710Sahl * so change the call to a retl-like instruction that returns 8281710Sahl * to that register value + 8 (rather than the typical %o7 + 8294685Sahl * 8); the delay slot instruction is left, but should have no 8304685Sahl * effect. Otherwise we change the call to be a nop. In the 8314685Sahl * first and the last case we adjust the offset to land on what 8324685Sahl * was once the delay slot of the call so we correctly get all 8334685Sahl * the arguments as they would have been passed in a normal 8344685Sahl * function call. 8351710Sahl */ 8361710Sahl if (DT_IS_RESTORE(ip[1])) { 8371710Sahl ip[0] = DT_OP_RET; 8384685Sahl (*off) += sizeof (ip[0]); 8391710Sahl } else if (DT_IS_MOV_O7(ip[1])) { 8401710Sahl ip[0] = DT_MAKE_RETL(DT_RS2(ip[1])); 8411710Sahl } else { 8421710Sahl ip[0] = DT_OP_NOP; 8431710Sahl (*off) += sizeof (ip[0]); 8441710Sahl } 8450Sstevel@tonic-gate } 8460Sstevel@tonic-gate 8470Sstevel@tonic-gate return (0); 8480Sstevel@tonic-gate } 8490Sstevel@tonic-gate 8500Sstevel@tonic-gate #elif defined(__i386) || defined(__amd64) 8510Sstevel@tonic-gate 8520Sstevel@tonic-gate #define DT_OP_NOP 0x90 853*6390Sahl #define DT_OP_RET 0xc3 8540Sstevel@tonic-gate #define DT_OP_CALL 0xe8 855*6390Sahl #define DT_OP_JMP32 0xe9 8561710Sahl #define DT_OP_REX_RAX 0x48 8571710Sahl #define DT_OP_XOR_EAX_0 0x33 8581710Sahl #define DT_OP_XOR_EAX_1 0xc0 8590Sstevel@tonic-gate 8600Sstevel@tonic-gate static int 8611710Sahl dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, 8621710Sahl uint32_t *off) 8630Sstevel@tonic-gate { 8640Sstevel@tonic-gate uint8_t *ip = (uint8_t *)(p + rela->r_offset - 1); 865*6390Sahl uint8_t ret; 8660Sstevel@tonic-gate 8670Sstevel@tonic-gate /* 8680Sstevel@tonic-gate * On x86, the first byte of the instruction is the call opcode and 8690Sstevel@tonic-gate * the next four bytes are the 32-bit address; the relocation is for 8701710Sahl * the address operand. We back up the offset to the first byte of 8711710Sahl * the instruction. For is-enabled probes, we later advance the offset 8721710Sahl * so that it hits the first nop in the instruction sequence. 8730Sstevel@tonic-gate */ 8740Sstevel@tonic-gate (*off) -= 1; 8750Sstevel@tonic-gate 8760Sstevel@tonic-gate /* 8770Sstevel@tonic-gate * We only know about some specific relocation types. Luckily 8780Sstevel@tonic-gate * these types have the same values on both 32-bit and 64-bit 8790Sstevel@tonic-gate * x86 architectures. 8800Sstevel@tonic-gate */ 8810Sstevel@tonic-gate if (GELF_R_TYPE(rela->r_info) != R_386_PC32 && 8820Sstevel@tonic-gate GELF_R_TYPE(rela->r_info) != R_386_PLT32) 8830Sstevel@tonic-gate return (-1); 8840Sstevel@tonic-gate 8850Sstevel@tonic-gate /* 8861710Sahl * We may have already processed this object file in an earlier linker 8871710Sahl * invocation. Check to see if the present instruction sequence matches 8881710Sahl * the one we would install. For is-enabled probes, we advance the 889*6390Sahl * offset to the first nop instruction in the sequence to match the 890*6390Sahl * text modification code below. 8910Sstevel@tonic-gate */ 8921710Sahl if (!isenabled) { 893*6390Sahl if ((ip[0] == DT_OP_NOP || ip[0] == DT_OP_RET) && 894*6390Sahl ip[1] == DT_OP_NOP && ip[2] == DT_OP_NOP && 895*6390Sahl ip[3] == DT_OP_NOP && ip[4] == DT_OP_NOP) 8961710Sahl return (0); 8971710Sahl } else if (dtp->dt_oflags & DTRACE_O_LP64) { 8981710Sahl if (ip[0] == DT_OP_REX_RAX && 8991710Sahl ip[1] == DT_OP_XOR_EAX_0 && ip[2] == DT_OP_XOR_EAX_1 && 900*6390Sahl (ip[3] == DT_OP_NOP || ip[3] == DT_OP_RET) && 901*6390Sahl ip[4] == DT_OP_NOP) { 9021710Sahl (*off) += 3; 9031710Sahl return (0); 9041710Sahl } 9051710Sahl } else { 9061710Sahl if (ip[0] == DT_OP_XOR_EAX_0 && ip[1] == DT_OP_XOR_EAX_1 && 907*6390Sahl (ip[2] == DT_OP_NOP || ip[2] == DT_OP_RET) && 908*6390Sahl ip[3] == DT_OP_NOP && ip[4] == DT_OP_NOP) { 9091710Sahl (*off) += 2; 9101710Sahl return (0); 9111710Sahl } 9121710Sahl } 9130Sstevel@tonic-gate 9140Sstevel@tonic-gate /* 915*6390Sahl * We expect either a call instrution with a 32-bit displacement or a 916*6390Sahl * jmp instruction with a 32-bit displacement acting as a tail-call. 9170Sstevel@tonic-gate */ 918*6390Sahl if (ip[0] != DT_OP_CALL && ip[0] != DT_OP_JMP32) { 919*6390Sahl dt_dprintf("found %x instead of a call or jmp instruction at " 920*6390Sahl "%llx\n", ip[0], (u_longlong_t)rela->r_offset); 9210Sstevel@tonic-gate return (-1); 9220Sstevel@tonic-gate } 9230Sstevel@tonic-gate 924*6390Sahl ret = (ip[0] == DT_OP_JMP32) ? DT_OP_RET : DT_OP_NOP; 925*6390Sahl 9261710Sahl /* 9271710Sahl * Establish the instruction sequence -- all nops for probes, and an 9281710Sahl * instruction to clear the return value register (%eax/%rax) followed 9291710Sahl * by nops for is-enabled probes. For is-enabled probes, we advance 9301710Sahl * the offset to the first nop. This isn't stricly necessary but makes 9311710Sahl * for more readable disassembly when the probe is enabled. 9321710Sahl */ 9331710Sahl if (!isenabled) { 934*6390Sahl ip[0] = ret; 9351710Sahl ip[1] = DT_OP_NOP; 9361710Sahl ip[2] = DT_OP_NOP; 9371710Sahl ip[3] = DT_OP_NOP; 9381710Sahl ip[4] = DT_OP_NOP; 9391710Sahl } else if (dtp->dt_oflags & DTRACE_O_LP64) { 9401710Sahl ip[0] = DT_OP_REX_RAX; 9411710Sahl ip[1] = DT_OP_XOR_EAX_0; 9421710Sahl ip[2] = DT_OP_XOR_EAX_1; 943*6390Sahl ip[3] = ret; 9441710Sahl ip[4] = DT_OP_NOP; 9451710Sahl (*off) += 3; 9461710Sahl } else { 9471710Sahl ip[0] = DT_OP_XOR_EAX_0; 9481710Sahl ip[1] = DT_OP_XOR_EAX_1; 949*6390Sahl ip[2] = ret; 9501710Sahl ip[3] = DT_OP_NOP; 9511710Sahl ip[4] = DT_OP_NOP; 9521710Sahl (*off) += 2; 9531710Sahl } 9540Sstevel@tonic-gate 9550Sstevel@tonic-gate return (0); 9560Sstevel@tonic-gate } 9570Sstevel@tonic-gate 9580Sstevel@tonic-gate #else 9590Sstevel@tonic-gate #error unknown ISA 9600Sstevel@tonic-gate #endif 9610Sstevel@tonic-gate 9621239Sahl /*PRINTFLIKE5*/ 9630Sstevel@tonic-gate static int 9641239Sahl dt_link_error(dtrace_hdl_t *dtp, Elf *elf, int fd, dt_link_pair_t *bufs, 9651239Sahl const char *format, ...) 9660Sstevel@tonic-gate { 9670Sstevel@tonic-gate va_list ap; 9681239Sahl dt_link_pair_t *pair; 9690Sstevel@tonic-gate 9700Sstevel@tonic-gate va_start(ap, format); 9710Sstevel@tonic-gate dt_set_errmsg(dtp, NULL, NULL, NULL, 0, format, ap); 9720Sstevel@tonic-gate va_end(ap); 9730Sstevel@tonic-gate 974265Smws if (elf != NULL) 975265Smws (void) elf_end(elf); 976265Smws 9771239Sahl if (fd >= 0) 9781239Sahl (void) close(fd); 9791239Sahl 9801239Sahl while ((pair = bufs) != NULL) { 9811239Sahl bufs = pair->dlp_next; 9821239Sahl dt_free(dtp, pair->dlp_str); 9831239Sahl dt_free(dtp, pair->dlp_sym); 9841239Sahl dt_free(dtp, pair); 9851239Sahl } 9861239Sahl 9870Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_COMPILER)); 9880Sstevel@tonic-gate } 9890Sstevel@tonic-gate 9900Sstevel@tonic-gate static int 9911710Sahl process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp) 9920Sstevel@tonic-gate { 9931710Sahl static const char dt_prefix[] = "__dtrace"; 9941710Sahl static const char dt_enabled[] = "enabled"; 9951239Sahl static const char dt_symprefix[] = "$dtrace"; 9961239Sahl static const char dt_symfmt[] = "%s%d.%s"; 9971710Sahl int fd, i, ndx, eprobe, mod = 0; 998265Smws Elf *elf = NULL; 9990Sstevel@tonic-gate GElf_Ehdr ehdr; 10001239Sahl Elf_Scn *scn_rel, *scn_sym, *scn_str, *scn_tgt; 10011239Sahl Elf_Data *data_rel, *data_sym, *data_str, *data_tgt; 10021239Sahl GElf_Shdr shdr_rel, shdr_sym, shdr_str, shdr_tgt; 10031239Sahl GElf_Sym rsym, fsym, dsym; 10040Sstevel@tonic-gate GElf_Rela rela; 10051239Sahl char *s, *p, *r; 10060Sstevel@tonic-gate char pname[DTRACE_PROVNAMELEN]; 10070Sstevel@tonic-gate dt_provider_t *pvp; 10080Sstevel@tonic-gate dt_probe_t *prp; 10090Sstevel@tonic-gate uint32_t off, eclass, emachine1, emachine2; 10102769Sahl size_t symsize, nsym, isym, istr, len; 10111239Sahl key_t objkey; 10121239Sahl dt_link_pair_t *pair, *bufs = NULL; 10132769Sahl dt_strtab_t *strtab; 10140Sstevel@tonic-gate 10150Sstevel@tonic-gate if ((fd = open64(obj, O_RDWR)) == -1) { 10161239Sahl return (dt_link_error(dtp, elf, fd, bufs, 10171239Sahl "failed to open %s: %s", obj, strerror(errno))); 10180Sstevel@tonic-gate } 10190Sstevel@tonic-gate 1020265Smws if ((elf = elf_begin(fd, ELF_C_RDWR, NULL)) == NULL) { 10211239Sahl return (dt_link_error(dtp, elf, fd, bufs, 10221239Sahl "failed to process %s: %s", obj, elf_errmsg(elf_errno()))); 10230Sstevel@tonic-gate } 10240Sstevel@tonic-gate 10250Sstevel@tonic-gate switch (elf_kind(elf)) { 10260Sstevel@tonic-gate case ELF_K_ELF: 10270Sstevel@tonic-gate break; 10280Sstevel@tonic-gate case ELF_K_AR: 10291239Sahl return (dt_link_error(dtp, elf, fd, bufs, "archives are not " 10301239Sahl "permitted; use the contents of the archive instead: %s", 10311239Sahl obj)); 10320Sstevel@tonic-gate default: 10331239Sahl return (dt_link_error(dtp, elf, fd, bufs, 10341239Sahl "invalid file type: %s", obj)); 10350Sstevel@tonic-gate } 10360Sstevel@tonic-gate 10371239Sahl if (gelf_getehdr(elf, &ehdr) == NULL) { 10381239Sahl return (dt_link_error(dtp, elf, fd, bufs, "corrupt file: %s", 10391239Sahl obj)); 10401239Sahl } 10410Sstevel@tonic-gate 10420Sstevel@tonic-gate if (dtp->dt_oflags & DTRACE_O_LP64) { 10430Sstevel@tonic-gate eclass = ELFCLASS64; 10440Sstevel@tonic-gate #if defined(__sparc) 10450Sstevel@tonic-gate emachine1 = emachine2 = EM_SPARCV9; 10460Sstevel@tonic-gate #elif defined(__i386) || defined(__amd64) 10470Sstevel@tonic-gate emachine1 = emachine2 = EM_AMD64; 10480Sstevel@tonic-gate #endif 10491239Sahl symsize = sizeof (Elf64_Sym); 10500Sstevel@tonic-gate } else { 10510Sstevel@tonic-gate eclass = ELFCLASS32; 10520Sstevel@tonic-gate #if defined(__sparc) 10530Sstevel@tonic-gate emachine1 = EM_SPARC; 10540Sstevel@tonic-gate emachine2 = EM_SPARC32PLUS; 10550Sstevel@tonic-gate #elif defined(__i386) || defined(__amd64) 10560Sstevel@tonic-gate emachine1 = emachine2 = EM_386; 10570Sstevel@tonic-gate #endif 10581239Sahl symsize = sizeof (Elf32_Sym); 10590Sstevel@tonic-gate } 10600Sstevel@tonic-gate 1061265Smws if (ehdr.e_ident[EI_CLASS] != eclass) { 10621239Sahl return (dt_link_error(dtp, elf, fd, bufs, 1063265Smws "incorrect ELF class for object file: %s", obj)); 1064265Smws } 10650Sstevel@tonic-gate 10661239Sahl if (ehdr.e_machine != emachine1 && ehdr.e_machine != emachine2) { 10671239Sahl return (dt_link_error(dtp, elf, fd, bufs, 10681239Sahl "incorrect ELF machine type for object file: %s", obj)); 10691239Sahl } 10701239Sahl 10711239Sahl /* 10721239Sahl * We use this token as a relatively unique handle for this file on the 10731239Sahl * system in order to disambiguate potential conflicts between files of 10741239Sahl * the same name which contain identially named local symbols. 10751239Sahl */ 10761239Sahl if ((objkey = ftok(obj, 0)) == (key_t)-1) { 10771239Sahl return (dt_link_error(dtp, elf, fd, bufs, 10781239Sahl "failed to generate unique key for object file: %s", obj)); 10791239Sahl } 10800Sstevel@tonic-gate 10810Sstevel@tonic-gate scn_rel = NULL; 10820Sstevel@tonic-gate while ((scn_rel = elf_nextscn(elf, scn_rel)) != NULL) { 10830Sstevel@tonic-gate if (gelf_getshdr(scn_rel, &shdr_rel) == NULL) 10840Sstevel@tonic-gate goto err; 10850Sstevel@tonic-gate 10861239Sahl /* 10871239Sahl * Skip any non-relocation sections. 10881239Sahl */ 10890Sstevel@tonic-gate if (shdr_rel.sh_type != SHT_RELA && shdr_rel.sh_type != SHT_REL) 10900Sstevel@tonic-gate continue; 10910Sstevel@tonic-gate 10920Sstevel@tonic-gate if ((data_rel = elf_getdata(scn_rel, NULL)) == NULL) 10930Sstevel@tonic-gate goto err; 10940Sstevel@tonic-gate 10951239Sahl /* 10961239Sahl * Grab the section, section header and section data for the 10971239Sahl * symbol table that this relocation section references. 10981239Sahl */ 10990Sstevel@tonic-gate if ((scn_sym = elf_getscn(elf, shdr_rel.sh_link)) == NULL || 11000Sstevel@tonic-gate gelf_getshdr(scn_sym, &shdr_sym) == NULL || 11010Sstevel@tonic-gate (data_sym = elf_getdata(scn_sym, NULL)) == NULL) 11020Sstevel@tonic-gate goto err; 11030Sstevel@tonic-gate 11041239Sahl /* 11051239Sahl * Ditto for that symbol table's string table. 11061239Sahl */ 11071239Sahl if ((scn_str = elf_getscn(elf, shdr_sym.sh_link)) == NULL || 11081239Sahl gelf_getshdr(scn_str, &shdr_str) == NULL || 11091239Sahl (data_str = elf_getdata(scn_str, NULL)) == NULL) 11101239Sahl goto err; 11111239Sahl 11121239Sahl /* 11131239Sahl * Grab the section, section header and section data for the 11141239Sahl * target section for the relocations. For the relocations 11151239Sahl * we're looking for -- this will typically be the text of the 11161239Sahl * object file. 11171239Sahl */ 11180Sstevel@tonic-gate if ((scn_tgt = elf_getscn(elf, shdr_rel.sh_info)) == NULL || 11190Sstevel@tonic-gate gelf_getshdr(scn_tgt, &shdr_tgt) == NULL || 11200Sstevel@tonic-gate (data_tgt = elf_getdata(scn_tgt, NULL)) == NULL) 11210Sstevel@tonic-gate goto err; 11220Sstevel@tonic-gate 11231239Sahl /* 11241239Sahl * We're looking for relocations to symbols matching this form: 11251239Sahl * 11261710Sahl * __dtrace[enabled]_<prov>___<probe> 11271239Sahl * 11281239Sahl * For the generated object, we need to record the location 11291239Sahl * identified by the relocation, and create a new relocation 11301239Sahl * in the generated object that will be resolved at link time 11311239Sahl * to the location of the function in which the probe is 11321239Sahl * embedded. In the target object, we change the matched symbol 11331239Sahl * so that it will be ignored at link time, and we modify the 11341239Sahl * target (text) section to replace the call instruction with 11351239Sahl * one or more nops. 11361239Sahl * 11371239Sahl * If the function containing the probe is locally scoped 11381239Sahl * (static), we create an alias used by the relocation in the 11391239Sahl * generated object. The alias, a new symbol, will be global 11401239Sahl * (so that the relocation from the generated object can be 11411239Sahl * resolved), and hidden (so that it is converted to a local 11421239Sahl * symbol at link time). Such aliases have this form: 11431239Sahl * 11441239Sahl * $dtrace<key>.<function> 11451239Sahl * 11461239Sahl * We take a first pass through all the relocations to 11472769Sahl * populate our string table and count the number of extra 11482769Sahl * symbols we'll require. 11491239Sahl */ 11502769Sahl strtab = dt_strtab_create(1); 11512769Sahl nsym = 0; 11523944Sahl isym = data_sym->d_size / symsize; 11533944Sahl istr = data_str->d_size; 11542769Sahl 11550Sstevel@tonic-gate for (i = 0; i < shdr_rel.sh_size / shdr_rel.sh_entsize; i++) { 11560Sstevel@tonic-gate 11570Sstevel@tonic-gate if (shdr_rel.sh_type == SHT_RELA) { 11580Sstevel@tonic-gate if (gelf_getrela(data_rel, i, &rela) == NULL) 11590Sstevel@tonic-gate continue; 11600Sstevel@tonic-gate } else { 11611239Sahl GElf_Rel rel; 11621239Sahl if (gelf_getrel(data_rel, i, &rel) == NULL) 11631239Sahl continue; 11641239Sahl rela.r_offset = rel.r_offset; 11651239Sahl rela.r_info = rel.r_info; 11661239Sahl rela.r_addend = 0; 11671239Sahl } 11681239Sahl 11691239Sahl if (gelf_getsym(data_sym, GELF_R_SYM(rela.r_info), 11702769Sahl &rsym) == NULL) { 11712769Sahl dt_strtab_destroy(strtab); 11721239Sahl goto err; 11732769Sahl } 11741239Sahl 11751239Sahl s = (char *)data_str->d_buf + rsym.st_name; 11761239Sahl 11771239Sahl if (strncmp(s, dt_prefix, sizeof (dt_prefix) - 1) != 0) 11781239Sahl continue; 11791239Sahl 11803944Sahl if (dt_symtab_lookup(data_sym, isym, rela.r_offset, 11812769Sahl shdr_rel.sh_info, &fsym) != 0) { 11822769Sahl dt_strtab_destroy(strtab); 11831239Sahl goto err; 11842769Sahl } 11851239Sahl 11861239Sahl if (GELF_ST_BIND(fsym.st_info) != STB_LOCAL) 11871239Sahl continue; 11881239Sahl 11892769Sahl if (fsym.st_name > data_str->d_size) { 11902769Sahl dt_strtab_destroy(strtab); 11911239Sahl goto err; 11922769Sahl } 11931239Sahl 11941239Sahl s = (char *)data_str->d_buf + fsym.st_name; 11951239Sahl 11961239Sahl /* 11971239Sahl * If this symbol isn't of type function, we've really 11981239Sahl * driven off the rails or the object file is corrupt. 11991239Sahl */ 12001239Sahl if (GELF_ST_TYPE(fsym.st_info) != STT_FUNC) { 12012769Sahl dt_strtab_destroy(strtab); 12021239Sahl return (dt_link_error(dtp, elf, fd, bufs, 12031239Sahl "expected %s to be of type function", s)); 12041239Sahl } 12051239Sahl 12062769Sahl len = snprintf(NULL, 0, dt_symfmt, dt_symprefix, 12072769Sahl objkey, s) + 1; 12082769Sahl if ((p = dt_alloc(dtp, len)) == NULL) { 12092769Sahl dt_strtab_destroy(strtab); 12102769Sahl goto err; 12112769Sahl } 12122769Sahl (void) snprintf(p, len, dt_symfmt, dt_symprefix, 12132769Sahl objkey, s); 12142769Sahl 12152769Sahl if (dt_strtab_index(strtab, p) == -1) { 12162769Sahl nsym++; 12172769Sahl (void) dt_strtab_insert(strtab, p); 12182769Sahl } 12192769Sahl 12202769Sahl dt_free(dtp, p); 12211239Sahl } 12221239Sahl 12231239Sahl /* 12241239Sahl * If needed, allocate the additional space for the symbol 12251239Sahl * table and string table copying the old data into the new 12261239Sahl * buffers, and marking the buffers as dirty. We inject those 12271239Sahl * newly allocated buffers into the libelf data structures, but 12281239Sahl * are still responsible for freeing them once we're done with 12291239Sahl * the elf handle. 12301239Sahl */ 12312769Sahl if (nsym > 0) { 12322769Sahl /* 12332769Sahl * The first byte of the string table is reserved for 12342769Sahl * the \0 entry. 12352769Sahl */ 12362769Sahl len = dt_strtab_size(strtab) - 1; 12372769Sahl 12382769Sahl assert(len > 0); 12392769Sahl assert(dt_strtab_index(strtab, "") == 0); 12402769Sahl 12412769Sahl dt_strtab_destroy(strtab); 12421239Sahl 12431239Sahl if ((pair = dt_alloc(dtp, sizeof (*pair))) == NULL) 12441239Sahl goto err; 12451239Sahl 12461239Sahl if ((pair->dlp_str = dt_alloc(dtp, data_str->d_size + 12472769Sahl len)) == NULL) { 12481239Sahl dt_free(dtp, pair); 12491239Sahl goto err; 12501239Sahl } 12511239Sahl 12521239Sahl if ((pair->dlp_sym = dt_alloc(dtp, data_sym->d_size + 12532769Sahl nsym * symsize)) == NULL) { 12541239Sahl dt_free(dtp, pair->dlp_str); 12551239Sahl dt_free(dtp, pair); 12561239Sahl goto err; 12571239Sahl } 12581239Sahl 12591239Sahl pair->dlp_next = bufs; 12601239Sahl bufs = pair; 12611239Sahl 12621239Sahl bcopy(data_str->d_buf, pair->dlp_str, data_str->d_size); 12631239Sahl data_str->d_buf = pair->dlp_str; 12642769Sahl data_str->d_size += len; 12651239Sahl (void) elf_flagdata(data_str, ELF_C_SET, ELF_F_DIRTY); 12661239Sahl 12672769Sahl shdr_str.sh_size += len; 12681239Sahl (void) gelf_update_shdr(scn_str, &shdr_str); 12691239Sahl 12701239Sahl bcopy(data_sym->d_buf, pair->dlp_sym, data_sym->d_size); 12711239Sahl data_sym->d_buf = pair->dlp_sym; 12722769Sahl data_sym->d_size += nsym * symsize; 12731239Sahl (void) elf_flagdata(data_sym, ELF_C_SET, ELF_F_DIRTY); 12741239Sahl 12752769Sahl shdr_sym.sh_size += nsym * symsize; 12761239Sahl (void) gelf_update_shdr(scn_sym, &shdr_sym); 12772769Sahl 12782769Sahl nsym += isym; 12792769Sahl } else { 12802769Sahl dt_strtab_destroy(strtab); 12811239Sahl } 12821239Sahl 12831239Sahl /* 12841239Sahl * Now that the tables have been allocated, perform the 12851239Sahl * modifications described above. 12861239Sahl */ 12871239Sahl for (i = 0; i < shdr_rel.sh_size / shdr_rel.sh_entsize; i++) { 12881239Sahl 12891239Sahl if (shdr_rel.sh_type == SHT_RELA) { 12901239Sahl if (gelf_getrela(data_rel, i, &rela) == NULL) 12911239Sahl continue; 12921239Sahl } else { 12931239Sahl GElf_Rel rel; 12940Sstevel@tonic-gate if (gelf_getrel(data_rel, i, &rel) == NULL) 12950Sstevel@tonic-gate continue; 12960Sstevel@tonic-gate rela.r_offset = rel.r_offset; 12970Sstevel@tonic-gate rela.r_info = rel.r_info; 12980Sstevel@tonic-gate rela.r_addend = 0; 12990Sstevel@tonic-gate } 13000Sstevel@tonic-gate 13010Sstevel@tonic-gate ndx = GELF_R_SYM(rela.r_info); 13020Sstevel@tonic-gate 13030Sstevel@tonic-gate if (gelf_getsym(data_sym, ndx, &rsym) == NULL || 13041239Sahl rsym.st_name > data_str->d_size) 13050Sstevel@tonic-gate goto err; 13060Sstevel@tonic-gate 13071239Sahl s = (char *)data_str->d_buf + rsym.st_name; 13081239Sahl 13090Sstevel@tonic-gate if (strncmp(s, dt_prefix, sizeof (dt_prefix) - 1) != 0) 13100Sstevel@tonic-gate continue; 13110Sstevel@tonic-gate 13120Sstevel@tonic-gate s += sizeof (dt_prefix) - 1; 13131710Sahl 13141710Sahl /* 13151710Sahl * Check to see if this is an 'is-enabled' check as 13161710Sahl * opposed to a normal probe. 13171710Sahl */ 13181710Sahl if (strncmp(s, dt_enabled, 13191710Sahl sizeof (dt_enabled) - 1) == 0) { 13201710Sahl s += sizeof (dt_enabled) - 1; 13211710Sahl eprobe = 1; 13221710Sahl *eprobesp = 1; 13231710Sahl dt_dprintf("is-enabled probe\n"); 13241710Sahl } else { 13251710Sahl eprobe = 0; 13261710Sahl dt_dprintf("normal probe\n"); 13271710Sahl } 13281710Sahl 13291710Sahl if (*s++ != '_') 13301710Sahl goto err; 13311710Sahl 13320Sstevel@tonic-gate if ((p = strstr(s, "___")) == NULL || 13330Sstevel@tonic-gate p - s >= sizeof (pname)) 13340Sstevel@tonic-gate goto err; 13350Sstevel@tonic-gate 13361239Sahl bcopy(s, pname, p - s); 13370Sstevel@tonic-gate pname[p - s] = '\0'; 13380Sstevel@tonic-gate 13390Sstevel@tonic-gate p = strhyphenate(p + 3); /* strlen("___") */ 13400Sstevel@tonic-gate 13413944Sahl if (dt_symtab_lookup(data_sym, isym, rela.r_offset, 13421239Sahl shdr_rel.sh_info, &fsym) != 0) 13431239Sahl goto err; 13441239Sahl 13451239Sahl if (fsym.st_name > data_str->d_size) 13460Sstevel@tonic-gate goto err; 13470Sstevel@tonic-gate 13481239Sahl assert(GELF_ST_TYPE(fsym.st_info) == STT_FUNC); 13491239Sahl 13501239Sahl /* 13511239Sahl * If a NULL relocation name is passed to 13521239Sahl * dt_probe_define(), the function name is used for the 13531239Sahl * relocation. The relocation needs to use a mangled 13541239Sahl * name if the symbol is locally scoped; the function 13551239Sahl * name may need to change if we've found the global 13561239Sahl * alias for the locally scoped symbol (we prefer 13571239Sahl * global symbols to locals in dt_symtab_lookup()). 13581239Sahl */ 13591239Sahl s = (char *)data_str->d_buf + fsym.st_name; 13601239Sahl r = NULL; 13611239Sahl 13621239Sahl if (GELF_ST_BIND(fsym.st_info) == STB_LOCAL) { 13631239Sahl dsym = fsym; 13642769Sahl dsym.st_name = istr; 13651239Sahl dsym.st_info = GELF_ST_INFO(STB_GLOBAL, 13661239Sahl STT_FUNC); 13675483Sahl dsym.st_other = 13685483Sahl ELF64_ST_VISIBILITY(STV_ELIMINATE); 13692769Sahl (void) gelf_update_sym(data_sym, isym, &dsym); 13701239Sahl 13712769Sahl r = (char *)data_str->d_buf + istr; 13722769Sahl istr += 1 + sprintf(r, dt_symfmt, 13731239Sahl dt_symprefix, objkey, s); 13742769Sahl isym++; 13752769Sahl assert(isym <= nsym); 13761239Sahl 13771239Sahl } else if (strncmp(s, dt_symprefix, 13781239Sahl strlen(dt_symprefix)) == 0) { 13791239Sahl r = s; 13801239Sahl if ((s = strchr(s, '.')) == NULL) 13811239Sahl goto err; 13821239Sahl s++; 13831239Sahl } 13841239Sahl 13850Sstevel@tonic-gate if ((pvp = dt_provider_lookup(dtp, pname)) == NULL) { 13861239Sahl return (dt_link_error(dtp, elf, fd, bufs, 13870Sstevel@tonic-gate "no such provider %s", pname)); 13880Sstevel@tonic-gate } 13890Sstevel@tonic-gate 13900Sstevel@tonic-gate if ((prp = dt_probe_lookup(pvp, p)) == NULL) { 13911239Sahl return (dt_link_error(dtp, elf, fd, bufs, 13920Sstevel@tonic-gate "no such probe %s", p)); 13930Sstevel@tonic-gate } 13940Sstevel@tonic-gate 13950Sstevel@tonic-gate assert(fsym.st_value <= rela.r_offset); 13960Sstevel@tonic-gate 13970Sstevel@tonic-gate off = rela.r_offset - fsym.st_value; 13981710Sahl if (dt_modtext(dtp, data_tgt->d_buf, eprobe, 13991710Sahl &rela, &off) != 0) { 14000Sstevel@tonic-gate goto err; 14011710Sahl } 14020Sstevel@tonic-gate 14031710Sahl if (dt_probe_define(pvp, prp, s, r, off, eprobe) != 0) { 14041239Sahl return (dt_link_error(dtp, elf, fd, bufs, 14051239Sahl "failed to allocate space for probe")); 14061239Sahl } 14070Sstevel@tonic-gate 14080Sstevel@tonic-gate mod = 1; 14091239Sahl (void) elf_flagdata(data_tgt, ELF_C_SET, ELF_F_DIRTY); 14100Sstevel@tonic-gate 14110Sstevel@tonic-gate /* 14120Sstevel@tonic-gate * This symbol may already have been marked to 14130Sstevel@tonic-gate * be ignored by another relocation referencing 14140Sstevel@tonic-gate * the same symbol or if this object file has 14150Sstevel@tonic-gate * already been processed by an earlier link 14160Sstevel@tonic-gate * invocation. 14170Sstevel@tonic-gate */ 14180Sstevel@tonic-gate if (rsym.st_shndx != SHN_SUNW_IGNORE) { 14190Sstevel@tonic-gate rsym.st_shndx = SHN_SUNW_IGNORE; 14200Sstevel@tonic-gate (void) gelf_update_sym(data_sym, ndx, &rsym); 14210Sstevel@tonic-gate } 14220Sstevel@tonic-gate } 14230Sstevel@tonic-gate } 14240Sstevel@tonic-gate 14250Sstevel@tonic-gate if (mod && elf_update(elf, ELF_C_WRITE) == -1) 14260Sstevel@tonic-gate goto err; 14270Sstevel@tonic-gate 1428265Smws (void) elf_end(elf); 14291239Sahl (void) close(fd); 14301239Sahl 14311239Sahl while ((pair = bufs) != NULL) { 14321239Sahl bufs = pair->dlp_next; 14331239Sahl dt_free(dtp, pair->dlp_str); 14341239Sahl dt_free(dtp, pair->dlp_sym); 14351239Sahl dt_free(dtp, pair); 14361239Sahl } 14371239Sahl 14380Sstevel@tonic-gate return (0); 14390Sstevel@tonic-gate 14400Sstevel@tonic-gate err: 14411239Sahl return (dt_link_error(dtp, elf, fd, bufs, 14420Sstevel@tonic-gate "an error was encountered while processing %s", obj)); 14430Sstevel@tonic-gate } 14440Sstevel@tonic-gate 14450Sstevel@tonic-gate int 14460Sstevel@tonic-gate dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags, 14470Sstevel@tonic-gate const char *file, int objc, char *const objv[]) 14480Sstevel@tonic-gate { 14490Sstevel@tonic-gate char drti[PATH_MAX]; 14500Sstevel@tonic-gate dof_hdr_t *dof; 1451191Sahl int fd, status, i, cur; 14520Sstevel@tonic-gate char *cmd, tmp; 14530Sstevel@tonic-gate size_t len; 14541710Sahl int eprobes = 0, ret = 0; 14550Sstevel@tonic-gate 1456191Sahl /* 1457191Sahl * A NULL program indicates a special use in which we just link 1458191Sahl * together a bunch of object files specified in objv and then 1459191Sahl * unlink(2) those object files. 1460191Sahl */ 1461191Sahl if (pgp == NULL) { 1462191Sahl const char *fmt = "%s -o %s -r"; 1463191Sahl 1464191Sahl len = snprintf(&tmp, 1, fmt, dtp->dt_ld_path, file) + 1; 1465191Sahl 1466191Sahl for (i = 0; i < objc; i++) 1467191Sahl len += strlen(objv[i]) + 1; 1468191Sahl 1469191Sahl cmd = alloca(len); 1470191Sahl 1471191Sahl cur = snprintf(cmd, len, fmt, dtp->dt_ld_path, file); 1472191Sahl 1473191Sahl for (i = 0; i < objc; i++) 1474191Sahl cur += snprintf(cmd + cur, len - cur, " %s", objv[i]); 1475191Sahl 1476191Sahl if ((status = system(cmd)) == -1) { 14771239Sahl return (dt_link_error(dtp, NULL, -1, NULL, 14781239Sahl "failed to run %s: %s", dtp->dt_ld_path, 14791239Sahl strerror(errno))); 1480191Sahl } 1481191Sahl 1482191Sahl if (WIFSIGNALED(status)) { 14831239Sahl return (dt_link_error(dtp, NULL, -1, NULL, 1484191Sahl "failed to link %s: %s failed due to signal %d", 1485191Sahl file, dtp->dt_ld_path, WTERMSIG(status))); 1486191Sahl } 1487191Sahl 1488191Sahl if (WEXITSTATUS(status) != 0) { 14891239Sahl return (dt_link_error(dtp, NULL, -1, NULL, 1490191Sahl "failed to link %s: %s exited with status %d\n", 1491191Sahl file, dtp->dt_ld_path, WEXITSTATUS(status))); 1492191Sahl } 1493191Sahl 1494191Sahl for (i = 0; i < objc; i++) { 1495191Sahl if (strcmp(objv[i], file) != 0) 1496191Sahl (void) unlink(objv[i]); 1497191Sahl } 1498191Sahl 1499191Sahl return (0); 1500191Sahl } 1501191Sahl 15020Sstevel@tonic-gate for (i = 0; i < objc; i++) { 15031710Sahl if (process_obj(dtp, objv[i], &eprobes) != 0) 15040Sstevel@tonic-gate return (-1); /* errno is set for us */ 15050Sstevel@tonic-gate } 15060Sstevel@tonic-gate 15071710Sahl /* 15081710Sahl * If there are is-enabled probes then we need to force use of DOF 15091710Sahl * version 2. 15101710Sahl */ 15111710Sahl if (eprobes && pgp->dp_dofversion < DOF_VERSION_2) 15121710Sahl pgp->dp_dofversion = DOF_VERSION_2; 15131710Sahl 15140Sstevel@tonic-gate if ((dof = dtrace_dof_create(dtp, pgp, dflags)) == NULL) 15150Sstevel@tonic-gate return (-1); /* errno is set for us */ 15160Sstevel@tonic-gate 15170Sstevel@tonic-gate /* 15180Sstevel@tonic-gate * Create a temporary file and then unlink it if we're going to 15190Sstevel@tonic-gate * combine it with drti.o later. We can still refer to it in child 15200Sstevel@tonic-gate * processes as /dev/fd/<fd>. 15210Sstevel@tonic-gate */ 15220Sstevel@tonic-gate if ((fd = open64(file, O_RDWR | O_CREAT | O_TRUNC, 0666)) == -1) { 15231239Sahl return (dt_link_error(dtp, NULL, -1, NULL, 15240Sstevel@tonic-gate "failed to open %s: %s", file, strerror(errno))); 15250Sstevel@tonic-gate } 15260Sstevel@tonic-gate 15270Sstevel@tonic-gate /* 15280Sstevel@tonic-gate * If -xlinktype=DOF has been selected, just write out the DOF. 15290Sstevel@tonic-gate * Otherwise proceed to the default of generating and linking ELF. 15300Sstevel@tonic-gate */ 15310Sstevel@tonic-gate switch (dtp->dt_linktype) { 15320Sstevel@tonic-gate case DT_LTYP_DOF: 15330Sstevel@tonic-gate if (dt_write(dtp, fd, dof, dof->dofh_filesz) < dof->dofh_filesz) 15340Sstevel@tonic-gate ret = errno; 15350Sstevel@tonic-gate 15360Sstevel@tonic-gate if (close(fd) != 0 && ret == 0) 15370Sstevel@tonic-gate ret = errno; 15380Sstevel@tonic-gate 15390Sstevel@tonic-gate if (ret != 0) { 15401239Sahl return (dt_link_error(dtp, NULL, -1, NULL, 15410Sstevel@tonic-gate "failed to write %s: %s", file, strerror(ret))); 15420Sstevel@tonic-gate } 15430Sstevel@tonic-gate 15440Sstevel@tonic-gate return (0); 15450Sstevel@tonic-gate 15460Sstevel@tonic-gate case DT_LTYP_ELF: 15470Sstevel@tonic-gate break; /* fall through to the rest of dtrace_program_link() */ 15480Sstevel@tonic-gate 15490Sstevel@tonic-gate default: 15501239Sahl return (dt_link_error(dtp, NULL, -1, NULL, 15510Sstevel@tonic-gate "invalid link type %u\n", dtp->dt_linktype)); 15520Sstevel@tonic-gate } 15530Sstevel@tonic-gate 15540Sstevel@tonic-gate 15550Sstevel@tonic-gate if (!dtp->dt_lazyload) 15560Sstevel@tonic-gate (void) unlink(file); 15570Sstevel@tonic-gate 15580Sstevel@tonic-gate if (dtp->dt_oflags & DTRACE_O_LP64) 15590Sstevel@tonic-gate status = dump_elf64(dtp, dof, fd); 15600Sstevel@tonic-gate else 15610Sstevel@tonic-gate status = dump_elf32(dtp, dof, fd); 15620Sstevel@tonic-gate 15630Sstevel@tonic-gate if (status != 0 || lseek(fd, 0, SEEK_SET) != 0) { 15641239Sahl return (dt_link_error(dtp, NULL, -1, NULL, 15650Sstevel@tonic-gate "failed to write %s: %s", file, strerror(errno))); 15660Sstevel@tonic-gate } 15670Sstevel@tonic-gate 15680Sstevel@tonic-gate if (!dtp->dt_lazyload) { 1569191Sahl const char *fmt = "%s -o %s -r -Blocal -Breduce /dev/fd/%d %s"; 1570191Sahl 15710Sstevel@tonic-gate if (dtp->dt_oflags & DTRACE_O_LP64) { 15720Sstevel@tonic-gate (void) snprintf(drti, sizeof (drti), 15730Sstevel@tonic-gate "%s/64/drti.o", _dtrace_libdir); 15740Sstevel@tonic-gate } else { 15750Sstevel@tonic-gate (void) snprintf(drti, sizeof (drti), 15760Sstevel@tonic-gate "%s/drti.o", _dtrace_libdir); 15770Sstevel@tonic-gate } 15780Sstevel@tonic-gate 1579191Sahl len = snprintf(&tmp, 1, fmt, dtp->dt_ld_path, file, fd, 1580191Sahl drti) + 1; 15810Sstevel@tonic-gate 15820Sstevel@tonic-gate cmd = alloca(len); 15830Sstevel@tonic-gate 1584191Sahl (void) snprintf(cmd, len, fmt, dtp->dt_ld_path, file, fd, drti); 15850Sstevel@tonic-gate 15860Sstevel@tonic-gate if ((status = system(cmd)) == -1) { 15871239Sahl ret = dt_link_error(dtp, NULL, -1, NULL, 15881239Sahl "failed to run %s: %s", dtp->dt_ld_path, 15891239Sahl strerror(errno)); 15900Sstevel@tonic-gate goto done; 15910Sstevel@tonic-gate } 15920Sstevel@tonic-gate 15930Sstevel@tonic-gate (void) close(fd); /* release temporary file */ 15940Sstevel@tonic-gate 15950Sstevel@tonic-gate if (WIFSIGNALED(status)) { 15961239Sahl ret = dt_link_error(dtp, NULL, -1, NULL, 15970Sstevel@tonic-gate "failed to link %s: %s failed due to signal %d", 15980Sstevel@tonic-gate file, dtp->dt_ld_path, WTERMSIG(status)); 15990Sstevel@tonic-gate goto done; 16000Sstevel@tonic-gate } 16010Sstevel@tonic-gate 16020Sstevel@tonic-gate if (WEXITSTATUS(status) != 0) { 16031239Sahl ret = dt_link_error(dtp, NULL, -1, NULL, 16040Sstevel@tonic-gate "failed to link %s: %s exited with status %d\n", 16050Sstevel@tonic-gate file, dtp->dt_ld_path, WEXITSTATUS(status)); 16060Sstevel@tonic-gate goto done; 16070Sstevel@tonic-gate } 16080Sstevel@tonic-gate } else { 16090Sstevel@tonic-gate (void) close(fd); 16100Sstevel@tonic-gate } 16110Sstevel@tonic-gate 16120Sstevel@tonic-gate done: 16130Sstevel@tonic-gate dtrace_dof_destroy(dtp, dof); 16140Sstevel@tonic-gate return (ret); 16150Sstevel@tonic-gate } 1616