1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #define ELF_TARGET_ALL 30*0Sstevel@tonic-gate #include <elf.h> 31*0Sstevel@tonic-gate 32*0Sstevel@tonic-gate #include <sys/types.h> 33*0Sstevel@tonic-gate #include <sys/sysmacros.h> 34*0Sstevel@tonic-gate 35*0Sstevel@tonic-gate #include <unistd.h> 36*0Sstevel@tonic-gate #include <strings.h> 37*0Sstevel@tonic-gate #include <alloca.h> 38*0Sstevel@tonic-gate #include <limits.h> 39*0Sstevel@tonic-gate #include <stddef.h> 40*0Sstevel@tonic-gate #include <stdlib.h> 41*0Sstevel@tonic-gate #include <stdio.h> 42*0Sstevel@tonic-gate #include <fcntl.h> 43*0Sstevel@tonic-gate #include <errno.h> 44*0Sstevel@tonic-gate #include <wait.h> 45*0Sstevel@tonic-gate #include <assert.h> 46*0Sstevel@tonic-gate 47*0Sstevel@tonic-gate #include <dt_impl.h> 48*0Sstevel@tonic-gate #include <dt_provider.h> 49*0Sstevel@tonic-gate #include <dt_string.h> 50*0Sstevel@tonic-gate 51*0Sstevel@tonic-gate #define ESHDR_NULL 0 52*0Sstevel@tonic-gate #define ESHDR_SHSTRTAB 1 53*0Sstevel@tonic-gate #define ESHDR_DOF 2 54*0Sstevel@tonic-gate #define ESHDR_STRTAB 3 55*0Sstevel@tonic-gate #define ESHDR_SYMTAB 4 56*0Sstevel@tonic-gate #define ESHDR_REL 5 57*0Sstevel@tonic-gate #define ESHDR_NUM 6 58*0Sstevel@tonic-gate 59*0Sstevel@tonic-gate #define PWRITE_SCN(index, data) \ 60*0Sstevel@tonic-gate (lseek64(fd, (off64_t)elf_file.shdr[(index)].sh_offset, SEEK_SET) != \ 61*0Sstevel@tonic-gate (off64_t)elf_file.shdr[(index)].sh_offset || \ 62*0Sstevel@tonic-gate dt_write(dtp, fd, (data), elf_file.shdr[(index)].sh_size) != \ 63*0Sstevel@tonic-gate elf_file.shdr[(index)].sh_size) 64*0Sstevel@tonic-gate 65*0Sstevel@tonic-gate static const char DTRACE_SHSTRTAB32[] = "\0" 66*0Sstevel@tonic-gate ".shstrtab\0" /* 1 */ 67*0Sstevel@tonic-gate ".SUNW_dof\0" /* 11 */ 68*0Sstevel@tonic-gate ".strtab\0" /* 21 */ 69*0Sstevel@tonic-gate ".symtab\0" /* 29 */ 70*0Sstevel@tonic-gate #ifdef __sparc 71*0Sstevel@tonic-gate ".rela.SUNW_dof"; /* 37 */ 72*0Sstevel@tonic-gate #else 73*0Sstevel@tonic-gate ".rel.SUNW_dof"; /* 37 */ 74*0Sstevel@tonic-gate #endif 75*0Sstevel@tonic-gate 76*0Sstevel@tonic-gate static const char DTRACE_SHSTRTAB64[] = "\0" 77*0Sstevel@tonic-gate ".shstrtab\0" /* 1 */ 78*0Sstevel@tonic-gate ".SUNW_dof\0" /* 11 */ 79*0Sstevel@tonic-gate ".strtab\0" /* 21 */ 80*0Sstevel@tonic-gate ".symtab\0" /* 29 */ 81*0Sstevel@tonic-gate ".rela.SUNW_dof"; /* 37 */ 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate static const char DOFSTR[] = "__SUNW_dof"; 84*0Sstevel@tonic-gate static const char DOFLAZYSTR[] = "___SUNW_dof"; 85*0Sstevel@tonic-gate 86*0Sstevel@tonic-gate typedef struct dof_elf32 { 87*0Sstevel@tonic-gate uint32_t de_nrel; /* relocation count */ 88*0Sstevel@tonic-gate #ifdef __sparc 89*0Sstevel@tonic-gate Elf32_Rela *de_rel; /* array of relocations for sparc */ 90*0Sstevel@tonic-gate #else 91*0Sstevel@tonic-gate Elf32_Rel *de_rel; /* array of relocations for x86 */ 92*0Sstevel@tonic-gate #endif 93*0Sstevel@tonic-gate uint32_t de_nsym; /* symbol count */ 94*0Sstevel@tonic-gate Elf32_Sym *de_sym; /* array of symbols */ 95*0Sstevel@tonic-gate uint32_t de_strlen; /* size of of string table */ 96*0Sstevel@tonic-gate char *de_strtab; /* string table */ 97*0Sstevel@tonic-gate uint32_t de_global; /* index of the first global symbol */ 98*0Sstevel@tonic-gate } dof_elf32_t; 99*0Sstevel@tonic-gate 100*0Sstevel@tonic-gate static int 101*0Sstevel@tonic-gate prepare_elf32(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf32_t *dep) 102*0Sstevel@tonic-gate { 103*0Sstevel@tonic-gate dof_sec_t *dofs, *s; 104*0Sstevel@tonic-gate dof_relohdr_t *dofrh; 105*0Sstevel@tonic-gate dof_relodesc_t *dofr; 106*0Sstevel@tonic-gate char *strtab; 107*0Sstevel@tonic-gate int i, j, nrel; 108*0Sstevel@tonic-gate size_t strtabsz = 1; 109*0Sstevel@tonic-gate uint32_t count = 0; 110*0Sstevel@tonic-gate size_t base; 111*0Sstevel@tonic-gate Elf32_Sym *sym; 112*0Sstevel@tonic-gate #ifdef __sparc 113*0Sstevel@tonic-gate Elf32_Rela *rel; 114*0Sstevel@tonic-gate #else 115*0Sstevel@tonic-gate Elf32_Rel *rel; 116*0Sstevel@tonic-gate #endif 117*0Sstevel@tonic-gate 118*0Sstevel@tonic-gate /*LINTED*/ 119*0Sstevel@tonic-gate dofs = (dof_sec_t *)((char *)dof + dof->dofh_secoff); 120*0Sstevel@tonic-gate 121*0Sstevel@tonic-gate /* 122*0Sstevel@tonic-gate * First compute the size of the string table and the number of 123*0Sstevel@tonic-gate * relocations present in the DOF. 124*0Sstevel@tonic-gate */ 125*0Sstevel@tonic-gate for (i = 0; i < dof->dofh_secnum; i++) { 126*0Sstevel@tonic-gate if (dofs[i].dofs_type != DOF_SECT_URELHDR) 127*0Sstevel@tonic-gate continue; 128*0Sstevel@tonic-gate 129*0Sstevel@tonic-gate /*LINTED*/ 130*0Sstevel@tonic-gate dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset); 131*0Sstevel@tonic-gate 132*0Sstevel@tonic-gate s = &dofs[dofrh->dofr_strtab]; 133*0Sstevel@tonic-gate strtab = (char *)dof + s->dofs_offset; 134*0Sstevel@tonic-gate assert(strtab[0] == '\0'); 135*0Sstevel@tonic-gate strtabsz += s->dofs_size - 1; 136*0Sstevel@tonic-gate 137*0Sstevel@tonic-gate s = &dofs[dofrh->dofr_relsec]; 138*0Sstevel@tonic-gate /*LINTED*/ 139*0Sstevel@tonic-gate dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset); 140*0Sstevel@tonic-gate count += s->dofs_size / s->dofs_entsize; 141*0Sstevel@tonic-gate } 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate dep->de_strlen = strtabsz; 144*0Sstevel@tonic-gate dep->de_nrel = count; 145*0Sstevel@tonic-gate dep->de_nsym = count + 1; /* the first symbol is always null */ 146*0Sstevel@tonic-gate 147*0Sstevel@tonic-gate if (dtp->dt_lazyload) { 148*0Sstevel@tonic-gate dep->de_strlen += sizeof (DOFLAZYSTR); 149*0Sstevel@tonic-gate dep->de_nsym++; 150*0Sstevel@tonic-gate } else { 151*0Sstevel@tonic-gate dep->de_strlen += sizeof (DOFSTR); 152*0Sstevel@tonic-gate dep->de_nsym++; 153*0Sstevel@tonic-gate } 154*0Sstevel@tonic-gate 155*0Sstevel@tonic-gate if ((dep->de_rel = calloc(dep->de_nrel, 156*0Sstevel@tonic-gate sizeof (dep->de_rel[0]))) == NULL) { 157*0Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 158*0Sstevel@tonic-gate } 159*0Sstevel@tonic-gate 160*0Sstevel@tonic-gate if ((dep->de_sym = calloc(dep->de_nsym, sizeof (Elf32_Sym))) == NULL) { 161*0Sstevel@tonic-gate free(dep->de_rel); 162*0Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 163*0Sstevel@tonic-gate } 164*0Sstevel@tonic-gate 165*0Sstevel@tonic-gate if ((dep->de_strtab = calloc(dep->de_strlen, 1)) == NULL) { 166*0Sstevel@tonic-gate free(dep->de_rel); 167*0Sstevel@tonic-gate free(dep->de_sym); 168*0Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 169*0Sstevel@tonic-gate } 170*0Sstevel@tonic-gate 171*0Sstevel@tonic-gate count = 0; 172*0Sstevel@tonic-gate strtabsz = 1; 173*0Sstevel@tonic-gate dep->de_strtab[0] = '\0'; 174*0Sstevel@tonic-gate rel = dep->de_rel; 175*0Sstevel@tonic-gate sym = dep->de_sym; 176*0Sstevel@tonic-gate dep->de_global = 1; 177*0Sstevel@tonic-gate 178*0Sstevel@tonic-gate /* 179*0Sstevel@tonic-gate * The first symbol table entry must be zeroed and is always ignored. 180*0Sstevel@tonic-gate */ 181*0Sstevel@tonic-gate bzero(sym, sizeof (Elf32_Sym)); 182*0Sstevel@tonic-gate sym++; 183*0Sstevel@tonic-gate 184*0Sstevel@tonic-gate /* 185*0Sstevel@tonic-gate * Take a second pass through the DOF sections filling in the 186*0Sstevel@tonic-gate * memory we allocated. 187*0Sstevel@tonic-gate */ 188*0Sstevel@tonic-gate for (i = 0; i < dof->dofh_secnum; i++) { 189*0Sstevel@tonic-gate if (dofs[i].dofs_type != DOF_SECT_URELHDR) 190*0Sstevel@tonic-gate continue; 191*0Sstevel@tonic-gate 192*0Sstevel@tonic-gate /*LINTED*/ 193*0Sstevel@tonic-gate dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset); 194*0Sstevel@tonic-gate 195*0Sstevel@tonic-gate s = &dofs[dofrh->dofr_strtab]; 196*0Sstevel@tonic-gate strtab = (char *)dof + s->dofs_offset; 197*0Sstevel@tonic-gate bcopy(strtab + 1, dep->de_strtab + strtabsz, s->dofs_size); 198*0Sstevel@tonic-gate base = strtabsz; 199*0Sstevel@tonic-gate strtabsz += s->dofs_size - 1; 200*0Sstevel@tonic-gate 201*0Sstevel@tonic-gate s = &dofs[dofrh->dofr_relsec]; 202*0Sstevel@tonic-gate /*LINTED*/ 203*0Sstevel@tonic-gate dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset); 204*0Sstevel@tonic-gate nrel = s->dofs_size / s->dofs_entsize; 205*0Sstevel@tonic-gate 206*0Sstevel@tonic-gate s = &dofs[dofrh->dofr_tgtsec]; 207*0Sstevel@tonic-gate 208*0Sstevel@tonic-gate for (j = 0; j < nrel; j++) { 209*0Sstevel@tonic-gate #if defined(__i386) || defined(__amd64) 210*0Sstevel@tonic-gate rel->r_offset = s->dofs_offset + 211*0Sstevel@tonic-gate dofr[j].dofr_offset; 212*0Sstevel@tonic-gate rel->r_info = ELF32_R_INFO(count + dep->de_global, 213*0Sstevel@tonic-gate R_386_32); 214*0Sstevel@tonic-gate #elif defined(__sparc) 215*0Sstevel@tonic-gate /* 216*0Sstevel@tonic-gate * Add 4 bytes to hit the low half of this 64-bit 217*0Sstevel@tonic-gate * big-endian address. 218*0Sstevel@tonic-gate */ 219*0Sstevel@tonic-gate rel->r_offset = s->dofs_offset + 220*0Sstevel@tonic-gate dofr[j].dofr_offset + 4; 221*0Sstevel@tonic-gate rel->r_info = ELF32_R_INFO(count + dep->de_global, 222*0Sstevel@tonic-gate R_SPARC_32); 223*0Sstevel@tonic-gate #else 224*0Sstevel@tonic-gate #error unknown ISA 225*0Sstevel@tonic-gate #endif 226*0Sstevel@tonic-gate 227*0Sstevel@tonic-gate sym->st_name = base + dofr[j].dofr_name - 1; 228*0Sstevel@tonic-gate sym->st_value = 0; 229*0Sstevel@tonic-gate sym->st_size = 0; 230*0Sstevel@tonic-gate sym->st_info = ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE); 231*0Sstevel@tonic-gate sym->st_other = 0; 232*0Sstevel@tonic-gate sym->st_shndx = SHN_UNDEF; 233*0Sstevel@tonic-gate 234*0Sstevel@tonic-gate rel++; 235*0Sstevel@tonic-gate sym++; 236*0Sstevel@tonic-gate count++; 237*0Sstevel@tonic-gate } 238*0Sstevel@tonic-gate } 239*0Sstevel@tonic-gate 240*0Sstevel@tonic-gate /* 241*0Sstevel@tonic-gate * Add a symbol for the DOF itself. We use a different symbol for 242*0Sstevel@tonic-gate * lazily and actively loaded DOF to make them easy to distinguish. 243*0Sstevel@tonic-gate */ 244*0Sstevel@tonic-gate sym->st_name = strtabsz; 245*0Sstevel@tonic-gate sym->st_value = 0; 246*0Sstevel@tonic-gate sym->st_size = dof->dofh_filesz; 247*0Sstevel@tonic-gate sym->st_info = ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT); 248*0Sstevel@tonic-gate sym->st_other = 0; 249*0Sstevel@tonic-gate sym->st_shndx = ESHDR_DOF; 250*0Sstevel@tonic-gate sym++; 251*0Sstevel@tonic-gate 252*0Sstevel@tonic-gate if (dtp->dt_lazyload) { 253*0Sstevel@tonic-gate bcopy(DOFLAZYSTR, dep->de_strtab + strtabsz, 254*0Sstevel@tonic-gate sizeof (DOFLAZYSTR)); 255*0Sstevel@tonic-gate strtabsz += sizeof (DOFLAZYSTR); 256*0Sstevel@tonic-gate } else { 257*0Sstevel@tonic-gate bcopy(DOFSTR, dep->de_strtab + strtabsz, sizeof (DOFSTR)); 258*0Sstevel@tonic-gate strtabsz += sizeof (DOFSTR); 259*0Sstevel@tonic-gate } 260*0Sstevel@tonic-gate 261*0Sstevel@tonic-gate assert(count == dep->de_nrel); 262*0Sstevel@tonic-gate assert(strtabsz == dep->de_strlen); 263*0Sstevel@tonic-gate 264*0Sstevel@tonic-gate return (0); 265*0Sstevel@tonic-gate } 266*0Sstevel@tonic-gate 267*0Sstevel@tonic-gate 268*0Sstevel@tonic-gate typedef struct dof_elf64 { 269*0Sstevel@tonic-gate uint32_t de_nrel; 270*0Sstevel@tonic-gate Elf64_Rela *de_rel; 271*0Sstevel@tonic-gate uint32_t de_nsym; 272*0Sstevel@tonic-gate Elf64_Sym *de_sym; 273*0Sstevel@tonic-gate 274*0Sstevel@tonic-gate uint32_t de_strlen; 275*0Sstevel@tonic-gate char *de_strtab; 276*0Sstevel@tonic-gate 277*0Sstevel@tonic-gate uint32_t de_global; 278*0Sstevel@tonic-gate } dof_elf64_t; 279*0Sstevel@tonic-gate 280*0Sstevel@tonic-gate static int 281*0Sstevel@tonic-gate prepare_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf64_t *dep) 282*0Sstevel@tonic-gate { 283*0Sstevel@tonic-gate dof_sec_t *dofs, *s; 284*0Sstevel@tonic-gate dof_relohdr_t *dofrh; 285*0Sstevel@tonic-gate dof_relodesc_t *dofr; 286*0Sstevel@tonic-gate char *strtab; 287*0Sstevel@tonic-gate int i, j, nrel; 288*0Sstevel@tonic-gate size_t strtabsz = 1; 289*0Sstevel@tonic-gate uint32_t count = 0; 290*0Sstevel@tonic-gate size_t base; 291*0Sstevel@tonic-gate Elf64_Sym *sym; 292*0Sstevel@tonic-gate Elf64_Rela *rel; 293*0Sstevel@tonic-gate 294*0Sstevel@tonic-gate /*LINTED*/ 295*0Sstevel@tonic-gate dofs = (dof_sec_t *)((char *)dof + dof->dofh_secoff); 296*0Sstevel@tonic-gate 297*0Sstevel@tonic-gate /* 298*0Sstevel@tonic-gate * First compute the size of the string table and the number of 299*0Sstevel@tonic-gate * relocations present in the DOF. 300*0Sstevel@tonic-gate */ 301*0Sstevel@tonic-gate for (i = 0; i < dof->dofh_secnum; i++) { 302*0Sstevel@tonic-gate if (dofs[i].dofs_type != DOF_SECT_URELHDR) 303*0Sstevel@tonic-gate continue; 304*0Sstevel@tonic-gate 305*0Sstevel@tonic-gate /*LINTED*/ 306*0Sstevel@tonic-gate dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset); 307*0Sstevel@tonic-gate 308*0Sstevel@tonic-gate s = &dofs[dofrh->dofr_strtab]; 309*0Sstevel@tonic-gate strtab = (char *)dof + s->dofs_offset; 310*0Sstevel@tonic-gate assert(strtab[0] == '\0'); 311*0Sstevel@tonic-gate strtabsz += s->dofs_size - 1; 312*0Sstevel@tonic-gate 313*0Sstevel@tonic-gate s = &dofs[dofrh->dofr_relsec]; 314*0Sstevel@tonic-gate /*LINTED*/ 315*0Sstevel@tonic-gate dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset); 316*0Sstevel@tonic-gate count += s->dofs_size / s->dofs_entsize; 317*0Sstevel@tonic-gate } 318*0Sstevel@tonic-gate 319*0Sstevel@tonic-gate dep->de_strlen = strtabsz; 320*0Sstevel@tonic-gate dep->de_nrel = count; 321*0Sstevel@tonic-gate dep->de_nsym = count + 1; /* the first symbol is always null */ 322*0Sstevel@tonic-gate 323*0Sstevel@tonic-gate if (dtp->dt_lazyload) { 324*0Sstevel@tonic-gate dep->de_strlen += sizeof (DOFLAZYSTR); 325*0Sstevel@tonic-gate dep->de_nsym++; 326*0Sstevel@tonic-gate } else { 327*0Sstevel@tonic-gate dep->de_strlen += sizeof (DOFSTR); 328*0Sstevel@tonic-gate dep->de_nsym++; 329*0Sstevel@tonic-gate } 330*0Sstevel@tonic-gate 331*0Sstevel@tonic-gate if ((dep->de_rel = calloc(dep->de_nrel, 332*0Sstevel@tonic-gate sizeof (dep->de_rel[0]))) == NULL) { 333*0Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 334*0Sstevel@tonic-gate } 335*0Sstevel@tonic-gate 336*0Sstevel@tonic-gate if ((dep->de_sym = calloc(dep->de_nsym, sizeof (Elf64_Sym))) == NULL) { 337*0Sstevel@tonic-gate free(dep->de_rel); 338*0Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 339*0Sstevel@tonic-gate } 340*0Sstevel@tonic-gate 341*0Sstevel@tonic-gate if ((dep->de_strtab = calloc(dep->de_strlen, 1)) == NULL) { 342*0Sstevel@tonic-gate free(dep->de_rel); 343*0Sstevel@tonic-gate free(dep->de_sym); 344*0Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 345*0Sstevel@tonic-gate } 346*0Sstevel@tonic-gate 347*0Sstevel@tonic-gate count = 0; 348*0Sstevel@tonic-gate strtabsz = 1; 349*0Sstevel@tonic-gate dep->de_strtab[0] = '\0'; 350*0Sstevel@tonic-gate rel = dep->de_rel; 351*0Sstevel@tonic-gate sym = dep->de_sym; 352*0Sstevel@tonic-gate dep->de_global = 1; 353*0Sstevel@tonic-gate 354*0Sstevel@tonic-gate /* 355*0Sstevel@tonic-gate * The first symbol table entry must be zeroed and is always ignored. 356*0Sstevel@tonic-gate */ 357*0Sstevel@tonic-gate bzero(sym, sizeof (Elf64_Sym)); 358*0Sstevel@tonic-gate sym++; 359*0Sstevel@tonic-gate 360*0Sstevel@tonic-gate /* 361*0Sstevel@tonic-gate * Take a second pass through the DOF sections filling in the 362*0Sstevel@tonic-gate * memory we allocated. 363*0Sstevel@tonic-gate */ 364*0Sstevel@tonic-gate for (i = 0; i < dof->dofh_secnum; i++) { 365*0Sstevel@tonic-gate if (dofs[i].dofs_type != DOF_SECT_URELHDR) 366*0Sstevel@tonic-gate continue; 367*0Sstevel@tonic-gate 368*0Sstevel@tonic-gate /*LINTED*/ 369*0Sstevel@tonic-gate dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset); 370*0Sstevel@tonic-gate 371*0Sstevel@tonic-gate s = &dofs[dofrh->dofr_strtab]; 372*0Sstevel@tonic-gate strtab = (char *)dof + s->dofs_offset; 373*0Sstevel@tonic-gate bcopy(strtab + 1, dep->de_strtab + strtabsz, s->dofs_size); 374*0Sstevel@tonic-gate base = strtabsz; 375*0Sstevel@tonic-gate strtabsz += s->dofs_size - 1; 376*0Sstevel@tonic-gate 377*0Sstevel@tonic-gate s = &dofs[dofrh->dofr_relsec]; 378*0Sstevel@tonic-gate /*LINTED*/ 379*0Sstevel@tonic-gate dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset); 380*0Sstevel@tonic-gate nrel = s->dofs_size / s->dofs_entsize; 381*0Sstevel@tonic-gate 382*0Sstevel@tonic-gate s = &dofs[dofrh->dofr_tgtsec]; 383*0Sstevel@tonic-gate 384*0Sstevel@tonic-gate for (j = 0; j < nrel; j++) { 385*0Sstevel@tonic-gate #if defined(__i386) || defined(__amd64) 386*0Sstevel@tonic-gate rel->r_offset = s->dofs_offset + 387*0Sstevel@tonic-gate dofr[j].dofr_offset; 388*0Sstevel@tonic-gate rel->r_info = ELF64_R_INFO(count + dep->de_global, 389*0Sstevel@tonic-gate R_AMD64_64); 390*0Sstevel@tonic-gate #elif defined(__sparc) 391*0Sstevel@tonic-gate rel->r_offset = s->dofs_offset + 392*0Sstevel@tonic-gate dofr[j].dofr_offset; 393*0Sstevel@tonic-gate rel->r_info = ELF64_R_INFO(count + dep->de_global, 394*0Sstevel@tonic-gate R_SPARC_64); 395*0Sstevel@tonic-gate #else 396*0Sstevel@tonic-gate #error unknown ISA 397*0Sstevel@tonic-gate #endif 398*0Sstevel@tonic-gate 399*0Sstevel@tonic-gate sym->st_name = base + dofr[j].dofr_name - 1; 400*0Sstevel@tonic-gate sym->st_value = 0; 401*0Sstevel@tonic-gate sym->st_size = 0; 402*0Sstevel@tonic-gate sym->st_info = ELF64_ST_INFO(STB_GLOBAL, STT_NOTYPE); 403*0Sstevel@tonic-gate sym->st_other = 0; 404*0Sstevel@tonic-gate sym->st_shndx = SHN_UNDEF; 405*0Sstevel@tonic-gate 406*0Sstevel@tonic-gate rel++; 407*0Sstevel@tonic-gate sym++; 408*0Sstevel@tonic-gate count++; 409*0Sstevel@tonic-gate } 410*0Sstevel@tonic-gate } 411*0Sstevel@tonic-gate 412*0Sstevel@tonic-gate /* 413*0Sstevel@tonic-gate * Add a symbol for the DOF itself. We use a different symbol for 414*0Sstevel@tonic-gate * lazily and actively loaded DOF to make them easy to distinguish. 415*0Sstevel@tonic-gate */ 416*0Sstevel@tonic-gate sym->st_name = strtabsz; 417*0Sstevel@tonic-gate sym->st_value = 0; 418*0Sstevel@tonic-gate sym->st_size = dof->dofh_filesz; 419*0Sstevel@tonic-gate sym->st_info = ELF64_ST_INFO(STB_GLOBAL, STT_OBJECT); 420*0Sstevel@tonic-gate sym->st_other = 0; 421*0Sstevel@tonic-gate sym->st_shndx = ESHDR_DOF; 422*0Sstevel@tonic-gate sym++; 423*0Sstevel@tonic-gate 424*0Sstevel@tonic-gate if (dtp->dt_lazyload) { 425*0Sstevel@tonic-gate bcopy(DOFLAZYSTR, dep->de_strtab + strtabsz, 426*0Sstevel@tonic-gate sizeof (DOFLAZYSTR)); 427*0Sstevel@tonic-gate strtabsz += sizeof (DOFLAZYSTR); 428*0Sstevel@tonic-gate } else { 429*0Sstevel@tonic-gate bcopy(DOFSTR, dep->de_strtab + strtabsz, sizeof (DOFSTR)); 430*0Sstevel@tonic-gate strtabsz += sizeof (DOFSTR); 431*0Sstevel@tonic-gate } 432*0Sstevel@tonic-gate 433*0Sstevel@tonic-gate assert(count == dep->de_nrel); 434*0Sstevel@tonic-gate assert(strtabsz == dep->de_strlen); 435*0Sstevel@tonic-gate 436*0Sstevel@tonic-gate return (0); 437*0Sstevel@tonic-gate } 438*0Sstevel@tonic-gate 439*0Sstevel@tonic-gate /* 440*0Sstevel@tonic-gate * Write out an ELF32 file prologue consisting of a header, section headers, 441*0Sstevel@tonic-gate * and a section header string table. The DOF data will follow this prologue 442*0Sstevel@tonic-gate * and complete the contents of the given ELF file. 443*0Sstevel@tonic-gate */ 444*0Sstevel@tonic-gate static int 445*0Sstevel@tonic-gate dump_elf32(dtrace_hdl_t *dtp, const dof_hdr_t *dof, int fd) 446*0Sstevel@tonic-gate { 447*0Sstevel@tonic-gate struct { 448*0Sstevel@tonic-gate Elf32_Ehdr ehdr; 449*0Sstevel@tonic-gate Elf32_Shdr shdr[ESHDR_NUM]; 450*0Sstevel@tonic-gate } elf_file; 451*0Sstevel@tonic-gate 452*0Sstevel@tonic-gate Elf32_Shdr *shp; 453*0Sstevel@tonic-gate Elf32_Off off; 454*0Sstevel@tonic-gate dof_elf32_t de; 455*0Sstevel@tonic-gate int ret = 0; 456*0Sstevel@tonic-gate uint_t nshdr; 457*0Sstevel@tonic-gate 458*0Sstevel@tonic-gate if (prepare_elf32(dtp, dof, &de) != 0) 459*0Sstevel@tonic-gate return (-1); /* errno is set for us */ 460*0Sstevel@tonic-gate 461*0Sstevel@tonic-gate /* 462*0Sstevel@tonic-gate * If there are no relocations, we only need enough sections for 463*0Sstevel@tonic-gate * the shstrtab and the DOF. 464*0Sstevel@tonic-gate */ 465*0Sstevel@tonic-gate nshdr = de.de_nrel == 0 ? ESHDR_SYMTAB + 1 : ESHDR_NUM; 466*0Sstevel@tonic-gate 467*0Sstevel@tonic-gate bzero(&elf_file, sizeof (elf_file)); 468*0Sstevel@tonic-gate 469*0Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_MAG0] = ELFMAG0; 470*0Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_MAG1] = ELFMAG1; 471*0Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_MAG2] = ELFMAG2; 472*0Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_MAG3] = ELFMAG3; 473*0Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_VERSION] = EV_CURRENT; 474*0Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_CLASS] = ELFCLASS32; 475*0Sstevel@tonic-gate #if defined(_BIG_ENDIAN) 476*0Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2MSB; 477*0Sstevel@tonic-gate #elif defined(_LITTLE_ENDIAN) 478*0Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2LSB; 479*0Sstevel@tonic-gate #endif 480*0Sstevel@tonic-gate elf_file.ehdr.e_type = ET_REL; 481*0Sstevel@tonic-gate #if defined(__sparc) 482*0Sstevel@tonic-gate elf_file.ehdr.e_machine = EM_SPARC; 483*0Sstevel@tonic-gate #elif defined(__i386) || defined(__amd64) 484*0Sstevel@tonic-gate elf_file.ehdr.e_machine = EM_386; 485*0Sstevel@tonic-gate #endif 486*0Sstevel@tonic-gate elf_file.ehdr.e_version = EV_CURRENT; 487*0Sstevel@tonic-gate elf_file.ehdr.e_shoff = sizeof (Elf32_Ehdr); 488*0Sstevel@tonic-gate elf_file.ehdr.e_ehsize = sizeof (Elf32_Ehdr); 489*0Sstevel@tonic-gate elf_file.ehdr.e_phentsize = sizeof (Elf32_Phdr); 490*0Sstevel@tonic-gate elf_file.ehdr.e_shentsize = sizeof (Elf32_Shdr); 491*0Sstevel@tonic-gate elf_file.ehdr.e_shnum = nshdr; 492*0Sstevel@tonic-gate elf_file.ehdr.e_shstrndx = ESHDR_SHSTRTAB; 493*0Sstevel@tonic-gate off = sizeof (elf_file) + nshdr * sizeof (Elf32_Shdr); 494*0Sstevel@tonic-gate 495*0Sstevel@tonic-gate shp = &elf_file.shdr[ESHDR_SHSTRTAB]; 496*0Sstevel@tonic-gate shp->sh_name = 1; /* DTRACE_SHSTRTAB32[1] = ".shstrtab" */ 497*0Sstevel@tonic-gate shp->sh_type = SHT_STRTAB; 498*0Sstevel@tonic-gate shp->sh_offset = off; 499*0Sstevel@tonic-gate shp->sh_size = sizeof (DTRACE_SHSTRTAB32); 500*0Sstevel@tonic-gate shp->sh_addralign = sizeof (char); 501*0Sstevel@tonic-gate off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8); 502*0Sstevel@tonic-gate 503*0Sstevel@tonic-gate shp = &elf_file.shdr[ESHDR_DOF]; 504*0Sstevel@tonic-gate shp->sh_name = 11; /* DTRACE_SHSTRTAB32[11] = ".SUNW_dof" */ 505*0Sstevel@tonic-gate shp->sh_flags = SHF_ALLOC; 506*0Sstevel@tonic-gate shp->sh_type = SHT_SUNW_dof; 507*0Sstevel@tonic-gate shp->sh_offset = off; 508*0Sstevel@tonic-gate shp->sh_size = dof->dofh_filesz; 509*0Sstevel@tonic-gate shp->sh_addralign = 8; 510*0Sstevel@tonic-gate off = shp->sh_offset + shp->sh_size; 511*0Sstevel@tonic-gate 512*0Sstevel@tonic-gate shp = &elf_file.shdr[ESHDR_STRTAB]; 513*0Sstevel@tonic-gate shp->sh_name = 21; /* DTRACE_SHSTRTAB32[21] = ".strtab" */ 514*0Sstevel@tonic-gate shp->sh_flags = SHF_ALLOC; 515*0Sstevel@tonic-gate shp->sh_type = SHT_STRTAB; 516*0Sstevel@tonic-gate shp->sh_offset = off; 517*0Sstevel@tonic-gate shp->sh_size = de.de_strlen; 518*0Sstevel@tonic-gate shp->sh_addralign = sizeof (char); 519*0Sstevel@tonic-gate off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 4); 520*0Sstevel@tonic-gate 521*0Sstevel@tonic-gate shp = &elf_file.shdr[ESHDR_SYMTAB]; 522*0Sstevel@tonic-gate shp->sh_name = 29; /* DTRACE_SHSTRTAB32[29] = ".symtab" */ 523*0Sstevel@tonic-gate shp->sh_flags = SHF_ALLOC; 524*0Sstevel@tonic-gate shp->sh_type = SHT_SYMTAB; 525*0Sstevel@tonic-gate shp->sh_entsize = sizeof (Elf32_Sym); 526*0Sstevel@tonic-gate shp->sh_link = ESHDR_STRTAB; 527*0Sstevel@tonic-gate shp->sh_offset = off; 528*0Sstevel@tonic-gate shp->sh_info = de.de_global; 529*0Sstevel@tonic-gate shp->sh_size = de.de_nsym * sizeof (Elf32_Sym); 530*0Sstevel@tonic-gate shp->sh_addralign = 4; 531*0Sstevel@tonic-gate off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 4); 532*0Sstevel@tonic-gate 533*0Sstevel@tonic-gate if (de.de_nrel == 0) { 534*0Sstevel@tonic-gate if (dt_write(dtp, fd, &elf_file, 535*0Sstevel@tonic-gate sizeof (elf_file)) != sizeof (elf_file) || 536*0Sstevel@tonic-gate PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB32) || 537*0Sstevel@tonic-gate PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || 538*0Sstevel@tonic-gate PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || 539*0Sstevel@tonic-gate PWRITE_SCN(ESHDR_DOF, dof)) { 540*0Sstevel@tonic-gate ret = dt_set_errno(dtp, errno); 541*0Sstevel@tonic-gate } 542*0Sstevel@tonic-gate } else { 543*0Sstevel@tonic-gate shp = &elf_file.shdr[ESHDR_REL]; 544*0Sstevel@tonic-gate shp->sh_name = 37; /* DTRACE_SHSTRTAB32[37] = ".rel.SUNW_dof" */ 545*0Sstevel@tonic-gate shp->sh_flags = SHF_ALLOC; 546*0Sstevel@tonic-gate #ifdef __sparc 547*0Sstevel@tonic-gate shp->sh_type = SHT_RELA; 548*0Sstevel@tonic-gate #else 549*0Sstevel@tonic-gate shp->sh_type = SHT_REL; 550*0Sstevel@tonic-gate #endif 551*0Sstevel@tonic-gate shp->sh_entsize = sizeof (de.de_rel[0]); 552*0Sstevel@tonic-gate shp->sh_link = ESHDR_SYMTAB; 553*0Sstevel@tonic-gate shp->sh_info = ESHDR_DOF; 554*0Sstevel@tonic-gate shp->sh_offset = off; 555*0Sstevel@tonic-gate shp->sh_size = de.de_nrel * sizeof (de.de_rel[0]); 556*0Sstevel@tonic-gate shp->sh_addralign = 4; 557*0Sstevel@tonic-gate 558*0Sstevel@tonic-gate if (dt_write(dtp, fd, &elf_file, 559*0Sstevel@tonic-gate sizeof (elf_file)) != sizeof (elf_file) || 560*0Sstevel@tonic-gate PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB32) || 561*0Sstevel@tonic-gate PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || 562*0Sstevel@tonic-gate PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || 563*0Sstevel@tonic-gate PWRITE_SCN(ESHDR_REL, de.de_rel) || 564*0Sstevel@tonic-gate PWRITE_SCN(ESHDR_DOF, dof)) { 565*0Sstevel@tonic-gate ret = dt_set_errno(dtp, errno); 566*0Sstevel@tonic-gate } 567*0Sstevel@tonic-gate } 568*0Sstevel@tonic-gate 569*0Sstevel@tonic-gate free(de.de_strtab); 570*0Sstevel@tonic-gate free(de.de_sym); 571*0Sstevel@tonic-gate free(de.de_rel); 572*0Sstevel@tonic-gate 573*0Sstevel@tonic-gate return (ret); 574*0Sstevel@tonic-gate } 575*0Sstevel@tonic-gate 576*0Sstevel@tonic-gate /* 577*0Sstevel@tonic-gate * Write out an ELF64 file prologue consisting of a header, section headers, 578*0Sstevel@tonic-gate * and a section header string table. The DOF data will follow this prologue 579*0Sstevel@tonic-gate * and complete the contents of the given ELF file. 580*0Sstevel@tonic-gate */ 581*0Sstevel@tonic-gate static int 582*0Sstevel@tonic-gate dump_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, int fd) 583*0Sstevel@tonic-gate { 584*0Sstevel@tonic-gate struct { 585*0Sstevel@tonic-gate Elf64_Ehdr ehdr; 586*0Sstevel@tonic-gate Elf64_Shdr shdr[ESHDR_NUM]; 587*0Sstevel@tonic-gate } elf_file; 588*0Sstevel@tonic-gate 589*0Sstevel@tonic-gate Elf64_Shdr *shp; 590*0Sstevel@tonic-gate Elf64_Off off; 591*0Sstevel@tonic-gate dof_elf64_t de; 592*0Sstevel@tonic-gate int ret = 0; 593*0Sstevel@tonic-gate uint_t nshdr; 594*0Sstevel@tonic-gate 595*0Sstevel@tonic-gate if (prepare_elf64(dtp, dof, &de) != 0) 596*0Sstevel@tonic-gate return (-1); /* errno is set for us */ 597*0Sstevel@tonic-gate 598*0Sstevel@tonic-gate /* 599*0Sstevel@tonic-gate * If there are no relocations, we only need enough sections for 600*0Sstevel@tonic-gate * the shstrtab and the DOF. 601*0Sstevel@tonic-gate */ 602*0Sstevel@tonic-gate nshdr = de.de_nrel == 0 ? ESHDR_SYMTAB + 1 : ESHDR_NUM; 603*0Sstevel@tonic-gate 604*0Sstevel@tonic-gate bzero(&elf_file, sizeof (elf_file)); 605*0Sstevel@tonic-gate 606*0Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_MAG0] = ELFMAG0; 607*0Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_MAG1] = ELFMAG1; 608*0Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_MAG2] = ELFMAG2; 609*0Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_MAG3] = ELFMAG3; 610*0Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_VERSION] = EV_CURRENT; 611*0Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_CLASS] = ELFCLASS64; 612*0Sstevel@tonic-gate #if defined(_BIG_ENDIAN) 613*0Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2MSB; 614*0Sstevel@tonic-gate #elif defined(_LITTLE_ENDIAN) 615*0Sstevel@tonic-gate elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2LSB; 616*0Sstevel@tonic-gate #endif 617*0Sstevel@tonic-gate elf_file.ehdr.e_type = ET_REL; 618*0Sstevel@tonic-gate #if defined(__sparc) 619*0Sstevel@tonic-gate elf_file.ehdr.e_machine = EM_SPARCV9; 620*0Sstevel@tonic-gate #elif defined(__i386) || defined(__amd64) 621*0Sstevel@tonic-gate elf_file.ehdr.e_machine = EM_AMD64; 622*0Sstevel@tonic-gate #endif 623*0Sstevel@tonic-gate elf_file.ehdr.e_version = EV_CURRENT; 624*0Sstevel@tonic-gate elf_file.ehdr.e_shoff = sizeof (Elf64_Ehdr); 625*0Sstevel@tonic-gate elf_file.ehdr.e_ehsize = sizeof (Elf64_Ehdr); 626*0Sstevel@tonic-gate elf_file.ehdr.e_phentsize = sizeof (Elf64_Phdr); 627*0Sstevel@tonic-gate elf_file.ehdr.e_shentsize = sizeof (Elf64_Shdr); 628*0Sstevel@tonic-gate elf_file.ehdr.e_shnum = nshdr; 629*0Sstevel@tonic-gate elf_file.ehdr.e_shstrndx = ESHDR_SHSTRTAB; 630*0Sstevel@tonic-gate off = sizeof (elf_file) + nshdr * sizeof (Elf64_Shdr); 631*0Sstevel@tonic-gate 632*0Sstevel@tonic-gate shp = &elf_file.shdr[ESHDR_SHSTRTAB]; 633*0Sstevel@tonic-gate shp->sh_name = 1; /* DTRACE_SHSTRTAB64[1] = ".shstrtab" */ 634*0Sstevel@tonic-gate shp->sh_type = SHT_STRTAB; 635*0Sstevel@tonic-gate shp->sh_offset = off; 636*0Sstevel@tonic-gate shp->sh_size = sizeof (DTRACE_SHSTRTAB64); 637*0Sstevel@tonic-gate shp->sh_addralign = sizeof (char); 638*0Sstevel@tonic-gate off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8); 639*0Sstevel@tonic-gate 640*0Sstevel@tonic-gate shp = &elf_file.shdr[ESHDR_DOF]; 641*0Sstevel@tonic-gate shp->sh_name = 11; /* DTRACE_SHSTRTAB64[11] = ".SUNW_dof" */ 642*0Sstevel@tonic-gate shp->sh_flags = SHF_ALLOC; 643*0Sstevel@tonic-gate shp->sh_type = SHT_SUNW_dof; 644*0Sstevel@tonic-gate shp->sh_offset = off; 645*0Sstevel@tonic-gate shp->sh_size = dof->dofh_filesz; 646*0Sstevel@tonic-gate shp->sh_addralign = 8; 647*0Sstevel@tonic-gate off = shp->sh_offset + shp->sh_size; 648*0Sstevel@tonic-gate 649*0Sstevel@tonic-gate shp = &elf_file.shdr[ESHDR_STRTAB]; 650*0Sstevel@tonic-gate shp->sh_name = 21; /* DTRACE_SHSTRTAB64[21] = ".strtab" */ 651*0Sstevel@tonic-gate shp->sh_flags = SHF_ALLOC; 652*0Sstevel@tonic-gate shp->sh_type = SHT_STRTAB; 653*0Sstevel@tonic-gate shp->sh_offset = off; 654*0Sstevel@tonic-gate shp->sh_size = de.de_strlen; 655*0Sstevel@tonic-gate shp->sh_addralign = sizeof (char); 656*0Sstevel@tonic-gate off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8); 657*0Sstevel@tonic-gate 658*0Sstevel@tonic-gate shp = &elf_file.shdr[ESHDR_SYMTAB]; 659*0Sstevel@tonic-gate shp->sh_name = 29; /* DTRACE_SHSTRTAB64[29] = ".symtab" */ 660*0Sstevel@tonic-gate shp->sh_flags = SHF_ALLOC; 661*0Sstevel@tonic-gate shp->sh_type = SHT_SYMTAB; 662*0Sstevel@tonic-gate shp->sh_entsize = sizeof (Elf64_Sym); 663*0Sstevel@tonic-gate shp->sh_link = ESHDR_STRTAB; 664*0Sstevel@tonic-gate shp->sh_offset = off; 665*0Sstevel@tonic-gate shp->sh_info = de.de_global; 666*0Sstevel@tonic-gate shp->sh_size = de.de_nsym * sizeof (Elf64_Sym); 667*0Sstevel@tonic-gate shp->sh_addralign = 8; 668*0Sstevel@tonic-gate off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8); 669*0Sstevel@tonic-gate 670*0Sstevel@tonic-gate if (de.de_nrel == 0) { 671*0Sstevel@tonic-gate if (dt_write(dtp, fd, &elf_file, 672*0Sstevel@tonic-gate sizeof (elf_file)) != sizeof (elf_file) || 673*0Sstevel@tonic-gate PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB64) || 674*0Sstevel@tonic-gate PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || 675*0Sstevel@tonic-gate PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || 676*0Sstevel@tonic-gate PWRITE_SCN(ESHDR_DOF, dof)) { 677*0Sstevel@tonic-gate ret = dt_set_errno(dtp, errno); 678*0Sstevel@tonic-gate } 679*0Sstevel@tonic-gate } else { 680*0Sstevel@tonic-gate shp = &elf_file.shdr[ESHDR_REL]; 681*0Sstevel@tonic-gate shp->sh_name = 37; /* DTRACE_SHSTRTAB64[37] = ".rel.SUNW_dof" */ 682*0Sstevel@tonic-gate shp->sh_flags = SHF_ALLOC; 683*0Sstevel@tonic-gate shp->sh_type = SHT_RELA; 684*0Sstevel@tonic-gate shp->sh_entsize = sizeof (de.de_rel[0]); 685*0Sstevel@tonic-gate shp->sh_link = ESHDR_SYMTAB; 686*0Sstevel@tonic-gate shp->sh_info = ESHDR_DOF; 687*0Sstevel@tonic-gate shp->sh_offset = off; 688*0Sstevel@tonic-gate shp->sh_size = de.de_nrel * sizeof (de.de_rel[0]); 689*0Sstevel@tonic-gate shp->sh_addralign = 8; 690*0Sstevel@tonic-gate 691*0Sstevel@tonic-gate if (dt_write(dtp, fd, &elf_file, 692*0Sstevel@tonic-gate sizeof (elf_file)) != sizeof (elf_file) || 693*0Sstevel@tonic-gate PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB64) || 694*0Sstevel@tonic-gate PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || 695*0Sstevel@tonic-gate PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || 696*0Sstevel@tonic-gate PWRITE_SCN(ESHDR_REL, de.de_rel) || 697*0Sstevel@tonic-gate PWRITE_SCN(ESHDR_DOF, dof)) { 698*0Sstevel@tonic-gate ret = dt_set_errno(dtp, errno); 699*0Sstevel@tonic-gate } 700*0Sstevel@tonic-gate } 701*0Sstevel@tonic-gate 702*0Sstevel@tonic-gate free(de.de_strtab); 703*0Sstevel@tonic-gate free(de.de_sym); 704*0Sstevel@tonic-gate free(de.de_rel); 705*0Sstevel@tonic-gate 706*0Sstevel@tonic-gate return (ret); 707*0Sstevel@tonic-gate } 708*0Sstevel@tonic-gate 709*0Sstevel@tonic-gate static int 710*0Sstevel@tonic-gate dt_symtab_lookup(Elf_Data *data_sym, uintptr_t addr, uint_t shn, GElf_Sym *sym) 711*0Sstevel@tonic-gate { 712*0Sstevel@tonic-gate int i, ret = -1; 713*0Sstevel@tonic-gate GElf_Sym s; 714*0Sstevel@tonic-gate 715*0Sstevel@tonic-gate for (i = 0; gelf_getsym(data_sym, i, sym) != NULL; i++) { 716*0Sstevel@tonic-gate if (GELF_ST_TYPE(sym->st_info) == STT_FUNC && 717*0Sstevel@tonic-gate shn == sym->st_shndx && 718*0Sstevel@tonic-gate sym->st_value <= addr && 719*0Sstevel@tonic-gate addr < sym->st_value + sym->st_size) { 720*0Sstevel@tonic-gate if (GELF_ST_BIND(sym->st_info) == STB_GLOBAL) 721*0Sstevel@tonic-gate return (0); 722*0Sstevel@tonic-gate 723*0Sstevel@tonic-gate ret = 0; 724*0Sstevel@tonic-gate s = *sym; 725*0Sstevel@tonic-gate } 726*0Sstevel@tonic-gate } 727*0Sstevel@tonic-gate 728*0Sstevel@tonic-gate if (ret == 0) 729*0Sstevel@tonic-gate *sym = s; 730*0Sstevel@tonic-gate return (ret); 731*0Sstevel@tonic-gate } 732*0Sstevel@tonic-gate 733*0Sstevel@tonic-gate #if defined(__sparc) 734*0Sstevel@tonic-gate 735*0Sstevel@tonic-gate #define DT_OP_RET 0x81c7e008 736*0Sstevel@tonic-gate #define DT_OP_NOP 0x01000000 737*0Sstevel@tonic-gate #define DT_OP_CALL 0x40000000 738*0Sstevel@tonic-gate 739*0Sstevel@tonic-gate #define DT_IS_MOV_O7(inst) (((inst) & 0xffffe000) == 0x9e100000) 740*0Sstevel@tonic-gate #define DT_IS_RESTORE(inst) (((inst) & 0xc1f80000) == 0x81e80000) 741*0Sstevel@tonic-gate #define DT_IS_RETL(inst) (((inst) & 0xfff83fff) == 0x81c02008) 742*0Sstevel@tonic-gate 743*0Sstevel@tonic-gate #define DT_RS2(inst) ((inst) & 0x1f) 744*0Sstevel@tonic-gate #define DT_MAKE_RETL(reg) (0x81c02008 | ((reg) << 14)) 745*0Sstevel@tonic-gate 746*0Sstevel@tonic-gate static int 747*0Sstevel@tonic-gate dt_modtext(char *p, GElf_Rela *rela, uint32_t *off) 748*0Sstevel@tonic-gate { 749*0Sstevel@tonic-gate uint32_t *ip; 750*0Sstevel@tonic-gate 751*0Sstevel@tonic-gate if ((rela->r_offset & (sizeof (uint32_t) - 1)) != 0) 752*0Sstevel@tonic-gate return (-1); 753*0Sstevel@tonic-gate 754*0Sstevel@tonic-gate /*LINTED*/ 755*0Sstevel@tonic-gate ip = (uint32_t *)(p + rela->r_offset); 756*0Sstevel@tonic-gate 757*0Sstevel@tonic-gate /* 758*0Sstevel@tonic-gate * We only know about some specific relocation types. 759*0Sstevel@tonic-gate */ 760*0Sstevel@tonic-gate if (GELF_R_TYPE(rela->r_info) != R_SPARC_WDISP30 && 761*0Sstevel@tonic-gate GELF_R_TYPE(rela->r_info) != R_SPARC_WPLT30) 762*0Sstevel@tonic-gate return (-1); 763*0Sstevel@tonic-gate 764*0Sstevel@tonic-gate /* 765*0Sstevel@tonic-gate * We may have already processed this object file in an earlier 766*0Sstevel@tonic-gate * linker invocation in which case we'd expect to see a ret/restore 767*0Sstevel@tonic-gate * pair, a retl-like/mov pair or a nop; return success in that case. 768*0Sstevel@tonic-gate */ 769*0Sstevel@tonic-gate if (DT_IS_RESTORE(ip[1])) { 770*0Sstevel@tonic-gate if (ip[0] == DT_OP_RET) { 771*0Sstevel@tonic-gate return (0); 772*0Sstevel@tonic-gate } 773*0Sstevel@tonic-gate } else if (DT_IS_MOV_O7(ip[1])) { 774*0Sstevel@tonic-gate if (DT_IS_RETL(ip[0])) { 775*0Sstevel@tonic-gate return (0); 776*0Sstevel@tonic-gate } 777*0Sstevel@tonic-gate } else { 778*0Sstevel@tonic-gate if (ip[0] == DT_OP_NOP) { 779*0Sstevel@tonic-gate (*off) += sizeof (ip[0]); 780*0Sstevel@tonic-gate return (0); 781*0Sstevel@tonic-gate } 782*0Sstevel@tonic-gate } 783*0Sstevel@tonic-gate 784*0Sstevel@tonic-gate /* 785*0Sstevel@tonic-gate * We only expect call instructions with a displacement of 0. 786*0Sstevel@tonic-gate */ 787*0Sstevel@tonic-gate if (ip[0] != DT_OP_CALL) { 788*0Sstevel@tonic-gate dt_dprintf("found %x instead of a call instruction at %llx\n", 789*0Sstevel@tonic-gate ip[0], (u_longlong_t)rela->r_offset); 790*0Sstevel@tonic-gate return (-1); 791*0Sstevel@tonic-gate } 792*0Sstevel@tonic-gate 793*0Sstevel@tonic-gate /* 794*0Sstevel@tonic-gate * If the call is followed by a restore, it's a tail call so change 795*0Sstevel@tonic-gate * the call to a ret. If the call if followed by a mov of a register 796*0Sstevel@tonic-gate * into %o7, it's a tail call in leaf context so change the call to 797*0Sstevel@tonic-gate * a retl-like instruction that returns to that register value + 8 798*0Sstevel@tonic-gate * (rather than the typical %o7 + 8). Otherwise we adjust the offset 799*0Sstevel@tonic-gate * to land on what was once the delay slot of the call so we 800*0Sstevel@tonic-gate * correctly get all the arguments. 801*0Sstevel@tonic-gate */ 802*0Sstevel@tonic-gate if (DT_IS_RESTORE(ip[1])) { 803*0Sstevel@tonic-gate ip[0] = DT_OP_RET; 804*0Sstevel@tonic-gate } else if (DT_IS_MOV_O7(ip[1])) { 805*0Sstevel@tonic-gate ip[0] = DT_MAKE_RETL(DT_RS2(ip[1])); 806*0Sstevel@tonic-gate } else { 807*0Sstevel@tonic-gate ip[0] = DT_OP_NOP; 808*0Sstevel@tonic-gate (*off) += sizeof (ip[0]); 809*0Sstevel@tonic-gate } 810*0Sstevel@tonic-gate 811*0Sstevel@tonic-gate return (0); 812*0Sstevel@tonic-gate } 813*0Sstevel@tonic-gate 814*0Sstevel@tonic-gate #elif defined(__i386) || defined(__amd64) 815*0Sstevel@tonic-gate 816*0Sstevel@tonic-gate #define DT_OP_NOP 0x90 817*0Sstevel@tonic-gate #define DT_OP_CALL 0xe8 818*0Sstevel@tonic-gate 819*0Sstevel@tonic-gate static int 820*0Sstevel@tonic-gate dt_modtext(char *p, GElf_Rela *rela, uint32_t *off) 821*0Sstevel@tonic-gate { 822*0Sstevel@tonic-gate uint8_t *ip = (uint8_t *)(p + rela->r_offset - 1); 823*0Sstevel@tonic-gate 824*0Sstevel@tonic-gate /* 825*0Sstevel@tonic-gate * On x86, the first byte of the instruction is the call opcode and 826*0Sstevel@tonic-gate * the next four bytes are the 32-bit address; the relocation is for 827*0Sstevel@tonic-gate * the address so we back up one byte to land on the opcode. 828*0Sstevel@tonic-gate */ 829*0Sstevel@tonic-gate (*off) -= 1; 830*0Sstevel@tonic-gate 831*0Sstevel@tonic-gate /* 832*0Sstevel@tonic-gate * We only know about some specific relocation types. Luckily 833*0Sstevel@tonic-gate * these types have the same values on both 32-bit and 64-bit 834*0Sstevel@tonic-gate * x86 architectures. 835*0Sstevel@tonic-gate */ 836*0Sstevel@tonic-gate if (GELF_R_TYPE(rela->r_info) != R_386_PC32 && 837*0Sstevel@tonic-gate GELF_R_TYPE(rela->r_info) != R_386_PLT32) 838*0Sstevel@tonic-gate return (-1); 839*0Sstevel@tonic-gate 840*0Sstevel@tonic-gate /* 841*0Sstevel@tonic-gate * We may have already processed this object file in an earlier 842*0Sstevel@tonic-gate * linker invocation in which case we'd expect to see a bunch 843*0Sstevel@tonic-gate * of nops; return success in that case. 844*0Sstevel@tonic-gate */ 845*0Sstevel@tonic-gate if (ip[0] == DT_OP_NOP && ip[1] == DT_OP_NOP && ip[2] == DT_OP_NOP && 846*0Sstevel@tonic-gate ip[3] == DT_OP_NOP && ip[4] == DT_OP_NOP) 847*0Sstevel@tonic-gate return (0); 848*0Sstevel@tonic-gate 849*0Sstevel@tonic-gate /* 850*0Sstevel@tonic-gate * We only expect a call instrution with a 32-bit displacement. 851*0Sstevel@tonic-gate */ 852*0Sstevel@tonic-gate if (ip[0] != DT_OP_CALL) { 853*0Sstevel@tonic-gate dt_dprintf("found %x instead of a call instruction at %llx\n", 854*0Sstevel@tonic-gate ip[0], (u_longlong_t)rela->r_offset); 855*0Sstevel@tonic-gate return (-1); 856*0Sstevel@tonic-gate } 857*0Sstevel@tonic-gate 858*0Sstevel@tonic-gate ip[0] = DT_OP_NOP; 859*0Sstevel@tonic-gate ip[1] = DT_OP_NOP; 860*0Sstevel@tonic-gate ip[2] = DT_OP_NOP; 861*0Sstevel@tonic-gate ip[3] = DT_OP_NOP; 862*0Sstevel@tonic-gate ip[4] = DT_OP_NOP; 863*0Sstevel@tonic-gate 864*0Sstevel@tonic-gate return (0); 865*0Sstevel@tonic-gate } 866*0Sstevel@tonic-gate 867*0Sstevel@tonic-gate #else 868*0Sstevel@tonic-gate #error unknown ISA 869*0Sstevel@tonic-gate #endif 870*0Sstevel@tonic-gate 871*0Sstevel@tonic-gate /*PRINTFLIKE2*/ 872*0Sstevel@tonic-gate static int 873*0Sstevel@tonic-gate dt_link_error(dtrace_hdl_t *dtp, const char *format, ...) 874*0Sstevel@tonic-gate { 875*0Sstevel@tonic-gate va_list ap; 876*0Sstevel@tonic-gate 877*0Sstevel@tonic-gate va_start(ap, format); 878*0Sstevel@tonic-gate dt_set_errmsg(dtp, NULL, NULL, NULL, 0, format, ap); 879*0Sstevel@tonic-gate va_end(ap); 880*0Sstevel@tonic-gate 881*0Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_COMPILER)); 882*0Sstevel@tonic-gate } 883*0Sstevel@tonic-gate 884*0Sstevel@tonic-gate static int 885*0Sstevel@tonic-gate process_obj(dtrace_hdl_t *dtp, const char *obj) 886*0Sstevel@tonic-gate { 887*0Sstevel@tonic-gate static const char dt_prefix[] = "__dtrace_"; 888*0Sstevel@tonic-gate int fd, i, ndx, mod = 0; 889*0Sstevel@tonic-gate Elf *elf; 890*0Sstevel@tonic-gate GElf_Ehdr ehdr; 891*0Sstevel@tonic-gate Elf_Scn *scn_rel, *scn_sym, *scn_tgt; 892*0Sstevel@tonic-gate Elf_Data *data_rel, *data_sym, *data_tgt; 893*0Sstevel@tonic-gate GElf_Shdr shdr_rel, shdr_sym, shdr_tgt; 894*0Sstevel@tonic-gate GElf_Sym rsym, fsym; 895*0Sstevel@tonic-gate GElf_Rela rela; 896*0Sstevel@tonic-gate GElf_Rel rel; 897*0Sstevel@tonic-gate char *s, *p; 898*0Sstevel@tonic-gate char pname[DTRACE_PROVNAMELEN]; 899*0Sstevel@tonic-gate dt_provider_t *pvp; 900*0Sstevel@tonic-gate dt_probe_t *prp; 901*0Sstevel@tonic-gate uint32_t off, eclass, emachine1, emachine2; 902*0Sstevel@tonic-gate 903*0Sstevel@tonic-gate if ((fd = open64(obj, O_RDWR)) == -1) { 904*0Sstevel@tonic-gate return (dt_link_error(dtp, "failed to open %s: %s", obj, 905*0Sstevel@tonic-gate strerror(errno))); 906*0Sstevel@tonic-gate } 907*0Sstevel@tonic-gate 908*0Sstevel@tonic-gate if (elf_version(EV_CURRENT) == EV_NONE || 909*0Sstevel@tonic-gate (elf = elf_begin(fd, ELF_C_RDWR, NULL)) == NULL) { 910*0Sstevel@tonic-gate return (dt_link_error(dtp, "failed to process %s: %s", obj, 911*0Sstevel@tonic-gate elf_errmsg(elf_errno()))); 912*0Sstevel@tonic-gate } 913*0Sstevel@tonic-gate 914*0Sstevel@tonic-gate switch (elf_kind(elf)) { 915*0Sstevel@tonic-gate case ELF_K_ELF: 916*0Sstevel@tonic-gate break; 917*0Sstevel@tonic-gate case ELF_K_AR: 918*0Sstevel@tonic-gate return (dt_link_error(dtp, "archive files are not permitted %s;" 919*0Sstevel@tonic-gate " use the contents of the archive instead", obj)); 920*0Sstevel@tonic-gate default: 921*0Sstevel@tonic-gate return (dt_link_error(dtp, "invalid file type for %s", obj)); 922*0Sstevel@tonic-gate } 923*0Sstevel@tonic-gate 924*0Sstevel@tonic-gate if (gelf_getehdr(elf, &ehdr) == NULL) 925*0Sstevel@tonic-gate return (dt_link_error(dtp, "corrupt object file %s", obj)); 926*0Sstevel@tonic-gate 927*0Sstevel@tonic-gate if (dtp->dt_oflags & DTRACE_O_LP64) { 928*0Sstevel@tonic-gate eclass = ELFCLASS64; 929*0Sstevel@tonic-gate #if defined(__sparc) 930*0Sstevel@tonic-gate emachine1 = emachine2 = EM_SPARCV9; 931*0Sstevel@tonic-gate #elif defined(__i386) || defined(__amd64) 932*0Sstevel@tonic-gate emachine1 = emachine2 = EM_AMD64; 933*0Sstevel@tonic-gate #endif 934*0Sstevel@tonic-gate } else { 935*0Sstevel@tonic-gate eclass = ELFCLASS32; 936*0Sstevel@tonic-gate #if defined(__sparc) 937*0Sstevel@tonic-gate emachine1 = EM_SPARC; 938*0Sstevel@tonic-gate emachine2 = EM_SPARC32PLUS; 939*0Sstevel@tonic-gate #elif defined(__i386) || defined(__amd64) 940*0Sstevel@tonic-gate emachine1 = emachine2 = EM_386; 941*0Sstevel@tonic-gate #endif 942*0Sstevel@tonic-gate } 943*0Sstevel@tonic-gate 944*0Sstevel@tonic-gate if (ehdr.e_ident[EI_CLASS] != eclass) 945*0Sstevel@tonic-gate return (dt_link_error(dtp, "incorrect ELF class for object " 946*0Sstevel@tonic-gate "file %s", obj)); 947*0Sstevel@tonic-gate 948*0Sstevel@tonic-gate if (ehdr.e_machine != emachine1 && ehdr.e_machine != emachine2) 949*0Sstevel@tonic-gate return (dt_link_error(dtp, "incorrect ELF machine type for " 950*0Sstevel@tonic-gate "object file %s", obj)); 951*0Sstevel@tonic-gate 952*0Sstevel@tonic-gate scn_rel = NULL; 953*0Sstevel@tonic-gate while ((scn_rel = elf_nextscn(elf, scn_rel)) != NULL) { 954*0Sstevel@tonic-gate if (gelf_getshdr(scn_rel, &shdr_rel) == NULL) 955*0Sstevel@tonic-gate goto err; 956*0Sstevel@tonic-gate 957*0Sstevel@tonic-gate if (shdr_rel.sh_type != SHT_RELA && shdr_rel.sh_type != SHT_REL) 958*0Sstevel@tonic-gate continue; 959*0Sstevel@tonic-gate 960*0Sstevel@tonic-gate if ((data_rel = elf_getdata(scn_rel, NULL)) == NULL) 961*0Sstevel@tonic-gate goto err; 962*0Sstevel@tonic-gate 963*0Sstevel@tonic-gate if ((scn_sym = elf_getscn(elf, shdr_rel.sh_link)) == NULL || 964*0Sstevel@tonic-gate gelf_getshdr(scn_sym, &shdr_sym) == NULL || 965*0Sstevel@tonic-gate (data_sym = elf_getdata(scn_sym, NULL)) == NULL) 966*0Sstevel@tonic-gate goto err; 967*0Sstevel@tonic-gate 968*0Sstevel@tonic-gate if ((scn_tgt = elf_getscn(elf, shdr_rel.sh_info)) == NULL || 969*0Sstevel@tonic-gate gelf_getshdr(scn_tgt, &shdr_tgt) == NULL || 970*0Sstevel@tonic-gate (data_tgt = elf_getdata(scn_tgt, NULL)) == NULL) 971*0Sstevel@tonic-gate goto err; 972*0Sstevel@tonic-gate 973*0Sstevel@tonic-gate for (i = 0; i < shdr_rel.sh_size / shdr_rel.sh_entsize; i++) { 974*0Sstevel@tonic-gate 975*0Sstevel@tonic-gate if (shdr_rel.sh_type == SHT_RELA) { 976*0Sstevel@tonic-gate if (gelf_getrela(data_rel, i, &rela) == NULL) 977*0Sstevel@tonic-gate continue; 978*0Sstevel@tonic-gate } else { 979*0Sstevel@tonic-gate if (gelf_getrel(data_rel, i, &rel) == NULL) 980*0Sstevel@tonic-gate continue; 981*0Sstevel@tonic-gate rela.r_offset = rel.r_offset; 982*0Sstevel@tonic-gate rela.r_info = rel.r_info; 983*0Sstevel@tonic-gate rela.r_addend = 0; 984*0Sstevel@tonic-gate } 985*0Sstevel@tonic-gate 986*0Sstevel@tonic-gate ndx = GELF_R_SYM(rela.r_info); 987*0Sstevel@tonic-gate 988*0Sstevel@tonic-gate if (gelf_getsym(data_sym, ndx, &rsym) == NULL || 989*0Sstevel@tonic-gate (s = elf_strptr(elf, shdr_sym.sh_link, 990*0Sstevel@tonic-gate rsym.st_name)) == NULL) 991*0Sstevel@tonic-gate goto err; 992*0Sstevel@tonic-gate 993*0Sstevel@tonic-gate if (strncmp(s, dt_prefix, sizeof (dt_prefix) - 1) != 0) 994*0Sstevel@tonic-gate continue; 995*0Sstevel@tonic-gate 996*0Sstevel@tonic-gate if (dt_symtab_lookup(data_sym, rela.r_offset, 997*0Sstevel@tonic-gate shdr_rel.sh_info, &fsym) != 0) 998*0Sstevel@tonic-gate goto err; 999*0Sstevel@tonic-gate 1000*0Sstevel@tonic-gate s += sizeof (dt_prefix) - 1; 1001*0Sstevel@tonic-gate if ((p = strstr(s, "___")) == NULL || 1002*0Sstevel@tonic-gate p - s >= sizeof (pname)) 1003*0Sstevel@tonic-gate goto err; 1004*0Sstevel@tonic-gate 1005*0Sstevel@tonic-gate (void) memcpy(pname, s, p - s); 1006*0Sstevel@tonic-gate pname[p - s] = '\0'; 1007*0Sstevel@tonic-gate 1008*0Sstevel@tonic-gate p = strhyphenate(p + 3); /* strlen("___") */ 1009*0Sstevel@tonic-gate 1010*0Sstevel@tonic-gate if ((s = elf_strptr(elf, shdr_sym.sh_link, 1011*0Sstevel@tonic-gate fsym.st_name)) == NULL) 1012*0Sstevel@tonic-gate goto err; 1013*0Sstevel@tonic-gate 1014*0Sstevel@tonic-gate if ((pvp = dt_provider_lookup(dtp, pname)) == NULL) { 1015*0Sstevel@tonic-gate return (dt_link_error(dtp, 1016*0Sstevel@tonic-gate "no such provider %s", pname)); 1017*0Sstevel@tonic-gate } 1018*0Sstevel@tonic-gate 1019*0Sstevel@tonic-gate if ((prp = dt_probe_lookup(pvp, p)) == NULL) { 1020*0Sstevel@tonic-gate return (dt_link_error(dtp, 1021*0Sstevel@tonic-gate "no such probe %s", p)); 1022*0Sstevel@tonic-gate } 1023*0Sstevel@tonic-gate 1024*0Sstevel@tonic-gate assert(fsym.st_value <= rela.r_offset); 1025*0Sstevel@tonic-gate 1026*0Sstevel@tonic-gate off = rela.r_offset - fsym.st_value; 1027*0Sstevel@tonic-gate if (dt_modtext(data_tgt->d_buf, &rela, &off) != 0) 1028*0Sstevel@tonic-gate goto err; 1029*0Sstevel@tonic-gate 1030*0Sstevel@tonic-gate if (dt_probe_define(pvp, prp, s, off) != 0) 1031*0Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 1032*0Sstevel@tonic-gate 1033*0Sstevel@tonic-gate mod = 1; 1034*0Sstevel@tonic-gate 1035*0Sstevel@tonic-gate /* 1036*0Sstevel@tonic-gate * This symbol may already have been marked to 1037*0Sstevel@tonic-gate * be ignored by another relocation referencing 1038*0Sstevel@tonic-gate * the same symbol or if this object file has 1039*0Sstevel@tonic-gate * already been processed by an earlier link 1040*0Sstevel@tonic-gate * invocation. 1041*0Sstevel@tonic-gate */ 1042*0Sstevel@tonic-gate if (rsym.st_shndx != SHN_SUNW_IGNORE) { 1043*0Sstevel@tonic-gate rsym.st_shndx = SHN_SUNW_IGNORE; 1044*0Sstevel@tonic-gate (void) gelf_update_sym(data_sym, ndx, &rsym); 1045*0Sstevel@tonic-gate } 1046*0Sstevel@tonic-gate } 1047*0Sstevel@tonic-gate } 1048*0Sstevel@tonic-gate 1049*0Sstevel@tonic-gate if (mod && elf_update(elf, ELF_C_WRITE) == -1) 1050*0Sstevel@tonic-gate goto err; 1051*0Sstevel@tonic-gate 1052*0Sstevel@tonic-gate return (0); 1053*0Sstevel@tonic-gate 1054*0Sstevel@tonic-gate err: 1055*0Sstevel@tonic-gate return (dt_link_error(dtp, 1056*0Sstevel@tonic-gate "an error was encountered while processing %s", obj)); 1057*0Sstevel@tonic-gate } 1058*0Sstevel@tonic-gate 1059*0Sstevel@tonic-gate int 1060*0Sstevel@tonic-gate dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags, 1061*0Sstevel@tonic-gate const char *file, int objc, char *const objv[]) 1062*0Sstevel@tonic-gate { 1063*0Sstevel@tonic-gate char drti[PATH_MAX]; 1064*0Sstevel@tonic-gate dof_hdr_t *dof; 1065*0Sstevel@tonic-gate int fd, status, i; 1066*0Sstevel@tonic-gate char *cmd, tmp; 1067*0Sstevel@tonic-gate size_t len; 1068*0Sstevel@tonic-gate int ret = 0; 1069*0Sstevel@tonic-gate 1070*0Sstevel@tonic-gate for (i = 0; i < objc; i++) { 1071*0Sstevel@tonic-gate if (process_obj(dtp, objv[i]) != 0) 1072*0Sstevel@tonic-gate return (-1); /* errno is set for us */ 1073*0Sstevel@tonic-gate } 1074*0Sstevel@tonic-gate 1075*0Sstevel@tonic-gate if ((dof = dtrace_dof_create(dtp, pgp, dflags)) == NULL) 1076*0Sstevel@tonic-gate return (-1); /* errno is set for us */ 1077*0Sstevel@tonic-gate 1078*0Sstevel@tonic-gate /* 1079*0Sstevel@tonic-gate * Create a temporary file and then unlink it if we're going to 1080*0Sstevel@tonic-gate * combine it with drti.o later. We can still refer to it in child 1081*0Sstevel@tonic-gate * processes as /dev/fd/<fd>. 1082*0Sstevel@tonic-gate */ 1083*0Sstevel@tonic-gate if ((fd = open64(file, O_RDWR | O_CREAT | O_TRUNC, 0666)) == -1) { 1084*0Sstevel@tonic-gate return (dt_link_error(dtp, 1085*0Sstevel@tonic-gate "failed to open %s: %s", file, strerror(errno))); 1086*0Sstevel@tonic-gate } 1087*0Sstevel@tonic-gate 1088*0Sstevel@tonic-gate /* 1089*0Sstevel@tonic-gate * If -xlinktype=DOF has been selected, just write out the DOF. 1090*0Sstevel@tonic-gate * Otherwise proceed to the default of generating and linking ELF. 1091*0Sstevel@tonic-gate */ 1092*0Sstevel@tonic-gate switch (dtp->dt_linktype) { 1093*0Sstevel@tonic-gate case DT_LTYP_DOF: 1094*0Sstevel@tonic-gate if (dt_write(dtp, fd, dof, dof->dofh_filesz) < dof->dofh_filesz) 1095*0Sstevel@tonic-gate ret = errno; 1096*0Sstevel@tonic-gate 1097*0Sstevel@tonic-gate if (close(fd) != 0 && ret == 0) 1098*0Sstevel@tonic-gate ret = errno; 1099*0Sstevel@tonic-gate 1100*0Sstevel@tonic-gate if (ret != 0) { 1101*0Sstevel@tonic-gate return (dt_link_error(dtp, 1102*0Sstevel@tonic-gate "failed to write %s: %s", file, strerror(ret))); 1103*0Sstevel@tonic-gate } 1104*0Sstevel@tonic-gate 1105*0Sstevel@tonic-gate return (0); 1106*0Sstevel@tonic-gate 1107*0Sstevel@tonic-gate case DT_LTYP_ELF: 1108*0Sstevel@tonic-gate break; /* fall through to the rest of dtrace_program_link() */ 1109*0Sstevel@tonic-gate 1110*0Sstevel@tonic-gate default: 1111*0Sstevel@tonic-gate return (dt_link_error(dtp, 1112*0Sstevel@tonic-gate "invalid link type %u\n", dtp->dt_linktype)); 1113*0Sstevel@tonic-gate } 1114*0Sstevel@tonic-gate 1115*0Sstevel@tonic-gate 1116*0Sstevel@tonic-gate if (!dtp->dt_lazyload) 1117*0Sstevel@tonic-gate (void) unlink(file); 1118*0Sstevel@tonic-gate 1119*0Sstevel@tonic-gate if (dtp->dt_oflags & DTRACE_O_LP64) 1120*0Sstevel@tonic-gate status = dump_elf64(dtp, dof, fd); 1121*0Sstevel@tonic-gate else 1122*0Sstevel@tonic-gate status = dump_elf32(dtp, dof, fd); 1123*0Sstevel@tonic-gate 1124*0Sstevel@tonic-gate if (status != 0 || lseek(fd, 0, SEEK_SET) != 0) { 1125*0Sstevel@tonic-gate return (dt_link_error(dtp, 1126*0Sstevel@tonic-gate "failed to write %s: %s", file, strerror(errno))); 1127*0Sstevel@tonic-gate } 1128*0Sstevel@tonic-gate 1129*0Sstevel@tonic-gate if (!dtp->dt_lazyload) { 1130*0Sstevel@tonic-gate if (dtp->dt_oflags & DTRACE_O_LP64) { 1131*0Sstevel@tonic-gate (void) snprintf(drti, sizeof (drti), 1132*0Sstevel@tonic-gate "%s/64/drti.o", _dtrace_libdir); 1133*0Sstevel@tonic-gate } else { 1134*0Sstevel@tonic-gate (void) snprintf(drti, sizeof (drti), 1135*0Sstevel@tonic-gate "%s/drti.o", _dtrace_libdir); 1136*0Sstevel@tonic-gate } 1137*0Sstevel@tonic-gate 1138*0Sstevel@tonic-gate len = snprintf(&tmp, 1, "%s -o %s -r /dev/fd/%d %s", 1139*0Sstevel@tonic-gate dtp->dt_ld_path, file, fd, drti) + 1; 1140*0Sstevel@tonic-gate 1141*0Sstevel@tonic-gate cmd = alloca(len); 1142*0Sstevel@tonic-gate 1143*0Sstevel@tonic-gate (void) snprintf(cmd, len, "%s -o %s -r /dev/fd/%d %s", 1144*0Sstevel@tonic-gate dtp->dt_ld_path, file, fd, drti); 1145*0Sstevel@tonic-gate 1146*0Sstevel@tonic-gate if ((status = system(cmd)) == -1) { 1147*0Sstevel@tonic-gate ret = dt_link_error(dtp, "failed to run %s: %s", 1148*0Sstevel@tonic-gate dtp->dt_ld_path, strerror(errno)); 1149*0Sstevel@tonic-gate goto done; 1150*0Sstevel@tonic-gate } 1151*0Sstevel@tonic-gate 1152*0Sstevel@tonic-gate (void) close(fd); /* release temporary file */ 1153*0Sstevel@tonic-gate 1154*0Sstevel@tonic-gate if (WIFSIGNALED(status)) { 1155*0Sstevel@tonic-gate ret = dt_link_error(dtp, 1156*0Sstevel@tonic-gate "failed to link %s: %s failed due to signal %d", 1157*0Sstevel@tonic-gate file, dtp->dt_ld_path, WTERMSIG(status)); 1158*0Sstevel@tonic-gate goto done; 1159*0Sstevel@tonic-gate } 1160*0Sstevel@tonic-gate 1161*0Sstevel@tonic-gate if (WEXITSTATUS(status) != 0) { 1162*0Sstevel@tonic-gate ret = dt_link_error(dtp, 1163*0Sstevel@tonic-gate "failed to link %s: %s exited with status %d\n", 1164*0Sstevel@tonic-gate file, dtp->dt_ld_path, WEXITSTATUS(status)); 1165*0Sstevel@tonic-gate goto done; 1166*0Sstevel@tonic-gate } 1167*0Sstevel@tonic-gate } else { 1168*0Sstevel@tonic-gate (void) close(fd); 1169*0Sstevel@tonic-gate } 1170*0Sstevel@tonic-gate 1171*0Sstevel@tonic-gate done: 1172*0Sstevel@tonic-gate dtrace_dof_destroy(dtp, dof); 1173*0Sstevel@tonic-gate return (ret); 1174*0Sstevel@tonic-gate } 1175