16ff6d951SJohn Birrell /* 26ff6d951SJohn Birrell * CDDL HEADER START 36ff6d951SJohn Birrell * 46ff6d951SJohn Birrell * The contents of this file are subject to the terms of the 56ff6d951SJohn Birrell * Common Development and Distribution License (the "License"). 66ff6d951SJohn Birrell * You may not use this file except in compliance with the License. 76ff6d951SJohn Birrell * 86ff6d951SJohn Birrell * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 96ff6d951SJohn Birrell * or http://www.opensolaris.org/os/licensing. 106ff6d951SJohn Birrell * See the License for the specific language governing permissions 116ff6d951SJohn Birrell * and limitations under the License. 126ff6d951SJohn Birrell * 136ff6d951SJohn Birrell * When distributing Covered Code, include this CDDL HEADER in each 146ff6d951SJohn Birrell * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 156ff6d951SJohn Birrell * If applicable, add the following below this CDDL HEADER, with the 166ff6d951SJohn Birrell * fields enclosed by brackets "[]" replaced with your own identifying 176ff6d951SJohn Birrell * information: Portions Copyright [yyyy] [name of copyright owner] 186ff6d951SJohn Birrell * 196ff6d951SJohn Birrell * CDDL HEADER END 206ff6d951SJohn Birrell */ 216ff6d951SJohn Birrell 226ff6d951SJohn Birrell /* 232693feb4SJohn Birrell * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 246ff6d951SJohn Birrell * Use is subject to license terms. 25df7165b8SMark Johnston * Copyright 2017-2018 Mark Johnston <markj@FreeBSD.org> 266ff6d951SJohn Birrell */ 276ff6d951SJohn Birrell 280e15d9fbSMark Johnston #include <sys/param.h> 290e15d9fbSMark Johnston #include <sys/mman.h> 300e15d9fbSMark Johnston #include <sys/wait.h> 316ff6d951SJohn Birrell 320e15d9fbSMark Johnston #include <assert.h> 336ff6d951SJohn Birrell #include <elf.h> 349e5787d2SMatt Macy #include <sys/types.h> 350e15d9fbSMark Johnston #include <fcntl.h> 360e15d9fbSMark Johnston #include <gelf.h> 376ff6d951SJohn Birrell #include <limits.h> 386ff6d951SJohn Birrell #include <stddef.h> 396ff6d951SJohn Birrell #include <stdio.h> 400e15d9fbSMark Johnston #include <stdlib.h> 410e15d9fbSMark Johnston #include <strings.h> 426ff6d951SJohn Birrell #include <errno.h> 430e15d9fbSMark Johnston #include <unistd.h> 440e15d9fbSMark Johnston 450f2bd1e8SRui Paulo #include <libelf.h> 466ff6d951SJohn Birrell 476ff6d951SJohn Birrell #include <dt_impl.h> 486ff6d951SJohn Birrell #include <dt_provider.h> 496ff6d951SJohn Birrell #include <dt_program.h> 506ff6d951SJohn Birrell #include <dt_string.h> 516ff6d951SJohn Birrell 526ff6d951SJohn Birrell #define ESHDR_NULL 0 536ff6d951SJohn Birrell #define ESHDR_SHSTRTAB 1 546ff6d951SJohn Birrell #define ESHDR_DOF 2 556ff6d951SJohn Birrell #define ESHDR_STRTAB 3 566ff6d951SJohn Birrell #define ESHDR_SYMTAB 4 576ff6d951SJohn Birrell #define ESHDR_REL 5 586ff6d951SJohn Birrell #define ESHDR_NUM 6 596ff6d951SJohn Birrell 606ff6d951SJohn Birrell #define PWRITE_SCN(index, data) \ 616ff6d951SJohn Birrell (lseek64(fd, (off64_t)elf_file.shdr[(index)].sh_offset, SEEK_SET) != \ 626ff6d951SJohn Birrell (off64_t)elf_file.shdr[(index)].sh_offset || \ 636ff6d951SJohn Birrell dt_write(dtp, fd, (data), elf_file.shdr[(index)].sh_size) != \ 646ff6d951SJohn Birrell elf_file.shdr[(index)].sh_size) 656ff6d951SJohn Birrell 666ff6d951SJohn Birrell static const char DTRACE_SHSTRTAB32[] = "\0" 676ff6d951SJohn Birrell ".shstrtab\0" /* 1 */ 686ff6d951SJohn Birrell ".SUNW_dof\0" /* 11 */ 696ff6d951SJohn Birrell ".strtab\0" /* 21 */ 706ff6d951SJohn Birrell ".symtab\0" /* 29 */ 716ff6d951SJohn Birrell ".rel.SUNW_dof"; /* 37 */ 726ff6d951SJohn Birrell 736ff6d951SJohn Birrell static const char DTRACE_SHSTRTAB64[] = "\0" 746ff6d951SJohn Birrell ".shstrtab\0" /* 1 */ 756ff6d951SJohn Birrell ".SUNW_dof\0" /* 11 */ 766ff6d951SJohn Birrell ".strtab\0" /* 21 */ 776ff6d951SJohn Birrell ".symtab\0" /* 29 */ 786ff6d951SJohn Birrell ".rela.SUNW_dof"; /* 37 */ 796ff6d951SJohn Birrell 806ff6d951SJohn Birrell static const char DOFSTR[] = "__SUNW_dof"; 816ff6d951SJohn Birrell static const char DOFLAZYSTR[] = "___SUNW_dof"; 826ff6d951SJohn Birrell 836ff6d951SJohn Birrell typedef struct dt_link_pair { 846ff6d951SJohn Birrell struct dt_link_pair *dlp_next; /* next pair in linked list */ 856ff6d951SJohn Birrell void *dlp_str; /* buffer for string table */ 866ff6d951SJohn Birrell void *dlp_sym; /* buffer for symbol table */ 876ff6d951SJohn Birrell } dt_link_pair_t; 886ff6d951SJohn Birrell 896ff6d951SJohn Birrell typedef struct dof_elf32 { 906ff6d951SJohn Birrell uint32_t de_nrel; /* relocation count */ 916ff6d951SJohn Birrell Elf32_Rel *de_rel; /* array of relocations for x86 */ 926ff6d951SJohn Birrell uint32_t de_nsym; /* symbol count */ 936ff6d951SJohn Birrell Elf32_Sym *de_sym; /* array of symbols */ 946ff6d951SJohn Birrell uint32_t de_strlen; /* size of of string table */ 956ff6d951SJohn Birrell char *de_strtab; /* string table */ 966ff6d951SJohn Birrell uint32_t de_global; /* index of the first global symbol */ 976ff6d951SJohn Birrell } dof_elf32_t; 986ff6d951SJohn Birrell 996ff6d951SJohn Birrell static int 1006ff6d951SJohn Birrell prepare_elf32(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf32_t *dep) 1016ff6d951SJohn Birrell { 1026ff6d951SJohn Birrell dof_sec_t *dofs, *s; 1036ff6d951SJohn Birrell dof_relohdr_t *dofrh; 1046ff6d951SJohn Birrell dof_relodesc_t *dofr; 1056ff6d951SJohn Birrell char *strtab; 1066ff6d951SJohn Birrell int i, j, nrel; 1076ff6d951SJohn Birrell size_t strtabsz = 1; 1086ff6d951SJohn Birrell uint32_t count = 0; 1096ff6d951SJohn Birrell size_t base; 1106ff6d951SJohn Birrell Elf32_Sym *sym; 1116ff6d951SJohn Birrell Elf32_Rel *rel; 1126ff6d951SJohn Birrell 1136ff6d951SJohn Birrell /*LINTED*/ 1146ff6d951SJohn Birrell dofs = (dof_sec_t *)((char *)dof + dof->dofh_secoff); 1156ff6d951SJohn Birrell 1166ff6d951SJohn Birrell /* 1176ff6d951SJohn Birrell * First compute the size of the string table and the number of 1186ff6d951SJohn Birrell * relocations present in the DOF. 1196ff6d951SJohn Birrell */ 1206ff6d951SJohn Birrell for (i = 0; i < dof->dofh_secnum; i++) { 1216ff6d951SJohn Birrell if (dofs[i].dofs_type != DOF_SECT_URELHDR) 1226ff6d951SJohn Birrell continue; 1236ff6d951SJohn Birrell 1246ff6d951SJohn Birrell /*LINTED*/ 1256ff6d951SJohn Birrell dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset); 1266ff6d951SJohn Birrell 1276ff6d951SJohn Birrell s = &dofs[dofrh->dofr_strtab]; 1286ff6d951SJohn Birrell strtab = (char *)dof + s->dofs_offset; 1296ff6d951SJohn Birrell assert(strtab[0] == '\0'); 1306ff6d951SJohn Birrell strtabsz += s->dofs_size - 1; 1316ff6d951SJohn Birrell 1326ff6d951SJohn Birrell s = &dofs[dofrh->dofr_relsec]; 1336ff6d951SJohn Birrell /*LINTED*/ 1346ff6d951SJohn Birrell dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset); 1356ff6d951SJohn Birrell count += s->dofs_size / s->dofs_entsize; 1366ff6d951SJohn Birrell } 1376ff6d951SJohn Birrell 1386ff6d951SJohn Birrell dep->de_strlen = strtabsz; 1396ff6d951SJohn Birrell dep->de_nrel = count; 1406ff6d951SJohn Birrell dep->de_nsym = count + 1; /* the first symbol is always null */ 1416ff6d951SJohn Birrell 1426ff6d951SJohn Birrell if (dtp->dt_lazyload) { 1436ff6d951SJohn Birrell dep->de_strlen += sizeof (DOFLAZYSTR); 1446ff6d951SJohn Birrell dep->de_nsym++; 1456ff6d951SJohn Birrell } else { 1466ff6d951SJohn Birrell dep->de_strlen += sizeof (DOFSTR); 1476ff6d951SJohn Birrell dep->de_nsym++; 1486ff6d951SJohn Birrell } 1496ff6d951SJohn Birrell 1506ff6d951SJohn Birrell if ((dep->de_rel = calloc(dep->de_nrel, 1516ff6d951SJohn Birrell sizeof (dep->de_rel[0]))) == NULL) { 1526ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_NOMEM)); 1536ff6d951SJohn Birrell } 1546ff6d951SJohn Birrell 1556ff6d951SJohn Birrell if ((dep->de_sym = calloc(dep->de_nsym, sizeof (Elf32_Sym))) == NULL) { 1566ff6d951SJohn Birrell free(dep->de_rel); 1576ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_NOMEM)); 1586ff6d951SJohn Birrell } 1596ff6d951SJohn Birrell 1606ff6d951SJohn Birrell if ((dep->de_strtab = calloc(dep->de_strlen, 1)) == NULL) { 1616ff6d951SJohn Birrell free(dep->de_rel); 1626ff6d951SJohn Birrell free(dep->de_sym); 1636ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_NOMEM)); 1646ff6d951SJohn Birrell } 1656ff6d951SJohn Birrell 1666ff6d951SJohn Birrell count = 0; 1676ff6d951SJohn Birrell strtabsz = 1; 1686ff6d951SJohn Birrell dep->de_strtab[0] = '\0'; 1696ff6d951SJohn Birrell rel = dep->de_rel; 1706ff6d951SJohn Birrell sym = dep->de_sym; 1716ff6d951SJohn Birrell dep->de_global = 1; 1726ff6d951SJohn Birrell 1736ff6d951SJohn Birrell /* 1746ff6d951SJohn Birrell * The first symbol table entry must be zeroed and is always ignored. 1756ff6d951SJohn Birrell */ 1766ff6d951SJohn Birrell bzero(sym, sizeof (Elf32_Sym)); 1776ff6d951SJohn Birrell sym++; 1786ff6d951SJohn Birrell 1796ff6d951SJohn Birrell /* 1806ff6d951SJohn Birrell * Take a second pass through the DOF sections filling in the 1816ff6d951SJohn Birrell * memory we allocated. 1826ff6d951SJohn Birrell */ 1836ff6d951SJohn Birrell for (i = 0; i < dof->dofh_secnum; i++) { 1846ff6d951SJohn Birrell if (dofs[i].dofs_type != DOF_SECT_URELHDR) 1856ff6d951SJohn Birrell continue; 1866ff6d951SJohn Birrell 1876ff6d951SJohn Birrell /*LINTED*/ 1886ff6d951SJohn Birrell dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset); 1896ff6d951SJohn Birrell 1906ff6d951SJohn Birrell s = &dofs[dofrh->dofr_strtab]; 1916ff6d951SJohn Birrell strtab = (char *)dof + s->dofs_offset; 1926ff6d951SJohn Birrell bcopy(strtab + 1, dep->de_strtab + strtabsz, s->dofs_size); 1936ff6d951SJohn Birrell base = strtabsz; 1946ff6d951SJohn Birrell strtabsz += s->dofs_size - 1; 1956ff6d951SJohn Birrell 1966ff6d951SJohn Birrell s = &dofs[dofrh->dofr_relsec]; 1976ff6d951SJohn Birrell /*LINTED*/ 1986ff6d951SJohn Birrell dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset); 1996ff6d951SJohn Birrell nrel = s->dofs_size / s->dofs_entsize; 2006ff6d951SJohn Birrell 2016ff6d951SJohn Birrell s = &dofs[dofrh->dofr_tgtsec]; 2026ff6d951SJohn Birrell 2036ff6d951SJohn Birrell for (j = 0; j < nrel; j++) { 204b78ee15eSRuslan Bukin #if defined(__aarch64__) 205a2ea7849SMark Johnston rel->r_offset = s->dofs_offset + 206a2ea7849SMark Johnston dofr[j].dofr_offset; 207a2ea7849SMark Johnston rel->r_info = ELF32_R_INFO(count + dep->de_global, 208a2ea7849SMark Johnston R_ARM_REL32); 209b78ee15eSRuslan Bukin #elif defined(__arm__) 2102693feb4SJohn Birrell /* XXX */ 211732f2c69SEd Maste printf("%s:%s(%d): arm not implemented\n", 212732f2c69SEd Maste __FUNCTION__, __FILE__, __LINE__); 2132693feb4SJohn Birrell #elif defined(__i386) || defined(__amd64) 2146ff6d951SJohn Birrell rel->r_offset = s->dofs_offset + 2156ff6d951SJohn Birrell dofr[j].dofr_offset; 2166ff6d951SJohn Birrell rel->r_info = ELF32_R_INFO(count + dep->de_global, 217e801af6fSMark Johnston R_386_PC32); 2182693feb4SJohn Birrell #elif defined(__powerpc__) 21930b318b9SJustin Hibbits /* 22030b318b9SJustin Hibbits * Add 4 bytes to hit the low half of this 64-bit 22130b318b9SJustin Hibbits * big-endian address. 22230b318b9SJustin Hibbits */ 22330b318b9SJustin Hibbits rel->r_offset = s->dofs_offset + 22430b318b9SJustin Hibbits dofr[j].dofr_offset + 4; 22530b318b9SJustin Hibbits rel->r_info = ELF32_R_INFO(count + dep->de_global, 22630b318b9SJustin Hibbits R_PPC_REL32); 227ca20f8ecSRuslan Bukin #elif defined(__riscv) 228f711d5c3SMitchell Horne rel->r_offset = s->dofs_offset + dofr[j].dofr_offset; 229f711d5c3SMitchell Horne rel->r_info = ELF32_R_INFO(count + dep->de_global, 230f711d5c3SMitchell Horne R_RISCV_32_PCREL); 2316ff6d951SJohn Birrell #else 2326ff6d951SJohn Birrell #error unknown ISA 2336ff6d951SJohn Birrell #endif 2346ff6d951SJohn Birrell 2356ff6d951SJohn Birrell sym->st_name = base + dofr[j].dofr_name - 1; 2366ff6d951SJohn Birrell sym->st_value = 0; 2376ff6d951SJohn Birrell sym->st_size = 0; 2386ff6d951SJohn Birrell sym->st_info = ELF32_ST_INFO(STB_GLOBAL, STT_FUNC); 239df7165b8SMark Johnston sym->st_other = ELF32_ST_VISIBILITY(STV_HIDDEN); 2406ff6d951SJohn Birrell sym->st_shndx = SHN_UNDEF; 2416ff6d951SJohn Birrell 2426ff6d951SJohn Birrell rel++; 2436ff6d951SJohn Birrell sym++; 2446ff6d951SJohn Birrell count++; 2456ff6d951SJohn Birrell } 2466ff6d951SJohn Birrell } 2476ff6d951SJohn Birrell 2486ff6d951SJohn Birrell /* 2496ff6d951SJohn Birrell * Add a symbol for the DOF itself. We use a different symbol for 2506ff6d951SJohn Birrell * lazily and actively loaded DOF to make them easy to distinguish. 2516ff6d951SJohn Birrell */ 2526ff6d951SJohn Birrell sym->st_name = strtabsz; 2536ff6d951SJohn Birrell sym->st_value = 0; 2546ff6d951SJohn Birrell sym->st_size = dof->dofh_filesz; 2556ff6d951SJohn Birrell sym->st_info = ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT); 25603a5f9f0SMark Johnston sym->st_other = ELF32_ST_VISIBILITY(STV_HIDDEN); 2576ff6d951SJohn Birrell sym->st_shndx = ESHDR_DOF; 2586ff6d951SJohn Birrell sym++; 2596ff6d951SJohn Birrell 2606ff6d951SJohn Birrell if (dtp->dt_lazyload) { 2616ff6d951SJohn Birrell bcopy(DOFLAZYSTR, dep->de_strtab + strtabsz, 2626ff6d951SJohn Birrell sizeof (DOFLAZYSTR)); 2636ff6d951SJohn Birrell strtabsz += sizeof (DOFLAZYSTR); 2646ff6d951SJohn Birrell } else { 2656ff6d951SJohn Birrell bcopy(DOFSTR, dep->de_strtab + strtabsz, sizeof (DOFSTR)); 2666ff6d951SJohn Birrell strtabsz += sizeof (DOFSTR); 2676ff6d951SJohn Birrell } 2686ff6d951SJohn Birrell 2696ff6d951SJohn Birrell assert(count == dep->de_nrel); 2706ff6d951SJohn Birrell assert(strtabsz == dep->de_strlen); 2716ff6d951SJohn Birrell 2726ff6d951SJohn Birrell return (0); 2736ff6d951SJohn Birrell } 2746ff6d951SJohn Birrell 2756ff6d951SJohn Birrell 2766ff6d951SJohn Birrell typedef struct dof_elf64 { 2776ff6d951SJohn Birrell uint32_t de_nrel; 2786ff6d951SJohn Birrell Elf64_Rela *de_rel; 2796ff6d951SJohn Birrell uint32_t de_nsym; 2806ff6d951SJohn Birrell Elf64_Sym *de_sym; 2816ff6d951SJohn Birrell 2826ff6d951SJohn Birrell uint32_t de_strlen; 2836ff6d951SJohn Birrell char *de_strtab; 2846ff6d951SJohn Birrell 2856ff6d951SJohn Birrell uint32_t de_global; 2866ff6d951SJohn Birrell } dof_elf64_t; 2876ff6d951SJohn Birrell 2886ff6d951SJohn Birrell static int 2896ff6d951SJohn Birrell prepare_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf64_t *dep) 2906ff6d951SJohn Birrell { 2916ff6d951SJohn Birrell dof_sec_t *dofs, *s; 2926ff6d951SJohn Birrell dof_relohdr_t *dofrh; 2936ff6d951SJohn Birrell dof_relodesc_t *dofr; 2946ff6d951SJohn Birrell char *strtab; 2956ff6d951SJohn Birrell int i, j, nrel; 2966ff6d951SJohn Birrell size_t strtabsz = 1; 2978caf8a8dSMark Johnston uint64_t count = 0; 2986ff6d951SJohn Birrell size_t base; 2996ff6d951SJohn Birrell Elf64_Sym *sym; 3006ff6d951SJohn Birrell Elf64_Rela *rel; 3016ff6d951SJohn Birrell 3026ff6d951SJohn Birrell /*LINTED*/ 3036ff6d951SJohn Birrell dofs = (dof_sec_t *)((char *)dof + dof->dofh_secoff); 3046ff6d951SJohn Birrell 3056ff6d951SJohn Birrell /* 3066ff6d951SJohn Birrell * First compute the size of the string table and the number of 3076ff6d951SJohn Birrell * relocations present in the DOF. 3086ff6d951SJohn Birrell */ 3096ff6d951SJohn Birrell for (i = 0; i < dof->dofh_secnum; i++) { 3106ff6d951SJohn Birrell if (dofs[i].dofs_type != DOF_SECT_URELHDR) 3116ff6d951SJohn Birrell continue; 3126ff6d951SJohn Birrell 3136ff6d951SJohn Birrell /*LINTED*/ 3146ff6d951SJohn Birrell dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset); 3156ff6d951SJohn Birrell 3166ff6d951SJohn Birrell s = &dofs[dofrh->dofr_strtab]; 3176ff6d951SJohn Birrell strtab = (char *)dof + s->dofs_offset; 3186ff6d951SJohn Birrell assert(strtab[0] == '\0'); 3196ff6d951SJohn Birrell strtabsz += s->dofs_size - 1; 3206ff6d951SJohn Birrell 3216ff6d951SJohn Birrell s = &dofs[dofrh->dofr_relsec]; 3226ff6d951SJohn Birrell /*LINTED*/ 3236ff6d951SJohn Birrell dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset); 3246ff6d951SJohn Birrell count += s->dofs_size / s->dofs_entsize; 3256ff6d951SJohn Birrell } 3266ff6d951SJohn Birrell 3276ff6d951SJohn Birrell dep->de_strlen = strtabsz; 3286ff6d951SJohn Birrell dep->de_nrel = count; 3296ff6d951SJohn Birrell dep->de_nsym = count + 1; /* the first symbol is always null */ 3306ff6d951SJohn Birrell 3316ff6d951SJohn Birrell if (dtp->dt_lazyload) { 3326ff6d951SJohn Birrell dep->de_strlen += sizeof (DOFLAZYSTR); 3336ff6d951SJohn Birrell dep->de_nsym++; 3346ff6d951SJohn Birrell } else { 3356ff6d951SJohn Birrell dep->de_strlen += sizeof (DOFSTR); 3366ff6d951SJohn Birrell dep->de_nsym++; 3376ff6d951SJohn Birrell } 3386ff6d951SJohn Birrell 3396ff6d951SJohn Birrell if ((dep->de_rel = calloc(dep->de_nrel, 3406ff6d951SJohn Birrell sizeof (dep->de_rel[0]))) == NULL) { 3416ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_NOMEM)); 3426ff6d951SJohn Birrell } 3436ff6d951SJohn Birrell 3446ff6d951SJohn Birrell if ((dep->de_sym = calloc(dep->de_nsym, sizeof (Elf64_Sym))) == NULL) { 3456ff6d951SJohn Birrell free(dep->de_rel); 3466ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_NOMEM)); 3476ff6d951SJohn Birrell } 3486ff6d951SJohn Birrell 3496ff6d951SJohn Birrell if ((dep->de_strtab = calloc(dep->de_strlen, 1)) == NULL) { 3506ff6d951SJohn Birrell free(dep->de_rel); 3516ff6d951SJohn Birrell free(dep->de_sym); 3526ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_NOMEM)); 3536ff6d951SJohn Birrell } 3546ff6d951SJohn Birrell 3556ff6d951SJohn Birrell count = 0; 3566ff6d951SJohn Birrell strtabsz = 1; 3576ff6d951SJohn Birrell dep->de_strtab[0] = '\0'; 3586ff6d951SJohn Birrell rel = dep->de_rel; 3596ff6d951SJohn Birrell sym = dep->de_sym; 3606ff6d951SJohn Birrell dep->de_global = 1; 3616ff6d951SJohn Birrell 3626ff6d951SJohn Birrell /* 3636ff6d951SJohn Birrell * The first symbol table entry must be zeroed and is always ignored. 3646ff6d951SJohn Birrell */ 3656ff6d951SJohn Birrell bzero(sym, sizeof (Elf64_Sym)); 3666ff6d951SJohn Birrell sym++; 3676ff6d951SJohn Birrell 3686ff6d951SJohn Birrell /* 3696ff6d951SJohn Birrell * Take a second pass through the DOF sections filling in the 3706ff6d951SJohn Birrell * memory we allocated. 3716ff6d951SJohn Birrell */ 3726ff6d951SJohn Birrell for (i = 0; i < dof->dofh_secnum; i++) { 3736ff6d951SJohn Birrell if (dofs[i].dofs_type != DOF_SECT_URELHDR) 3746ff6d951SJohn Birrell continue; 3756ff6d951SJohn Birrell 3766ff6d951SJohn Birrell /*LINTED*/ 3776ff6d951SJohn Birrell dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset); 3786ff6d951SJohn Birrell 3796ff6d951SJohn Birrell s = &dofs[dofrh->dofr_strtab]; 3806ff6d951SJohn Birrell strtab = (char *)dof + s->dofs_offset; 3816ff6d951SJohn Birrell bcopy(strtab + 1, dep->de_strtab + strtabsz, s->dofs_size); 3826ff6d951SJohn Birrell base = strtabsz; 3836ff6d951SJohn Birrell strtabsz += s->dofs_size - 1; 3846ff6d951SJohn Birrell 3856ff6d951SJohn Birrell s = &dofs[dofrh->dofr_relsec]; 3866ff6d951SJohn Birrell /*LINTED*/ 3876ff6d951SJohn Birrell dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset); 3886ff6d951SJohn Birrell nrel = s->dofs_size / s->dofs_entsize; 3896ff6d951SJohn Birrell 3906ff6d951SJohn Birrell s = &dofs[dofrh->dofr_tgtsec]; 3916ff6d951SJohn Birrell 3926ff6d951SJohn Birrell for (j = 0; j < nrel; j++) { 393b78ee15eSRuslan Bukin #if defined(__aarch64__) 394a2ea7849SMark Johnston rel->r_offset = s->dofs_offset + 395a2ea7849SMark Johnston dofr[j].dofr_offset; 396a2ea7849SMark Johnston rel->r_info = ELF64_R_INFO(count + dep->de_global, 397a2ea7849SMark Johnston R_AARCH64_PREL64); 398b78ee15eSRuslan Bukin #elif defined(__arm__) 3992693feb4SJohn Birrell /* XXX */ 4002693feb4SJohn Birrell #elif defined(__powerpc__) 40130b318b9SJustin Hibbits rel->r_offset = s->dofs_offset + 40230b318b9SJustin Hibbits dofr[j].dofr_offset; 40330b318b9SJustin Hibbits rel->r_info = ELF64_R_INFO(count + dep->de_global, 40430b318b9SJustin Hibbits R_PPC64_REL64); 405ca20f8ecSRuslan Bukin #elif defined(__riscv) 406f711d5c3SMitchell Horne rel->r_offset = s->dofs_offset + dofr[j].dofr_offset; 407f711d5c3SMitchell Horne rel->r_info = ELF64_R_INFO(count + dep->de_global, 408f711d5c3SMitchell Horne R_RISCV_32_PCREL); 4092693feb4SJohn Birrell #elif defined(__i386) || defined(__amd64) 4106ff6d951SJohn Birrell rel->r_offset = s->dofs_offset + 4116ff6d951SJohn Birrell dofr[j].dofr_offset; 4126ff6d951SJohn Birrell rel->r_info = ELF64_R_INFO(count + dep->de_global, 413e801af6fSMark Johnston R_X86_64_PC64); 4146ff6d951SJohn Birrell #else 4156ff6d951SJohn Birrell #error unknown ISA 4166ff6d951SJohn Birrell #endif 4176ff6d951SJohn Birrell 4186ff6d951SJohn Birrell sym->st_name = base + dofr[j].dofr_name - 1; 4196ff6d951SJohn Birrell sym->st_value = 0; 4206ff6d951SJohn Birrell sym->st_size = 0; 4216ff6d951SJohn Birrell sym->st_info = GELF_ST_INFO(STB_GLOBAL, STT_FUNC); 422df7165b8SMark Johnston sym->st_other = ELF64_ST_VISIBILITY(STV_HIDDEN); 4236ff6d951SJohn Birrell sym->st_shndx = SHN_UNDEF; 4246ff6d951SJohn Birrell 4256ff6d951SJohn Birrell rel++; 4266ff6d951SJohn Birrell sym++; 4276ff6d951SJohn Birrell count++; 4286ff6d951SJohn Birrell } 4296ff6d951SJohn Birrell } 4306ff6d951SJohn Birrell 4316ff6d951SJohn Birrell /* 4326ff6d951SJohn Birrell * Add a symbol for the DOF itself. We use a different symbol for 4336ff6d951SJohn Birrell * lazily and actively loaded DOF to make them easy to distinguish. 4346ff6d951SJohn Birrell */ 4356ff6d951SJohn Birrell sym->st_name = strtabsz; 4366ff6d951SJohn Birrell sym->st_value = 0; 4376ff6d951SJohn Birrell sym->st_size = dof->dofh_filesz; 4386ff6d951SJohn Birrell sym->st_info = GELF_ST_INFO(STB_GLOBAL, STT_OBJECT); 43903a5f9f0SMark Johnston sym->st_other = ELF64_ST_VISIBILITY(STV_HIDDEN); 4406ff6d951SJohn Birrell sym->st_shndx = ESHDR_DOF; 4416ff6d951SJohn Birrell sym++; 4426ff6d951SJohn Birrell 4436ff6d951SJohn Birrell if (dtp->dt_lazyload) { 4446ff6d951SJohn Birrell bcopy(DOFLAZYSTR, dep->de_strtab + strtabsz, 4456ff6d951SJohn Birrell sizeof (DOFLAZYSTR)); 4466ff6d951SJohn Birrell strtabsz += sizeof (DOFLAZYSTR); 4476ff6d951SJohn Birrell } else { 4486ff6d951SJohn Birrell bcopy(DOFSTR, dep->de_strtab + strtabsz, sizeof (DOFSTR)); 4496ff6d951SJohn Birrell strtabsz += sizeof (DOFSTR); 4506ff6d951SJohn Birrell } 4516ff6d951SJohn Birrell 4526ff6d951SJohn Birrell assert(count == dep->de_nrel); 4536ff6d951SJohn Birrell assert(strtabsz == dep->de_strlen); 4546ff6d951SJohn Birrell 4556ff6d951SJohn Birrell return (0); 4566ff6d951SJohn Birrell } 4576ff6d951SJohn Birrell 4586ff6d951SJohn Birrell /* 4596ff6d951SJohn Birrell * Write out an ELF32 file prologue consisting of a header, section headers, 4606ff6d951SJohn Birrell * and a section header string table. The DOF data will follow this prologue 4616ff6d951SJohn Birrell * and complete the contents of the given ELF file. 4626ff6d951SJohn Birrell */ 4636ff6d951SJohn Birrell static int 4646ff6d951SJohn Birrell dump_elf32(dtrace_hdl_t *dtp, const dof_hdr_t *dof, int fd) 4656ff6d951SJohn Birrell { 4666ff6d951SJohn Birrell struct { 4676ff6d951SJohn Birrell Elf32_Ehdr ehdr; 4686ff6d951SJohn Birrell Elf32_Shdr shdr[ESHDR_NUM]; 4696ff6d951SJohn Birrell } elf_file; 4706ff6d951SJohn Birrell 4716ff6d951SJohn Birrell Elf32_Shdr *shp; 4726ff6d951SJohn Birrell Elf32_Off off; 4736ff6d951SJohn Birrell dof_elf32_t de; 4746ff6d951SJohn Birrell int ret = 0; 4756ff6d951SJohn Birrell uint_t nshdr; 4766ff6d951SJohn Birrell 4776ff6d951SJohn Birrell if (prepare_elf32(dtp, dof, &de) != 0) 4786ff6d951SJohn Birrell return (-1); /* errno is set for us */ 4796ff6d951SJohn Birrell 4806ff6d951SJohn Birrell /* 4816ff6d951SJohn Birrell * If there are no relocations, we only need enough sections for 4826ff6d951SJohn Birrell * the shstrtab and the DOF. 4836ff6d951SJohn Birrell */ 4846ff6d951SJohn Birrell nshdr = de.de_nrel == 0 ? ESHDR_SYMTAB + 1 : ESHDR_NUM; 4856ff6d951SJohn Birrell 4866ff6d951SJohn Birrell bzero(&elf_file, sizeof (elf_file)); 4876ff6d951SJohn Birrell 4886ff6d951SJohn Birrell elf_file.ehdr.e_ident[EI_MAG0] = ELFMAG0; 4896ff6d951SJohn Birrell elf_file.ehdr.e_ident[EI_MAG1] = ELFMAG1; 4906ff6d951SJohn Birrell elf_file.ehdr.e_ident[EI_MAG2] = ELFMAG2; 4916ff6d951SJohn Birrell elf_file.ehdr.e_ident[EI_MAG3] = ELFMAG3; 4926ff6d951SJohn Birrell elf_file.ehdr.e_ident[EI_VERSION] = EV_CURRENT; 4936ff6d951SJohn Birrell elf_file.ehdr.e_ident[EI_CLASS] = ELFCLASS32; 4942693feb4SJohn Birrell #if BYTE_ORDER == _BIG_ENDIAN 4956ff6d951SJohn Birrell elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2MSB; 4962693feb4SJohn Birrell #else 4976ff6d951SJohn Birrell elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2LSB; 4986ff6d951SJohn Birrell #endif 4992693feb4SJohn Birrell elf_file.ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD; 5006ff6d951SJohn Birrell elf_file.ehdr.e_type = ET_REL; 5012693feb4SJohn Birrell #if defined(__arm__) 5022693feb4SJohn Birrell elf_file.ehdr.e_machine = EM_ARM; 5032693feb4SJohn Birrell #elif defined(__powerpc__) 5042693feb4SJohn Birrell elf_file.ehdr.e_machine = EM_PPC; 5056ff6d951SJohn Birrell #elif defined(__i386) || defined(__amd64) 5066ff6d951SJohn Birrell elf_file.ehdr.e_machine = EM_386; 507a2ea7849SMark Johnston #elif defined(__aarch64__) 508a2ea7849SMark Johnston elf_file.ehdr.e_machine = EM_AARCH64; 509f711d5c3SMitchell Horne #elif defined(__riscv) 510f711d5c3SMitchell Horne elf_file.ehdr.e_machine = EM_RISCV; 511f711d5c3SMitchell Horne 512f711d5c3SMitchell Horne /* Set the ELF flags according to our current ABI */ 513f711d5c3SMitchell Horne #if defined(__riscv_compressed) 514f711d5c3SMitchell Horne elf_file.ehdr.e_flags |= EF_RISCV_RVC; 515f711d5c3SMitchell Horne #endif 516f711d5c3SMitchell Horne #if defined(__riscv_float_abi_soft) 517f711d5c3SMitchell Horne elf_file.ehdr.e_flags |= EF_RISCV_FLOAT_ABI_SOFT; 518f711d5c3SMitchell Horne #endif 519f711d5c3SMitchell Horne #if defined(__riscv_float_abi_single) 520f711d5c3SMitchell Horne elf_file.ehdr.e_flags |= EF_RISCV_FLOAT_ABI_SINGLE; 521f711d5c3SMitchell Horne #endif 522f711d5c3SMitchell Horne #if defined(__riscv_float_abi_double) 523f711d5c3SMitchell Horne elf_file.ehdr.e_flags |= EF_RISCV_FLOAT_ABI_DOUBLE; 524f711d5c3SMitchell Horne #endif 5256ff6d951SJohn Birrell #endif 5266ff6d951SJohn Birrell elf_file.ehdr.e_version = EV_CURRENT; 5276ff6d951SJohn Birrell elf_file.ehdr.e_shoff = sizeof (Elf32_Ehdr); 5286ff6d951SJohn Birrell elf_file.ehdr.e_ehsize = sizeof (Elf32_Ehdr); 5296ff6d951SJohn Birrell elf_file.ehdr.e_phentsize = sizeof (Elf32_Phdr); 5306ff6d951SJohn Birrell elf_file.ehdr.e_shentsize = sizeof (Elf32_Shdr); 5316ff6d951SJohn Birrell elf_file.ehdr.e_shnum = nshdr; 5326ff6d951SJohn Birrell elf_file.ehdr.e_shstrndx = ESHDR_SHSTRTAB; 5336ff6d951SJohn Birrell off = sizeof (elf_file) + nshdr * sizeof (Elf32_Shdr); 5346ff6d951SJohn Birrell 5356ff6d951SJohn Birrell shp = &elf_file.shdr[ESHDR_SHSTRTAB]; 5366ff6d951SJohn Birrell shp->sh_name = 1; /* DTRACE_SHSTRTAB32[1] = ".shstrtab" */ 5376ff6d951SJohn Birrell shp->sh_type = SHT_STRTAB; 5386ff6d951SJohn Birrell shp->sh_offset = off; 5396ff6d951SJohn Birrell shp->sh_size = sizeof (DTRACE_SHSTRTAB32); 5406ff6d951SJohn Birrell shp->sh_addralign = sizeof (char); 5410e15d9fbSMark Johnston off = roundup2(shp->sh_offset + shp->sh_size, 8); 5426ff6d951SJohn Birrell 5436ff6d951SJohn Birrell shp = &elf_file.shdr[ESHDR_DOF]; 5446ff6d951SJohn Birrell shp->sh_name = 11; /* DTRACE_SHSTRTAB32[11] = ".SUNW_dof" */ 5456ff6d951SJohn Birrell shp->sh_flags = SHF_ALLOC; 5466ff6d951SJohn Birrell shp->sh_type = SHT_SUNW_dof; 5476ff6d951SJohn Birrell shp->sh_offset = off; 5486ff6d951SJohn Birrell shp->sh_size = dof->dofh_filesz; 5496ff6d951SJohn Birrell shp->sh_addralign = 8; 5506ff6d951SJohn Birrell off = shp->sh_offset + shp->sh_size; 5516ff6d951SJohn Birrell 5526ff6d951SJohn Birrell shp = &elf_file.shdr[ESHDR_STRTAB]; 5536ff6d951SJohn Birrell shp->sh_name = 21; /* DTRACE_SHSTRTAB32[21] = ".strtab" */ 5546ff6d951SJohn Birrell shp->sh_flags = SHF_ALLOC; 5556ff6d951SJohn Birrell shp->sh_type = SHT_STRTAB; 5566ff6d951SJohn Birrell shp->sh_offset = off; 5576ff6d951SJohn Birrell shp->sh_size = de.de_strlen; 5586ff6d951SJohn Birrell shp->sh_addralign = sizeof (char); 5590e15d9fbSMark Johnston off = roundup2(shp->sh_offset + shp->sh_size, 4); 5606ff6d951SJohn Birrell 5616ff6d951SJohn Birrell shp = &elf_file.shdr[ESHDR_SYMTAB]; 5626ff6d951SJohn Birrell shp->sh_name = 29; /* DTRACE_SHSTRTAB32[29] = ".symtab" */ 5636ff6d951SJohn Birrell shp->sh_flags = SHF_ALLOC; 5646ff6d951SJohn Birrell shp->sh_type = SHT_SYMTAB; 5656ff6d951SJohn Birrell shp->sh_entsize = sizeof (Elf32_Sym); 5666ff6d951SJohn Birrell shp->sh_link = ESHDR_STRTAB; 5676ff6d951SJohn Birrell shp->sh_offset = off; 5686ff6d951SJohn Birrell shp->sh_info = de.de_global; 5696ff6d951SJohn Birrell shp->sh_size = de.de_nsym * sizeof (Elf32_Sym); 5706ff6d951SJohn Birrell shp->sh_addralign = 4; 5710e15d9fbSMark Johnston off = roundup2(shp->sh_offset + shp->sh_size, 4); 5726ff6d951SJohn Birrell 5736ff6d951SJohn Birrell if (de.de_nrel == 0) { 5746ff6d951SJohn Birrell if (dt_write(dtp, fd, &elf_file, 5756ff6d951SJohn Birrell sizeof (elf_file)) != sizeof (elf_file) || 5766ff6d951SJohn Birrell PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB32) || 5776ff6d951SJohn Birrell PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || 5786ff6d951SJohn Birrell PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || 5796ff6d951SJohn Birrell PWRITE_SCN(ESHDR_DOF, dof)) { 5806ff6d951SJohn Birrell ret = dt_set_errno(dtp, errno); 5816ff6d951SJohn Birrell } 5826ff6d951SJohn Birrell } else { 5836ff6d951SJohn Birrell shp = &elf_file.shdr[ESHDR_REL]; 5846ff6d951SJohn Birrell shp->sh_name = 37; /* DTRACE_SHSTRTAB32[37] = ".rel.SUNW_dof" */ 5856ff6d951SJohn Birrell shp->sh_flags = SHF_ALLOC; 5866ff6d951SJohn Birrell shp->sh_type = SHT_REL; 5876ff6d951SJohn Birrell shp->sh_entsize = sizeof (de.de_rel[0]); 5886ff6d951SJohn Birrell shp->sh_link = ESHDR_SYMTAB; 5896ff6d951SJohn Birrell shp->sh_info = ESHDR_DOF; 5906ff6d951SJohn Birrell shp->sh_offset = off; 5916ff6d951SJohn Birrell shp->sh_size = de.de_nrel * sizeof (de.de_rel[0]); 5926ff6d951SJohn Birrell shp->sh_addralign = 4; 5936ff6d951SJohn Birrell 5946ff6d951SJohn Birrell if (dt_write(dtp, fd, &elf_file, 5956ff6d951SJohn Birrell sizeof (elf_file)) != sizeof (elf_file) || 5966ff6d951SJohn Birrell PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB32) || 5976ff6d951SJohn Birrell PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || 5986ff6d951SJohn Birrell PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || 5996ff6d951SJohn Birrell PWRITE_SCN(ESHDR_REL, de.de_rel) || 6006ff6d951SJohn Birrell PWRITE_SCN(ESHDR_DOF, dof)) { 6016ff6d951SJohn Birrell ret = dt_set_errno(dtp, errno); 6026ff6d951SJohn Birrell } 6036ff6d951SJohn Birrell } 6046ff6d951SJohn Birrell 6056ff6d951SJohn Birrell free(de.de_strtab); 6066ff6d951SJohn Birrell free(de.de_sym); 6076ff6d951SJohn Birrell free(de.de_rel); 6086ff6d951SJohn Birrell 6096ff6d951SJohn Birrell return (ret); 6106ff6d951SJohn Birrell } 6116ff6d951SJohn Birrell 6126ff6d951SJohn Birrell /* 6136ff6d951SJohn Birrell * Write out an ELF64 file prologue consisting of a header, section headers, 6146ff6d951SJohn Birrell * and a section header string table. The DOF data will follow this prologue 6156ff6d951SJohn Birrell * and complete the contents of the given ELF file. 6166ff6d951SJohn Birrell */ 6176ff6d951SJohn Birrell static int 6186ff6d951SJohn Birrell dump_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, int fd) 6196ff6d951SJohn Birrell { 6206ff6d951SJohn Birrell struct { 6216ff6d951SJohn Birrell Elf64_Ehdr ehdr; 6226ff6d951SJohn Birrell Elf64_Shdr shdr[ESHDR_NUM]; 6236ff6d951SJohn Birrell } elf_file; 6246ff6d951SJohn Birrell 6256ff6d951SJohn Birrell Elf64_Shdr *shp; 6266ff6d951SJohn Birrell Elf64_Off off; 6276ff6d951SJohn Birrell dof_elf64_t de; 6286ff6d951SJohn Birrell int ret = 0; 6296ff6d951SJohn Birrell uint_t nshdr; 6306ff6d951SJohn Birrell 6316ff6d951SJohn Birrell if (prepare_elf64(dtp, dof, &de) != 0) 6326ff6d951SJohn Birrell return (-1); /* errno is set for us */ 6336ff6d951SJohn Birrell 6346ff6d951SJohn Birrell /* 6356ff6d951SJohn Birrell * If there are no relocations, we only need enough sections for 6366ff6d951SJohn Birrell * the shstrtab and the DOF. 6376ff6d951SJohn Birrell */ 6386ff6d951SJohn Birrell nshdr = de.de_nrel == 0 ? ESHDR_SYMTAB + 1 : ESHDR_NUM; 6396ff6d951SJohn Birrell 6406ff6d951SJohn Birrell bzero(&elf_file, sizeof (elf_file)); 6416ff6d951SJohn Birrell 6426ff6d951SJohn Birrell elf_file.ehdr.e_ident[EI_MAG0] = ELFMAG0; 6436ff6d951SJohn Birrell elf_file.ehdr.e_ident[EI_MAG1] = ELFMAG1; 6446ff6d951SJohn Birrell elf_file.ehdr.e_ident[EI_MAG2] = ELFMAG2; 6456ff6d951SJohn Birrell elf_file.ehdr.e_ident[EI_MAG3] = ELFMAG3; 6466ff6d951SJohn Birrell elf_file.ehdr.e_ident[EI_VERSION] = EV_CURRENT; 6476ff6d951SJohn Birrell elf_file.ehdr.e_ident[EI_CLASS] = ELFCLASS64; 6482693feb4SJohn Birrell #if BYTE_ORDER == _BIG_ENDIAN 6496ff6d951SJohn Birrell elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2MSB; 6502693feb4SJohn Birrell #else 6516ff6d951SJohn Birrell elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2LSB; 6526ff6d951SJohn Birrell #endif 6532693feb4SJohn Birrell elf_file.ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD; 6546ff6d951SJohn Birrell elf_file.ehdr.e_type = ET_REL; 6552693feb4SJohn Birrell #if defined(__arm__) 6562693feb4SJohn Birrell elf_file.ehdr.e_machine = EM_ARM; 657b08e2b04SJustin Hibbits #elif defined(__powerpc64__) 6587283901aSBrandon Bergren #if defined(_CALL_ELF) && _CALL_ELF == 2 6597283901aSBrandon Bergren elf_file.ehdr.e_flags = 2; 6607283901aSBrandon Bergren #endif 661b08e2b04SJustin Hibbits elf_file.ehdr.e_machine = EM_PPC64; 6626ff6d951SJohn Birrell #elif defined(__i386) || defined(__amd64) 6636ff6d951SJohn Birrell elf_file.ehdr.e_machine = EM_AMD64; 664a2ea7849SMark Johnston #elif defined(__aarch64__) 665a2ea7849SMark Johnston elf_file.ehdr.e_machine = EM_AARCH64; 666f711d5c3SMitchell Horne #elif defined(__riscv) 667f711d5c3SMitchell Horne elf_file.ehdr.e_machine = EM_RISCV; 668f711d5c3SMitchell Horne 669f711d5c3SMitchell Horne /* Set the ELF flags according to our current ABI */ 670f711d5c3SMitchell Horne #if defined(__riscv_compressed) 671f711d5c3SMitchell Horne elf_file.ehdr.e_flags |= EF_RISCV_RVC; 672f711d5c3SMitchell Horne #endif 673f711d5c3SMitchell Horne #if defined(__riscv_float_abi_soft) 674f711d5c3SMitchell Horne elf_file.ehdr.e_flags |= EF_RISCV_FLOAT_ABI_SOFT; 675f711d5c3SMitchell Horne #endif 676f711d5c3SMitchell Horne #if defined(__riscv_float_abi_single) 677f711d5c3SMitchell Horne elf_file.ehdr.e_flags |= EF_RISCV_FLOAT_ABI_SINGLE; 678f711d5c3SMitchell Horne #endif 679f711d5c3SMitchell Horne #if defined(__riscv_float_abi_double) 680f711d5c3SMitchell Horne elf_file.ehdr.e_flags |= EF_RISCV_FLOAT_ABI_DOUBLE; 681f711d5c3SMitchell Horne #endif 6826ff6d951SJohn Birrell #endif 6836ff6d951SJohn Birrell elf_file.ehdr.e_version = EV_CURRENT; 6846ff6d951SJohn Birrell elf_file.ehdr.e_shoff = sizeof (Elf64_Ehdr); 6856ff6d951SJohn Birrell elf_file.ehdr.e_ehsize = sizeof (Elf64_Ehdr); 6866ff6d951SJohn Birrell elf_file.ehdr.e_phentsize = sizeof (Elf64_Phdr); 6876ff6d951SJohn Birrell elf_file.ehdr.e_shentsize = sizeof (Elf64_Shdr); 6886ff6d951SJohn Birrell elf_file.ehdr.e_shnum = nshdr; 6896ff6d951SJohn Birrell elf_file.ehdr.e_shstrndx = ESHDR_SHSTRTAB; 6906ff6d951SJohn Birrell off = sizeof (elf_file) + nshdr * sizeof (Elf64_Shdr); 6916ff6d951SJohn Birrell 6926ff6d951SJohn Birrell shp = &elf_file.shdr[ESHDR_SHSTRTAB]; 6936ff6d951SJohn Birrell shp->sh_name = 1; /* DTRACE_SHSTRTAB64[1] = ".shstrtab" */ 6946ff6d951SJohn Birrell shp->sh_type = SHT_STRTAB; 6956ff6d951SJohn Birrell shp->sh_offset = off; 6966ff6d951SJohn Birrell shp->sh_size = sizeof (DTRACE_SHSTRTAB64); 6976ff6d951SJohn Birrell shp->sh_addralign = sizeof (char); 6980e15d9fbSMark Johnston off = roundup2(shp->sh_offset + shp->sh_size, 8); 6996ff6d951SJohn Birrell 7006ff6d951SJohn Birrell shp = &elf_file.shdr[ESHDR_DOF]; 7016ff6d951SJohn Birrell shp->sh_name = 11; /* DTRACE_SHSTRTAB64[11] = ".SUNW_dof" */ 7026ff6d951SJohn Birrell shp->sh_flags = SHF_ALLOC; 7036ff6d951SJohn Birrell shp->sh_type = SHT_SUNW_dof; 7046ff6d951SJohn Birrell shp->sh_offset = off; 7056ff6d951SJohn Birrell shp->sh_size = dof->dofh_filesz; 7066ff6d951SJohn Birrell shp->sh_addralign = 8; 7076ff6d951SJohn Birrell off = shp->sh_offset + shp->sh_size; 7086ff6d951SJohn Birrell 7096ff6d951SJohn Birrell shp = &elf_file.shdr[ESHDR_STRTAB]; 7106ff6d951SJohn Birrell shp->sh_name = 21; /* DTRACE_SHSTRTAB64[21] = ".strtab" */ 7116ff6d951SJohn Birrell shp->sh_flags = SHF_ALLOC; 7126ff6d951SJohn Birrell shp->sh_type = SHT_STRTAB; 7136ff6d951SJohn Birrell shp->sh_offset = off; 7146ff6d951SJohn Birrell shp->sh_size = de.de_strlen; 7156ff6d951SJohn Birrell shp->sh_addralign = sizeof (char); 7160e15d9fbSMark Johnston off = roundup2(shp->sh_offset + shp->sh_size, 8); 7176ff6d951SJohn Birrell 7186ff6d951SJohn Birrell shp = &elf_file.shdr[ESHDR_SYMTAB]; 7196ff6d951SJohn Birrell shp->sh_name = 29; /* DTRACE_SHSTRTAB64[29] = ".symtab" */ 7206ff6d951SJohn Birrell shp->sh_flags = SHF_ALLOC; 7216ff6d951SJohn Birrell shp->sh_type = SHT_SYMTAB; 7226ff6d951SJohn Birrell shp->sh_entsize = sizeof (Elf64_Sym); 7236ff6d951SJohn Birrell shp->sh_link = ESHDR_STRTAB; 7246ff6d951SJohn Birrell shp->sh_offset = off; 7256ff6d951SJohn Birrell shp->sh_info = de.de_global; 7266ff6d951SJohn Birrell shp->sh_size = de.de_nsym * sizeof (Elf64_Sym); 7276ff6d951SJohn Birrell shp->sh_addralign = 8; 7280e15d9fbSMark Johnston off = roundup2(shp->sh_offset + shp->sh_size, 8); 7296ff6d951SJohn Birrell 7306ff6d951SJohn Birrell if (de.de_nrel == 0) { 7316ff6d951SJohn Birrell if (dt_write(dtp, fd, &elf_file, 7326ff6d951SJohn Birrell sizeof (elf_file)) != sizeof (elf_file) || 7336ff6d951SJohn Birrell PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB64) || 7346ff6d951SJohn Birrell PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || 7356ff6d951SJohn Birrell PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || 7366ff6d951SJohn Birrell PWRITE_SCN(ESHDR_DOF, dof)) { 7376ff6d951SJohn Birrell ret = dt_set_errno(dtp, errno); 7386ff6d951SJohn Birrell } 7396ff6d951SJohn Birrell } else { 7406ff6d951SJohn Birrell shp = &elf_file.shdr[ESHDR_REL]; 7416ff6d951SJohn Birrell shp->sh_name = 37; /* DTRACE_SHSTRTAB64[37] = ".rel.SUNW_dof" */ 7426ff6d951SJohn Birrell shp->sh_flags = SHF_ALLOC; 7436ff6d951SJohn Birrell shp->sh_type = SHT_RELA; 7446ff6d951SJohn Birrell shp->sh_entsize = sizeof (de.de_rel[0]); 7456ff6d951SJohn Birrell shp->sh_link = ESHDR_SYMTAB; 7466ff6d951SJohn Birrell shp->sh_info = ESHDR_DOF; 7476ff6d951SJohn Birrell shp->sh_offset = off; 7486ff6d951SJohn Birrell shp->sh_size = de.de_nrel * sizeof (de.de_rel[0]); 7496ff6d951SJohn Birrell shp->sh_addralign = 8; 7506ff6d951SJohn Birrell 7516ff6d951SJohn Birrell if (dt_write(dtp, fd, &elf_file, 7526ff6d951SJohn Birrell sizeof (elf_file)) != sizeof (elf_file) || 7536ff6d951SJohn Birrell PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB64) || 7546ff6d951SJohn Birrell PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || 7556ff6d951SJohn Birrell PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || 7566ff6d951SJohn Birrell PWRITE_SCN(ESHDR_REL, de.de_rel) || 7576ff6d951SJohn Birrell PWRITE_SCN(ESHDR_DOF, dof)) { 7586ff6d951SJohn Birrell ret = dt_set_errno(dtp, errno); 7596ff6d951SJohn Birrell } 7606ff6d951SJohn Birrell } 7616ff6d951SJohn Birrell 7626ff6d951SJohn Birrell free(de.de_strtab); 7636ff6d951SJohn Birrell free(de.de_sym); 7646ff6d951SJohn Birrell free(de.de_rel); 7656ff6d951SJohn Birrell 7666ff6d951SJohn Birrell return (ret); 7676ff6d951SJohn Birrell } 7686ff6d951SJohn Birrell 7696ff6d951SJohn Birrell static int 770e801af6fSMark Johnston dt_symtab_lookup(Elf_Data *data_sym, int start, int end, uintptr_t addr, 771e801af6fSMark Johnston uint_t shn, GElf_Sym *sym, int uses_funcdesc, Elf *elf) 7726ff6d951SJohn Birrell { 773b08e2b04SJustin Hibbits Elf64_Addr symval; 774b08e2b04SJustin Hibbits Elf_Scn *opd_scn; 775b08e2b04SJustin Hibbits Elf_Data *opd_desc; 776e801af6fSMark Johnston int i; 7776ff6d951SJohn Birrell 778e801af6fSMark Johnston for (i = start; i < end && gelf_getsym(data_sym, i, sym) != NULL; i++) { 779b08e2b04SJustin Hibbits if (GELF_ST_TYPE(sym->st_info) == STT_FUNC) { 780b08e2b04SJustin Hibbits symval = sym->st_value; 781b08e2b04SJustin Hibbits if (uses_funcdesc) { 782b08e2b04SJustin Hibbits opd_scn = elf_getscn(elf, sym->st_shndx); 783b08e2b04SJustin Hibbits opd_desc = elf_rawdata(opd_scn, NULL); 784b08e2b04SJustin Hibbits symval = 785b08e2b04SJustin Hibbits *(uint64_t*)((char *)opd_desc->d_buf + symval); 786b08e2b04SJustin Hibbits } 787b08e2b04SJustin Hibbits if ((uses_funcdesc || shn == sym->st_shndx) && 788e801af6fSMark Johnston symval <= addr && addr < symval + sym->st_size) 7896ff6d951SJohn Birrell return (0); 7906ff6d951SJohn Birrell } 791b08e2b04SJustin Hibbits } 7926ff6d951SJohn Birrell 793e801af6fSMark Johnston return (-1); 7946ff6d951SJohn Birrell } 7956ff6d951SJohn Birrell 796b78ee15eSRuslan Bukin #if defined(__aarch64__) 797a2ea7849SMark Johnston #define DT_OP_NOP 0xd503201f 798a2ea7849SMark Johnston #define DT_OP_RET 0xd65f03c0 799a2ea7849SMark Johnston #define DT_OP_CALL26 0x94000000 800a2ea7849SMark Johnston #define DT_OP_JUMP26 0x14000000 801e627909dSMark Johnston #define DT_REL_NONE R_AARCH64_NONE 802a2ea7849SMark Johnston 803b78ee15eSRuslan Bukin static int 804b78ee15eSRuslan Bukin dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, 805b78ee15eSRuslan Bukin uint32_t *off) 806b78ee15eSRuslan Bukin { 807a2ea7849SMark Johnston uint32_t *ip; 808a2ea7849SMark Johnston 809a2ea7849SMark Johnston /* 810a2ea7849SMark Johnston * Ensure that the offset is aligned on an instruction boundary. 811a2ea7849SMark Johnston */ 812a2ea7849SMark Johnston if ((rela->r_offset & (sizeof (uint32_t) - 1)) != 0) 8134e4805ddSEd Maste return (-1); 814a2ea7849SMark Johnston 815a2ea7849SMark Johnston /* 816a2ea7849SMark Johnston * We only know about some specific relocation types. 817a2ea7849SMark Johnston * We also recognize relocation type NONE, since that gets used for 818a2ea7849SMark Johnston * relocations of USDT probes, and we might be re-processing a file. 819a2ea7849SMark Johnston */ 820a2ea7849SMark Johnston if (GELF_R_TYPE(rela->r_info) != R_AARCH64_CALL26 && 821a2ea7849SMark Johnston GELF_R_TYPE(rela->r_info) != R_AARCH64_JUMP26 && 822a2ea7849SMark Johnston GELF_R_TYPE(rela->r_info) != R_AARCH64_NONE) 823a2ea7849SMark Johnston return (-1); 824a2ea7849SMark Johnston 825a2ea7849SMark Johnston ip = (uint32_t *)(p + rela->r_offset); 826a2ea7849SMark Johnston 827a2ea7849SMark Johnston /* 828a2ea7849SMark Johnston * We may have already processed this object file in an earlier linker 829a2ea7849SMark Johnston * invocation. Check to see if the present instruction sequence matches 830a2ea7849SMark Johnston * the one we would install below. 831a2ea7849SMark Johnston */ 832a2ea7849SMark Johnston if (ip[0] == DT_OP_NOP || ip[0] == DT_OP_RET) 833a2ea7849SMark Johnston return (0); 834a2ea7849SMark Johnston 835a2ea7849SMark Johnston /* 836a2ea7849SMark Johnston * We only expect call instructions with a displacement of 0, or a jump 837a2ea7849SMark Johnston * instruction acting as a tail call. 838a2ea7849SMark Johnston */ 839a2ea7849SMark Johnston if (ip[0] != DT_OP_CALL26 && ip[0] != DT_OP_JUMP26) { 840a2ea7849SMark Johnston dt_dprintf("found %x instead of a call or jmp instruction at " 841a2ea7849SMark Johnston "%llx\n", ip[0], (u_longlong_t)rela->r_offset); 842a2ea7849SMark Johnston return (-1); 843a2ea7849SMark Johnston } 844a2ea7849SMark Johnston 845a2ea7849SMark Johnston /* 846a2ea7849SMark Johnston * On arm64, we do not have to differentiate between regular probes and 847a2ea7849SMark Johnston * is-enabled probes. Both cases are encoded as a regular branch for 848a2ea7849SMark Johnston * non-tail call locations, and a jump for tail call locations. Calls 849a2ea7849SMark Johnston * are to be converted into a no-op whereas jumps should become a 850a2ea7849SMark Johnston * return. 851a2ea7849SMark Johnston */ 852a2ea7849SMark Johnston if (ip[0] == DT_OP_CALL26) 853a2ea7849SMark Johnston ip[0] = DT_OP_NOP; 854a2ea7849SMark Johnston else 855a2ea7849SMark Johnston ip[0] = DT_OP_RET; 856a2ea7849SMark Johnston 857a2ea7849SMark Johnston return (0); 858b78ee15eSRuslan Bukin } 859b78ee15eSRuslan Bukin #elif defined(__arm__) 860d2d16e56SMark Johnston #define DT_REL_NONE R_ARM_NONE 861d2d16e56SMark Johnston 8622693feb4SJohn Birrell static int 8632693feb4SJohn Birrell dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, 8642693feb4SJohn Birrell uint32_t *off) 8652693feb4SJohn Birrell { 866732f2c69SEd Maste printf("%s:%s(%d): arm not implemented\n", __FUNCTION__, __FILE__, 867732f2c69SEd Maste __LINE__); 8684e4805ddSEd Maste return (-1); 8692693feb4SJohn Birrell } 8702693feb4SJohn Birrell #elif defined(__powerpc__) 87130b318b9SJustin Hibbits /* The sentinel is 'xor r3,r3,r3'. */ 87230b318b9SJustin Hibbits #define DT_OP_XOR_R3 0x7c631a78 87330b318b9SJustin Hibbits 87430b318b9SJustin Hibbits #define DT_OP_NOP 0x60000000 87530b318b9SJustin Hibbits #define DT_OP_BLR 0x4e800020 87630b318b9SJustin Hibbits 87730b318b9SJustin Hibbits /* This captures all forms of branching to address. */ 87830b318b9SJustin Hibbits #define DT_IS_BRANCH(inst) ((inst & 0xfc000000) == 0x48000000) 87930b318b9SJustin Hibbits #define DT_IS_BL(inst) (DT_IS_BRANCH(inst) && (inst & 0x01)) 88030b318b9SJustin Hibbits 881d2d16e56SMark Johnston #define DT_REL_NONE R_PPC_NONE 882d2d16e56SMark Johnston 8832693feb4SJohn Birrell static int 8842693feb4SJohn Birrell dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, 8852693feb4SJohn Birrell uint32_t *off) 8862693feb4SJohn Birrell { 88730b318b9SJustin Hibbits uint32_t *ip; 88830b318b9SJustin Hibbits 88930b318b9SJustin Hibbits if ((rela->r_offset & (sizeof (uint32_t) - 1)) != 0) 89030b318b9SJustin Hibbits return (-1); 89130b318b9SJustin Hibbits 89230b318b9SJustin Hibbits /*LINTED*/ 89330b318b9SJustin Hibbits ip = (uint32_t *)(p + rela->r_offset); 89430b318b9SJustin Hibbits 89530b318b9SJustin Hibbits /* 89630b318b9SJustin Hibbits * We only know about some specific relocation types. 89730b318b9SJustin Hibbits */ 89830b318b9SJustin Hibbits if (GELF_R_TYPE(rela->r_info) != R_PPC_REL24 && 899d2d16e56SMark Johnston GELF_R_TYPE(rela->r_info) != R_PPC_PLTREL24 && 900d2d16e56SMark Johnston GELF_R_TYPE(rela->r_info) != R_PPC_NONE) 90130b318b9SJustin Hibbits return (-1); 90230b318b9SJustin Hibbits 90330b318b9SJustin Hibbits /* 90430b318b9SJustin Hibbits * We may have already processed this object file in an earlier linker 90530b318b9SJustin Hibbits * invocation. Check to see if the present instruction sequence matches 90630b318b9SJustin Hibbits * the one we would install below. 90730b318b9SJustin Hibbits */ 90830b318b9SJustin Hibbits if (isenabled) { 90930b318b9SJustin Hibbits if (ip[0] == DT_OP_XOR_R3) { 91030b318b9SJustin Hibbits (*off) += sizeof (ip[0]); 91130b318b9SJustin Hibbits return (0); 91230b318b9SJustin Hibbits } 91330b318b9SJustin Hibbits } else { 91430b318b9SJustin Hibbits if (ip[0] == DT_OP_NOP) { 91530b318b9SJustin Hibbits (*off) += sizeof (ip[0]); 91630b318b9SJustin Hibbits return (0); 91730b318b9SJustin Hibbits } 91830b318b9SJustin Hibbits } 91930b318b9SJustin Hibbits 92030b318b9SJustin Hibbits /* 92130b318b9SJustin Hibbits * We only expect branch to address instructions. 92230b318b9SJustin Hibbits */ 92330b318b9SJustin Hibbits if (!DT_IS_BRANCH(ip[0])) { 92430b318b9SJustin Hibbits dt_dprintf("found %x instead of a branch instruction at %llx\n", 92530b318b9SJustin Hibbits ip[0], (u_longlong_t)rela->r_offset); 92630b318b9SJustin Hibbits return (-1); 92730b318b9SJustin Hibbits } 92830b318b9SJustin Hibbits 92930b318b9SJustin Hibbits if (isenabled) { 93030b318b9SJustin Hibbits /* 93130b318b9SJustin Hibbits * It would necessarily indicate incorrect usage if an is- 93230b318b9SJustin Hibbits * enabled probe were tail-called so flag that as an error. 93330b318b9SJustin Hibbits * It's also potentially (very) tricky to handle gracefully, 93430b318b9SJustin Hibbits * but could be done if this were a desired use scenario. 93530b318b9SJustin Hibbits */ 93630b318b9SJustin Hibbits if (!DT_IS_BL(ip[0])) { 93730b318b9SJustin Hibbits dt_dprintf("tail call to is-enabled probe at %llx\n", 93830b318b9SJustin Hibbits (u_longlong_t)rela->r_offset); 93930b318b9SJustin Hibbits return (-1); 94030b318b9SJustin Hibbits } 94130b318b9SJustin Hibbits 94230b318b9SJustin Hibbits ip[0] = DT_OP_XOR_R3; 94330b318b9SJustin Hibbits (*off) += sizeof (ip[0]); 94430b318b9SJustin Hibbits } else { 94530b318b9SJustin Hibbits if (DT_IS_BL(ip[0])) 94630b318b9SJustin Hibbits ip[0] = DT_OP_NOP; 94730b318b9SJustin Hibbits else 94830b318b9SJustin Hibbits ip[0] = DT_OP_BLR; 94930b318b9SJustin Hibbits } 95030b318b9SJustin Hibbits 9512693feb4SJohn Birrell return (0); 9522693feb4SJohn Birrell } 953ca20f8ecSRuslan Bukin #elif defined(__riscv) 954f711d5c3SMitchell Horne #define DT_OP_NOP 0x00000013 /* addi x0, x0, 0 */ 955f711d5c3SMitchell Horne #define DT_OP_RET 0x00008067 /* jalr x0, x1, 0 */ 956f711d5c3SMitchell Horne #define DT_OP_IS_AUIPC(op) (((op) & 0x7f) == 0x17) 957f711d5c3SMitchell Horne #define DT_OP_IS_JALR(op) (((op) & 0x707f) == 0x67) 958f711d5c3SMitchell Horne #define DT_OP_JALR_CALL 0x000080e7 /* jalr x1, x1, 0 */ 959f711d5c3SMitchell Horne #define DT_OP_JALR_TAIL 0x00030067 /* jalr x0, x6, 0 */ 960d2d16e56SMark Johnston #define DT_REL_NONE R_RISCV_NONE 961f711d5c3SMitchell Horne 962fed1ca4bSRuslan Bukin static int 963fed1ca4bSRuslan Bukin dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, 964fed1ca4bSRuslan Bukin uint32_t *off) 965fed1ca4bSRuslan Bukin { 966f711d5c3SMitchell Horne uint32_t *ip; 967f711d5c3SMitchell Horne 968f711d5c3SMitchell Horne /* 969f711d5c3SMitchell Horne * XXX: this implementation is untested, but should serve as a decent 970f711d5c3SMitchell Horne * starting point. 971f711d5c3SMitchell Horne */ 972f711d5c3SMitchell Horne 973f711d5c3SMitchell Horne /* 974f711d5c3SMitchell Horne * Ensure that the offset is aligned on a compressed-instruction 975f711d5c3SMitchell Horne * boundary. 976f711d5c3SMitchell Horne */ 977f711d5c3SMitchell Horne if ((rela->r_offset & (sizeof (uint16_t) - 1)) != 0) 9784e4805ddSEd Maste return (-1); 979f711d5c3SMitchell Horne 980f711d5c3SMitchell Horne /* 981f711d5c3SMitchell Horne * We only know about some specific relocation types. 982f711d5c3SMitchell Horne * We also recognize relocation type NONE, since that gets used for 983f711d5c3SMitchell Horne * relocations of USDT probes, and we might be re-processing a file. 984f711d5c3SMitchell Horne */ 985f711d5c3SMitchell Horne if (GELF_R_TYPE(rela->r_info) != R_RISCV_CALL && 986f711d5c3SMitchell Horne GELF_R_TYPE(rela->r_info) != R_RISCV_CALL_PLT && 987f711d5c3SMitchell Horne GELF_R_TYPE(rela->r_info) != R_RISCV_NONE) 988f711d5c3SMitchell Horne return (-1); 989f711d5c3SMitchell Horne 990f711d5c3SMitchell Horne ip = (uint32_t *)(p + rela->r_offset); 991f711d5c3SMitchell Horne 992f711d5c3SMitchell Horne /* 993f711d5c3SMitchell Horne * We may have already processed this object file in an earlier linker 994f711d5c3SMitchell Horne * invocation. Check to see if the present instruction sequence matches 995f711d5c3SMitchell Horne * the one we would install below. 996f711d5c3SMitchell Horne */ 997f711d5c3SMitchell Horne if (ip[0] == DT_OP_NOP && (ip[1] == DT_OP_NOP || ip[1] == DT_OP_RET)) 998f711d5c3SMitchell Horne return (0); 999f711d5c3SMitchell Horne 1000f711d5c3SMitchell Horne /* 1001f711d5c3SMitchell Horne * We expect a auipc+jalr pair, either from a call or a tail. 1002f711d5c3SMitchell Horne * - call: auipc x1 0; jalr x1, x1, 0 1003f711d5c3SMitchell Horne * - tail: auipc x6 0; jalr x0, x6, 0 1004f711d5c3SMitchell Horne */ 1005f711d5c3SMitchell Horne if (!DT_OP_IS_AUIPC(ip[0]) || !DT_OP_IS_JALR(ip[1])) 1006f711d5c3SMitchell Horne return (-1); 1007f711d5c3SMitchell Horne 1008f711d5c3SMitchell Horne /* 1009f711d5c3SMitchell Horne * On riscv, we do not have to differentiate between regular probes and 1010f711d5c3SMitchell Horne * is-enabled probes. Calls are to be converted into a no-op whereas 1011f711d5c3SMitchell Horne * tail calls should become a return. 1012f711d5c3SMitchell Horne */ 1013f711d5c3SMitchell Horne if (ip[1] == DT_OP_JALR_CALL) { 1014f711d5c3SMitchell Horne ip[0] = DT_OP_NOP; 1015f711d5c3SMitchell Horne ip[1] = DT_OP_NOP; 1016f711d5c3SMitchell Horne } else { 1017f711d5c3SMitchell Horne ip[0] = DT_OP_NOP; 1018f711d5c3SMitchell Horne ip[1] = DT_OP_RET; 1019f711d5c3SMitchell Horne } 1020f711d5c3SMitchell Horne 1021f711d5c3SMitchell Horne return (0); 1022fed1ca4bSRuslan Bukin } 10236ff6d951SJohn Birrell 10246ff6d951SJohn Birrell #elif defined(__i386) || defined(__amd64) 10256ff6d951SJohn Birrell 10266ff6d951SJohn Birrell #define DT_OP_NOP 0x90 10272693feb4SJohn Birrell #define DT_OP_RET 0xc3 10286ff6d951SJohn Birrell #define DT_OP_CALL 0xe8 10292693feb4SJohn Birrell #define DT_OP_JMP32 0xe9 10306ff6d951SJohn Birrell #define DT_OP_REX_RAX 0x48 10316ff6d951SJohn Birrell #define DT_OP_XOR_EAX_0 0x33 10326ff6d951SJohn Birrell #define DT_OP_XOR_EAX_1 0xc0 10336ff6d951SJohn Birrell 1034d2d16e56SMark Johnston #define DT_REL_NONE R_386_NONE 1035d2d16e56SMark Johnston 10366ff6d951SJohn Birrell static int 10376ff6d951SJohn Birrell dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, 10386ff6d951SJohn Birrell uint32_t *off) 10396ff6d951SJohn Birrell { 10406ff6d951SJohn Birrell uint8_t *ip = (uint8_t *)(p + rela->r_offset - 1); 10412693feb4SJohn Birrell uint8_t ret; 10426ff6d951SJohn Birrell 10436ff6d951SJohn Birrell /* 10446ff6d951SJohn Birrell * On x86, the first byte of the instruction is the call opcode and 10456ff6d951SJohn Birrell * the next four bytes are the 32-bit address; the relocation is for 10466ff6d951SJohn Birrell * the address operand. We back up the offset to the first byte of 10476ff6d951SJohn Birrell * the instruction. For is-enabled probes, we later advance the offset 10486ff6d951SJohn Birrell * so that it hits the first nop in the instruction sequence. 10496ff6d951SJohn Birrell */ 10506ff6d951SJohn Birrell (*off) -= 1; 10516ff6d951SJohn Birrell 10526ff6d951SJohn Birrell /* 10536ff6d951SJohn Birrell * We only know about some specific relocation types. Luckily 10546ff6d951SJohn Birrell * these types have the same values on both 32-bit and 64-bit 10556ff6d951SJohn Birrell * x86 architectures. 10566ff6d951SJohn Birrell */ 10576ff6d951SJohn Birrell if (GELF_R_TYPE(rela->r_info) != R_386_PC32 && 1058d2d16e56SMark Johnston GELF_R_TYPE(rela->r_info) != R_386_PLT32 && 1059d2d16e56SMark Johnston GELF_R_TYPE(rela->r_info) != R_386_NONE) 10606ff6d951SJohn Birrell return (-1); 10616ff6d951SJohn Birrell 10626ff6d951SJohn Birrell /* 10636ff6d951SJohn Birrell * We may have already processed this object file in an earlier linker 10646ff6d951SJohn Birrell * invocation. Check to see if the present instruction sequence matches 10656ff6d951SJohn Birrell * the one we would install. For is-enabled probes, we advance the 10662693feb4SJohn Birrell * offset to the first nop instruction in the sequence to match the 10672693feb4SJohn Birrell * text modification code below. 10686ff6d951SJohn Birrell */ 10696ff6d951SJohn Birrell if (!isenabled) { 10702693feb4SJohn Birrell if ((ip[0] == DT_OP_NOP || ip[0] == DT_OP_RET) && 10712693feb4SJohn Birrell ip[1] == DT_OP_NOP && ip[2] == DT_OP_NOP && 10722693feb4SJohn Birrell ip[3] == DT_OP_NOP && ip[4] == DT_OP_NOP) 10736ff6d951SJohn Birrell return (0); 10746ff6d951SJohn Birrell } else if (dtp->dt_oflags & DTRACE_O_LP64) { 10756ff6d951SJohn Birrell if (ip[0] == DT_OP_REX_RAX && 10766ff6d951SJohn Birrell ip[1] == DT_OP_XOR_EAX_0 && ip[2] == DT_OP_XOR_EAX_1 && 10772693feb4SJohn Birrell (ip[3] == DT_OP_NOP || ip[3] == DT_OP_RET) && 10782693feb4SJohn Birrell ip[4] == DT_OP_NOP) { 10796ff6d951SJohn Birrell (*off) += 3; 10806ff6d951SJohn Birrell return (0); 10816ff6d951SJohn Birrell } 10826ff6d951SJohn Birrell } else { 10836ff6d951SJohn Birrell if (ip[0] == DT_OP_XOR_EAX_0 && ip[1] == DT_OP_XOR_EAX_1 && 10842693feb4SJohn Birrell (ip[2] == DT_OP_NOP || ip[2] == DT_OP_RET) && 10852693feb4SJohn Birrell ip[3] == DT_OP_NOP && ip[4] == DT_OP_NOP) { 10866ff6d951SJohn Birrell (*off) += 2; 10876ff6d951SJohn Birrell return (0); 10886ff6d951SJohn Birrell } 10896ff6d951SJohn Birrell } 10906ff6d951SJohn Birrell 10916ff6d951SJohn Birrell /* 10922693feb4SJohn Birrell * We expect either a call instrution with a 32-bit displacement or a 10932693feb4SJohn Birrell * jmp instruction with a 32-bit displacement acting as a tail-call. 10946ff6d951SJohn Birrell */ 10952693feb4SJohn Birrell if (ip[0] != DT_OP_CALL && ip[0] != DT_OP_JMP32) { 10962693feb4SJohn Birrell dt_dprintf("found %x instead of a call or jmp instruction at " 10972693feb4SJohn Birrell "%llx\n", ip[0], (u_longlong_t)rela->r_offset); 10986ff6d951SJohn Birrell return (-1); 10996ff6d951SJohn Birrell } 11006ff6d951SJohn Birrell 11012693feb4SJohn Birrell ret = (ip[0] == DT_OP_JMP32) ? DT_OP_RET : DT_OP_NOP; 11022693feb4SJohn Birrell 11036ff6d951SJohn Birrell /* 11046ff6d951SJohn Birrell * Establish the instruction sequence -- all nops for probes, and an 11056ff6d951SJohn Birrell * instruction to clear the return value register (%eax/%rax) followed 11066ff6d951SJohn Birrell * by nops for is-enabled probes. For is-enabled probes, we advance 11076ff6d951SJohn Birrell * the offset to the first nop. This isn't stricly necessary but makes 11086ff6d951SJohn Birrell * for more readable disassembly when the probe is enabled. 11096ff6d951SJohn Birrell */ 11106ff6d951SJohn Birrell if (!isenabled) { 11112693feb4SJohn Birrell ip[0] = ret; 11126ff6d951SJohn Birrell ip[1] = DT_OP_NOP; 11136ff6d951SJohn Birrell ip[2] = DT_OP_NOP; 11146ff6d951SJohn Birrell ip[3] = DT_OP_NOP; 11156ff6d951SJohn Birrell ip[4] = DT_OP_NOP; 11166ff6d951SJohn Birrell } else if (dtp->dt_oflags & DTRACE_O_LP64) { 11176ff6d951SJohn Birrell ip[0] = DT_OP_REX_RAX; 11186ff6d951SJohn Birrell ip[1] = DT_OP_XOR_EAX_0; 11196ff6d951SJohn Birrell ip[2] = DT_OP_XOR_EAX_1; 11202693feb4SJohn Birrell ip[3] = ret; 11216ff6d951SJohn Birrell ip[4] = DT_OP_NOP; 11226ff6d951SJohn Birrell (*off) += 3; 11236ff6d951SJohn Birrell } else { 11246ff6d951SJohn Birrell ip[0] = DT_OP_XOR_EAX_0; 11256ff6d951SJohn Birrell ip[1] = DT_OP_XOR_EAX_1; 11262693feb4SJohn Birrell ip[2] = ret; 11276ff6d951SJohn Birrell ip[3] = DT_OP_NOP; 11286ff6d951SJohn Birrell ip[4] = DT_OP_NOP; 11296ff6d951SJohn Birrell (*off) += 2; 11306ff6d951SJohn Birrell } 11316ff6d951SJohn Birrell 11326ff6d951SJohn Birrell return (0); 11336ff6d951SJohn Birrell } 11346ff6d951SJohn Birrell 11356ff6d951SJohn Birrell #else 11366ff6d951SJohn Birrell #error unknown ISA 11376ff6d951SJohn Birrell #endif 11386ff6d951SJohn Birrell 11396ff6d951SJohn Birrell /*PRINTFLIKE5*/ 11406ff6d951SJohn Birrell static int 11416ff6d951SJohn Birrell dt_link_error(dtrace_hdl_t *dtp, Elf *elf, int fd, dt_link_pair_t *bufs, 11426ff6d951SJohn Birrell const char *format, ...) 11436ff6d951SJohn Birrell { 11446ff6d951SJohn Birrell va_list ap; 11456ff6d951SJohn Birrell dt_link_pair_t *pair; 11466ff6d951SJohn Birrell 11476ff6d951SJohn Birrell va_start(ap, format); 11486ff6d951SJohn Birrell dt_set_errmsg(dtp, NULL, NULL, NULL, 0, format, ap); 11496ff6d951SJohn Birrell va_end(ap); 11506ff6d951SJohn Birrell 11516ff6d951SJohn Birrell if (elf != NULL) 11526ff6d951SJohn Birrell (void) elf_end(elf); 11536ff6d951SJohn Birrell 11546ff6d951SJohn Birrell if (fd >= 0) 11556ff6d951SJohn Birrell (void) close(fd); 11566ff6d951SJohn Birrell 11576ff6d951SJohn Birrell while ((pair = bufs) != NULL) { 11586ff6d951SJohn Birrell bufs = pair->dlp_next; 11596ff6d951SJohn Birrell dt_free(dtp, pair->dlp_str); 11606ff6d951SJohn Birrell dt_free(dtp, pair->dlp_sym); 11616ff6d951SJohn Birrell dt_free(dtp, pair); 11626ff6d951SJohn Birrell } 11636ff6d951SJohn Birrell 11646ff6d951SJohn Birrell return (dt_set_errno(dtp, EDT_COMPILER)); 11656ff6d951SJohn Birrell } 11666ff6d951SJohn Birrell 1167938acb08SMark Johnston /* 1168938acb08SMark Johnston * Provide a unique identifier used when adding global symbols to an object. 1169938acb08SMark Johnston * This is the FNV-1a hash of an absolute path for the file. 1170938acb08SMark Johnston */ 1171938acb08SMark Johnston static unsigned int 1172938acb08SMark Johnston hash_obj(const char *obj, int fd) 1173938acb08SMark Johnston { 1174938acb08SMark Johnston char path[PATH_MAX]; 1175938acb08SMark Johnston unsigned int h; 1176938acb08SMark Johnston 1177938acb08SMark Johnston if (realpath(obj, path) == NULL) 1178938acb08SMark Johnston return (-1); 1179938acb08SMark Johnston 1180938acb08SMark Johnston for (h = 2166136261u, obj = &path[0]; *obj != '\0'; obj++) 1181938acb08SMark Johnston h = (h ^ *obj) * 16777619; 1182938acb08SMark Johnston h &= 0x7fffffff; 1183938acb08SMark Johnston return (h); 1184938acb08SMark Johnston } 1185938acb08SMark Johnston 11866ff6d951SJohn Birrell static int 11876ff6d951SJohn Birrell process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp) 11886ff6d951SJohn Birrell { 11896ff6d951SJohn Birrell static const char dt_prefix[] = "__dtrace"; 11906ff6d951SJohn Birrell static const char dt_enabled[] = "enabled"; 11916ff6d951SJohn Birrell static const char dt_symprefix[] = "$dtrace"; 1192938acb08SMark Johnston static const char dt_symfmt[] = "%s%u.%s"; 1193281e4f2dSMark Johnston static const char dt_weaksymfmt[] = "%s.%s"; 11943a3e3279SMark Johnston char probename[DTRACE_NAMELEN]; 11957283901aSBrandon Bergren int fd, i, ndx, eprobe, uses_funcdesc = 0, mod = 0; 11966ff6d951SJohn Birrell Elf *elf = NULL; 11976ff6d951SJohn Birrell GElf_Ehdr ehdr; 11986ff6d951SJohn Birrell Elf_Scn *scn_rel, *scn_sym, *scn_str, *scn_tgt; 11996ff6d951SJohn Birrell Elf_Data *data_rel, *data_sym, *data_str, *data_tgt; 12006ff6d951SJohn Birrell GElf_Shdr shdr_rel, shdr_sym, shdr_str, shdr_tgt; 12016ff6d951SJohn Birrell GElf_Sym rsym, fsym, dsym; 12026ff6d951SJohn Birrell GElf_Rela rela; 12036ff6d951SJohn Birrell char *s, *p, *r; 12046ff6d951SJohn Birrell char pname[DTRACE_PROVNAMELEN]; 12056ff6d951SJohn Birrell dt_provider_t *pvp; 12066ff6d951SJohn Birrell dt_probe_t *prp; 12076ff6d951SJohn Birrell uint32_t off, eclass, emachine1, emachine2; 1208e801af6fSMark Johnston size_t symsize, osym, nsym, isym, istr, len; 1209938acb08SMark Johnston unsigned int objkey; 12106ff6d951SJohn Birrell dt_link_pair_t *pair, *bufs = NULL; 12116ff6d951SJohn Birrell dt_strtab_t *strtab; 1212273efb05SMark Johnston void *tmp; 12136ff6d951SJohn Birrell 12146ff6d951SJohn Birrell if ((fd = open64(obj, O_RDWR)) == -1) { 12156ff6d951SJohn Birrell return (dt_link_error(dtp, elf, fd, bufs, 12166ff6d951SJohn Birrell "failed to open %s: %s", obj, strerror(errno))); 12176ff6d951SJohn Birrell } 12186ff6d951SJohn Birrell 12196ff6d951SJohn Birrell if ((elf = elf_begin(fd, ELF_C_RDWR, NULL)) == NULL) { 12206ff6d951SJohn Birrell return (dt_link_error(dtp, elf, fd, bufs, 12216ff6d951SJohn Birrell "failed to process %s: %s", obj, elf_errmsg(elf_errno()))); 12226ff6d951SJohn Birrell } 12236ff6d951SJohn Birrell 12246ff6d951SJohn Birrell switch (elf_kind(elf)) { 12256ff6d951SJohn Birrell case ELF_K_ELF: 12266ff6d951SJohn Birrell break; 12276ff6d951SJohn Birrell case ELF_K_AR: 12286ff6d951SJohn Birrell return (dt_link_error(dtp, elf, fd, bufs, "archives are not " 12296ff6d951SJohn Birrell "permitted; use the contents of the archive instead: %s", 12306ff6d951SJohn Birrell obj)); 12316ff6d951SJohn Birrell default: 12326ff6d951SJohn Birrell return (dt_link_error(dtp, elf, fd, bufs, 12336ff6d951SJohn Birrell "invalid file type: %s", obj)); 12346ff6d951SJohn Birrell } 12356ff6d951SJohn Birrell 12366ff6d951SJohn Birrell if (gelf_getehdr(elf, &ehdr) == NULL) { 12376ff6d951SJohn Birrell return (dt_link_error(dtp, elf, fd, bufs, "corrupt file: %s", 12386ff6d951SJohn Birrell obj)); 12396ff6d951SJohn Birrell } 12406ff6d951SJohn Birrell 12416ff6d951SJohn Birrell if (dtp->dt_oflags & DTRACE_O_LP64) { 12426ff6d951SJohn Birrell eclass = ELFCLASS64; 12432166649fSMitchell Horne #if defined(__powerpc__) 12442693feb4SJohn Birrell emachine1 = emachine2 = EM_PPC64; 12457283901aSBrandon Bergren #if !defined(_CALL_ELF) || _CALL_ELF == 1 12467283901aSBrandon Bergren uses_funcdesc = 1; 12477283901aSBrandon Bergren #endif 12486ff6d951SJohn Birrell #elif defined(__i386) || defined(__amd64) 12496ff6d951SJohn Birrell emachine1 = emachine2 = EM_AMD64; 1250a2ea7849SMark Johnston #elif defined(__aarch64__) 1251a2ea7849SMark Johnston emachine1 = emachine2 = EM_AARCH64; 1252f711d5c3SMitchell Horne #elif defined(__riscv) 1253f711d5c3SMitchell Horne emachine1 = emachine2 = EM_RISCV; 12546ff6d951SJohn Birrell #endif 12556ff6d951SJohn Birrell symsize = sizeof (Elf64_Sym); 12566ff6d951SJohn Birrell } else { 12576ff6d951SJohn Birrell eclass = ELFCLASS32; 12582693feb4SJohn Birrell #if defined(__arm__) 12592693feb4SJohn Birrell emachine1 = emachine2 = EM_ARM; 12602693feb4SJohn Birrell #elif defined(__powerpc__) 12612693feb4SJohn Birrell emachine1 = emachine2 = EM_PPC; 1262e7d939bdSMarcel Moolenaar #elif defined(__i386) || defined(__amd64) 12636ff6d951SJohn Birrell emachine1 = emachine2 = EM_386; 12646ff6d951SJohn Birrell #endif 12656ff6d951SJohn Birrell symsize = sizeof (Elf32_Sym); 12666ff6d951SJohn Birrell } 12676ff6d951SJohn Birrell 12686ff6d951SJohn Birrell if (ehdr.e_ident[EI_CLASS] != eclass) { 12696ff6d951SJohn Birrell return (dt_link_error(dtp, elf, fd, bufs, 12706ff6d951SJohn Birrell "incorrect ELF class for object file: %s", obj)); 12716ff6d951SJohn Birrell } 12726ff6d951SJohn Birrell 12736ff6d951SJohn Birrell if (ehdr.e_machine != emachine1 && ehdr.e_machine != emachine2) { 12746ff6d951SJohn Birrell return (dt_link_error(dtp, elf, fd, bufs, 12756ff6d951SJohn Birrell "incorrect ELF machine type for object file: %s", obj)); 12766ff6d951SJohn Birrell } 12776ff6d951SJohn Birrell 12786ff6d951SJohn Birrell /* 12796ff6d951SJohn Birrell * We use this token as a relatively unique handle for this file on the 12806ff6d951SJohn Birrell * system in order to disambiguate potential conflicts between files of 12816ff6d951SJohn Birrell * the same name which contain identially named local symbols. 12826ff6d951SJohn Birrell */ 1283938acb08SMark Johnston if ((objkey = hash_obj(obj, fd)) == (unsigned int)-1) 12846ff6d951SJohn Birrell return (dt_link_error(dtp, elf, fd, bufs, 12856ff6d951SJohn Birrell "failed to generate unique key for object file: %s", obj)); 12866ff6d951SJohn Birrell 12876ff6d951SJohn Birrell scn_rel = NULL; 12886ff6d951SJohn Birrell while ((scn_rel = elf_nextscn(elf, scn_rel)) != NULL) { 12896ff6d951SJohn Birrell if (gelf_getshdr(scn_rel, &shdr_rel) == NULL) 12906ff6d951SJohn Birrell goto err; 12916ff6d951SJohn Birrell 12926ff6d951SJohn Birrell /* 12936ff6d951SJohn Birrell * Skip any non-relocation sections. 12946ff6d951SJohn Birrell */ 12956ff6d951SJohn Birrell if (shdr_rel.sh_type != SHT_RELA && shdr_rel.sh_type != SHT_REL) 12966ff6d951SJohn Birrell continue; 12976ff6d951SJohn Birrell 12986ff6d951SJohn Birrell if ((data_rel = elf_getdata(scn_rel, NULL)) == NULL) 12996ff6d951SJohn Birrell goto err; 13006ff6d951SJohn Birrell 13016ff6d951SJohn Birrell /* 13026ff6d951SJohn Birrell * Grab the section, section header and section data for the 13036ff6d951SJohn Birrell * symbol table that this relocation section references. 13046ff6d951SJohn Birrell */ 13056ff6d951SJohn Birrell if ((scn_sym = elf_getscn(elf, shdr_rel.sh_link)) == NULL || 13066ff6d951SJohn Birrell gelf_getshdr(scn_sym, &shdr_sym) == NULL || 13076ff6d951SJohn Birrell (data_sym = elf_getdata(scn_sym, NULL)) == NULL) 13086ff6d951SJohn Birrell goto err; 13096ff6d951SJohn Birrell 13106ff6d951SJohn Birrell /* 13116ff6d951SJohn Birrell * Ditto for that symbol table's string table. 13126ff6d951SJohn Birrell */ 13136ff6d951SJohn Birrell if ((scn_str = elf_getscn(elf, shdr_sym.sh_link)) == NULL || 13146ff6d951SJohn Birrell gelf_getshdr(scn_str, &shdr_str) == NULL || 13156ff6d951SJohn Birrell (data_str = elf_getdata(scn_str, NULL)) == NULL) 13166ff6d951SJohn Birrell goto err; 13176ff6d951SJohn Birrell 13186ff6d951SJohn Birrell /* 13196ff6d951SJohn Birrell * Grab the section, section header and section data for the 13206ff6d951SJohn Birrell * target section for the relocations. For the relocations 13216ff6d951SJohn Birrell * we're looking for -- this will typically be the text of the 13226ff6d951SJohn Birrell * object file. 13236ff6d951SJohn Birrell */ 13246ff6d951SJohn Birrell if ((scn_tgt = elf_getscn(elf, shdr_rel.sh_info)) == NULL || 13256ff6d951SJohn Birrell gelf_getshdr(scn_tgt, &shdr_tgt) == NULL || 13266ff6d951SJohn Birrell (data_tgt = elf_getdata(scn_tgt, NULL)) == NULL) 13276ff6d951SJohn Birrell goto err; 13286ff6d951SJohn Birrell 13296ff6d951SJohn Birrell /* 13306ff6d951SJohn Birrell * We're looking for relocations to symbols matching this form: 13316ff6d951SJohn Birrell * 13326ff6d951SJohn Birrell * __dtrace[enabled]_<prov>___<probe> 13336ff6d951SJohn Birrell * 13346ff6d951SJohn Birrell * For the generated object, we need to record the location 13356ff6d951SJohn Birrell * identified by the relocation, and create a new relocation 13366ff6d951SJohn Birrell * in the generated object that will be resolved at link time 13376ff6d951SJohn Birrell * to the location of the function in which the probe is 13386ff6d951SJohn Birrell * embedded. In the target object, we change the matched symbol 13396ff6d951SJohn Birrell * so that it will be ignored at link time, and we modify the 13406ff6d951SJohn Birrell * target (text) section to replace the call instruction with 13416ff6d951SJohn Birrell * one or more nops. 13426ff6d951SJohn Birrell * 1343e801af6fSMark Johnston * To avoid runtime overhead, the relocations added to the 1344e801af6fSMark Johnston * generated object should be resolved at static link time. We 1345e801af6fSMark Johnston * therefore create aliases for the functions that contain 1346e801af6fSMark Johnston * probes. An alias is global (so that the relocation from the 1347e801af6fSMark Johnston * generated object can be resolved), and hidden (so that its 1348e801af6fSMark Johnston * address is known at static link time). Such aliases have this 1349e801af6fSMark Johnston * form: 13506ff6d951SJohn Birrell * 13516ff6d951SJohn Birrell * $dtrace<key>.<function> 13526ff6d951SJohn Birrell * 13536ff6d951SJohn Birrell * We take a first pass through all the relocations to 13546ff6d951SJohn Birrell * populate our string table and count the number of extra 13556ff6d951SJohn Birrell * symbols we'll require. 1356d2d16e56SMark Johnston * 1357d2d16e56SMark Johnston * We also handle the case where the object has already been 1358d2d16e56SMark Johnston * processed, to support incremental rebuilds. Relocations 1359d2d16e56SMark Johnston * of interest are converted to type NONE, but all information 1360d2d16e56SMark Johnston * needed to reconstruct the output DOF is retained. 13616ff6d951SJohn Birrell */ 13626ff6d951SJohn Birrell strtab = dt_strtab_create(1); 13636ff6d951SJohn Birrell nsym = 0; 13646ff6d951SJohn Birrell isym = data_sym->d_size / symsize; 13656ff6d951SJohn Birrell istr = data_str->d_size; 13666ff6d951SJohn Birrell 13676ff6d951SJohn Birrell for (i = 0; i < shdr_rel.sh_size / shdr_rel.sh_entsize; i++) { 13686ff6d951SJohn Birrell if (shdr_rel.sh_type == SHT_RELA) { 13696ff6d951SJohn Birrell if (gelf_getrela(data_rel, i, &rela) == NULL) 13706ff6d951SJohn Birrell continue; 13716ff6d951SJohn Birrell } else { 13726ff6d951SJohn Birrell GElf_Rel rel; 13736ff6d951SJohn Birrell if (gelf_getrel(data_rel, i, &rel) == NULL) 13746ff6d951SJohn Birrell continue; 13756ff6d951SJohn Birrell rela.r_offset = rel.r_offset; 13766ff6d951SJohn Birrell rela.r_info = rel.r_info; 13776ff6d951SJohn Birrell rela.r_addend = 0; 13786ff6d951SJohn Birrell } 13796ff6d951SJohn Birrell 13806ff6d951SJohn Birrell if (gelf_getsym(data_sym, GELF_R_SYM(rela.r_info), 13816ff6d951SJohn Birrell &rsym) == NULL) { 13826ff6d951SJohn Birrell dt_strtab_destroy(strtab); 13836ff6d951SJohn Birrell goto err; 13846ff6d951SJohn Birrell } 13856ff6d951SJohn Birrell 13866ff6d951SJohn Birrell s = (char *)data_str->d_buf + rsym.st_name; 13876ff6d951SJohn Birrell 13886ff6d951SJohn Birrell if (strncmp(s, dt_prefix, sizeof (dt_prefix) - 1) != 0) 13896ff6d951SJohn Birrell continue; 13906ff6d951SJohn Birrell 1391e801af6fSMark Johnston if (dt_symtab_lookup(data_sym, 0, isym, rela.r_offset, 13927283901aSBrandon Bergren shdr_rel.sh_info, &fsym, uses_funcdesc, 1393e801af6fSMark Johnston elf) != 0) { 13946ff6d951SJohn Birrell dt_strtab_destroy(strtab); 13956ff6d951SJohn Birrell goto err; 13966ff6d951SJohn Birrell } 13976ff6d951SJohn Birrell 13986ff6d951SJohn Birrell if (fsym.st_name > data_str->d_size) { 13996ff6d951SJohn Birrell dt_strtab_destroy(strtab); 14006ff6d951SJohn Birrell goto err; 14016ff6d951SJohn Birrell } 14026ff6d951SJohn Birrell 14036ff6d951SJohn Birrell s = (char *)data_str->d_buf + fsym.st_name; 14046ff6d951SJohn Birrell 14056ff6d951SJohn Birrell /* 14066ff6d951SJohn Birrell * If this symbol isn't of type function, we've really 14076ff6d951SJohn Birrell * driven off the rails or the object file is corrupt. 14086ff6d951SJohn Birrell */ 14096ff6d951SJohn Birrell if (GELF_ST_TYPE(fsym.st_info) != STT_FUNC) { 14106ff6d951SJohn Birrell dt_strtab_destroy(strtab); 14116ff6d951SJohn Birrell return (dt_link_error(dtp, elf, fd, bufs, 14126ff6d951SJohn Birrell "expected %s to be of type function", s)); 14136ff6d951SJohn Birrell } 14146ff6d951SJohn Birrell 1415ad1633b3SMark Johnston /* 1416ad1633b3SMark Johnston * Aliases of weak symbols don't get a uniquifier. 1417ad1633b3SMark Johnston */ 1418d00431a7SMark Johnston if (GELF_ST_BIND(fsym.st_info) == STB_WEAK) { 1419ad1633b3SMark Johnston len = snprintf(NULL, 0, dt_weaksymfmt, 1420ad1633b3SMark Johnston dt_symprefix, s) + 1; 1421d00431a7SMark Johnston } else { 14226ff6d951SJohn Birrell len = snprintf(NULL, 0, dt_symfmt, dt_symprefix, 14236ff6d951SJohn Birrell objkey, s) + 1; 1424d00431a7SMark Johnston } 14256ff6d951SJohn Birrell if ((p = dt_alloc(dtp, len)) == NULL) { 14266ff6d951SJohn Birrell dt_strtab_destroy(strtab); 14276ff6d951SJohn Birrell goto err; 14286ff6d951SJohn Birrell } 1429d00431a7SMark Johnston if (GELF_ST_BIND(fsym.st_info) == STB_WEAK) { 1430d00431a7SMark Johnston (void) snprintf(p, len, dt_weaksymfmt, 1431d00431a7SMark Johnston dt_symprefix, s); 1432d00431a7SMark Johnston } else { 14336ff6d951SJohn Birrell (void) snprintf(p, len, dt_symfmt, dt_symprefix, 14346ff6d951SJohn Birrell objkey, s); 1435d00431a7SMark Johnston } 14366ff6d951SJohn Birrell 14376ff6d951SJohn Birrell if (dt_strtab_index(strtab, p) == -1) { 1438d2d16e56SMark Johnston /* 1439d2d16e56SMark Johnston * Do not add new symbols if this object file 1440d2d16e56SMark Johnston * has already been processed. 1441d2d16e56SMark Johnston */ 1442d2d16e56SMark Johnston if (GELF_R_TYPE(rela.r_info) != DT_REL_NONE) 14436ff6d951SJohn Birrell nsym++; 14446ff6d951SJohn Birrell (void) dt_strtab_insert(strtab, p); 14456ff6d951SJohn Birrell } 14466ff6d951SJohn Birrell 14476ff6d951SJohn Birrell dt_free(dtp, p); 14486ff6d951SJohn Birrell } 14496ff6d951SJohn Birrell 14506ff6d951SJohn Birrell /* 1451d2d16e56SMark Johnston * If any new probes were found, allocate the additional space 1452d2d16e56SMark Johnston * for the symbol table and string table, copying the old data 1453d2d16e56SMark Johnston * into the new buffers, and marking the buffers as dirty. We 1454d2d16e56SMark Johnston * inject those newly allocated buffers into the libelf data 1455e801af6fSMark Johnston * structures, but are still responsible for freeing them once 1456e801af6fSMark Johnston * we're done with the elf handle. 14576ff6d951SJohn Birrell */ 1458d2d16e56SMark Johnston osym = isym; 14596ff6d951SJohn Birrell if (nsym > 0) { 14606ff6d951SJohn Birrell /* 14616ff6d951SJohn Birrell * The first byte of the string table is reserved for 14626ff6d951SJohn Birrell * the \0 entry. 14636ff6d951SJohn Birrell */ 14646ff6d951SJohn Birrell len = dt_strtab_size(strtab) - 1; 14656ff6d951SJohn Birrell 14666ff6d951SJohn Birrell assert(len > 0); 14676ff6d951SJohn Birrell assert(dt_strtab_index(strtab, "") == 0); 14686ff6d951SJohn Birrell 14696ff6d951SJohn Birrell dt_strtab_destroy(strtab); 14706ff6d951SJohn Birrell 14716ff6d951SJohn Birrell if ((pair = dt_alloc(dtp, sizeof (*pair))) == NULL) 14726ff6d951SJohn Birrell goto err; 14736ff6d951SJohn Birrell 14746ff6d951SJohn Birrell if ((pair->dlp_str = dt_alloc(dtp, data_str->d_size + 14756ff6d951SJohn Birrell len)) == NULL) { 14766ff6d951SJohn Birrell dt_free(dtp, pair); 14776ff6d951SJohn Birrell goto err; 14786ff6d951SJohn Birrell } 14796ff6d951SJohn Birrell 14806ff6d951SJohn Birrell if ((pair->dlp_sym = dt_alloc(dtp, data_sym->d_size + 14816ff6d951SJohn Birrell nsym * symsize)) == NULL) { 14826ff6d951SJohn Birrell dt_free(dtp, pair->dlp_str); 14836ff6d951SJohn Birrell dt_free(dtp, pair); 14846ff6d951SJohn Birrell goto err; 14856ff6d951SJohn Birrell } 14866ff6d951SJohn Birrell 14876ff6d951SJohn Birrell pair->dlp_next = bufs; 14886ff6d951SJohn Birrell bufs = pair; 14896ff6d951SJohn Birrell 14906ff6d951SJohn Birrell bcopy(data_str->d_buf, pair->dlp_str, data_str->d_size); 1491273efb05SMark Johnston tmp = data_str->d_buf; 14926ff6d951SJohn Birrell data_str->d_buf = pair->dlp_str; 1493273efb05SMark Johnston pair->dlp_str = tmp; 14946ff6d951SJohn Birrell data_str->d_size += len; 14956ff6d951SJohn Birrell (void) elf_flagdata(data_str, ELF_C_SET, ELF_F_DIRTY); 14966ff6d951SJohn Birrell 14976ff6d951SJohn Birrell shdr_str.sh_size += len; 14986ff6d951SJohn Birrell (void) gelf_update_shdr(scn_str, &shdr_str); 14996ff6d951SJohn Birrell 15006ff6d951SJohn Birrell bcopy(data_sym->d_buf, pair->dlp_sym, data_sym->d_size); 1501273efb05SMark Johnston tmp = data_sym->d_buf; 15026ff6d951SJohn Birrell data_sym->d_buf = pair->dlp_sym; 1503273efb05SMark Johnston pair->dlp_sym = tmp; 15046ff6d951SJohn Birrell data_sym->d_size += nsym * symsize; 15056ff6d951SJohn Birrell (void) elf_flagdata(data_sym, ELF_C_SET, ELF_F_DIRTY); 15066ff6d951SJohn Birrell 15076ff6d951SJohn Birrell shdr_sym.sh_size += nsym * symsize; 15086ff6d951SJohn Birrell (void) gelf_update_shdr(scn_sym, &shdr_sym); 15096ff6d951SJohn Birrell 15106ff6d951SJohn Birrell nsym += isym; 1511d2d16e56SMark Johnston } else if (dt_strtab_empty(strtab)) { 15126ff6d951SJohn Birrell dt_strtab_destroy(strtab); 1513e801af6fSMark Johnston continue; 15146ff6d951SJohn Birrell } 15156ff6d951SJohn Birrell 15166ff6d951SJohn Birrell /* 15176ff6d951SJohn Birrell * Now that the tables have been allocated, perform the 15186ff6d951SJohn Birrell * modifications described above. 15196ff6d951SJohn Birrell */ 15206ff6d951SJohn Birrell for (i = 0; i < shdr_rel.sh_size / shdr_rel.sh_entsize; i++) { 15216ff6d951SJohn Birrell if (shdr_rel.sh_type == SHT_RELA) { 15226ff6d951SJohn Birrell if (gelf_getrela(data_rel, i, &rela) == NULL) 15236ff6d951SJohn Birrell continue; 15246ff6d951SJohn Birrell } else { 15256ff6d951SJohn Birrell GElf_Rel rel; 15266ff6d951SJohn Birrell if (gelf_getrel(data_rel, i, &rel) == NULL) 15276ff6d951SJohn Birrell continue; 15286ff6d951SJohn Birrell rela.r_offset = rel.r_offset; 15296ff6d951SJohn Birrell rela.r_info = rel.r_info; 15306ff6d951SJohn Birrell rela.r_addend = 0; 15316ff6d951SJohn Birrell } 15326ff6d951SJohn Birrell 15336ff6d951SJohn Birrell ndx = GELF_R_SYM(rela.r_info); 15346ff6d951SJohn Birrell 15356ff6d951SJohn Birrell if (gelf_getsym(data_sym, ndx, &rsym) == NULL || 15366ff6d951SJohn Birrell rsym.st_name > data_str->d_size) 15376ff6d951SJohn Birrell goto err; 15386ff6d951SJohn Birrell 15396ff6d951SJohn Birrell s = (char *)data_str->d_buf + rsym.st_name; 15406ff6d951SJohn Birrell 15416ff6d951SJohn Birrell if (strncmp(s, dt_prefix, sizeof (dt_prefix) - 1) != 0) 15426ff6d951SJohn Birrell continue; 15436ff6d951SJohn Birrell 15446ff6d951SJohn Birrell s += sizeof (dt_prefix) - 1; 15456ff6d951SJohn Birrell 15466ff6d951SJohn Birrell /* 15476ff6d951SJohn Birrell * Check to see if this is an 'is-enabled' check as 15486ff6d951SJohn Birrell * opposed to a normal probe. 15496ff6d951SJohn Birrell */ 15506ff6d951SJohn Birrell if (strncmp(s, dt_enabled, 15516ff6d951SJohn Birrell sizeof (dt_enabled) - 1) == 0) { 15526ff6d951SJohn Birrell s += sizeof (dt_enabled) - 1; 15536ff6d951SJohn Birrell eprobe = 1; 15546ff6d951SJohn Birrell *eprobesp = 1; 15556ff6d951SJohn Birrell dt_dprintf("is-enabled probe\n"); 15566ff6d951SJohn Birrell } else { 15576ff6d951SJohn Birrell eprobe = 0; 15586ff6d951SJohn Birrell dt_dprintf("normal probe\n"); 15596ff6d951SJohn Birrell } 15606ff6d951SJohn Birrell 15616ff6d951SJohn Birrell if (*s++ != '_') 15626ff6d951SJohn Birrell goto err; 15636ff6d951SJohn Birrell 15646ff6d951SJohn Birrell if ((p = strstr(s, "___")) == NULL || 15656ff6d951SJohn Birrell p - s >= sizeof (pname)) 15666ff6d951SJohn Birrell goto err; 15676ff6d951SJohn Birrell 15686ff6d951SJohn Birrell bcopy(s, pname, p - s); 15696ff6d951SJohn Birrell pname[p - s] = '\0'; 15706ff6d951SJohn Birrell 1571e801af6fSMark Johnston if (dt_symtab_lookup(data_sym, osym, isym, 1572e801af6fSMark Johnston rela.r_offset, shdr_rel.sh_info, &fsym, 15737283901aSBrandon Bergren uses_funcdesc, elf) == 0) { 15746ff6d951SJohn Birrell if (fsym.st_name > data_str->d_size) 15756ff6d951SJohn Birrell goto err; 15766ff6d951SJohn Birrell 1577281e4f2dSMark Johnston r = s = (char *) data_str->d_buf + fsym.st_name; 1578281e4f2dSMark Johnston assert(strstr(s, dt_symprefix) == s); 1579281e4f2dSMark Johnston s = strchr(s, '.') + 1; 1580281e4f2dSMark Johnston } else if (dt_symtab_lookup(data_sym, 0, osym, 1581281e4f2dSMark Johnston rela.r_offset, shdr_rel.sh_info, &fsym, 15827283901aSBrandon Bergren uses_funcdesc, elf) == 0) { 1583281e4f2dSMark Johnston u_int bind; 1584281e4f2dSMark Johnston 1585281e4f2dSMark Johnston bind = GELF_ST_BIND(fsym.st_info) == STB_WEAK ? 1586281e4f2dSMark Johnston STB_WEAK : STB_GLOBAL; 1587d2d16e56SMark Johnston s = (char *) data_str->d_buf + fsym.st_name; 1588d2d16e56SMark Johnston if (GELF_R_TYPE(rela.r_info) != DT_REL_NONE) { 15896ff6d951SJohn Birrell /* 1590d2d16e56SMark Johnston * Emit an alias for the symbol. It 1591d2d16e56SMark Johnston * needs to be non-preemptible so that 1592d2d16e56SMark Johnston * .SUNW_dof relocations may be resolved 1593d2d16e56SMark Johnston * at static link time. Aliases of weak 1594d2d16e56SMark Johnston * symbols are given a non-unique name 1595d2d16e56SMark Johnston * so that they may be merged by the 1596d2d16e56SMark Johnston * linker. 15976ff6d951SJohn Birrell */ 15986ff6d951SJohn Birrell dsym = fsym; 15996ff6d951SJohn Birrell dsym.st_name = istr; 1600d2d16e56SMark Johnston dsym.st_info = GELF_ST_INFO(bind, 1601d2d16e56SMark Johnston STT_FUNC); 1602d2d16e56SMark Johnston dsym.st_other = 1603d2d16e56SMark Johnston GELF_ST_VISIBILITY(STV_HIDDEN); 1604d2d16e56SMark Johnston (void) gelf_update_sym(data_sym, isym, 1605d2d16e56SMark Johnston &dsym); 16066ff6d951SJohn Birrell isym++; 16076ff6d951SJohn Birrell assert(isym <= nsym); 1608d2d16e56SMark Johnston 1609d2d16e56SMark Johnston r = (char *) data_str->d_buf + istr; 1610d2d16e56SMark Johnston if (bind == STB_WEAK) { 1611d2d16e56SMark Johnston istr += sprintf(r, 1612d2d16e56SMark Johnston dt_weaksymfmt, dt_symprefix, 1613d2d16e56SMark Johnston s); 1614d2d16e56SMark Johnston } else { 1615d2d16e56SMark Johnston istr += sprintf(r, dt_symfmt, 1616d2d16e56SMark Johnston dt_symprefix, objkey, s); 1617d2d16e56SMark Johnston } 1618d2d16e56SMark Johnston istr++; 1619d2d16e56SMark Johnston } else { 1620d2d16e56SMark Johnston if (bind == STB_WEAK) { 1621d2d16e56SMark Johnston (void) asprintf(&r, 1622d2d16e56SMark Johnston dt_weaksymfmt, dt_symprefix, 1623d2d16e56SMark Johnston s); 1624d2d16e56SMark Johnston } else { 1625d2d16e56SMark Johnston (void) asprintf(&r, dt_symfmt, 1626d2d16e56SMark Johnston dt_symprefix, objkey, s); 1627d2d16e56SMark Johnston } 1628d2d16e56SMark Johnston } 1629d2d16e56SMark Johnston } else { 1630281e4f2dSMark Johnston goto err; 1631d2d16e56SMark Johnston } 16326ff6d951SJohn Birrell 16336ff6d951SJohn Birrell if ((pvp = dt_provider_lookup(dtp, pname)) == NULL) { 16346ff6d951SJohn Birrell return (dt_link_error(dtp, elf, fd, bufs, 16356ff6d951SJohn Birrell "no such provider %s", pname)); 16366ff6d951SJohn Birrell } 16376ff6d951SJohn Birrell 16383a3e3279SMark Johnston if (strlcpy(probename, p + 3, sizeof (probename)) >= 16393a3e3279SMark Johnston sizeof (probename)) 16406ff6d951SJohn Birrell return (dt_link_error(dtp, elf, fd, bufs, 16413a3e3279SMark Johnston "invalid probe name %s", probename)); 16423a3e3279SMark Johnston (void) strhyphenate(probename); 16433a3e3279SMark Johnston if ((prp = dt_probe_lookup(pvp, probename)) == NULL) 16443a3e3279SMark Johnston return (dt_link_error(dtp, elf, fd, bufs, 16453a3e3279SMark Johnston "no such probe %s", probename)); 16466ff6d951SJohn Birrell 16476ff6d951SJohn Birrell assert(fsym.st_value <= rela.r_offset); 16486ff6d951SJohn Birrell 16496ff6d951SJohn Birrell off = rela.r_offset - fsym.st_value; 16506ff6d951SJohn Birrell if (dt_modtext(dtp, data_tgt->d_buf, eprobe, 16510f2bd1e8SRui Paulo &rela, &off) != 0) 16526ff6d951SJohn Birrell goto err; 16536ff6d951SJohn Birrell 16546ff6d951SJohn Birrell if (dt_probe_define(pvp, prp, s, r, off, eprobe) != 0) { 16556ff6d951SJohn Birrell return (dt_link_error(dtp, elf, fd, bufs, 16566ff6d951SJohn Birrell "failed to allocate space for probe")); 16576ff6d951SJohn Birrell } 16580e15d9fbSMark Johnston 16590f2bd1e8SRui Paulo /* 1660d2d16e56SMark Johnston * We are done with this relocation, but it must be 1661d2d16e56SMark Johnston * preserved in order to support incremental rebuilds. 16620f2bd1e8SRui Paulo */ 16632b374230SMark Johnston if (shdr_rel.sh_type == SHT_RELA) { 1664c612709bSMark Johnston rela.r_info = GELF_R_INFO( 1665c612709bSMark Johnston GELF_R_SYM(rela.r_info), DT_REL_NONE); 16660f2bd1e8SRui Paulo (void) gelf_update_rela(data_rel, i, &rela); 16672b374230SMark Johnston } else { 16682b374230SMark Johnston GElf_Rel rel; 1669d2d16e56SMark Johnston rel.r_offset = rela.r_offset; 1670c612709bSMark Johnston rel.r_info = GELF_R_INFO( 1671c612709bSMark Johnston GELF_R_SYM(rela.r_info), DT_REL_NONE); 16722b374230SMark Johnston (void) gelf_update_rel(data_rel, i, &rel); 16732b374230SMark Johnston } 16746ff6d951SJohn Birrell 16756ff6d951SJohn Birrell mod = 1; 16766ff6d951SJohn Birrell (void) elf_flagdata(data_tgt, ELF_C_SET, ELF_F_DIRTY); 16776ff6d951SJohn Birrell 16786ff6d951SJohn Birrell /* 16796ff6d951SJohn Birrell * This symbol may already have been marked to 16806ff6d951SJohn Birrell * be ignored by another relocation referencing 16816ff6d951SJohn Birrell * the same symbol or if this object file has 16826ff6d951SJohn Birrell * already been processed by an earlier link 16836ff6d951SJohn Birrell * invocation. 16846ff6d951SJohn Birrell */ 16850e15d9fbSMark Johnston if (rsym.st_shndx != SHN_ABS) { 1686be39466aSMark Johnston rsym.st_info = GELF_ST_INFO(STB_WEAK, STT_FUNC); 16870e15d9fbSMark Johnston rsym.st_shndx = SHN_ABS; 16886ff6d951SJohn Birrell (void) gelf_update_sym(data_sym, ndx, &rsym); 16896ff6d951SJohn Birrell } 16906ff6d951SJohn Birrell } 16916ff6d951SJohn Birrell } 16926ff6d951SJohn Birrell 16936ff6d951SJohn Birrell if (mod && elf_update(elf, ELF_C_WRITE) == -1) 16946ff6d951SJohn Birrell goto err; 16956ff6d951SJohn Birrell 16966ff6d951SJohn Birrell (void) elf_end(elf); 16976ff6d951SJohn Birrell (void) close(fd); 16986ff6d951SJohn Birrell 16996ff6d951SJohn Birrell while ((pair = bufs) != NULL) { 17006ff6d951SJohn Birrell bufs = pair->dlp_next; 17016ff6d951SJohn Birrell dt_free(dtp, pair->dlp_str); 17026ff6d951SJohn Birrell dt_free(dtp, pair->dlp_sym); 17036ff6d951SJohn Birrell dt_free(dtp, pair); 17046ff6d951SJohn Birrell } 17056ff6d951SJohn Birrell 17066ff6d951SJohn Birrell return (0); 17076ff6d951SJohn Birrell 17086ff6d951SJohn Birrell err: 17096ff6d951SJohn Birrell return (dt_link_error(dtp, elf, fd, bufs, 17106ff6d951SJohn Birrell "an error was encountered while processing %s", obj)); 17116ff6d951SJohn Birrell } 17126ff6d951SJohn Birrell 17136ff6d951SJohn Birrell int 17146ff6d951SJohn Birrell dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags, 17156ff6d951SJohn Birrell const char *file, int objc, char *const objv[]) 17166ff6d951SJohn Birrell { 17172693feb4SJohn Birrell char tfile[PATH_MAX]; 17186ff6d951SJohn Birrell char drti[PATH_MAX]; 17196ff6d951SJohn Birrell dof_hdr_t *dof; 17206ff6d951SJohn Birrell int fd, status, i, cur; 17216ff6d951SJohn Birrell char *cmd, tmp; 17226ff6d951SJohn Birrell size_t len; 17236ff6d951SJohn Birrell int eprobes = 0, ret = 0; 17246ff6d951SJohn Birrell 17256ff6d951SJohn Birrell /* 17266ff6d951SJohn Birrell * A NULL program indicates a special use in which we just link 17276ff6d951SJohn Birrell * together a bunch of object files specified in objv and then 17286ff6d951SJohn Birrell * unlink(2) those object files. 17296ff6d951SJohn Birrell */ 17306ff6d951SJohn Birrell if (pgp == NULL) { 17316ff6d951SJohn Birrell const char *fmt = "%s -o %s -r"; 17326ff6d951SJohn Birrell 17336ff6d951SJohn Birrell len = snprintf(&tmp, 1, fmt, dtp->dt_ld_path, file) + 1; 17346ff6d951SJohn Birrell 17356ff6d951SJohn Birrell for (i = 0; i < objc; i++) 17366ff6d951SJohn Birrell len += strlen(objv[i]) + 1; 17376ff6d951SJohn Birrell 17386ff6d951SJohn Birrell cmd = alloca(len); 17396ff6d951SJohn Birrell 17406ff6d951SJohn Birrell cur = snprintf(cmd, len, fmt, dtp->dt_ld_path, file); 17416ff6d951SJohn Birrell 17426ff6d951SJohn Birrell for (i = 0; i < objc; i++) 17436ff6d951SJohn Birrell cur += snprintf(cmd + cur, len - cur, " %s", objv[i]); 17446ff6d951SJohn Birrell 17456ff6d951SJohn Birrell if ((status = system(cmd)) == -1) { 17466ff6d951SJohn Birrell return (dt_link_error(dtp, NULL, -1, NULL, 17476ff6d951SJohn Birrell "failed to run %s: %s", dtp->dt_ld_path, 17486ff6d951SJohn Birrell strerror(errno))); 17496ff6d951SJohn Birrell } 17506ff6d951SJohn Birrell 17516ff6d951SJohn Birrell if (WIFSIGNALED(status)) { 17526ff6d951SJohn Birrell return (dt_link_error(dtp, NULL, -1, NULL, 17536ff6d951SJohn Birrell "failed to link %s: %s failed due to signal %d", 17546ff6d951SJohn Birrell file, dtp->dt_ld_path, WTERMSIG(status))); 17556ff6d951SJohn Birrell } 17566ff6d951SJohn Birrell 17576ff6d951SJohn Birrell if (WEXITSTATUS(status) != 0) { 17586ff6d951SJohn Birrell return (dt_link_error(dtp, NULL, -1, NULL, 17596ff6d951SJohn Birrell "failed to link %s: %s exited with status %d\n", 17606ff6d951SJohn Birrell file, dtp->dt_ld_path, WEXITSTATUS(status))); 17616ff6d951SJohn Birrell } 17626ff6d951SJohn Birrell 17636ff6d951SJohn Birrell for (i = 0; i < objc; i++) { 17646ff6d951SJohn Birrell if (strcmp(objv[i], file) != 0) 17656ff6d951SJohn Birrell (void) unlink(objv[i]); 17666ff6d951SJohn Birrell } 17676ff6d951SJohn Birrell 17686ff6d951SJohn Birrell return (0); 17696ff6d951SJohn Birrell } 17706ff6d951SJohn Birrell 17716ff6d951SJohn Birrell for (i = 0; i < objc; i++) { 17726ff6d951SJohn Birrell if (process_obj(dtp, objv[i], &eprobes) != 0) 17736ff6d951SJohn Birrell return (-1); /* errno is set for us */ 17746ff6d951SJohn Birrell } 17756ff6d951SJohn Birrell 17766ff6d951SJohn Birrell /* 17776ff6d951SJohn Birrell * If there are is-enabled probes then we need to force use of DOF 17786ff6d951SJohn Birrell * version 2. 17796ff6d951SJohn Birrell */ 17806ff6d951SJohn Birrell if (eprobes && pgp->dp_dofversion < DOF_VERSION_2) 17816ff6d951SJohn Birrell pgp->dp_dofversion = DOF_VERSION_2; 17826ff6d951SJohn Birrell 17836ff6d951SJohn Birrell if ((dof = dtrace_dof_create(dtp, pgp, dflags)) == NULL) 17846ff6d951SJohn Birrell return (-1); /* errno is set for us */ 17856ff6d951SJohn Birrell 178633d84250SMark Johnston snprintf(tfile, sizeof(tfile), "%s.XXXXXX", file); 1787ed09cc1bSMark Johnston if ((fd = mkostemp(tfile, O_CLOEXEC)) == -1) 17882693feb4SJohn Birrell return (dt_link_error(dtp, NULL, -1, NULL, 178933d84250SMark Johnston "failed to create temporary file %s: %s", 179033d84250SMark Johnston tfile, strerror(errno))); 17916ff6d951SJohn Birrell 17926ff6d951SJohn Birrell /* 17936ff6d951SJohn Birrell * If -xlinktype=DOF has been selected, just write out the DOF. 17946ff6d951SJohn Birrell * Otherwise proceed to the default of generating and linking ELF. 17956ff6d951SJohn Birrell */ 17966ff6d951SJohn Birrell switch (dtp->dt_linktype) { 17976ff6d951SJohn Birrell case DT_LTYP_DOF: 17986ff6d951SJohn Birrell if (dt_write(dtp, fd, dof, dof->dofh_filesz) < dof->dofh_filesz) 17996ff6d951SJohn Birrell ret = errno; 18006ff6d951SJohn Birrell 18016ff6d951SJohn Birrell if (close(fd) != 0 && ret == 0) 18026ff6d951SJohn Birrell ret = errno; 18036ff6d951SJohn Birrell 18046ff6d951SJohn Birrell if (ret != 0) { 18056ff6d951SJohn Birrell return (dt_link_error(dtp, NULL, -1, NULL, 18066ff6d951SJohn Birrell "failed to write %s: %s", file, strerror(ret))); 18076ff6d951SJohn Birrell } 18086ff6d951SJohn Birrell 18096ff6d951SJohn Birrell return (0); 18106ff6d951SJohn Birrell 18116ff6d951SJohn Birrell case DT_LTYP_ELF: 18126ff6d951SJohn Birrell break; /* fall through to the rest of dtrace_program_link() */ 18136ff6d951SJohn Birrell 18146ff6d951SJohn Birrell default: 18156ff6d951SJohn Birrell return (dt_link_error(dtp, NULL, -1, NULL, 18166ff6d951SJohn Birrell "invalid link type %u\n", dtp->dt_linktype)); 18176ff6d951SJohn Birrell } 18186ff6d951SJohn Birrell 18196ff6d951SJohn Birrell 18206ff6d951SJohn Birrell if (dtp->dt_oflags & DTRACE_O_LP64) 18216ff6d951SJohn Birrell status = dump_elf64(dtp, dof, fd); 18226ff6d951SJohn Birrell else 18236ff6d951SJohn Birrell status = dump_elf32(dtp, dof, fd); 18246ff6d951SJohn Birrell 18258caf8a8dSMark Johnston if (status != 0) 182633d84250SMark Johnston return (dt_link_error(dtp, NULL, -1, NULL, 18278caf8a8dSMark Johnston "failed to write %s: %s", tfile, 18288caf8a8dSMark Johnston strerror(dtrace_errno(dtp)))); 18296ff6d951SJohn Birrell 18306ff6d951SJohn Birrell if (!dtp->dt_lazyload) { 18318caf8a8dSMark Johnston const char *fmt = "%s -o %s -r %s %s"; 18320fff3baaSMark Johnston dt_dirpath_t *dp = dt_list_next(&dtp->dt_lib_path); 18332693feb4SJohn Birrell 18340fff3baaSMark Johnston (void) snprintf(drti, sizeof (drti), "%s/drti.o", dp->dir_path); 18352693feb4SJohn Birrell 18362693feb4SJohn Birrell len = snprintf(&tmp, 1, fmt, dtp->dt_ld_path, file, tfile, 18372693feb4SJohn Birrell drti) + 1; 18382693feb4SJohn Birrell 18392693feb4SJohn Birrell cmd = alloca(len); 18402693feb4SJohn Birrell 18418caf8a8dSMark Johnston (void) snprintf(cmd, len, fmt, dtp->dt_ld_path, file, tfile, 18420f2bd1e8SRui Paulo drti); 18436ff6d951SJohn Birrell if ((status = system(cmd)) == -1) { 184403a5f9f0SMark Johnston ret = dt_link_error(dtp, NULL, fd, NULL, 18456ff6d951SJohn Birrell "failed to run %s: %s", dtp->dt_ld_path, 18466ff6d951SJohn Birrell strerror(errno)); 18476ff6d951SJohn Birrell goto done; 18486ff6d951SJohn Birrell } 18496ff6d951SJohn Birrell 18506ff6d951SJohn Birrell if (WIFSIGNALED(status)) { 185103a5f9f0SMark Johnston ret = dt_link_error(dtp, NULL, fd, NULL, 18526ff6d951SJohn Birrell "failed to link %s: %s failed due to signal %d", 18536ff6d951SJohn Birrell file, dtp->dt_ld_path, WTERMSIG(status)); 18546ff6d951SJohn Birrell goto done; 18556ff6d951SJohn Birrell } 18566ff6d951SJohn Birrell 18576ff6d951SJohn Birrell if (WEXITSTATUS(status) != 0) { 185803a5f9f0SMark Johnston ret = dt_link_error(dtp, NULL, fd, NULL, 18596ff6d951SJohn Birrell "failed to link %s: %s exited with status %d\n", 18606ff6d951SJohn Birrell file, dtp->dt_ld_path, WEXITSTATUS(status)); 18616ff6d951SJohn Birrell goto done; 18626ff6d951SJohn Birrell } 18630f2bd1e8SRui Paulo (void) close(fd); /* release temporary file */ 186403a5f9f0SMark Johnston 186503a5f9f0SMark Johnston /* 186603a5f9f0SMark Johnston * Now that we've linked drti.o, reduce the global __SUNW_dof 186703a5f9f0SMark Johnston * symbol to a local symbol. This is needed to so that multiple 186803a5f9f0SMark Johnston * generated object files (for different providers, for 186903a5f9f0SMark Johnston * instance) can be linked together. This is accomplished using 187003a5f9f0SMark Johnston * the -Blocal flag with Sun's linker, but GNU ld doesn't appear 187103a5f9f0SMark Johnston * to have an equivalent option. 187203a5f9f0SMark Johnston */ 187303a5f9f0SMark Johnston asprintf(&cmd, "%s --localize-hidden %s", dtp->dt_objcopy_path, 187403a5f9f0SMark Johnston file); 187503a5f9f0SMark Johnston if ((status = system(cmd)) == -1) { 187603a5f9f0SMark Johnston ret = dt_link_error(dtp, NULL, -1, NULL, 187703a5f9f0SMark Johnston "failed to run %s: %s", dtp->dt_objcopy_path, 187803a5f9f0SMark Johnston strerror(errno)); 187903a5f9f0SMark Johnston free(cmd); 188003a5f9f0SMark Johnston goto done; 188103a5f9f0SMark Johnston } 188203a5f9f0SMark Johnston free(cmd); 188303a5f9f0SMark Johnston 188403a5f9f0SMark Johnston if (WIFSIGNALED(status)) { 188503a5f9f0SMark Johnston ret = dt_link_error(dtp, NULL, -1, NULL, 188603a5f9f0SMark Johnston "failed to link %s: %s failed due to signal %d", 188703a5f9f0SMark Johnston file, dtp->dt_objcopy_path, WTERMSIG(status)); 188803a5f9f0SMark Johnston goto done; 188903a5f9f0SMark Johnston } 189003a5f9f0SMark Johnston 189103a5f9f0SMark Johnston if (WEXITSTATUS(status) != 0) { 189203a5f9f0SMark Johnston ret = dt_link_error(dtp, NULL, -1, NULL, 189303a5f9f0SMark Johnston "failed to link %s: %s exited with status %d\n", 189403a5f9f0SMark Johnston file, dtp->dt_objcopy_path, WEXITSTATUS(status)); 189503a5f9f0SMark Johnston goto done; 189603a5f9f0SMark Johnston } 18976ff6d951SJohn Birrell } else { 1898ed09cc1bSMark Johnston if (rename(tfile, file) != 0) { 1899ed09cc1bSMark Johnston ret = dt_link_error(dtp, NULL, fd, NULL, 1900ed09cc1bSMark Johnston "failed to rename %s to %s: %s", tfile, file, 1901ed09cc1bSMark Johnston strerror(errno)); 1902ed09cc1bSMark Johnston goto done; 1903ed09cc1bSMark Johnston } 19046ff6d951SJohn Birrell (void) close(fd); 19056ff6d951SJohn Birrell } 19066ff6d951SJohn Birrell 19076ff6d951SJohn Birrell done: 19086ff6d951SJohn Birrell dtrace_dof_destroy(dtp, dof); 19092693feb4SJohn Birrell 1910ed09cc1bSMark Johnston if (!dtp->dt_lazyload) 1911ed09cc1bSMark Johnston (void) unlink(tfile); 19126ff6d951SJohn Birrell return (ret); 19136ff6d951SJohn Birrell } 1914