1178479Sjb/* 2178479Sjb * CDDL HEADER START 3178479Sjb * 4178479Sjb * The contents of this file are subject to the terms of the 5178479Sjb * Common Development and Distribution License (the "License"). 6178479Sjb * You may not use this file except in compliance with the License. 7178479Sjb * 8178479Sjb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9178479Sjb * or http://www.opensolaris.org/os/licensing. 10178479Sjb * See the License for the specific language governing permissions 11178479Sjb * and limitations under the License. 12178479Sjb * 13178479Sjb * When distributing Covered Code, include this CDDL HEADER in each 14178479Sjb * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15178479Sjb * If applicable, add the following below this CDDL HEADER, with the 16178479Sjb * fields enclosed by brackets "[]" replaced with your own identifying 17178479Sjb * information: Portions Copyright [yyyy] [name of copyright owner] 18178479Sjb * 19178479Sjb * CDDL HEADER END 20178479Sjb */ 21178479Sjb 22178479Sjb/* 23178573Sjb * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24178479Sjb * Use is subject to license terms. 25178479Sjb */ 26178479Sjb 27178479Sjb#pragma ident "%Z%%M% %I% %E% SMI" 28178479Sjb 29178479Sjb#define ELF_TARGET_ALL 30178479Sjb#include <elf.h> 31178479Sjb 32178479Sjb#include <sys/types.h> 33178573Sjb#if defined(sun) 34178479Sjb#include <sys/sysmacros.h> 35178573Sjb#else 36178573Sjb#define P2ROUNDUP(x, align) (-(-(x) & -(align))) 37178573Sjb#endif 38178479Sjb 39178479Sjb#include <unistd.h> 40178479Sjb#include <strings.h> 41178573Sjb#if defined(sun) 42178479Sjb#include <alloca.h> 43178573Sjb#endif 44178479Sjb#include <limits.h> 45178479Sjb#include <stddef.h> 46178479Sjb#include <stdlib.h> 47178479Sjb#include <stdio.h> 48178479Sjb#include <fcntl.h> 49178479Sjb#include <errno.h> 50178573Sjb#if defined(sun) 51178479Sjb#include <wait.h> 52178573Sjb#else 53178573Sjb#include <sys/wait.h> 54211554Srpaulo#include <libelf.h> 55211554Srpaulo#include <gelf.h> 56211554Srpaulo#include <sys/mman.h> 57178573Sjb#endif 58178479Sjb#include <assert.h> 59178479Sjb#include <sys/ipc.h> 60178479Sjb 61178479Sjb#include <dt_impl.h> 62178479Sjb#include <dt_provider.h> 63178479Sjb#include <dt_program.h> 64178479Sjb#include <dt_string.h> 65178479Sjb 66178479Sjb#define ESHDR_NULL 0 67178479Sjb#define ESHDR_SHSTRTAB 1 68178479Sjb#define ESHDR_DOF 2 69178479Sjb#define ESHDR_STRTAB 3 70178479Sjb#define ESHDR_SYMTAB 4 71178479Sjb#define ESHDR_REL 5 72178479Sjb#define ESHDR_NUM 6 73178479Sjb 74178479Sjb#define PWRITE_SCN(index, data) \ 75178479Sjb (lseek64(fd, (off64_t)elf_file.shdr[(index)].sh_offset, SEEK_SET) != \ 76178479Sjb (off64_t)elf_file.shdr[(index)].sh_offset || \ 77178479Sjb dt_write(dtp, fd, (data), elf_file.shdr[(index)].sh_size) != \ 78178479Sjb elf_file.shdr[(index)].sh_size) 79178479Sjb 80178479Sjbstatic const char DTRACE_SHSTRTAB32[] = "\0" 81178479Sjb".shstrtab\0" /* 1 */ 82178479Sjb".SUNW_dof\0" /* 11 */ 83178479Sjb".strtab\0" /* 21 */ 84178479Sjb".symtab\0" /* 29 */ 85178479Sjb#ifdef __sparc 86178479Sjb".rela.SUNW_dof"; /* 37 */ 87178479Sjb#else 88178479Sjb".rel.SUNW_dof"; /* 37 */ 89178479Sjb#endif 90178479Sjb 91178479Sjbstatic const char DTRACE_SHSTRTAB64[] = "\0" 92178479Sjb".shstrtab\0" /* 1 */ 93178479Sjb".SUNW_dof\0" /* 11 */ 94178479Sjb".strtab\0" /* 21 */ 95178479Sjb".symtab\0" /* 29 */ 96178479Sjb".rela.SUNW_dof"; /* 37 */ 97178479Sjb 98178479Sjbstatic const char DOFSTR[] = "__SUNW_dof"; 99178479Sjbstatic const char DOFLAZYSTR[] = "___SUNW_dof"; 100178479Sjb 101178479Sjbtypedef struct dt_link_pair { 102178479Sjb struct dt_link_pair *dlp_next; /* next pair in linked list */ 103178479Sjb void *dlp_str; /* buffer for string table */ 104178479Sjb void *dlp_sym; /* buffer for symbol table */ 105178479Sjb} dt_link_pair_t; 106178479Sjb 107178479Sjbtypedef struct dof_elf32 { 108178479Sjb uint32_t de_nrel; /* relocation count */ 109178479Sjb#ifdef __sparc 110178479Sjb Elf32_Rela *de_rel; /* array of relocations for sparc */ 111178479Sjb#else 112178479Sjb Elf32_Rel *de_rel; /* array of relocations for x86 */ 113178479Sjb#endif 114178479Sjb uint32_t de_nsym; /* symbol count */ 115178479Sjb Elf32_Sym *de_sym; /* array of symbols */ 116178479Sjb uint32_t de_strlen; /* size of of string table */ 117178479Sjb char *de_strtab; /* string table */ 118178479Sjb uint32_t de_global; /* index of the first global symbol */ 119178479Sjb} dof_elf32_t; 120178479Sjb 121178479Sjbstatic int 122178479Sjbprepare_elf32(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf32_t *dep) 123178479Sjb{ 124178479Sjb dof_sec_t *dofs, *s; 125178479Sjb dof_relohdr_t *dofrh; 126178479Sjb dof_relodesc_t *dofr; 127178479Sjb char *strtab; 128178479Sjb int i, j, nrel; 129178479Sjb size_t strtabsz = 1; 130178479Sjb uint32_t count = 0; 131178479Sjb size_t base; 132178479Sjb Elf32_Sym *sym; 133178479Sjb#ifdef __sparc 134178479Sjb Elf32_Rela *rel; 135178479Sjb#else 136178479Sjb Elf32_Rel *rel; 137178479Sjb#endif 138178479Sjb 139178479Sjb /*LINTED*/ 140178479Sjb dofs = (dof_sec_t *)((char *)dof + dof->dofh_secoff); 141178479Sjb 142178479Sjb /* 143178479Sjb * First compute the size of the string table and the number of 144178479Sjb * relocations present in the DOF. 145178479Sjb */ 146178479Sjb for (i = 0; i < dof->dofh_secnum; i++) { 147178479Sjb if (dofs[i].dofs_type != DOF_SECT_URELHDR) 148178479Sjb continue; 149178479Sjb 150178479Sjb /*LINTED*/ 151178479Sjb dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset); 152178479Sjb 153178479Sjb s = &dofs[dofrh->dofr_strtab]; 154178479Sjb strtab = (char *)dof + s->dofs_offset; 155178479Sjb assert(strtab[0] == '\0'); 156178479Sjb strtabsz += s->dofs_size - 1; 157178479Sjb 158178479Sjb s = &dofs[dofrh->dofr_relsec]; 159178479Sjb /*LINTED*/ 160178479Sjb dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset); 161178479Sjb count += s->dofs_size / s->dofs_entsize; 162178479Sjb } 163178479Sjb 164178479Sjb dep->de_strlen = strtabsz; 165178479Sjb dep->de_nrel = count; 166178479Sjb dep->de_nsym = count + 1; /* the first symbol is always null */ 167178479Sjb 168178479Sjb if (dtp->dt_lazyload) { 169178479Sjb dep->de_strlen += sizeof (DOFLAZYSTR); 170178479Sjb dep->de_nsym++; 171178479Sjb } else { 172178479Sjb dep->de_strlen += sizeof (DOFSTR); 173178479Sjb dep->de_nsym++; 174178479Sjb } 175178479Sjb 176178479Sjb if ((dep->de_rel = calloc(dep->de_nrel, 177178479Sjb sizeof (dep->de_rel[0]))) == NULL) { 178178479Sjb return (dt_set_errno(dtp, EDT_NOMEM)); 179178479Sjb } 180178479Sjb 181178479Sjb if ((dep->de_sym = calloc(dep->de_nsym, sizeof (Elf32_Sym))) == NULL) { 182178479Sjb free(dep->de_rel); 183178479Sjb return (dt_set_errno(dtp, EDT_NOMEM)); 184178479Sjb } 185178479Sjb 186178479Sjb if ((dep->de_strtab = calloc(dep->de_strlen, 1)) == NULL) { 187178479Sjb free(dep->de_rel); 188178479Sjb free(dep->de_sym); 189178479Sjb return (dt_set_errno(dtp, EDT_NOMEM)); 190178479Sjb } 191178479Sjb 192178479Sjb count = 0; 193178479Sjb strtabsz = 1; 194178479Sjb dep->de_strtab[0] = '\0'; 195178479Sjb rel = dep->de_rel; 196178479Sjb sym = dep->de_sym; 197178479Sjb dep->de_global = 1; 198178479Sjb 199178479Sjb /* 200178479Sjb * The first symbol table entry must be zeroed and is always ignored. 201178479Sjb */ 202178479Sjb bzero(sym, sizeof (Elf32_Sym)); 203178479Sjb sym++; 204178479Sjb 205178479Sjb /* 206178479Sjb * Take a second pass through the DOF sections filling in the 207178479Sjb * memory we allocated. 208178479Sjb */ 209178479Sjb for (i = 0; i < dof->dofh_secnum; i++) { 210178479Sjb if (dofs[i].dofs_type != DOF_SECT_URELHDR) 211178479Sjb continue; 212178479Sjb 213178479Sjb /*LINTED*/ 214178479Sjb dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset); 215178479Sjb 216178479Sjb s = &dofs[dofrh->dofr_strtab]; 217178479Sjb strtab = (char *)dof + s->dofs_offset; 218178479Sjb bcopy(strtab + 1, dep->de_strtab + strtabsz, s->dofs_size); 219178479Sjb base = strtabsz; 220178479Sjb strtabsz += s->dofs_size - 1; 221178479Sjb 222178479Sjb s = &dofs[dofrh->dofr_relsec]; 223178479Sjb /*LINTED*/ 224178479Sjb dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset); 225178479Sjb nrel = s->dofs_size / s->dofs_entsize; 226178479Sjb 227178479Sjb s = &dofs[dofrh->dofr_tgtsec]; 228178479Sjb 229178479Sjb for (j = 0; j < nrel; j++) { 230178573Sjb#if defined(__arm__) 231178573Sjb/* XXX */ 232178573Sjbprintf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__); 233178573Sjb#elif defined(__ia64__) 234178573Sjb/* XXX */ 235178573Sjbprintf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__); 236178573Sjb#elif defined(__i386) || defined(__amd64) 237178479Sjb rel->r_offset = s->dofs_offset + 238178479Sjb dofr[j].dofr_offset; 239178479Sjb rel->r_info = ELF32_R_INFO(count + dep->de_global, 240178479Sjb R_386_32); 241178573Sjb#elif defined(__mips__) 242178573Sjb/* XXX */ 243178573Sjbprintf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__); 244178573Sjb#elif defined(__powerpc__) 245260670Sjhibbits /* 246260670Sjhibbits * Add 4 bytes to hit the low half of this 64-bit 247260670Sjhibbits * big-endian address. 248260670Sjhibbits */ 249260670Sjhibbits rel->r_offset = s->dofs_offset + 250260670Sjhibbits dofr[j].dofr_offset + 4; 251260670Sjhibbits rel->r_info = ELF32_R_INFO(count + dep->de_global, 252260670Sjhibbits R_PPC_REL32); 253178479Sjb#elif defined(__sparc) 254178479Sjb /* 255178479Sjb * Add 4 bytes to hit the low half of this 64-bit 256178479Sjb * big-endian address. 257178479Sjb */ 258178479Sjb rel->r_offset = s->dofs_offset + 259178479Sjb dofr[j].dofr_offset + 4; 260178479Sjb rel->r_info = ELF32_R_INFO(count + dep->de_global, 261178479Sjb R_SPARC_32); 262178479Sjb#else 263178479Sjb#error unknown ISA 264178479Sjb#endif 265178479Sjb 266178479Sjb sym->st_name = base + dofr[j].dofr_name - 1; 267178479Sjb sym->st_value = 0; 268178479Sjb sym->st_size = 0; 269178479Sjb sym->st_info = ELF32_ST_INFO(STB_GLOBAL, STT_FUNC); 270178479Sjb sym->st_other = 0; 271178479Sjb sym->st_shndx = SHN_UNDEF; 272178479Sjb 273178479Sjb rel++; 274178479Sjb sym++; 275178479Sjb count++; 276178479Sjb } 277178479Sjb } 278178479Sjb 279178479Sjb /* 280178479Sjb * Add a symbol for the DOF itself. We use a different symbol for 281178479Sjb * lazily and actively loaded DOF to make them easy to distinguish. 282178479Sjb */ 283178479Sjb sym->st_name = strtabsz; 284178479Sjb sym->st_value = 0; 285178479Sjb sym->st_size = dof->dofh_filesz; 286178479Sjb sym->st_info = ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT); 287178479Sjb sym->st_other = 0; 288178479Sjb sym->st_shndx = ESHDR_DOF; 289178479Sjb sym++; 290178479Sjb 291178479Sjb if (dtp->dt_lazyload) { 292178479Sjb bcopy(DOFLAZYSTR, dep->de_strtab + strtabsz, 293178479Sjb sizeof (DOFLAZYSTR)); 294178479Sjb strtabsz += sizeof (DOFLAZYSTR); 295178479Sjb } else { 296178479Sjb bcopy(DOFSTR, dep->de_strtab + strtabsz, sizeof (DOFSTR)); 297178479Sjb strtabsz += sizeof (DOFSTR); 298178479Sjb } 299178479Sjb 300178479Sjb assert(count == dep->de_nrel); 301178479Sjb assert(strtabsz == dep->de_strlen); 302178479Sjb 303178479Sjb return (0); 304178479Sjb} 305178479Sjb 306178479Sjb 307178479Sjbtypedef struct dof_elf64 { 308178479Sjb uint32_t de_nrel; 309178479Sjb Elf64_Rela *de_rel; 310178479Sjb uint32_t de_nsym; 311178479Sjb Elf64_Sym *de_sym; 312178479Sjb 313178479Sjb uint32_t de_strlen; 314178479Sjb char *de_strtab; 315178479Sjb 316178479Sjb uint32_t de_global; 317178479Sjb} dof_elf64_t; 318178479Sjb 319178479Sjbstatic int 320178479Sjbprepare_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf64_t *dep) 321178479Sjb{ 322178479Sjb dof_sec_t *dofs, *s; 323178479Sjb dof_relohdr_t *dofrh; 324178479Sjb dof_relodesc_t *dofr; 325178479Sjb char *strtab; 326178479Sjb int i, j, nrel; 327178479Sjb size_t strtabsz = 1; 328178479Sjb uint32_t count = 0; 329178479Sjb size_t base; 330178479Sjb Elf64_Sym *sym; 331178479Sjb Elf64_Rela *rel; 332178479Sjb 333178479Sjb /*LINTED*/ 334178479Sjb dofs = (dof_sec_t *)((char *)dof + dof->dofh_secoff); 335178479Sjb 336178479Sjb /* 337178479Sjb * First compute the size of the string table and the number of 338178479Sjb * relocations present in the DOF. 339178479Sjb */ 340178479Sjb for (i = 0; i < dof->dofh_secnum; i++) { 341178479Sjb if (dofs[i].dofs_type != DOF_SECT_URELHDR) 342178479Sjb continue; 343178479Sjb 344178479Sjb /*LINTED*/ 345178479Sjb dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset); 346178479Sjb 347178479Sjb s = &dofs[dofrh->dofr_strtab]; 348178479Sjb strtab = (char *)dof + s->dofs_offset; 349178479Sjb assert(strtab[0] == '\0'); 350178479Sjb strtabsz += s->dofs_size - 1; 351178479Sjb 352178479Sjb s = &dofs[dofrh->dofr_relsec]; 353178479Sjb /*LINTED*/ 354178479Sjb dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset); 355178479Sjb count += s->dofs_size / s->dofs_entsize; 356178479Sjb } 357178479Sjb 358178479Sjb dep->de_strlen = strtabsz; 359178479Sjb dep->de_nrel = count; 360178479Sjb dep->de_nsym = count + 1; /* the first symbol is always null */ 361178479Sjb 362178479Sjb if (dtp->dt_lazyload) { 363178479Sjb dep->de_strlen += sizeof (DOFLAZYSTR); 364178479Sjb dep->de_nsym++; 365178479Sjb } else { 366178479Sjb dep->de_strlen += sizeof (DOFSTR); 367178479Sjb dep->de_nsym++; 368178479Sjb } 369178479Sjb 370178479Sjb if ((dep->de_rel = calloc(dep->de_nrel, 371178479Sjb sizeof (dep->de_rel[0]))) == NULL) { 372178479Sjb return (dt_set_errno(dtp, EDT_NOMEM)); 373178479Sjb } 374178479Sjb 375178479Sjb if ((dep->de_sym = calloc(dep->de_nsym, sizeof (Elf64_Sym))) == NULL) { 376178479Sjb free(dep->de_rel); 377178479Sjb return (dt_set_errno(dtp, EDT_NOMEM)); 378178479Sjb } 379178479Sjb 380178479Sjb if ((dep->de_strtab = calloc(dep->de_strlen, 1)) == NULL) { 381178479Sjb free(dep->de_rel); 382178479Sjb free(dep->de_sym); 383178479Sjb return (dt_set_errno(dtp, EDT_NOMEM)); 384178479Sjb } 385178479Sjb 386178479Sjb count = 0; 387178479Sjb strtabsz = 1; 388178479Sjb dep->de_strtab[0] = '\0'; 389178479Sjb rel = dep->de_rel; 390178479Sjb sym = dep->de_sym; 391178479Sjb dep->de_global = 1; 392178479Sjb 393178479Sjb /* 394178479Sjb * The first symbol table entry must be zeroed and is always ignored. 395178479Sjb */ 396178479Sjb bzero(sym, sizeof (Elf64_Sym)); 397178479Sjb sym++; 398178479Sjb 399178479Sjb /* 400178479Sjb * Take a second pass through the DOF sections filling in the 401178479Sjb * memory we allocated. 402178479Sjb */ 403178479Sjb for (i = 0; i < dof->dofh_secnum; i++) { 404178479Sjb if (dofs[i].dofs_type != DOF_SECT_URELHDR) 405178479Sjb continue; 406178479Sjb 407178479Sjb /*LINTED*/ 408178479Sjb dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset); 409178479Sjb 410178479Sjb s = &dofs[dofrh->dofr_strtab]; 411178479Sjb strtab = (char *)dof + s->dofs_offset; 412178479Sjb bcopy(strtab + 1, dep->de_strtab + strtabsz, s->dofs_size); 413178479Sjb base = strtabsz; 414178479Sjb strtabsz += s->dofs_size - 1; 415178479Sjb 416178479Sjb s = &dofs[dofrh->dofr_relsec]; 417178479Sjb /*LINTED*/ 418178479Sjb dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset); 419178479Sjb nrel = s->dofs_size / s->dofs_entsize; 420178479Sjb 421178479Sjb s = &dofs[dofrh->dofr_tgtsec]; 422178479Sjb 423178479Sjb for (j = 0; j < nrel; j++) { 424178573Sjb#ifdef DOODAD 425178573Sjb#if defined(__arm__) 426178573Sjb/* XXX */ 427178573Sjb#elif defined(__ia64__) 428178573Sjb/* XXX */ 429178573Sjb#elif defined(__mips__) 430178573Sjb/* XXX */ 431178573Sjb#elif defined(__powerpc__) 432260670Sjhibbits rel->r_offset = s->dofs_offset + 433260670Sjhibbits dofr[j].dofr_offset; 434260670Sjhibbits rel->r_info = ELF64_R_INFO(count + dep->de_global, 435260670Sjhibbits R_PPC64_REL64); 436178573Sjb#elif defined(__i386) || defined(__amd64) 437178479Sjb rel->r_offset = s->dofs_offset + 438178479Sjb dofr[j].dofr_offset; 439178479Sjb rel->r_info = ELF64_R_INFO(count + dep->de_global, 440178479Sjb R_AMD64_64); 441178479Sjb#elif defined(__sparc) 442178479Sjb rel->r_offset = s->dofs_offset + 443178479Sjb dofr[j].dofr_offset; 444178479Sjb rel->r_info = ELF64_R_INFO(count + dep->de_global, 445178479Sjb R_SPARC_64); 446178479Sjb#else 447178479Sjb#error unknown ISA 448178479Sjb#endif 449178573Sjb#endif 450178479Sjb 451178479Sjb sym->st_name = base + dofr[j].dofr_name - 1; 452178479Sjb sym->st_value = 0; 453178479Sjb sym->st_size = 0; 454178479Sjb sym->st_info = GELF_ST_INFO(STB_GLOBAL, STT_FUNC); 455178479Sjb sym->st_other = 0; 456178479Sjb sym->st_shndx = SHN_UNDEF; 457178479Sjb 458178479Sjb rel++; 459178479Sjb sym++; 460178479Sjb count++; 461178479Sjb } 462178479Sjb } 463178479Sjb 464178479Sjb /* 465178479Sjb * Add a symbol for the DOF itself. We use a different symbol for 466178479Sjb * lazily and actively loaded DOF to make them easy to distinguish. 467178479Sjb */ 468178479Sjb sym->st_name = strtabsz; 469178479Sjb sym->st_value = 0; 470178479Sjb sym->st_size = dof->dofh_filesz; 471178479Sjb sym->st_info = GELF_ST_INFO(STB_GLOBAL, STT_OBJECT); 472178479Sjb sym->st_other = 0; 473178479Sjb sym->st_shndx = ESHDR_DOF; 474178479Sjb sym++; 475178479Sjb 476178479Sjb if (dtp->dt_lazyload) { 477178479Sjb bcopy(DOFLAZYSTR, dep->de_strtab + strtabsz, 478178479Sjb sizeof (DOFLAZYSTR)); 479178479Sjb strtabsz += sizeof (DOFLAZYSTR); 480178479Sjb } else { 481178479Sjb bcopy(DOFSTR, dep->de_strtab + strtabsz, sizeof (DOFSTR)); 482178479Sjb strtabsz += sizeof (DOFSTR); 483178479Sjb } 484178479Sjb 485178479Sjb assert(count == dep->de_nrel); 486178479Sjb assert(strtabsz == dep->de_strlen); 487178479Sjb 488178479Sjb return (0); 489178479Sjb} 490178479Sjb 491178479Sjb/* 492178479Sjb * Write out an ELF32 file prologue consisting of a header, section headers, 493178479Sjb * and a section header string table. The DOF data will follow this prologue 494178479Sjb * and complete the contents of the given ELF file. 495178479Sjb */ 496178479Sjbstatic int 497178479Sjbdump_elf32(dtrace_hdl_t *dtp, const dof_hdr_t *dof, int fd) 498178479Sjb{ 499178479Sjb struct { 500178479Sjb Elf32_Ehdr ehdr; 501178479Sjb Elf32_Shdr shdr[ESHDR_NUM]; 502178479Sjb } elf_file; 503178479Sjb 504178479Sjb Elf32_Shdr *shp; 505178479Sjb Elf32_Off off; 506178479Sjb dof_elf32_t de; 507178479Sjb int ret = 0; 508178479Sjb uint_t nshdr; 509178479Sjb 510178479Sjb if (prepare_elf32(dtp, dof, &de) != 0) 511178479Sjb return (-1); /* errno is set for us */ 512178479Sjb 513178479Sjb /* 514178479Sjb * If there are no relocations, we only need enough sections for 515178479Sjb * the shstrtab and the DOF. 516178479Sjb */ 517178479Sjb nshdr = de.de_nrel == 0 ? ESHDR_SYMTAB + 1 : ESHDR_NUM; 518178479Sjb 519178479Sjb bzero(&elf_file, sizeof (elf_file)); 520178479Sjb 521178479Sjb elf_file.ehdr.e_ident[EI_MAG0] = ELFMAG0; 522178479Sjb elf_file.ehdr.e_ident[EI_MAG1] = ELFMAG1; 523178479Sjb elf_file.ehdr.e_ident[EI_MAG2] = ELFMAG2; 524178479Sjb elf_file.ehdr.e_ident[EI_MAG3] = ELFMAG3; 525178479Sjb elf_file.ehdr.e_ident[EI_VERSION] = EV_CURRENT; 526178479Sjb elf_file.ehdr.e_ident[EI_CLASS] = ELFCLASS32; 527178573Sjb#if BYTE_ORDER == _BIG_ENDIAN 528178479Sjb elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2MSB; 529178573Sjb#else 530178479Sjb elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2LSB; 531178479Sjb#endif 532178573Sjb#if defined(__FreeBSD__) 533178573Sjb elf_file.ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD; 534178573Sjb#endif 535178479Sjb elf_file.ehdr.e_type = ET_REL; 536178573Sjb#if defined(__arm__) 537178573Sjb elf_file.ehdr.e_machine = EM_ARM; 538178573Sjb#elif defined(__ia64__) 539178573Sjb elf_file.ehdr.e_machine = EM_IA_64; 540178573Sjb#elif defined(__mips__) 541178573Sjb elf_file.ehdr.e_machine = EM_MIPS; 542178573Sjb#elif defined(__powerpc__) 543178573Sjb elf_file.ehdr.e_machine = EM_PPC; 544178573Sjb#elif defined(__sparc) 545178479Sjb elf_file.ehdr.e_machine = EM_SPARC; 546178479Sjb#elif defined(__i386) || defined(__amd64) 547178479Sjb elf_file.ehdr.e_machine = EM_386; 548178479Sjb#endif 549178479Sjb elf_file.ehdr.e_version = EV_CURRENT; 550178479Sjb elf_file.ehdr.e_shoff = sizeof (Elf32_Ehdr); 551178479Sjb elf_file.ehdr.e_ehsize = sizeof (Elf32_Ehdr); 552178479Sjb elf_file.ehdr.e_phentsize = sizeof (Elf32_Phdr); 553178479Sjb elf_file.ehdr.e_shentsize = sizeof (Elf32_Shdr); 554178479Sjb elf_file.ehdr.e_shnum = nshdr; 555178479Sjb elf_file.ehdr.e_shstrndx = ESHDR_SHSTRTAB; 556178479Sjb off = sizeof (elf_file) + nshdr * sizeof (Elf32_Shdr); 557178479Sjb 558178479Sjb shp = &elf_file.shdr[ESHDR_SHSTRTAB]; 559178479Sjb shp->sh_name = 1; /* DTRACE_SHSTRTAB32[1] = ".shstrtab" */ 560178479Sjb shp->sh_type = SHT_STRTAB; 561178479Sjb shp->sh_offset = off; 562178479Sjb shp->sh_size = sizeof (DTRACE_SHSTRTAB32); 563178479Sjb shp->sh_addralign = sizeof (char); 564178479Sjb off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8); 565178479Sjb 566178479Sjb shp = &elf_file.shdr[ESHDR_DOF]; 567178479Sjb shp->sh_name = 11; /* DTRACE_SHSTRTAB32[11] = ".SUNW_dof" */ 568178479Sjb shp->sh_flags = SHF_ALLOC; 569178479Sjb shp->sh_type = SHT_SUNW_dof; 570178479Sjb shp->sh_offset = off; 571178479Sjb shp->sh_size = dof->dofh_filesz; 572178479Sjb shp->sh_addralign = 8; 573178479Sjb off = shp->sh_offset + shp->sh_size; 574178479Sjb 575178479Sjb shp = &elf_file.shdr[ESHDR_STRTAB]; 576178479Sjb shp->sh_name = 21; /* DTRACE_SHSTRTAB32[21] = ".strtab" */ 577178479Sjb shp->sh_flags = SHF_ALLOC; 578178479Sjb shp->sh_type = SHT_STRTAB; 579178479Sjb shp->sh_offset = off; 580178479Sjb shp->sh_size = de.de_strlen; 581178479Sjb shp->sh_addralign = sizeof (char); 582178479Sjb off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 4); 583178479Sjb 584178479Sjb shp = &elf_file.shdr[ESHDR_SYMTAB]; 585178479Sjb shp->sh_name = 29; /* DTRACE_SHSTRTAB32[29] = ".symtab" */ 586178479Sjb shp->sh_flags = SHF_ALLOC; 587178479Sjb shp->sh_type = SHT_SYMTAB; 588178479Sjb shp->sh_entsize = sizeof (Elf32_Sym); 589178479Sjb shp->sh_link = ESHDR_STRTAB; 590178479Sjb shp->sh_offset = off; 591178479Sjb shp->sh_info = de.de_global; 592178479Sjb shp->sh_size = de.de_nsym * sizeof (Elf32_Sym); 593178479Sjb shp->sh_addralign = 4; 594178479Sjb off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 4); 595178479Sjb 596178479Sjb if (de.de_nrel == 0) { 597178479Sjb if (dt_write(dtp, fd, &elf_file, 598178479Sjb sizeof (elf_file)) != sizeof (elf_file) || 599178479Sjb PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB32) || 600178479Sjb PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || 601178479Sjb PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || 602178479Sjb PWRITE_SCN(ESHDR_DOF, dof)) { 603178479Sjb ret = dt_set_errno(dtp, errno); 604178479Sjb } 605178479Sjb } else { 606178479Sjb shp = &elf_file.shdr[ESHDR_REL]; 607178479Sjb shp->sh_name = 37; /* DTRACE_SHSTRTAB32[37] = ".rel.SUNW_dof" */ 608178479Sjb shp->sh_flags = SHF_ALLOC; 609178479Sjb#ifdef __sparc 610178479Sjb shp->sh_type = SHT_RELA; 611178479Sjb#else 612178479Sjb shp->sh_type = SHT_REL; 613178479Sjb#endif 614178479Sjb shp->sh_entsize = sizeof (de.de_rel[0]); 615178479Sjb shp->sh_link = ESHDR_SYMTAB; 616178479Sjb shp->sh_info = ESHDR_DOF; 617178479Sjb shp->sh_offset = off; 618178479Sjb shp->sh_size = de.de_nrel * sizeof (de.de_rel[0]); 619178479Sjb shp->sh_addralign = 4; 620178479Sjb 621178479Sjb if (dt_write(dtp, fd, &elf_file, 622178479Sjb sizeof (elf_file)) != sizeof (elf_file) || 623178479Sjb PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB32) || 624178479Sjb PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || 625178479Sjb PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || 626178479Sjb PWRITE_SCN(ESHDR_REL, de.de_rel) || 627178479Sjb PWRITE_SCN(ESHDR_DOF, dof)) { 628178479Sjb ret = dt_set_errno(dtp, errno); 629178479Sjb } 630178479Sjb } 631178479Sjb 632178479Sjb free(de.de_strtab); 633178479Sjb free(de.de_sym); 634178479Sjb free(de.de_rel); 635178479Sjb 636178479Sjb return (ret); 637178479Sjb} 638178479Sjb 639178479Sjb/* 640178479Sjb * Write out an ELF64 file prologue consisting of a header, section headers, 641178479Sjb * and a section header string table. The DOF data will follow this prologue 642178479Sjb * and complete the contents of the given ELF file. 643178479Sjb */ 644178479Sjbstatic int 645178479Sjbdump_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, int fd) 646178479Sjb{ 647178479Sjb struct { 648178479Sjb Elf64_Ehdr ehdr; 649178479Sjb Elf64_Shdr shdr[ESHDR_NUM]; 650178479Sjb } elf_file; 651178479Sjb 652178479Sjb Elf64_Shdr *shp; 653178479Sjb Elf64_Off off; 654178479Sjb dof_elf64_t de; 655178479Sjb int ret = 0; 656178479Sjb uint_t nshdr; 657178479Sjb 658178479Sjb if (prepare_elf64(dtp, dof, &de) != 0) 659178479Sjb return (-1); /* errno is set for us */ 660178479Sjb 661178479Sjb /* 662178479Sjb * If there are no relocations, we only need enough sections for 663178479Sjb * the shstrtab and the DOF. 664178479Sjb */ 665178479Sjb nshdr = de.de_nrel == 0 ? ESHDR_SYMTAB + 1 : ESHDR_NUM; 666178479Sjb 667178479Sjb bzero(&elf_file, sizeof (elf_file)); 668178479Sjb 669178479Sjb elf_file.ehdr.e_ident[EI_MAG0] = ELFMAG0; 670178479Sjb elf_file.ehdr.e_ident[EI_MAG1] = ELFMAG1; 671178479Sjb elf_file.ehdr.e_ident[EI_MAG2] = ELFMAG2; 672178479Sjb elf_file.ehdr.e_ident[EI_MAG3] = ELFMAG3; 673178479Sjb elf_file.ehdr.e_ident[EI_VERSION] = EV_CURRENT; 674178479Sjb elf_file.ehdr.e_ident[EI_CLASS] = ELFCLASS64; 675178573Sjb#if BYTE_ORDER == _BIG_ENDIAN 676178479Sjb elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2MSB; 677178573Sjb#else 678178479Sjb elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2LSB; 679178479Sjb#endif 680178573Sjb#if defined(__FreeBSD__) 681178573Sjb elf_file.ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD; 682178573Sjb#endif 683178479Sjb elf_file.ehdr.e_type = ET_REL; 684178573Sjb#if defined(__arm__) 685178573Sjb elf_file.ehdr.e_machine = EM_ARM; 686178573Sjb#elif defined(__ia64__) 687178573Sjb elf_file.ehdr.e_machine = EM_IA_64; 688178573Sjb#elif defined(__mips__) 689178573Sjb elf_file.ehdr.e_machine = EM_MIPS; 690178573Sjb#elif defined(__powerpc__) 691178573Sjb elf_file.ehdr.e_machine = EM_PPC; 692178573Sjb#elif defined(__sparc) 693178479Sjb elf_file.ehdr.e_machine = EM_SPARCV9; 694178479Sjb#elif defined(__i386) || defined(__amd64) 695178479Sjb elf_file.ehdr.e_machine = EM_AMD64; 696178479Sjb#endif 697178479Sjb elf_file.ehdr.e_version = EV_CURRENT; 698178479Sjb elf_file.ehdr.e_shoff = sizeof (Elf64_Ehdr); 699178479Sjb elf_file.ehdr.e_ehsize = sizeof (Elf64_Ehdr); 700178479Sjb elf_file.ehdr.e_phentsize = sizeof (Elf64_Phdr); 701178479Sjb elf_file.ehdr.e_shentsize = sizeof (Elf64_Shdr); 702178479Sjb elf_file.ehdr.e_shnum = nshdr; 703178479Sjb elf_file.ehdr.e_shstrndx = ESHDR_SHSTRTAB; 704178479Sjb off = sizeof (elf_file) + nshdr * sizeof (Elf64_Shdr); 705178479Sjb 706178479Sjb shp = &elf_file.shdr[ESHDR_SHSTRTAB]; 707178479Sjb shp->sh_name = 1; /* DTRACE_SHSTRTAB64[1] = ".shstrtab" */ 708178479Sjb shp->sh_type = SHT_STRTAB; 709178479Sjb shp->sh_offset = off; 710178479Sjb shp->sh_size = sizeof (DTRACE_SHSTRTAB64); 711178479Sjb shp->sh_addralign = sizeof (char); 712178479Sjb off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8); 713178479Sjb 714178479Sjb shp = &elf_file.shdr[ESHDR_DOF]; 715178479Sjb shp->sh_name = 11; /* DTRACE_SHSTRTAB64[11] = ".SUNW_dof" */ 716178479Sjb shp->sh_flags = SHF_ALLOC; 717178479Sjb shp->sh_type = SHT_SUNW_dof; 718178479Sjb shp->sh_offset = off; 719178479Sjb shp->sh_size = dof->dofh_filesz; 720178479Sjb shp->sh_addralign = 8; 721178479Sjb off = shp->sh_offset + shp->sh_size; 722178479Sjb 723178479Sjb shp = &elf_file.shdr[ESHDR_STRTAB]; 724178479Sjb shp->sh_name = 21; /* DTRACE_SHSTRTAB64[21] = ".strtab" */ 725178479Sjb shp->sh_flags = SHF_ALLOC; 726178479Sjb shp->sh_type = SHT_STRTAB; 727178479Sjb shp->sh_offset = off; 728178479Sjb shp->sh_size = de.de_strlen; 729178479Sjb shp->sh_addralign = sizeof (char); 730178479Sjb off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8); 731178479Sjb 732178479Sjb shp = &elf_file.shdr[ESHDR_SYMTAB]; 733178479Sjb shp->sh_name = 29; /* DTRACE_SHSTRTAB64[29] = ".symtab" */ 734178479Sjb shp->sh_flags = SHF_ALLOC; 735178479Sjb shp->sh_type = SHT_SYMTAB; 736178479Sjb shp->sh_entsize = sizeof (Elf64_Sym); 737178479Sjb shp->sh_link = ESHDR_STRTAB; 738178479Sjb shp->sh_offset = off; 739178479Sjb shp->sh_info = de.de_global; 740178479Sjb shp->sh_size = de.de_nsym * sizeof (Elf64_Sym); 741178479Sjb shp->sh_addralign = 8; 742178479Sjb off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8); 743178479Sjb 744178479Sjb if (de.de_nrel == 0) { 745178479Sjb if (dt_write(dtp, fd, &elf_file, 746178479Sjb sizeof (elf_file)) != sizeof (elf_file) || 747178479Sjb PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB64) || 748178479Sjb PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || 749178479Sjb PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || 750178479Sjb PWRITE_SCN(ESHDR_DOF, dof)) { 751178479Sjb ret = dt_set_errno(dtp, errno); 752178479Sjb } 753178479Sjb } else { 754178479Sjb shp = &elf_file.shdr[ESHDR_REL]; 755178479Sjb shp->sh_name = 37; /* DTRACE_SHSTRTAB64[37] = ".rel.SUNW_dof" */ 756178479Sjb shp->sh_flags = SHF_ALLOC; 757178479Sjb shp->sh_type = SHT_RELA; 758178479Sjb shp->sh_entsize = sizeof (de.de_rel[0]); 759178479Sjb shp->sh_link = ESHDR_SYMTAB; 760178479Sjb shp->sh_info = ESHDR_DOF; 761178479Sjb shp->sh_offset = off; 762178479Sjb shp->sh_size = de.de_nrel * sizeof (de.de_rel[0]); 763178479Sjb shp->sh_addralign = 8; 764178479Sjb 765178479Sjb if (dt_write(dtp, fd, &elf_file, 766178479Sjb sizeof (elf_file)) != sizeof (elf_file) || 767178479Sjb PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB64) || 768178479Sjb PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || 769178479Sjb PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || 770178479Sjb PWRITE_SCN(ESHDR_REL, de.de_rel) || 771178479Sjb PWRITE_SCN(ESHDR_DOF, dof)) { 772178479Sjb ret = dt_set_errno(dtp, errno); 773178479Sjb } 774178479Sjb } 775178479Sjb 776178479Sjb free(de.de_strtab); 777178479Sjb free(de.de_sym); 778178479Sjb free(de.de_rel); 779178479Sjb 780178479Sjb return (ret); 781178479Sjb} 782178479Sjb 783178479Sjbstatic int 784178479Sjbdt_symtab_lookup(Elf_Data *data_sym, int nsym, uintptr_t addr, uint_t shn, 785178479Sjb GElf_Sym *sym) 786178479Sjb{ 787178479Sjb int i, ret = -1; 788178479Sjb GElf_Sym s; 789178479Sjb 790178479Sjb for (i = 0; i < nsym && gelf_getsym(data_sym, i, sym) != NULL; i++) { 791178479Sjb if (GELF_ST_TYPE(sym->st_info) == STT_FUNC && 792178479Sjb shn == sym->st_shndx && 793178479Sjb sym->st_value <= addr && 794178479Sjb addr < sym->st_value + sym->st_size) { 795178479Sjb if (GELF_ST_BIND(sym->st_info) == STB_GLOBAL) 796178479Sjb return (0); 797178479Sjb 798178479Sjb ret = 0; 799178479Sjb s = *sym; 800178479Sjb } 801178479Sjb } 802178479Sjb 803178479Sjb if (ret == 0) 804178479Sjb *sym = s; 805178479Sjb return (ret); 806178479Sjb} 807178479Sjb 808178573Sjb#if defined(__arm__) 809178573Sjb/* XXX */ 810178573Sjbstatic int 811178573Sjbdt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, 812178573Sjb uint32_t *off) 813178573Sjb{ 814178573Sjbprintf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__); 815178573Sjb return (0); 816178573Sjb} 817178573Sjb#elif defined(__ia64__) 818178573Sjb/* XXX */ 819178573Sjbstatic int 820178573Sjbdt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, 821178573Sjb uint32_t *off) 822178573Sjb{ 823178573Sjbprintf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__); 824178573Sjb return (0); 825178573Sjb} 826178573Sjb#elif defined(__mips__) 827178573Sjb/* XXX */ 828178573Sjbstatic int 829178573Sjbdt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, 830178573Sjb uint32_t *off) 831178573Sjb{ 832178573Sjbprintf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__); 833178573Sjb return (0); 834178573Sjb} 835178573Sjb#elif defined(__powerpc__) 836260670Sjhibbits/* The sentinel is 'xor r3,r3,r3'. */ 837260670Sjhibbits#define DT_OP_XOR_R3 0x7c631a78 838260670Sjhibbits 839260670Sjhibbits#define DT_OP_NOP 0x60000000 840260670Sjhibbits#define DT_OP_BLR 0x4e800020 841260670Sjhibbits 842260670Sjhibbits/* This captures all forms of branching to address. */ 843260670Sjhibbits#define DT_IS_BRANCH(inst) ((inst & 0xfc000000) == 0x48000000) 844260670Sjhibbits#define DT_IS_BL(inst) (DT_IS_BRANCH(inst) && (inst & 0x01)) 845260670Sjhibbits 846178573Sjb/* XXX */ 847178573Sjbstatic int 848178573Sjbdt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, 849178573Sjb uint32_t *off) 850178573Sjb{ 851260670Sjhibbits uint32_t *ip; 852260670Sjhibbits 853260670Sjhibbits if ((rela->r_offset & (sizeof (uint32_t) - 1)) != 0) 854260670Sjhibbits return (-1); 855260670Sjhibbits 856260670Sjhibbits /*LINTED*/ 857260670Sjhibbits ip = (uint32_t *)(p + rela->r_offset); 858260670Sjhibbits 859260670Sjhibbits /* 860260670Sjhibbits * We only know about some specific relocation types. 861260670Sjhibbits */ 862260670Sjhibbits if (GELF_R_TYPE(rela->r_info) != R_PPC_REL24 && 863260670Sjhibbits GELF_R_TYPE(rela->r_info) != R_PPC_PLTREL24) 864260670Sjhibbits return (-1); 865260670Sjhibbits 866260670Sjhibbits /* 867260670Sjhibbits * We may have already processed this object file in an earlier linker 868260670Sjhibbits * invocation. Check to see if the present instruction sequence matches 869260670Sjhibbits * the one we would install below. 870260670Sjhibbits */ 871260670Sjhibbits if (isenabled) { 872260670Sjhibbits if (ip[0] == DT_OP_XOR_R3) { 873260670Sjhibbits (*off) += sizeof (ip[0]); 874260670Sjhibbits return (0); 875260670Sjhibbits } 876260670Sjhibbits } else { 877260670Sjhibbits if (ip[0] == DT_OP_NOP) { 878260670Sjhibbits (*off) += sizeof (ip[0]); 879260670Sjhibbits return (0); 880260670Sjhibbits } 881260670Sjhibbits } 882260670Sjhibbits 883260670Sjhibbits /* 884260670Sjhibbits * We only expect branch to address instructions. 885260670Sjhibbits */ 886260670Sjhibbits if (!DT_IS_BRANCH(ip[0])) { 887260670Sjhibbits dt_dprintf("found %x instead of a branch instruction at %llx\n", 888260670Sjhibbits ip[0], (u_longlong_t)rela->r_offset); 889260670Sjhibbits return (-1); 890260670Sjhibbits } 891260670Sjhibbits 892260670Sjhibbits if (isenabled) { 893260670Sjhibbits /* 894260670Sjhibbits * It would necessarily indicate incorrect usage if an is- 895260670Sjhibbits * enabled probe were tail-called so flag that as an error. 896260670Sjhibbits * It's also potentially (very) tricky to handle gracefully, 897260670Sjhibbits * but could be done if this were a desired use scenario. 898260670Sjhibbits */ 899260670Sjhibbits if (!DT_IS_BL(ip[0])) { 900260670Sjhibbits dt_dprintf("tail call to is-enabled probe at %llx\n", 901260670Sjhibbits (u_longlong_t)rela->r_offset); 902260670Sjhibbits return (-1); 903260670Sjhibbits } 904260670Sjhibbits 905260670Sjhibbits ip[0] = DT_OP_XOR_R3; 906260670Sjhibbits (*off) += sizeof (ip[0]); 907260670Sjhibbits } else { 908260670Sjhibbits if (DT_IS_BL(ip[0])) 909260670Sjhibbits ip[0] = DT_OP_NOP; 910260670Sjhibbits else 911260670Sjhibbits ip[0] = DT_OP_BLR; 912260670Sjhibbits } 913260670Sjhibbits 914178573Sjb return (0); 915178573Sjb} 916178479Sjb 917178573Sjb#elif defined(__sparc) 918178573Sjb 919178479Sjb#define DT_OP_RET 0x81c7e008 920178479Sjb#define DT_OP_NOP 0x01000000 921178479Sjb#define DT_OP_CALL 0x40000000 922178479Sjb#define DT_OP_CLR_O0 0x90102000 923178479Sjb 924178479Sjb#define DT_IS_MOV_O7(inst) (((inst) & 0xffffe000) == 0x9e100000) 925178479Sjb#define DT_IS_RESTORE(inst) (((inst) & 0xc1f80000) == 0x81e80000) 926178479Sjb#define DT_IS_RETL(inst) (((inst) & 0xfff83fff) == 0x81c02008) 927178479Sjb 928178479Sjb#define DT_RS2(inst) ((inst) & 0x1f) 929178479Sjb#define DT_MAKE_RETL(reg) (0x81c02008 | ((reg) << 14)) 930178479Sjb 931178479Sjb/*ARGSUSED*/ 932178479Sjbstatic int 933178479Sjbdt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, 934178479Sjb uint32_t *off) 935178479Sjb{ 936178479Sjb uint32_t *ip; 937178479Sjb 938178479Sjb if ((rela->r_offset & (sizeof (uint32_t) - 1)) != 0) 939178479Sjb return (-1); 940178479Sjb 941178479Sjb /*LINTED*/ 942178479Sjb ip = (uint32_t *)(p + rela->r_offset); 943178479Sjb 944178479Sjb /* 945178479Sjb * We only know about some specific relocation types. 946178479Sjb */ 947178479Sjb if (GELF_R_TYPE(rela->r_info) != R_SPARC_WDISP30 && 948178479Sjb GELF_R_TYPE(rela->r_info) != R_SPARC_WPLT30) 949178479Sjb return (-1); 950178479Sjb 951178479Sjb /* 952178479Sjb * We may have already processed this object file in an earlier linker 953178479Sjb * invocation. Check to see if the present instruction sequence matches 954184696Srodrigc * the one we would install below. 955178479Sjb */ 956178479Sjb if (isenabled) { 957184696Srodrigc if (ip[0] == DT_OP_NOP) { 958184696Srodrigc (*off) += sizeof (ip[0]); 959178479Sjb return (0); 960184696Srodrigc } 961178479Sjb } else { 962178479Sjb if (DT_IS_RESTORE(ip[1])) { 963184696Srodrigc if (ip[0] == DT_OP_RET) { 964184696Srodrigc (*off) += sizeof (ip[0]); 965178479Sjb return (0); 966184696Srodrigc } 967178479Sjb } else if (DT_IS_MOV_O7(ip[1])) { 968178479Sjb if (DT_IS_RETL(ip[0])) 969178479Sjb return (0); 970178479Sjb } else { 971178479Sjb if (ip[0] == DT_OP_NOP) { 972178479Sjb (*off) += sizeof (ip[0]); 973178479Sjb return (0); 974178479Sjb } 975178479Sjb } 976178479Sjb } 977178479Sjb 978178479Sjb /* 979178479Sjb * We only expect call instructions with a displacement of 0. 980178479Sjb */ 981178479Sjb if (ip[0] != DT_OP_CALL) { 982178479Sjb dt_dprintf("found %x instead of a call instruction at %llx\n", 983178479Sjb ip[0], (u_longlong_t)rela->r_offset); 984178479Sjb return (-1); 985178479Sjb } 986178479Sjb 987178479Sjb if (isenabled) { 988178479Sjb /* 989178479Sjb * It would necessarily indicate incorrect usage if an is- 990178479Sjb * enabled probe were tail-called so flag that as an error. 991178479Sjb * It's also potentially (very) tricky to handle gracefully, 992178479Sjb * but could be done if this were a desired use scenario. 993178479Sjb */ 994178479Sjb if (DT_IS_RESTORE(ip[1]) || DT_IS_MOV_O7(ip[1])) { 995178479Sjb dt_dprintf("tail call to is-enabled probe at %llx\n", 996178479Sjb (u_longlong_t)rela->r_offset); 997178479Sjb return (-1); 998178479Sjb } 999178479Sjb 1000184696Srodrigc 1001184696Srodrigc /* 1002184696Srodrigc * On SPARC, we take advantage of the fact that the first 1003184696Srodrigc * argument shares the same register as for the return value. 1004184696Srodrigc * The macro handles the work of zeroing that register so we 1005184696Srodrigc * don't need to do anything special here. We instrument the 1006184696Srodrigc * instruction in the delay slot as we'll need to modify the 1007184696Srodrigc * return register after that instruction has been emulated. 1008184696Srodrigc */ 1009184696Srodrigc ip[0] = DT_OP_NOP; 1010184696Srodrigc (*off) += sizeof (ip[0]); 1011178479Sjb } else { 1012178479Sjb /* 1013178479Sjb * If the call is followed by a restore, it's a tail call so 1014178479Sjb * change the call to a ret. If the call if followed by a mov 1015178479Sjb * of a register into %o7, it's a tail call in leaf context 1016178479Sjb * so change the call to a retl-like instruction that returns 1017178479Sjb * to that register value + 8 (rather than the typical %o7 + 1018178479Sjb * 8); the delay slot instruction is left, but should have no 1019184696Srodrigc * effect. Otherwise we change the call to be a nop. We 1020184696Srodrigc * identify the subsequent instruction as the probe point in 1021184696Srodrigc * all but the leaf tail-call case to ensure that arguments to 1022184696Srodrigc * the probe are complete and consistent. An astute, though 1023184696Srodrigc * largely hypothetical, observer would note that there is the 1024184696Srodrigc * possibility of a false-positive probe firing if the function 1025184696Srodrigc * contained a branch to the instruction in the delay slot of 1026184696Srodrigc * the call. Fixing this would require significant in-kernel 1027184696Srodrigc * modifications, and isn't worth doing until we see it in the 1028184696Srodrigc * wild. 1029178479Sjb */ 1030178479Sjb if (DT_IS_RESTORE(ip[1])) { 1031178479Sjb ip[0] = DT_OP_RET; 1032178479Sjb (*off) += sizeof (ip[0]); 1033178479Sjb } else if (DT_IS_MOV_O7(ip[1])) { 1034178479Sjb ip[0] = DT_MAKE_RETL(DT_RS2(ip[1])); 1035178479Sjb } else { 1036178479Sjb ip[0] = DT_OP_NOP; 1037178479Sjb (*off) += sizeof (ip[0]); 1038178479Sjb } 1039178479Sjb } 1040178479Sjb 1041178479Sjb return (0); 1042178479Sjb} 1043178479Sjb 1044178479Sjb#elif defined(__i386) || defined(__amd64) 1045178479Sjb 1046178479Sjb#define DT_OP_NOP 0x90 1047178573Sjb#define DT_OP_RET 0xc3 1048178479Sjb#define DT_OP_CALL 0xe8 1049178573Sjb#define DT_OP_JMP32 0xe9 1050178479Sjb#define DT_OP_REX_RAX 0x48 1051178479Sjb#define DT_OP_XOR_EAX_0 0x33 1052178479Sjb#define DT_OP_XOR_EAX_1 0xc0 1053178479Sjb 1054178479Sjbstatic int 1055178479Sjbdt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, 1056178479Sjb uint32_t *off) 1057178479Sjb{ 1058178479Sjb uint8_t *ip = (uint8_t *)(p + rela->r_offset - 1); 1059178573Sjb uint8_t ret; 1060178479Sjb 1061178479Sjb /* 1062178479Sjb * On x86, the first byte of the instruction is the call opcode and 1063178479Sjb * the next four bytes are the 32-bit address; the relocation is for 1064178479Sjb * the address operand. We back up the offset to the first byte of 1065178479Sjb * the instruction. For is-enabled probes, we later advance the offset 1066178479Sjb * so that it hits the first nop in the instruction sequence. 1067178479Sjb */ 1068178479Sjb (*off) -= 1; 1069178479Sjb 1070178479Sjb /* 1071178479Sjb * We only know about some specific relocation types. Luckily 1072178479Sjb * these types have the same values on both 32-bit and 64-bit 1073178479Sjb * x86 architectures. 1074178479Sjb */ 1075178479Sjb if (GELF_R_TYPE(rela->r_info) != R_386_PC32 && 1076178479Sjb GELF_R_TYPE(rela->r_info) != R_386_PLT32) 1077178479Sjb return (-1); 1078178479Sjb 1079178479Sjb /* 1080178479Sjb * We may have already processed this object file in an earlier linker 1081178479Sjb * invocation. Check to see if the present instruction sequence matches 1082178479Sjb * the one we would install. For is-enabled probes, we advance the 1083178573Sjb * offset to the first nop instruction in the sequence to match the 1084178573Sjb * text modification code below. 1085178479Sjb */ 1086178479Sjb if (!isenabled) { 1087178573Sjb if ((ip[0] == DT_OP_NOP || ip[0] == DT_OP_RET) && 1088178573Sjb ip[1] == DT_OP_NOP && ip[2] == DT_OP_NOP && 1089178573Sjb ip[3] == DT_OP_NOP && ip[4] == DT_OP_NOP) 1090178479Sjb return (0); 1091178479Sjb } else if (dtp->dt_oflags & DTRACE_O_LP64) { 1092178479Sjb if (ip[0] == DT_OP_REX_RAX && 1093178479Sjb ip[1] == DT_OP_XOR_EAX_0 && ip[2] == DT_OP_XOR_EAX_1 && 1094178573Sjb (ip[3] == DT_OP_NOP || ip[3] == DT_OP_RET) && 1095178573Sjb ip[4] == DT_OP_NOP) { 1096178479Sjb (*off) += 3; 1097178479Sjb return (0); 1098178479Sjb } 1099178479Sjb } else { 1100178479Sjb if (ip[0] == DT_OP_XOR_EAX_0 && ip[1] == DT_OP_XOR_EAX_1 && 1101178573Sjb (ip[2] == DT_OP_NOP || ip[2] == DT_OP_RET) && 1102178573Sjb ip[3] == DT_OP_NOP && ip[4] == DT_OP_NOP) { 1103178479Sjb (*off) += 2; 1104178479Sjb return (0); 1105178479Sjb } 1106178479Sjb } 1107178479Sjb 1108178479Sjb /* 1109178573Sjb * We expect either a call instrution with a 32-bit displacement or a 1110178573Sjb * jmp instruction with a 32-bit displacement acting as a tail-call. 1111178479Sjb */ 1112178573Sjb if (ip[0] != DT_OP_CALL && ip[0] != DT_OP_JMP32) { 1113178573Sjb dt_dprintf("found %x instead of a call or jmp instruction at " 1114178573Sjb "%llx\n", ip[0], (u_longlong_t)rela->r_offset); 1115178479Sjb return (-1); 1116178479Sjb } 1117178479Sjb 1118178573Sjb ret = (ip[0] == DT_OP_JMP32) ? DT_OP_RET : DT_OP_NOP; 1119178573Sjb 1120178479Sjb /* 1121178479Sjb * Establish the instruction sequence -- all nops for probes, and an 1122178479Sjb * instruction to clear the return value register (%eax/%rax) followed 1123178479Sjb * by nops for is-enabled probes. For is-enabled probes, we advance 1124178479Sjb * the offset to the first nop. This isn't stricly necessary but makes 1125178479Sjb * for more readable disassembly when the probe is enabled. 1126178479Sjb */ 1127178479Sjb if (!isenabled) { 1128178573Sjb ip[0] = ret; 1129178479Sjb ip[1] = DT_OP_NOP; 1130178479Sjb ip[2] = DT_OP_NOP; 1131178479Sjb ip[3] = DT_OP_NOP; 1132178479Sjb ip[4] = DT_OP_NOP; 1133178479Sjb } else if (dtp->dt_oflags & DTRACE_O_LP64) { 1134178479Sjb ip[0] = DT_OP_REX_RAX; 1135178479Sjb ip[1] = DT_OP_XOR_EAX_0; 1136178479Sjb ip[2] = DT_OP_XOR_EAX_1; 1137178573Sjb ip[3] = ret; 1138178479Sjb ip[4] = DT_OP_NOP; 1139178479Sjb (*off) += 3; 1140178479Sjb } else { 1141178479Sjb ip[0] = DT_OP_XOR_EAX_0; 1142178479Sjb ip[1] = DT_OP_XOR_EAX_1; 1143178573Sjb ip[2] = ret; 1144178479Sjb ip[3] = DT_OP_NOP; 1145178479Sjb ip[4] = DT_OP_NOP; 1146178479Sjb (*off) += 2; 1147178479Sjb } 1148178479Sjb 1149178479Sjb return (0); 1150178479Sjb} 1151178479Sjb 1152178479Sjb#else 1153178479Sjb#error unknown ISA 1154178479Sjb#endif 1155178479Sjb 1156178479Sjb/*PRINTFLIKE5*/ 1157178479Sjbstatic int 1158178479Sjbdt_link_error(dtrace_hdl_t *dtp, Elf *elf, int fd, dt_link_pair_t *bufs, 1159178479Sjb const char *format, ...) 1160178479Sjb{ 1161178479Sjb va_list ap; 1162178479Sjb dt_link_pair_t *pair; 1163178479Sjb 1164178479Sjb va_start(ap, format); 1165178479Sjb dt_set_errmsg(dtp, NULL, NULL, NULL, 0, format, ap); 1166178479Sjb va_end(ap); 1167178479Sjb 1168178479Sjb if (elf != NULL) 1169178479Sjb (void) elf_end(elf); 1170178479Sjb 1171178479Sjb if (fd >= 0) 1172178479Sjb (void) close(fd); 1173178479Sjb 1174178479Sjb while ((pair = bufs) != NULL) { 1175178479Sjb bufs = pair->dlp_next; 1176178479Sjb dt_free(dtp, pair->dlp_str); 1177178479Sjb dt_free(dtp, pair->dlp_sym); 1178178479Sjb dt_free(dtp, pair); 1179178479Sjb } 1180178479Sjb 1181178479Sjb return (dt_set_errno(dtp, EDT_COMPILER)); 1182178479Sjb} 1183178479Sjb 1184178479Sjbstatic int 1185178479Sjbprocess_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp) 1186178479Sjb{ 1187178479Sjb static const char dt_prefix[] = "__dtrace"; 1188178479Sjb static const char dt_enabled[] = "enabled"; 1189178479Sjb static const char dt_symprefix[] = "$dtrace"; 1190228549Sdim static const char dt_symfmt[] = "%s%ld.%s"; 1191178479Sjb int fd, i, ndx, eprobe, mod = 0; 1192178479Sjb Elf *elf = NULL; 1193178479Sjb GElf_Ehdr ehdr; 1194178479Sjb Elf_Scn *scn_rel, *scn_sym, *scn_str, *scn_tgt; 1195178479Sjb Elf_Data *data_rel, *data_sym, *data_str, *data_tgt; 1196178479Sjb GElf_Shdr shdr_rel, shdr_sym, shdr_str, shdr_tgt; 1197178479Sjb GElf_Sym rsym, fsym, dsym; 1198178479Sjb GElf_Rela rela; 1199178479Sjb char *s, *p, *r; 1200178479Sjb char pname[DTRACE_PROVNAMELEN]; 1201178479Sjb dt_provider_t *pvp; 1202178479Sjb dt_probe_t *prp; 1203178479Sjb uint32_t off, eclass, emachine1, emachine2; 1204178479Sjb size_t symsize, nsym, isym, istr, len; 1205178479Sjb key_t objkey; 1206178479Sjb dt_link_pair_t *pair, *bufs = NULL; 1207178479Sjb dt_strtab_t *strtab; 1208178479Sjb 1209178479Sjb if ((fd = open64(obj, O_RDWR)) == -1) { 1210178479Sjb return (dt_link_error(dtp, elf, fd, bufs, 1211178479Sjb "failed to open %s: %s", obj, strerror(errno))); 1212178479Sjb } 1213178479Sjb 1214178479Sjb if ((elf = elf_begin(fd, ELF_C_RDWR, NULL)) == NULL) { 1215178479Sjb return (dt_link_error(dtp, elf, fd, bufs, 1216178479Sjb "failed to process %s: %s", obj, elf_errmsg(elf_errno()))); 1217178479Sjb } 1218178479Sjb 1219178479Sjb switch (elf_kind(elf)) { 1220178479Sjb case ELF_K_ELF: 1221178479Sjb break; 1222178479Sjb case ELF_K_AR: 1223178479Sjb return (dt_link_error(dtp, elf, fd, bufs, "archives are not " 1224178479Sjb "permitted; use the contents of the archive instead: %s", 1225178479Sjb obj)); 1226178479Sjb default: 1227178479Sjb return (dt_link_error(dtp, elf, fd, bufs, 1228178479Sjb "invalid file type: %s", obj)); 1229178479Sjb } 1230178479Sjb 1231178479Sjb if (gelf_getehdr(elf, &ehdr) == NULL) { 1232178479Sjb return (dt_link_error(dtp, elf, fd, bufs, "corrupt file: %s", 1233178479Sjb obj)); 1234178479Sjb } 1235178479Sjb 1236178479Sjb if (dtp->dt_oflags & DTRACE_O_LP64) { 1237178479Sjb eclass = ELFCLASS64; 1238178573Sjb#if defined(__ia64__) 1239178573Sjb emachine1 = emachine2 = EM_IA_64; 1240178573Sjb#elif defined(__mips__) 1241178573Sjb emachine1 = emachine2 = EM_MIPS; 1242178573Sjb#elif defined(__powerpc__) 1243178573Sjb emachine1 = emachine2 = EM_PPC64; 1244178573Sjb#elif defined(__sparc) 1245178479Sjb emachine1 = emachine2 = EM_SPARCV9; 1246178479Sjb#elif defined(__i386) || defined(__amd64) 1247178479Sjb emachine1 = emachine2 = EM_AMD64; 1248178479Sjb#endif 1249178479Sjb symsize = sizeof (Elf64_Sym); 1250178479Sjb } else { 1251178479Sjb eclass = ELFCLASS32; 1252178573Sjb#if defined(__arm__) 1253178573Sjb emachine1 = emachine2 = EM_ARM; 1254178573Sjb#elif defined(__mips__) 1255178573Sjb emachine1 = emachine2 = EM_MIPS; 1256178573Sjb#elif defined(__powerpc__) 1257178573Sjb emachine1 = emachine2 = EM_PPC; 1258178573Sjb#elif defined(__sparc) 1259178479Sjb emachine1 = EM_SPARC; 1260178479Sjb emachine2 = EM_SPARC32PLUS; 1261178573Sjb#elif defined(__i386) || defined(__amd64) || defined(__ia64__) 1262178479Sjb emachine1 = emachine2 = EM_386; 1263178479Sjb#endif 1264178479Sjb symsize = sizeof (Elf32_Sym); 1265178479Sjb } 1266178479Sjb 1267178479Sjb if (ehdr.e_ident[EI_CLASS] != eclass) { 1268178479Sjb return (dt_link_error(dtp, elf, fd, bufs, 1269178479Sjb "incorrect ELF class for object file: %s", obj)); 1270178479Sjb } 1271178479Sjb 1272178479Sjb if (ehdr.e_machine != emachine1 && ehdr.e_machine != emachine2) { 1273178479Sjb return (dt_link_error(dtp, elf, fd, bufs, 1274178479Sjb "incorrect ELF machine type for object file: %s", obj)); 1275178479Sjb } 1276178479Sjb 1277178479Sjb /* 1278178479Sjb * We use this token as a relatively unique handle for this file on the 1279178479Sjb * system in order to disambiguate potential conflicts between files of 1280178479Sjb * the same name which contain identially named local symbols. 1281178479Sjb */ 1282178479Sjb if ((objkey = ftok(obj, 0)) == (key_t)-1) { 1283178479Sjb return (dt_link_error(dtp, elf, fd, bufs, 1284178479Sjb "failed to generate unique key for object file: %s", obj)); 1285178479Sjb } 1286178479Sjb 1287178479Sjb scn_rel = NULL; 1288178479Sjb while ((scn_rel = elf_nextscn(elf, scn_rel)) != NULL) { 1289178479Sjb if (gelf_getshdr(scn_rel, &shdr_rel) == NULL) 1290178479Sjb goto err; 1291178479Sjb 1292178479Sjb /* 1293178479Sjb * Skip any non-relocation sections. 1294178479Sjb */ 1295178479Sjb if (shdr_rel.sh_type != SHT_RELA && shdr_rel.sh_type != SHT_REL) 1296178479Sjb continue; 1297178479Sjb 1298178479Sjb if ((data_rel = elf_getdata(scn_rel, NULL)) == NULL) 1299178479Sjb goto err; 1300178479Sjb 1301178479Sjb /* 1302178479Sjb * Grab the section, section header and section data for the 1303178479Sjb * symbol table that this relocation section references. 1304178479Sjb */ 1305178479Sjb if ((scn_sym = elf_getscn(elf, shdr_rel.sh_link)) == NULL || 1306178479Sjb gelf_getshdr(scn_sym, &shdr_sym) == NULL || 1307178479Sjb (data_sym = elf_getdata(scn_sym, NULL)) == NULL) 1308178479Sjb goto err; 1309178479Sjb 1310178479Sjb /* 1311178479Sjb * Ditto for that symbol table's string table. 1312178479Sjb */ 1313178479Sjb if ((scn_str = elf_getscn(elf, shdr_sym.sh_link)) == NULL || 1314178479Sjb gelf_getshdr(scn_str, &shdr_str) == NULL || 1315178479Sjb (data_str = elf_getdata(scn_str, NULL)) == NULL) 1316178479Sjb goto err; 1317178479Sjb 1318178479Sjb /* 1319178479Sjb * Grab the section, section header and section data for the 1320178479Sjb * target section for the relocations. For the relocations 1321178479Sjb * we're looking for -- this will typically be the text of the 1322178479Sjb * object file. 1323178479Sjb */ 1324178479Sjb if ((scn_tgt = elf_getscn(elf, shdr_rel.sh_info)) == NULL || 1325178479Sjb gelf_getshdr(scn_tgt, &shdr_tgt) == NULL || 1326178479Sjb (data_tgt = elf_getdata(scn_tgt, NULL)) == NULL) 1327178479Sjb goto err; 1328178479Sjb 1329178479Sjb /* 1330178479Sjb * We're looking for relocations to symbols matching this form: 1331178479Sjb * 1332178479Sjb * __dtrace[enabled]_<prov>___<probe> 1333178479Sjb * 1334178479Sjb * For the generated object, we need to record the location 1335178479Sjb * identified by the relocation, and create a new relocation 1336178479Sjb * in the generated object that will be resolved at link time 1337178479Sjb * to the location of the function in which the probe is 1338178479Sjb * embedded. In the target object, we change the matched symbol 1339178479Sjb * so that it will be ignored at link time, and we modify the 1340178479Sjb * target (text) section to replace the call instruction with 1341178479Sjb * one or more nops. 1342178479Sjb * 1343178479Sjb * If the function containing the probe is locally scoped 1344178479Sjb * (static), we create an alias used by the relocation in the 1345178479Sjb * generated object. The alias, a new symbol, will be global 1346178479Sjb * (so that the relocation from the generated object can be 1347178479Sjb * resolved), and hidden (so that it is converted to a local 1348178479Sjb * symbol at link time). Such aliases have this form: 1349178479Sjb * 1350178479Sjb * $dtrace<key>.<function> 1351178479Sjb * 1352178479Sjb * We take a first pass through all the relocations to 1353178479Sjb * populate our string table and count the number of extra 1354178479Sjb * symbols we'll require. 1355178479Sjb */ 1356178479Sjb strtab = dt_strtab_create(1); 1357178479Sjb nsym = 0; 1358178479Sjb isym = data_sym->d_size / symsize; 1359178479Sjb istr = data_str->d_size; 1360178479Sjb 1361178479Sjb for (i = 0; i < shdr_rel.sh_size / shdr_rel.sh_entsize; i++) { 1362178479Sjb 1363178479Sjb if (shdr_rel.sh_type == SHT_RELA) { 1364178479Sjb if (gelf_getrela(data_rel, i, &rela) == NULL) 1365178479Sjb continue; 1366178479Sjb } else { 1367178479Sjb GElf_Rel rel; 1368178479Sjb if (gelf_getrel(data_rel, i, &rel) == NULL) 1369178479Sjb continue; 1370178479Sjb rela.r_offset = rel.r_offset; 1371178479Sjb rela.r_info = rel.r_info; 1372178479Sjb rela.r_addend = 0; 1373178479Sjb } 1374178479Sjb 1375178479Sjb if (gelf_getsym(data_sym, GELF_R_SYM(rela.r_info), 1376178479Sjb &rsym) == NULL) { 1377178479Sjb dt_strtab_destroy(strtab); 1378178479Sjb goto err; 1379178479Sjb } 1380178479Sjb 1381178479Sjb s = (char *)data_str->d_buf + rsym.st_name; 1382178479Sjb 1383178479Sjb if (strncmp(s, dt_prefix, sizeof (dt_prefix) - 1) != 0) 1384178479Sjb continue; 1385178479Sjb 1386178479Sjb if (dt_symtab_lookup(data_sym, isym, rela.r_offset, 1387178479Sjb shdr_rel.sh_info, &fsym) != 0) { 1388178479Sjb dt_strtab_destroy(strtab); 1389178479Sjb goto err; 1390178479Sjb } 1391178479Sjb 1392178479Sjb if (GELF_ST_BIND(fsym.st_info) != STB_LOCAL) 1393178479Sjb continue; 1394178479Sjb 1395178479Sjb if (fsym.st_name > data_str->d_size) { 1396178479Sjb dt_strtab_destroy(strtab); 1397178479Sjb goto err; 1398178479Sjb } 1399178479Sjb 1400178479Sjb s = (char *)data_str->d_buf + fsym.st_name; 1401178479Sjb 1402178479Sjb /* 1403178479Sjb * If this symbol isn't of type function, we've really 1404178479Sjb * driven off the rails or the object file is corrupt. 1405178479Sjb */ 1406178479Sjb if (GELF_ST_TYPE(fsym.st_info) != STT_FUNC) { 1407178479Sjb dt_strtab_destroy(strtab); 1408178479Sjb return (dt_link_error(dtp, elf, fd, bufs, 1409178479Sjb "expected %s to be of type function", s)); 1410178479Sjb } 1411178479Sjb 1412178479Sjb len = snprintf(NULL, 0, dt_symfmt, dt_symprefix, 1413178479Sjb objkey, s) + 1; 1414178479Sjb if ((p = dt_alloc(dtp, len)) == NULL) { 1415178479Sjb dt_strtab_destroy(strtab); 1416178479Sjb goto err; 1417178479Sjb } 1418178479Sjb (void) snprintf(p, len, dt_symfmt, dt_symprefix, 1419178479Sjb objkey, s); 1420178479Sjb 1421178479Sjb if (dt_strtab_index(strtab, p) == -1) { 1422178479Sjb nsym++; 1423178479Sjb (void) dt_strtab_insert(strtab, p); 1424178479Sjb } 1425178479Sjb 1426178479Sjb dt_free(dtp, p); 1427178479Sjb } 1428178479Sjb 1429178479Sjb /* 1430178479Sjb * If needed, allocate the additional space for the symbol 1431178479Sjb * table and string table copying the old data into the new 1432178479Sjb * buffers, and marking the buffers as dirty. We inject those 1433178479Sjb * newly allocated buffers into the libelf data structures, but 1434178479Sjb * are still responsible for freeing them once we're done with 1435178479Sjb * the elf handle. 1436178479Sjb */ 1437178479Sjb if (nsym > 0) { 1438178479Sjb /* 1439178479Sjb * The first byte of the string table is reserved for 1440178479Sjb * the \0 entry. 1441178479Sjb */ 1442178479Sjb len = dt_strtab_size(strtab) - 1; 1443178479Sjb 1444178479Sjb assert(len > 0); 1445178479Sjb assert(dt_strtab_index(strtab, "") == 0); 1446178479Sjb 1447178479Sjb dt_strtab_destroy(strtab); 1448178479Sjb 1449178479Sjb if ((pair = dt_alloc(dtp, sizeof (*pair))) == NULL) 1450178479Sjb goto err; 1451178479Sjb 1452178479Sjb if ((pair->dlp_str = dt_alloc(dtp, data_str->d_size + 1453178479Sjb len)) == NULL) { 1454178479Sjb dt_free(dtp, pair); 1455178479Sjb goto err; 1456178479Sjb } 1457178479Sjb 1458178479Sjb if ((pair->dlp_sym = dt_alloc(dtp, data_sym->d_size + 1459178479Sjb nsym * symsize)) == NULL) { 1460178479Sjb dt_free(dtp, pair->dlp_str); 1461178479Sjb dt_free(dtp, pair); 1462178479Sjb goto err; 1463178479Sjb } 1464178479Sjb 1465178479Sjb pair->dlp_next = bufs; 1466178479Sjb bufs = pair; 1467178479Sjb 1468178479Sjb bcopy(data_str->d_buf, pair->dlp_str, data_str->d_size); 1469178479Sjb data_str->d_buf = pair->dlp_str; 1470178479Sjb data_str->d_size += len; 1471178479Sjb (void) elf_flagdata(data_str, ELF_C_SET, ELF_F_DIRTY); 1472178479Sjb 1473178479Sjb shdr_str.sh_size += len; 1474178479Sjb (void) gelf_update_shdr(scn_str, &shdr_str); 1475178479Sjb 1476178479Sjb bcopy(data_sym->d_buf, pair->dlp_sym, data_sym->d_size); 1477178479Sjb data_sym->d_buf = pair->dlp_sym; 1478178479Sjb data_sym->d_size += nsym * symsize; 1479178479Sjb (void) elf_flagdata(data_sym, ELF_C_SET, ELF_F_DIRTY); 1480178479Sjb 1481178479Sjb shdr_sym.sh_size += nsym * symsize; 1482178479Sjb (void) gelf_update_shdr(scn_sym, &shdr_sym); 1483178479Sjb 1484178479Sjb nsym += isym; 1485178479Sjb } else { 1486178479Sjb dt_strtab_destroy(strtab); 1487178479Sjb } 1488178479Sjb 1489178479Sjb /* 1490178479Sjb * Now that the tables have been allocated, perform the 1491178479Sjb * modifications described above. 1492178479Sjb */ 1493178479Sjb for (i = 0; i < shdr_rel.sh_size / shdr_rel.sh_entsize; i++) { 1494178479Sjb 1495178479Sjb if (shdr_rel.sh_type == SHT_RELA) { 1496178479Sjb if (gelf_getrela(data_rel, i, &rela) == NULL) 1497178479Sjb continue; 1498178479Sjb } else { 1499178479Sjb GElf_Rel rel; 1500178479Sjb if (gelf_getrel(data_rel, i, &rel) == NULL) 1501178479Sjb continue; 1502178479Sjb rela.r_offset = rel.r_offset; 1503178479Sjb rela.r_info = rel.r_info; 1504178479Sjb rela.r_addend = 0; 1505178479Sjb } 1506178479Sjb 1507178479Sjb ndx = GELF_R_SYM(rela.r_info); 1508178479Sjb 1509178479Sjb if (gelf_getsym(data_sym, ndx, &rsym) == NULL || 1510178479Sjb rsym.st_name > data_str->d_size) 1511178479Sjb goto err; 1512178479Sjb 1513178479Sjb s = (char *)data_str->d_buf + rsym.st_name; 1514178479Sjb 1515178479Sjb if (strncmp(s, dt_prefix, sizeof (dt_prefix) - 1) != 0) 1516178479Sjb continue; 1517178479Sjb 1518178479Sjb s += sizeof (dt_prefix) - 1; 1519178479Sjb 1520178479Sjb /* 1521178479Sjb * Check to see if this is an 'is-enabled' check as 1522178479Sjb * opposed to a normal probe. 1523178479Sjb */ 1524178479Sjb if (strncmp(s, dt_enabled, 1525178479Sjb sizeof (dt_enabled) - 1) == 0) { 1526178479Sjb s += sizeof (dt_enabled) - 1; 1527178479Sjb eprobe = 1; 1528178479Sjb *eprobesp = 1; 1529178479Sjb dt_dprintf("is-enabled probe\n"); 1530178479Sjb } else { 1531178479Sjb eprobe = 0; 1532178479Sjb dt_dprintf("normal probe\n"); 1533178479Sjb } 1534178479Sjb 1535178479Sjb if (*s++ != '_') 1536178479Sjb goto err; 1537178479Sjb 1538178479Sjb if ((p = strstr(s, "___")) == NULL || 1539178479Sjb p - s >= sizeof (pname)) 1540178479Sjb goto err; 1541178479Sjb 1542178479Sjb bcopy(s, pname, p - s); 1543178479Sjb pname[p - s] = '\0'; 1544178479Sjb 1545178479Sjb p = strhyphenate(p + 3); /* strlen("___") */ 1546178479Sjb 1547178479Sjb if (dt_symtab_lookup(data_sym, isym, rela.r_offset, 1548178479Sjb shdr_rel.sh_info, &fsym) != 0) 1549178479Sjb goto err; 1550178479Sjb 1551178479Sjb if (fsym.st_name > data_str->d_size) 1552178479Sjb goto err; 1553178479Sjb 1554178479Sjb assert(GELF_ST_TYPE(fsym.st_info) == STT_FUNC); 1555178479Sjb 1556178479Sjb /* 1557178479Sjb * If a NULL relocation name is passed to 1558178479Sjb * dt_probe_define(), the function name is used for the 1559178479Sjb * relocation. The relocation needs to use a mangled 1560178479Sjb * name if the symbol is locally scoped; the function 1561178479Sjb * name may need to change if we've found the global 1562178479Sjb * alias for the locally scoped symbol (we prefer 1563178479Sjb * global symbols to locals in dt_symtab_lookup()). 1564178479Sjb */ 1565178479Sjb s = (char *)data_str->d_buf + fsym.st_name; 1566178479Sjb r = NULL; 1567178479Sjb 1568178479Sjb if (GELF_ST_BIND(fsym.st_info) == STB_LOCAL) { 1569178479Sjb dsym = fsym; 1570178479Sjb dsym.st_name = istr; 1571178479Sjb dsym.st_info = GELF_ST_INFO(STB_GLOBAL, 1572178479Sjb STT_FUNC); 1573178479Sjb dsym.st_other = 1574178479Sjb ELF64_ST_VISIBILITY(STV_ELIMINATE); 1575178479Sjb (void) gelf_update_sym(data_sym, isym, &dsym); 1576178479Sjb 1577178479Sjb r = (char *)data_str->d_buf + istr; 1578178479Sjb istr += 1 + sprintf(r, dt_symfmt, 1579178479Sjb dt_symprefix, objkey, s); 1580178479Sjb isym++; 1581178479Sjb assert(isym <= nsym); 1582178479Sjb 1583178479Sjb } else if (strncmp(s, dt_symprefix, 1584178479Sjb strlen(dt_symprefix)) == 0) { 1585178479Sjb r = s; 1586178479Sjb if ((s = strchr(s, '.')) == NULL) 1587178479Sjb goto err; 1588178479Sjb s++; 1589178479Sjb } 1590178479Sjb 1591178479Sjb if ((pvp = dt_provider_lookup(dtp, pname)) == NULL) { 1592178479Sjb return (dt_link_error(dtp, elf, fd, bufs, 1593178479Sjb "no such provider %s", pname)); 1594178479Sjb } 1595178479Sjb 1596178479Sjb if ((prp = dt_probe_lookup(pvp, p)) == NULL) { 1597178479Sjb return (dt_link_error(dtp, elf, fd, bufs, 1598178479Sjb "no such probe %s", p)); 1599178479Sjb } 1600178479Sjb 1601178479Sjb assert(fsym.st_value <= rela.r_offset); 1602178479Sjb 1603178479Sjb off = rela.r_offset - fsym.st_value; 1604178479Sjb if (dt_modtext(dtp, data_tgt->d_buf, eprobe, 1605211554Srpaulo &rela, &off) != 0) 1606178479Sjb goto err; 1607178479Sjb 1608178479Sjb if (dt_probe_define(pvp, prp, s, r, off, eprobe) != 0) { 1609178479Sjb return (dt_link_error(dtp, elf, fd, bufs, 1610178479Sjb "failed to allocate space for probe")); 1611178479Sjb } 1612211554Srpaulo#if !defined(sun) 1613211554Srpaulo /* 1614211554Srpaulo * Our linker doesn't understand the SUNW_IGNORE ndx and 1615211554Srpaulo * will try to use this relocation when we build the 1616211554Srpaulo * final executable. Since we are done processing this 1617211554Srpaulo * relocation, mark it as inexistant and let libelf 1618211554Srpaulo * remove it from the file. 1619211554Srpaulo * If this wasn't done, we would have garbage added to 1620211554Srpaulo * the executable file as the symbol is going to be 1621211554Srpaulo * change from UND to ABS. 1622211554Srpaulo */ 1623262060Smarkj if (shdr_rel.sh_type == SHT_RELA) { 1624262060Smarkj rela.r_offset = 0; 1625262060Smarkj rela.r_info = 0; 1626262060Smarkj rela.r_addend = 0; 1627262060Smarkj (void) gelf_update_rela(data_rel, i, &rela); 1628262060Smarkj } else { 1629262060Smarkj GElf_Rel rel; 1630262060Smarkj rel.r_offset = 0; 1631262060Smarkj rel.r_info = 0; 1632262060Smarkj (void) gelf_update_rel(data_rel, i, &rel); 1633262060Smarkj } 1634211554Srpaulo#endif 1635178479Sjb 1636178479Sjb mod = 1; 1637178479Sjb (void) elf_flagdata(data_tgt, ELF_C_SET, ELF_F_DIRTY); 1638178479Sjb 1639178479Sjb /* 1640178479Sjb * This symbol may already have been marked to 1641178479Sjb * be ignored by another relocation referencing 1642178479Sjb * the same symbol or if this object file has 1643178479Sjb * already been processed by an earlier link 1644178479Sjb * invocation. 1645178479Sjb */ 1646211554Srpaulo#if !defined(sun) 1647211554Srpaulo#define SHN_SUNW_IGNORE SHN_ABS 1648211554Srpaulo#endif 1649178479Sjb if (rsym.st_shndx != SHN_SUNW_IGNORE) { 1650178479Sjb rsym.st_shndx = SHN_SUNW_IGNORE; 1651178479Sjb (void) gelf_update_sym(data_sym, ndx, &rsym); 1652178479Sjb } 1653178479Sjb } 1654178479Sjb } 1655178479Sjb 1656178479Sjb if (mod && elf_update(elf, ELF_C_WRITE) == -1) 1657178479Sjb goto err; 1658178479Sjb 1659178479Sjb (void) elf_end(elf); 1660178479Sjb (void) close(fd); 1661178479Sjb 1662211554Srpaulo#if !defined(sun) 1663211554Srpaulo if (nsym > 0) 1664211554Srpaulo#endif 1665178479Sjb while ((pair = bufs) != NULL) { 1666178479Sjb bufs = pair->dlp_next; 1667178479Sjb dt_free(dtp, pair->dlp_str); 1668178479Sjb dt_free(dtp, pair->dlp_sym); 1669178479Sjb dt_free(dtp, pair); 1670178479Sjb } 1671178479Sjb 1672178479Sjb return (0); 1673178479Sjb 1674178479Sjberr: 1675178479Sjb return (dt_link_error(dtp, elf, fd, bufs, 1676178479Sjb "an error was encountered while processing %s", obj)); 1677178479Sjb} 1678178479Sjb 1679178479Sjbint 1680178479Sjbdtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags, 1681178479Sjb const char *file, int objc, char *const objv[]) 1682178479Sjb{ 1683178573Sjb#if !defined(sun) 1684178573Sjb char tfile[PATH_MAX]; 1685211554Srpaulo Elf *e; 1686211554Srpaulo Elf_Scn *scn; 1687211554Srpaulo Elf_Data *data; 1688211554Srpaulo GElf_Shdr shdr; 1689211554Srpaulo int efd; 1690211554Srpaulo size_t stridx; 1691211554Srpaulo unsigned char *buf; 1692211554Srpaulo char *s; 1693211554Srpaulo int loc; 1694211554Srpaulo GElf_Ehdr ehdr; 1695211554Srpaulo Elf_Scn *scn0; 1696211554Srpaulo GElf_Shdr shdr0; 1697211554Srpaulo uint64_t off, rc; 1698178573Sjb#endif 1699178479Sjb char drti[PATH_MAX]; 1700178479Sjb dof_hdr_t *dof; 1701178479Sjb int fd, status, i, cur; 1702178479Sjb char *cmd, tmp; 1703178479Sjb size_t len; 1704178479Sjb int eprobes = 0, ret = 0; 1705178479Sjb 1706178573Sjb#if !defined(sun) 1707212358Srpaulo if (access(file, R_OK) == 0) { 1708212358Srpaulo fprintf(stderr, "dtrace: target object (%s) already exists. " 1709212358Srpaulo "Please remove the target\ndtrace: object and rebuild all " 1710212358Srpaulo "the source objects if you wish to run the DTrace\n" 1711212358Srpaulo "dtrace: linking process again\n", file); 1712212358Srpaulo /* 1713212358Srpaulo * Several build infrastructures run DTrace twice (e.g. 1714212358Srpaulo * postgres) and we don't want the build to fail. Return 1715212358Srpaulo * 0 here since this isn't really a fatal error. 1716212358Srpaulo */ 1717212358Srpaulo return (0); 1718212358Srpaulo } 1719178573Sjb /* XXX Should get a temp file name here. */ 1720178573Sjb snprintf(tfile, sizeof(tfile), "%s.tmp", file); 1721178573Sjb#endif 1722178573Sjb 1723178479Sjb /* 1724178479Sjb * A NULL program indicates a special use in which we just link 1725178479Sjb * together a bunch of object files specified in objv and then 1726178479Sjb * unlink(2) those object files. 1727178479Sjb */ 1728178479Sjb if (pgp == NULL) { 1729178479Sjb const char *fmt = "%s -o %s -r"; 1730178479Sjb 1731178479Sjb len = snprintf(&tmp, 1, fmt, dtp->dt_ld_path, file) + 1; 1732178479Sjb 1733178479Sjb for (i = 0; i < objc; i++) 1734178479Sjb len += strlen(objv[i]) + 1; 1735178479Sjb 1736178479Sjb cmd = alloca(len); 1737178479Sjb 1738178479Sjb cur = snprintf(cmd, len, fmt, dtp->dt_ld_path, file); 1739178479Sjb 1740178479Sjb for (i = 0; i < objc; i++) 1741178479Sjb cur += snprintf(cmd + cur, len - cur, " %s", objv[i]); 1742178479Sjb 1743178479Sjb if ((status = system(cmd)) == -1) { 1744178479Sjb return (dt_link_error(dtp, NULL, -1, NULL, 1745178479Sjb "failed to run %s: %s", dtp->dt_ld_path, 1746178479Sjb strerror(errno))); 1747178479Sjb } 1748178479Sjb 1749178479Sjb if (WIFSIGNALED(status)) { 1750178479Sjb return (dt_link_error(dtp, NULL, -1, NULL, 1751178479Sjb "failed to link %s: %s failed due to signal %d", 1752178479Sjb file, dtp->dt_ld_path, WTERMSIG(status))); 1753178479Sjb } 1754178479Sjb 1755178479Sjb if (WEXITSTATUS(status) != 0) { 1756178479Sjb return (dt_link_error(dtp, NULL, -1, NULL, 1757178479Sjb "failed to link %s: %s exited with status %d\n", 1758178479Sjb file, dtp->dt_ld_path, WEXITSTATUS(status))); 1759178479Sjb } 1760178479Sjb 1761178479Sjb for (i = 0; i < objc; i++) { 1762178479Sjb if (strcmp(objv[i], file) != 0) 1763178479Sjb (void) unlink(objv[i]); 1764178479Sjb } 1765178479Sjb 1766178479Sjb return (0); 1767178479Sjb } 1768178479Sjb 1769178479Sjb for (i = 0; i < objc; i++) { 1770178479Sjb if (process_obj(dtp, objv[i], &eprobes) != 0) 1771178479Sjb return (-1); /* errno is set for us */ 1772178479Sjb } 1773178479Sjb 1774178479Sjb /* 1775178479Sjb * If there are is-enabled probes then we need to force use of DOF 1776178479Sjb * version 2. 1777178479Sjb */ 1778178479Sjb if (eprobes && pgp->dp_dofversion < DOF_VERSION_2) 1779178479Sjb pgp->dp_dofversion = DOF_VERSION_2; 1780178479Sjb 1781178479Sjb if ((dof = dtrace_dof_create(dtp, pgp, dflags)) == NULL) 1782178479Sjb return (-1); /* errno is set for us */ 1783178479Sjb 1784178573Sjb#if defined(sun) 1785178479Sjb /* 1786178479Sjb * Create a temporary file and then unlink it if we're going to 1787178479Sjb * combine it with drti.o later. We can still refer to it in child 1788178479Sjb * processes as /dev/fd/<fd>. 1789178479Sjb */ 1790178479Sjb if ((fd = open64(file, O_RDWR | O_CREAT | O_TRUNC, 0666)) == -1) { 1791178479Sjb return (dt_link_error(dtp, NULL, -1, NULL, 1792178479Sjb "failed to open %s: %s", file, strerror(errno))); 1793178479Sjb } 1794178573Sjb#else 1795178573Sjb if ((fd = open(tfile, O_RDWR | O_CREAT | O_TRUNC, 0666)) == -1) 1796178573Sjb return (dt_link_error(dtp, NULL, -1, NULL, 1797178573Sjb "failed to open %s: %s", tfile, strerror(errno))); 1798178573Sjb#endif 1799178479Sjb 1800178479Sjb /* 1801178479Sjb * If -xlinktype=DOF has been selected, just write out the DOF. 1802178479Sjb * Otherwise proceed to the default of generating and linking ELF. 1803178479Sjb */ 1804178479Sjb switch (dtp->dt_linktype) { 1805178479Sjb case DT_LTYP_DOF: 1806178479Sjb if (dt_write(dtp, fd, dof, dof->dofh_filesz) < dof->dofh_filesz) 1807178479Sjb ret = errno; 1808178479Sjb 1809178479Sjb if (close(fd) != 0 && ret == 0) 1810178479Sjb ret = errno; 1811178479Sjb 1812178479Sjb if (ret != 0) { 1813178479Sjb return (dt_link_error(dtp, NULL, -1, NULL, 1814178479Sjb "failed to write %s: %s", file, strerror(ret))); 1815178479Sjb } 1816178479Sjb 1817178479Sjb return (0); 1818178479Sjb 1819178479Sjb case DT_LTYP_ELF: 1820178479Sjb break; /* fall through to the rest of dtrace_program_link() */ 1821178479Sjb 1822178479Sjb default: 1823178479Sjb return (dt_link_error(dtp, NULL, -1, NULL, 1824178479Sjb "invalid link type %u\n", dtp->dt_linktype)); 1825178479Sjb } 1826178479Sjb 1827178479Sjb 1828178573Sjb#if defined(sun) 1829178479Sjb if (!dtp->dt_lazyload) 1830178479Sjb (void) unlink(file); 1831178573Sjb#endif 1832178479Sjb 1833211554Srpaulo#if defined(sun) 1834178479Sjb if (dtp->dt_oflags & DTRACE_O_LP64) 1835178479Sjb status = dump_elf64(dtp, dof, fd); 1836178479Sjb else 1837178479Sjb status = dump_elf32(dtp, dof, fd); 1838178479Sjb 1839178479Sjb if (status != 0 || lseek(fd, 0, SEEK_SET) != 0) { 1840211554Srpaulo#else 1841211554Srpaulo /* We don't write the ELF header, just the DOF section */ 1842211554Srpaulo if (dt_write(dtp, fd, dof, dof->dofh_filesz) < dof->dofh_filesz) { 1843211554Srpaulo#endif 1844178479Sjb return (dt_link_error(dtp, NULL, -1, NULL, 1845178479Sjb "failed to write %s: %s", file, strerror(errno))); 1846178479Sjb } 1847178479Sjb 1848178479Sjb if (!dtp->dt_lazyload) { 1849178573Sjb#if defined(sun) 1850178479Sjb const char *fmt = "%s -o %s -r -Blocal -Breduce /dev/fd/%d %s"; 1851178479Sjb 1852178479Sjb if (dtp->dt_oflags & DTRACE_O_LP64) { 1853178479Sjb (void) snprintf(drti, sizeof (drti), 1854178479Sjb "%s/64/drti.o", _dtrace_libdir); 1855178479Sjb } else { 1856178479Sjb (void) snprintf(drti, sizeof (drti), 1857178479Sjb "%s/drti.o", _dtrace_libdir); 1858178479Sjb } 1859178479Sjb 1860178479Sjb len = snprintf(&tmp, 1, fmt, dtp->dt_ld_path, file, fd, 1861178479Sjb drti) + 1; 1862178479Sjb 1863178479Sjb cmd = alloca(len); 1864178479Sjb 1865178479Sjb (void) snprintf(cmd, len, fmt, dtp->dt_ld_path, file, fd, drti); 1866178573Sjb#else 1867211554Srpaulo const char *fmt = "%s -o %s -r %s"; 1868178479Sjb 1869178573Sjb#if defined(__amd64__) 1870178573Sjb /* 1871178573Sjb * Arches which default to 64-bit need to explicitly use 1872178573Sjb * the 32-bit library path. 1873178573Sjb */ 1874269986Smarkj int use_32 = (dtp->dt_oflags & DTRACE_O_ILP32); 1875178573Sjb#else 1876178573Sjb /* 1877178573Sjb * Arches which are 32-bit only just use the normal 1878178573Sjb * library path. 1879178573Sjb */ 1880178573Sjb int use_32 = 0; 1881178573Sjb#endif 1882178573Sjb 1883178573Sjb (void) snprintf(drti, sizeof (drti), "/usr/lib%s/dtrace/drti.o", 1884187347Sjhb use_32 ? "32":""); 1885178573Sjb 1886178573Sjb len = snprintf(&tmp, 1, fmt, dtp->dt_ld_path, file, tfile, 1887178573Sjb drti) + 1; 1888178573Sjb 1889211554Srpaulo len *= 2; 1890178573Sjb cmd = alloca(len); 1891178573Sjb 1892211554Srpaulo (void) snprintf(cmd, len, fmt, dtp->dt_ld_path, file, 1893211554Srpaulo drti); 1894178573Sjb#endif 1895178479Sjb if ((status = system(cmd)) == -1) { 1896178479Sjb ret = dt_link_error(dtp, NULL, -1, NULL, 1897178479Sjb "failed to run %s: %s", dtp->dt_ld_path, 1898178479Sjb strerror(errno)); 1899178479Sjb goto done; 1900178479Sjb } 1901178479Sjb 1902178479Sjb if (WIFSIGNALED(status)) { 1903178479Sjb ret = dt_link_error(dtp, NULL, -1, NULL, 1904178479Sjb "failed to link %s: %s failed due to signal %d", 1905178479Sjb file, dtp->dt_ld_path, WTERMSIG(status)); 1906178479Sjb goto done; 1907178479Sjb } 1908178479Sjb 1909178479Sjb if (WEXITSTATUS(status) != 0) { 1910178479Sjb ret = dt_link_error(dtp, NULL, -1, NULL, 1911178479Sjb "failed to link %s: %s exited with status %d\n", 1912178479Sjb file, dtp->dt_ld_path, WEXITSTATUS(status)); 1913178479Sjb goto done; 1914178479Sjb } 1915211554Srpaulo#if !defined(sun) 1916211554Srpaulo /* 1917211554Srpaulo * FreeBSD's ld(1) is not instructed to interpret and add 1918211554Srpaulo * correctly the SUNW_dof section present in tfile. 1919211554Srpaulo * We use libelf to add this section manually and hope the next 1920211554Srpaulo * ld invocation won't remove it. 1921211554Srpaulo */ 1922211554Srpaulo elf_version(EV_CURRENT); 1923211554Srpaulo if ((efd = open(file, O_RDWR, 0)) < 0) { 1924211554Srpaulo ret = dt_link_error(dtp, NULL, -1, NULL, 1925211554Srpaulo "failed to open file %s: %s", 1926211554Srpaulo file, strerror(errno)); 1927211554Srpaulo goto done; 1928211554Srpaulo } 1929211554Srpaulo if ((e = elf_begin(efd, ELF_C_RDWR, NULL)) == NULL) { 1930211554Srpaulo close(efd); 1931211554Srpaulo ret = dt_link_error(dtp, NULL, -1, NULL, 1932211554Srpaulo "failed to open elf file: %s", 1933211554Srpaulo elf_errmsg(elf_errno())); 1934211554Srpaulo goto done; 1935211554Srpaulo } 1936211554Srpaulo /* 1937211554Srpaulo * Add the string '.SUWN_dof' to the shstrtab section. 1938211554Srpaulo */ 1939211554Srpaulo elf_getshdrstrndx(e, &stridx); 1940211554Srpaulo scn = elf_getscn(e, stridx); 1941211554Srpaulo gelf_getshdr(scn, &shdr); 1942211554Srpaulo data = elf_newdata(scn); 1943211554Srpaulo data->d_off = shdr.sh_size; 1944211554Srpaulo data->d_buf = ".SUNW_dof"; 1945211554Srpaulo data->d_size = 10; 1946211554Srpaulo data->d_type = ELF_T_BYTE; 1947211554Srpaulo loc = shdr.sh_size; 1948211554Srpaulo shdr.sh_size += data->d_size; 1949211554Srpaulo gelf_update_shdr(scn, &shdr); 1950211554Srpaulo /* 1951211554Srpaulo * Construct the .SUNW_dof section. 1952211554Srpaulo */ 1953211554Srpaulo scn = elf_newscn(e); 1954211554Srpaulo data = elf_newdata(scn); 1955211554Srpaulo buf = mmap(NULL, dof->dofh_filesz, PROT_READ, MAP_SHARED, 1956211554Srpaulo fd, 0); 1957211554Srpaulo if (buf == MAP_FAILED) { 1958211554Srpaulo ret = dt_link_error(dtp, NULL, -1, NULL, 1959211554Srpaulo "failed to mmap buffer %s", strerror(errno)); 1960211554Srpaulo elf_end(e); 1961211554Srpaulo close(efd); 1962211554Srpaulo goto done; 1963211554Srpaulo } 1964211554Srpaulo data->d_buf = buf; 1965211554Srpaulo data->d_align = 4; 1966211554Srpaulo data->d_size = dof->dofh_filesz; 1967211554Srpaulo data->d_version = EV_CURRENT; 1968211554Srpaulo gelf_getshdr(scn, &shdr); 1969211554Srpaulo shdr.sh_name = loc; 1970211554Srpaulo shdr.sh_flags = SHF_ALLOC; 1971211554Srpaulo /* 1972211554Srpaulo * Actually this should be SHT_SUNW_dof, but FreeBSD's ld(1) 1973211554Srpaulo * will remove this 'unknown' section when we try to create an 1974211554Srpaulo * executable using the object we are modifying, so we stop 1975211554Srpaulo * playing by the rules and use SHT_PROGBITS. 1976211554Srpaulo * Also, note that our drti has modifications to handle this. 1977211554Srpaulo */ 1978211554Srpaulo shdr.sh_type = SHT_PROGBITS; 1979211554Srpaulo shdr.sh_addralign = 4; 1980211554Srpaulo gelf_update_shdr(scn, &shdr); 1981211554Srpaulo if (elf_update(e, ELF_C_WRITE) < 0) { 1982211554Srpaulo ret = dt_link_error(dtp, NULL, -1, NULL, 1983211554Srpaulo "failed to add the SUNW_dof section: %s", 1984211554Srpaulo elf_errmsg(elf_errno())); 1985211554Srpaulo munmap(buf, dof->dofh_filesz); 1986211554Srpaulo elf_end(e); 1987211554Srpaulo close(efd); 1988211554Srpaulo goto done; 1989211554Srpaulo } 1990211554Srpaulo munmap(buf, dof->dofh_filesz); 1991211554Srpaulo elf_end(e); 1992211554Srpaulo close(efd); 1993211554Srpaulo#endif 1994211554Srpaulo (void) close(fd); /* release temporary file */ 1995178479Sjb } else { 1996178479Sjb (void) close(fd); 1997178479Sjb } 1998178479Sjb 1999178479Sjbdone: 2000178479Sjb dtrace_dof_destroy(dtp, dof); 2001178573Sjb 2002178573Sjb#if !defined(sun) 2003178573Sjb unlink(tfile); 2004178573Sjb#endif 2005178479Sjb return (ret); 2006178479Sjb} 2007